page.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. * Copyright (c) 2006-2019, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2019-11-01 Jesven The first version
  9. */
  10. #include <stdint.h>
  11. #include <rthw.h>
  12. #include <rtthread.h>
  13. #ifdef RT_USING_USERSPACE
  14. #include <page.h>
  15. #include <mmu.h>
  16. #define ARCH_PAGE_LIST_SIZE (ARCH_ADDRESS_WIDTH_BITS - ARCH_PAGE_SHIFT)
  17. #define DBG_TAG "PAGE"
  18. #define DBG_LVL DBG_WARNING
  19. #include <rtdbg.h>
  20. struct page
  21. {
  22. struct page *next; // same level next
  23. struct page *pre; // same level pre
  24. uint32_t size_bits; // if is ARCH_ADDRESS_WIDTH_BITS, means not free
  25. };
  26. static struct page* page_start;
  27. static void* page_addr;
  28. static size_t page_nr;
  29. static struct page *page_list[ARCH_PAGE_LIST_SIZE];
  30. size_t rt_page_bits(size_t size)
  31. {
  32. int bit;
  33. bit = __builtin_clz(size);
  34. bit = (31 - bit);
  35. if ((size ^ (1UL << bit)) != 0)
  36. {
  37. bit++;
  38. }
  39. bit -= ARCH_PAGE_SHIFT;
  40. if (bit < 0)
  41. {
  42. bit = 0;
  43. }
  44. return bit;
  45. }
  46. static struct page * addr_to_page(void *addr)
  47. {
  48. size_t off;
  49. if (addr < page_addr)
  50. {
  51. return 0;
  52. }
  53. off = addr - page_addr;
  54. off >>= ARCH_PAGE_SHIFT;
  55. if (off >= page_nr)
  56. {
  57. return 0;
  58. }
  59. return &page_start[off];
  60. }
  61. static void* page_to_addr(struct page* p)
  62. {
  63. if (!p)
  64. {
  65. return 0;
  66. }
  67. return page_addr + ((p - page_start) << ARCH_PAGE_SHIFT);
  68. }
  69. static inline struct page *buddy_get(struct page *p, uint32_t size_bits)
  70. {
  71. size_t addr;
  72. addr = (size_t)page_to_addr(p);
  73. addr ^= (1UL << (size_bits + ARCH_PAGE_SHIFT));
  74. return addr_to_page((void*)addr);
  75. }
  76. static void page_remove(struct page *p, uint32_t size_bits)
  77. {
  78. if (p->pre)
  79. {
  80. p->pre->next = p->next;
  81. }
  82. else
  83. {
  84. page_list[size_bits] = p->next;
  85. }
  86. if (p->next)
  87. {
  88. p->next->pre = p->pre;
  89. }
  90. p->size_bits = ARCH_ADDRESS_WIDTH_BITS;
  91. }
  92. static void page_insert(struct page *p, uint32_t size_bits)
  93. {
  94. p->next = page_list[size_bits];
  95. if (p->next)
  96. {
  97. p->next->pre = p;
  98. }
  99. p->pre = 0;
  100. page_list[size_bits] = p;
  101. p->size_bits = size_bits;
  102. }
  103. static void _pages_free(struct page *p, uint32_t size_bits)
  104. {
  105. uint32_t level = size_bits;
  106. uint32_t high = ARCH_ADDRESS_WIDTH_BITS - size_bits - 1;
  107. struct page *buddy;
  108. while (level < high)
  109. {
  110. buddy = buddy_get(p, level);
  111. if (buddy && buddy->size_bits == level)
  112. {
  113. page_remove(buddy, level);
  114. p = (p < buddy) ? p : buddy;
  115. level++;
  116. }
  117. else
  118. {
  119. break;
  120. }
  121. }
  122. page_insert(p, level);
  123. }
  124. static struct page *_pages_alloc(uint32_t size_bits)
  125. {
  126. struct page *p;
  127. if (page_list[size_bits])
  128. {
  129. p = page_list[size_bits];
  130. page_remove(p, size_bits);
  131. }
  132. else
  133. {
  134. uint32_t level;
  135. uint32_t high = ARCH_ADDRESS_WIDTH_BITS - size_bits - 1;
  136. for (level = size_bits + 1; level <= high; level++)
  137. {
  138. if (page_list[level])
  139. {
  140. break;
  141. }
  142. }
  143. if (level == high + 1)
  144. {
  145. return 0;
  146. }
  147. p = page_list[level];
  148. page_remove(p, level);
  149. while (level > size_bits)
  150. {
  151. page_insert(p, level - 1);
  152. p = buddy_get(p, level - 1);
  153. level--;
  154. }
  155. }
  156. return p;
  157. }
  158. void *rt_pages_alloc(uint32_t size_bits)
  159. {
  160. struct page *p;
  161. rt_base_t level;
  162. level = rt_hw_interrupt_disable();
  163. p = _pages_alloc(size_bits);
  164. rt_hw_interrupt_enable(level);
  165. return page_to_addr(p);
  166. }
  167. void rt_pages_free(void *addr, uint32_t size_bits)
  168. {
  169. struct page *p;
  170. p = addr_to_page(addr);
  171. if (p)
  172. {
  173. rt_base_t level;
  174. level = rt_hw_interrupt_disable();
  175. _pages_free(p, size_bits);
  176. rt_hw_interrupt_enable(level);
  177. }
  178. }
  179. void rt_pageinfo_dump(void)
  180. {
  181. int i;
  182. size_t total = 0;
  183. rt_base_t level;
  184. level = rt_hw_interrupt_disable();
  185. for (i = 0; i < ARCH_PAGE_LIST_SIZE; i++)
  186. {
  187. struct page *p = page_list[i];
  188. rt_kprintf("level %d ", i);
  189. while (p)
  190. {
  191. total += (1UL << i);
  192. rt_kprintf("[0x%08x]", page_to_addr(p));
  193. p = p->next;
  194. }
  195. rt_kprintf("\n");
  196. }
  197. rt_hw_interrupt_enable(level);
  198. rt_kprintf("free pages is %08x\n", total);
  199. rt_kprintf("-------------------------------\n");
  200. }
  201. MSH_CMD_EXPORT(rt_pageinfo_dump, show page info);
  202. void rt_page_get_info(size_t *total_nr, size_t *free_nr)
  203. {
  204. int i;
  205. size_t total_free = 0;
  206. rt_base_t level;
  207. level = rt_hw_interrupt_disable();
  208. for (i = 0; i < ARCH_PAGE_LIST_SIZE; i++)
  209. {
  210. struct page *p = page_list[i];
  211. while (p)
  212. {
  213. total_free += (1UL << i);
  214. p = p->next;
  215. }
  216. }
  217. rt_hw_interrupt_enable(level);
  218. *total_nr = page_nr;
  219. *free_nr = total_free;
  220. }
  221. void rt_page_init(rt_region_t reg)
  222. {
  223. uint32_t align_bits;
  224. uint32_t size_bits;
  225. int i;
  226. LOG_D("split 0x%08x 0x%08x\n", reg.start, reg.end);
  227. reg.start += ARCH_PAGE_MASK;
  228. reg.start &= ~ARCH_PAGE_MASK;
  229. reg.end &= ~ARCH_PAGE_MASK;
  230. {
  231. int nr = ARCH_PAGE_SIZE/sizeof(struct page);
  232. int total = (reg.end - reg.start) >> ARCH_PAGE_SHIFT;
  233. int mnr = (total + nr)/(nr + 1);
  234. LOG_D("nr = 0x%08x\n", nr);
  235. LOG_D("total = 0x%08x\n", total);
  236. LOG_D("mnr = 0x%08x\n", mnr);
  237. page_start = (struct page*)reg.start;
  238. reg.start += (mnr << ARCH_PAGE_SHIFT);
  239. page_addr = (void*)reg.start;
  240. page_nr = (reg.end - reg.start) >> ARCH_PAGE_SHIFT;
  241. }
  242. LOG_D("align 0x%08x 0x%08x\n", reg.start, reg.end);
  243. /* init page struct */
  244. for (i = 0; i < page_nr; i++)
  245. {
  246. page_start[i].size_bits = ARCH_ADDRESS_WIDTH_BITS;
  247. }
  248. /* init free list */
  249. for (i = 0; i < ARCH_PAGE_LIST_SIZE; i++)
  250. {
  251. page_list[i] = 0;
  252. }
  253. while (reg.start != reg.end)
  254. {
  255. size_bits = ARCH_ADDRESS_WIDTH_BITS - 1 - __builtin_clz(reg.end - reg.start);
  256. align_bits = __builtin_ctz(reg.start);
  257. if (align_bits < size_bits)
  258. {
  259. size_bits = align_bits;
  260. }
  261. _pages_free(addr_to_page((void*)reg.start), size_bits - ARCH_PAGE_SHIFT);
  262. reg.start += (1U << size_bits);
  263. }
  264. }
  265. #endif