mm.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. #include "mm.h"
  2. #include "slab.h"
  3. #include <common/printk.h>
  4. #include <common/kprint.h>
  5. #include <driver/multiboot2/multiboot2.h>
  6. #include <process/process.h>
  7. #include <common/compiler.h>
  8. #include <common/errno.h>
  9. #include <debug/traceback/traceback.h>
  10. static ul Total_Memory = 0;
  11. static ul total_2M_pages = 0;
  12. static ul root_page_table_phys_addr = 0; // 内核层根页表的物理地址
  13. #pragma GCC push_options
  14. #pragma GCC optimize("O0")
  15. struct memory_desc memory_management_struct = {{0}, 0};
  16. /**
  17. * @brief 虚拟地址长度所需要的entry数量
  18. *
  19. */
  20. typedef struct
  21. {
  22. int64_t num_PML4E;
  23. int64_t num_PDPTE;
  24. int64_t num_PDE;
  25. int64_t num_PTE;
  26. } mm_pgt_entry_num_t;
  27. /**
  28. * @brief 计算虚拟地址长度对应的页表entry数量
  29. *
  30. * @param length 长度
  31. * @param ent 返回的entry数量结构体
  32. */
  33. static void mm_calculate_entry_num(uint64_t length, mm_pgt_entry_num_t *ent)
  34. {
  35. if (ent == NULL)
  36. return;
  37. ent->num_PML4E = (length + (1UL << PAGE_GDT_SHIFT) - 1) >> PAGE_GDT_SHIFT;
  38. ent->num_PDPTE = (length + PAGE_1G_SIZE - 1) >> PAGE_1G_SHIFT;
  39. ent->num_PDE = (length + PAGE_2M_SIZE - 1) >> PAGE_2M_SHIFT;
  40. ent->num_PTE = (length + PAGE_4K_SIZE - 1) >> PAGE_4K_SHIFT;
  41. }
  42. /**
  43. * @brief 从页表中获取pdt页表项的内容
  44. *
  45. * @param proc_page_table_addr 页表的地址
  46. * @param is_phys 页表地址是否为物理地址
  47. * @param virt_addr_start 要清除的虚拟地址的起始地址
  48. * @param length 要清除的区域的长度
  49. * @param clear 是否清除标志位
  50. */
  51. uint64_t mm_get_PDE(ul proc_page_table_addr, bool is_phys, ul virt_addr, bool clear);
  52. /**
  53. * @brief 检查页表是否存在不为0的页表项
  54. *
  55. * @param ptr 页表基指针
  56. * @return int8_t 存在 -> 1
  57. * 不存在 -> 0
  58. */
  59. int8_t mm_check_page_table(uint64_t *ptr)
  60. {
  61. for (int i = 0; i < 512; ++i, ++ptr)
  62. {
  63. if (*ptr != 0)
  64. return 1;
  65. }
  66. return 0;
  67. }
  68. void mm_init()
  69. {
  70. kinfo("Initializing memory management unit...");
  71. // 设置内核程序不同部分的起止地址
  72. memory_management_struct.kernel_code_start = (ul)&_text;
  73. memory_management_struct.kernel_code_end = (ul)&_etext;
  74. memory_management_struct.kernel_data_end = (ul)&_edata;
  75. memory_management_struct.rodata_end = (ul)&_erodata;
  76. memory_management_struct.start_brk = (ul)&_end;
  77. struct multiboot_mmap_entry_t mb2_mem_info[512];
  78. int count;
  79. multiboot2_iter(multiboot2_get_memory, mb2_mem_info, &count);
  80. for (int i = 0; i < count; ++i)
  81. {
  82. //可用的内存
  83. if (mb2_mem_info->type == 1)
  84. Total_Memory += mb2_mem_info->len;
  85. kdebug("[i=%d] mb2_mem_info[i].type=%d, mb2_mem_info[i].addr=%#018lx", i, mb2_mem_info[i].type, mb2_mem_info[i].addr);
  86. // 保存信息到mms
  87. memory_management_struct.e820[i].BaseAddr = mb2_mem_info[i].addr;
  88. memory_management_struct.e820[i].Length = mb2_mem_info[i].len;
  89. memory_management_struct.e820[i].type = mb2_mem_info[i].type;
  90. memory_management_struct.len_e820 = i;
  91. // 脏数据
  92. if (mb2_mem_info[i].type > 4 || mb2_mem_info[i].len == 0 || mb2_mem_info[i].type < 1)
  93. break;
  94. }
  95. printk("[ INFO ] Total amounts of RAM : %ld bytes\n", Total_Memory);
  96. // 计算有效内存页数
  97. for (int i = 0; i < memory_management_struct.len_e820; ++i)
  98. {
  99. if (memory_management_struct.e820[i].type != 1)
  100. continue;
  101. // 将内存段的起始物理地址按照2M进行对齐
  102. ul addr_start = PAGE_2M_ALIGN(memory_management_struct.e820[i].BaseAddr);
  103. // 将内存段的终止物理地址的低2M区域清空,以实现对齐
  104. ul addr_end = ((memory_management_struct.e820[i].BaseAddr + memory_management_struct.e820[i].Length) & PAGE_2M_MASK);
  105. // 内存段不可用
  106. if (addr_end <= addr_start)
  107. continue;
  108. total_2M_pages += ((addr_end - addr_start) >> PAGE_2M_SHIFT);
  109. }
  110. kinfo("Total amounts of 2M pages : %ld.", total_2M_pages);
  111. // 物理地址空间的最大地址(包含了物理内存、内存空洞、ROM等)
  112. ul max_addr = memory_management_struct.e820[memory_management_struct.len_e820].BaseAddr + memory_management_struct.e820[memory_management_struct.len_e820].Length;
  113. // 初始化mms的bitmap
  114. // bmp的指针指向截止位置的4k对齐的上边界(防止修改了别的数据)
  115. memory_management_struct.bmp = (unsigned long *)((memory_management_struct.start_brk + PAGE_4K_SIZE - 1) & PAGE_4K_MASK);
  116. memory_management_struct.bits_size = max_addr >> PAGE_2M_SHIFT; // 物理地址空间的最大页面数
  117. memory_management_struct.bmp_len = (((unsigned long)(max_addr >> PAGE_2M_SHIFT) + sizeof(unsigned long) * 8 - 1) / 8) & (~(sizeof(unsigned long) - 1)); // bmp由多少个unsigned long变量组成
  118. // 初始化bitmap, 先将整个bmp空间全部置位。稍后再将可用物理内存页复位。
  119. memset(memory_management_struct.bmp, 0xff, memory_management_struct.bmp_len);
  120. // 初始化内存页结构
  121. // 将页结构映射于bmp之后
  122. memory_management_struct.pages_struct = (struct Page *)(((unsigned long)memory_management_struct.bmp + memory_management_struct.bmp_len + PAGE_4K_SIZE - 1) & PAGE_4K_MASK);
  123. memory_management_struct.count_pages = max_addr >> PAGE_2M_SHIFT;
  124. memory_management_struct.pages_struct_len = ((max_addr >> PAGE_2M_SHIFT) * sizeof(struct Page) + sizeof(long) - 1) & (~(sizeof(long) - 1));
  125. // 将pages_struct全部清空,以备后续初始化
  126. memset(memory_management_struct.pages_struct, 0x00, memory_management_struct.pages_struct_len); // init pages memory
  127. // 初始化内存区域
  128. memory_management_struct.zones_struct = (struct Zone *)(((ul)memory_management_struct.pages_struct + memory_management_struct.pages_struct_len + PAGE_4K_SIZE - 1) & PAGE_4K_MASK);
  129. // 由于暂时无法计算zone结构体的数量,因此先将其设为0
  130. memory_management_struct.count_zones = 0;
  131. // zones-struct 成员变量暂时按照5个来计算
  132. memory_management_struct.zones_struct_len = (10 * sizeof(struct Zone) + sizeof(ul) - 1) & (~(sizeof(ul) - 1));
  133. memset(memory_management_struct.zones_struct, 0x00, memory_management_struct.zones_struct_len);
  134. // ==== 遍历e820数组,完成成员变量初始化工作 ===
  135. for (int i = 0; i < memory_management_struct.len_e820; ++i)
  136. {
  137. if (memory_management_struct.e820[i].type != 1) // 不是操作系统可以使用的物理内存
  138. continue;
  139. ul addr_start = PAGE_2M_ALIGN(memory_management_struct.e820[i].BaseAddr);
  140. ul addr_end = (memory_management_struct.e820[i].BaseAddr + memory_management_struct.e820[i].Length) & PAGE_2M_MASK;
  141. if (addr_end <= addr_start)
  142. continue;
  143. // zone init
  144. struct Zone *z = memory_management_struct.zones_struct + memory_management_struct.count_zones;
  145. ++memory_management_struct.count_zones;
  146. z->zone_addr_start = addr_start;
  147. z->zone_addr_end = addr_end;
  148. z->zone_length = addr_end - addr_start;
  149. z->count_pages_using = 0;
  150. z->count_pages_free = (addr_end - addr_start) >> PAGE_2M_SHIFT;
  151. z->total_pages_link = 0;
  152. z->attr = 0;
  153. z->gmd_struct = &memory_management_struct;
  154. z->count_pages = (addr_end - addr_start) >> PAGE_2M_SHIFT;
  155. z->pages_group = (struct Page *)(memory_management_struct.pages_struct + (addr_start >> PAGE_2M_SHIFT));
  156. // 初始化页
  157. struct Page *p = z->pages_group;
  158. for (int j = 0; j < z->count_pages; ++j, ++p)
  159. {
  160. p->zone = z;
  161. p->addr_phys = addr_start + PAGE_2M_SIZE * j;
  162. p->attr = 0;
  163. p->ref_counts = 0;
  164. p->age = 0;
  165. // 将bmp中对应的位 复位
  166. *(memory_management_struct.bmp + ((p->addr_phys >> PAGE_2M_SHIFT) >> 6)) ^= (1UL << ((p->addr_phys >> PAGE_2M_SHIFT) % 64));
  167. }
  168. }
  169. // 初始化0~2MB的物理页
  170. // 由于这个区间的内存由多个内存段组成,因此不会被以上代码初始化,需要我们手动配置page[0]。
  171. memory_management_struct.pages_struct->zone = memory_management_struct.zones_struct;
  172. memory_management_struct.pages_struct->addr_phys = 0UL;
  173. set_page_attr(memory_management_struct.pages_struct, PAGE_PGT_MAPPED | PAGE_KERNEL_INIT | PAGE_KERNEL);
  174. memory_management_struct.pages_struct->ref_counts = 1;
  175. memory_management_struct.pages_struct->age = 0;
  176. // 将第0页的标志位给置上
  177. //*(memory_management_struct.bmp) |= 1UL;
  178. // 计算zone结构体的总长度(按照64位对齐)
  179. memory_management_struct.zones_struct_len = (memory_management_struct.count_zones * sizeof(struct Zone) + sizeof(ul) - 1) & (~(sizeof(ul) - 1));
  180. ZONE_DMA_INDEX = 0;
  181. ZONE_NORMAL_INDEX = 0;
  182. ZONE_UNMAPPED_INDEX = 0;
  183. /*
  184. for (int i = 0; i < memory_management_struct.count_zones; ++i)
  185. {
  186. struct Zone *z = memory_management_struct.zones_struct + i;
  187. // printk_color(ORANGE, BLACK, "zone_addr_start:%#18lx, zone_addr_end:%#18lx, zone_length:%#18lx, pages_group:%#18lx, count_pages:%#18lx\n",
  188. // z->zone_addr_start, z->zone_addr_end, z->zone_length, z->pages_group, z->count_pages);
  189. // 1GB以上的内存空间不做映射
  190. // if (z->zone_addr_start >= 0x100000000 && (!ZONE_UNMAPPED_INDEX))
  191. // ZONE_UNMAPPED_INDEX = i;
  192. }
  193. */
  194. // kdebug("ZONE_DMA_INDEX=%d\tZONE_NORMAL_INDEX=%d\tZONE_UNMAPPED_INDEX=%d", ZONE_DMA_INDEX, ZONE_NORMAL_INDEX, ZONE_UNMAPPED_INDEX);
  195. // 设置内存页管理结构的地址,预留了一段空间,防止内存越界。
  196. memory_management_struct.end_of_struct = (ul)((ul)memory_management_struct.zones_struct + memory_management_struct.zones_struct_len + sizeof(long) * 32) & (~(sizeof(long) - 1));
  197. // printk_color(ORANGE, BLACK, "code_start:%#18lx, code_end:%#18lx, data_end:%#18lx, kernel_end:%#18lx, end_of_struct:%#18lx\n",
  198. // memory_management_struct.kernel_code_start, memory_management_struct.kernel_code_end, memory_management_struct.kernel_data_end, memory_management_struct.kernel_end, memory_management_struct.end_of_struct);
  199. // 初始化内存管理单元结构所占的物理页的结构体
  200. ul mms_max_page = (virt_2_phys(memory_management_struct.end_of_struct) >> PAGE_2M_SHIFT); // 内存管理单元所占据的序号最大的物理页
  201. // kdebug("mms_max_page=%ld", mms_max_page);
  202. struct Page *tmp_page = NULL;
  203. ul page_num;
  204. // 第0个page已经在上方配置
  205. for (ul j = 1; j <= mms_max_page; ++j)
  206. {
  207. tmp_page = memory_management_struct.pages_struct + j;
  208. page_init(tmp_page, PAGE_PGT_MAPPED | PAGE_KERNEL | PAGE_KERNEL_INIT);
  209. page_num = tmp_page->addr_phys >> PAGE_2M_SHIFT;
  210. *(memory_management_struct.bmp + (page_num >> 6)) |= (1UL << (page_num % 64));
  211. ++tmp_page->zone->count_pages_using;
  212. --tmp_page->zone->count_pages_free;
  213. }
  214. kinfo("Memory management unit initialize complete!");
  215. flush_tlb();
  216. // 初始化slab内存池
  217. slab_init();
  218. page_table_init();
  219. // init_frame_buffer();
  220. }
  221. /**
  222. * @brief 初始化内存页
  223. *
  224. * @param page 内存页结构体
  225. * @param flags 标志位
  226. * 本函数只负责初始化内存页,允许对同一页面进行多次初始化
  227. * 而维护计数器及置位bmp标志位的功能,应当在分配页面的时候手动完成
  228. * @return unsigned long
  229. */
  230. unsigned long page_init(struct Page *page, ul flags)
  231. {
  232. page->attr |= flags;
  233. // 若页面的引用计数为0或是共享页,增加引用计数
  234. if ((!page->ref_counts) || (page->attr & PAGE_SHARED))
  235. {
  236. ++page->ref_counts;
  237. barrier();
  238. ++page->zone->total_pages_link;
  239. }
  240. return 0;
  241. }
  242. /**
  243. * @brief 从已初始化的页结构中搜索符合申请条件的、连续num个struct page
  244. *
  245. * @param zone_select 选择内存区域, 可选项:dma, mapped in pgt(normal), unmapped in pgt
  246. * @param num 需要申请的连续内存页的数量 num<64
  247. * @param flags 将页面属性设置成flag
  248. * @return struct Page*
  249. */
  250. struct Page *alloc_pages(unsigned int zone_select, int num, ul flags)
  251. {
  252. ul zone_start = 0, zone_end = 0;
  253. if (num >= 64 && num <= 0)
  254. {
  255. kerror("alloc_pages(): num is invalid.");
  256. return NULL;
  257. }
  258. ul attr = flags;
  259. switch (zone_select)
  260. {
  261. case ZONE_DMA:
  262. // DMA区域
  263. zone_start = 0;
  264. zone_end = ZONE_DMA_INDEX;
  265. attr |= PAGE_PGT_MAPPED;
  266. break;
  267. case ZONE_NORMAL:
  268. zone_start = ZONE_DMA_INDEX;
  269. zone_end = ZONE_NORMAL_INDEX;
  270. attr |= PAGE_PGT_MAPPED;
  271. break;
  272. case ZONE_UNMAPPED_IN_PGT:
  273. zone_start = ZONE_NORMAL_INDEX;
  274. zone_end = ZONE_UNMAPPED_INDEX;
  275. attr = 0;
  276. break;
  277. default:
  278. kerror("In alloc_pages: param: zone_select incorrect.");
  279. // 返回空
  280. return NULL;
  281. break;
  282. }
  283. for (int i = zone_start; i <= zone_end; ++i)
  284. {
  285. if ((memory_management_struct.zones_struct + i)->count_pages_free < num)
  286. continue;
  287. struct Zone *z = memory_management_struct.zones_struct + i;
  288. // 区域对应的起止页号
  289. ul page_start = (z->zone_addr_start >> PAGE_2M_SHIFT);
  290. ul page_end = (z->zone_addr_end >> PAGE_2M_SHIFT);
  291. ul tmp = 64 - page_start % 64;
  292. for (ul j = page_start; j < page_end; j += ((j % 64) ? tmp : 64))
  293. {
  294. // 按照bmp中的每一个元素进行查找
  295. // 先将p定位到bmp的起始元素
  296. ul *p = memory_management_struct.bmp + (j >> 6);
  297. ul shift = j % 64;
  298. ul tmp_num = ((1UL << num) - 1);
  299. for (ul k = shift; k < 64; ++k)
  300. {
  301. // 寻找连续num个空页
  302. if (!((k ? ((*p >> k) | (*(p + 1) << (64 - k))) : *p) & tmp_num))
  303. {
  304. ul start_page_num = j + k - shift; // 计算得到要开始获取的内存页的页号
  305. for (ul l = 0; l < num; ++l)
  306. {
  307. struct Page *x = memory_management_struct.pages_struct + start_page_num + l;
  308. // 分配页面,手动配置属性及计数器
  309. // 置位bmp
  310. *(memory_management_struct.bmp + ((x->addr_phys >> PAGE_2M_SHIFT) >> 6)) |= (1UL << (x->addr_phys >> PAGE_2M_SHIFT) % 64);
  311. ++(z->count_pages_using);
  312. --(z->count_pages_free);
  313. x->attr = attr;
  314. }
  315. // 成功分配了页面,返回第一个页面的指针
  316. // kwarn("start page num=%d\n", start_page_num);
  317. return (struct Page *)(memory_management_struct.pages_struct + start_page_num);
  318. }
  319. }
  320. }
  321. }
  322. kBUG("Cannot alloc page, ZONE=%d\tnums=%d, total_2M_pages=%d", zone_select, num, total_2M_pages);
  323. return NULL;
  324. }
  325. /**
  326. * @brief 清除页面的引用计数, 计数为0时清空除页表已映射以外的所有属性
  327. *
  328. * @param p 物理页结构体
  329. * @return unsigned long
  330. */
  331. unsigned long page_clean(struct Page *p)
  332. {
  333. --p->ref_counts;
  334. --p->zone->total_pages_link;
  335. // 若引用计数为空,则清空除PAGE_PGT_MAPPED以外的所有属性
  336. if (!p->ref_counts)
  337. {
  338. p->attr &= PAGE_PGT_MAPPED;
  339. }
  340. return 0;
  341. }
  342. /**
  343. * @brief Get the page's attr
  344. *
  345. * @param page 内存页结构体
  346. * @return ul 属性
  347. */
  348. ul get_page_attr(struct Page *page)
  349. {
  350. if (page == NULL)
  351. {
  352. kBUG("get_page_attr(): page == NULL");
  353. return EPAGE_NULL;
  354. }
  355. else
  356. return page->attr;
  357. }
  358. /**
  359. * @brief Set the page's attr
  360. *
  361. * @param page 内存页结构体
  362. * @param flags 属性
  363. * @return ul 错误码
  364. */
  365. ul set_page_attr(struct Page *page, ul flags)
  366. {
  367. if (page == NULL)
  368. {
  369. kBUG("get_page_attr(): page == NULL");
  370. return EPAGE_NULL;
  371. }
  372. else
  373. {
  374. page->attr = flags;
  375. return 0;
  376. }
  377. }
  378. /**
  379. * @brief 释放连续number个内存页
  380. *
  381. * @param page 第一个要被释放的页面的结构体
  382. * @param number 要释放的内存页数量 number<64
  383. */
  384. void free_pages(struct Page *page, int number)
  385. {
  386. if (page == NULL)
  387. {
  388. kerror("free_pages() page is invalid.");
  389. return;
  390. }
  391. if (number >= 64 || number <= 0)
  392. {
  393. kerror("free_pages(): number %d is invalid.", number);
  394. return;
  395. }
  396. ul page_num;
  397. for (int i = 0; i < number; ++i, ++page)
  398. {
  399. page_num = page->addr_phys >> PAGE_2M_SHIFT;
  400. // 复位bmp
  401. *(memory_management_struct.bmp + (page_num >> 6)) &= ~(1UL << (page_num % 64));
  402. // 更新计数器
  403. --page->zone->count_pages_using;
  404. ++page->zone->count_pages_free;
  405. page->attr = 0;
  406. }
  407. return;
  408. }
  409. /**
  410. * @brief 重新初始化页表的函数
  411. * 将所有物理页映射到线性地址空间
  412. */
  413. void page_table_init()
  414. {
  415. kinfo("Re-Initializing page table...");
  416. ul *global_CR3 = get_CR3();
  417. int js = 0;
  418. ul *tmp_addr;
  419. for (int i = 0; i < memory_management_struct.count_zones; ++i)
  420. {
  421. struct Zone *z = memory_management_struct.zones_struct + i;
  422. struct Page *p = z->pages_group;
  423. if (i == ZONE_UNMAPPED_INDEX && ZONE_UNMAPPED_INDEX != 0)
  424. break;
  425. for (int j = 0; j < z->count_pages; ++j)
  426. {
  427. mm_map_proc_page_table((uint64_t)get_CR3(), true, (ul)phys_2_virt(p->addr_phys), p->addr_phys, PAGE_2M_SIZE, PAGE_KERNEL_PAGE, false, true, false);
  428. ++p;
  429. ++js;
  430. }
  431. }
  432. flush_tlb();
  433. kinfo("Page table Initialized. Affects:%d", js);
  434. }
  435. /**
  436. * @brief 将物理地址映射到页表的函数
  437. *
  438. * @param virt_addr_start 要映射到的虚拟地址的起始位置
  439. * @param phys_addr_start 物理地址的起始位置
  440. * @param length 要映射的区域的长度(字节)
  441. * @param flags 标志位
  442. * @param use4k 是否使用4k页
  443. */
  444. int mm_map_phys_addr(ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool use4k)
  445. {
  446. uint64_t global_CR3 = (uint64_t)get_CR3();
  447. return mm_map_proc_page_table(global_CR3, true, virt_addr_start, phys_addr_start, length, flags, false, true, use4k);
  448. }
  449. int mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul flags)
  450. {
  451. uint64_t global_CR3 = (uint64_t)get_CR3();
  452. return mm_map_proc_page_table(global_CR3, true, virt_addr_start, phys_addr_start, length, flags, true, true, false);
  453. }
  454. /**
  455. * @brief 将将物理地址填写到进程的页表的函数
  456. *
  457. * @param proc_page_table_addr 页表的基地址
  458. * @param is_phys 页表的基地址是否为物理地址
  459. * @param virt_addr_start 要映射到的虚拟地址的起始位置
  460. * @param phys_addr_start 物理地址的起始位置
  461. * @param length 要映射的区域的长度(字节)
  462. * @param user 用户态是否可访问
  463. * @param flush 是否刷新tlb
  464. * @param use4k 是否使用4k页
  465. */
  466. int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool user, bool flush, bool use4k)
  467. {
  468. // 计算线性地址对应的pml4页表项的地址
  469. mm_pgt_entry_num_t pgt_num;
  470. mm_calculate_entry_num(length, &pgt_num);
  471. // kdebug("ent1=%d ent2=%d ent3=%d, ent4=%d", pgt_num.num_PML4E, pgt_num.num_PDPTE, pgt_num.num_PDE, pgt_num.num_PTE);
  472. // 已映射的内存大小
  473. uint64_t length_mapped = 0;
  474. uint64_t pml4e_id = ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff);
  475. uint64_t *pml4_ptr;
  476. if (is_phys)
  477. pml4_ptr = phys_2_virt((ul *)((ul)proc_page_table_addr & (~0xfffUL)));
  478. else
  479. pml4_ptr = (ul *)((ul)proc_page_table_addr & (~0xfffUL));
  480. // 循环填写顶层页表
  481. for (; (pgt_num.num_PML4E > 0) && pml4e_id < 512; ++pml4e_id)
  482. {
  483. // 剩余需要处理的pml4E -1
  484. --(pgt_num.num_PML4E);
  485. ul *pml4e_ptr = pml4_ptr + pml4e_id;
  486. // 创建新的二级页表
  487. if (*pml4e_ptr == 0)
  488. {
  489. ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
  490. memset(virt_addr, 0, PAGE_4K_SIZE);
  491. set_pml4t(pml4e_ptr, mk_pml4t(virt_2_phys(virt_addr), (user ? PAGE_USER_PGT : PAGE_KERNEL_PGT)));
  492. }
  493. uint64_t pdpte_id = (((virt_addr_start + length_mapped) >> PAGE_1G_SHIFT) & 0x1ff);
  494. uint64_t *pdpt_ptr = (uint64_t *)phys_2_virt(*pml4e_ptr & (~0xfffUL));
  495. // kdebug("pdpt_ptr=%#018lx", pdpt_ptr);
  496. // 循环填写二级页表
  497. for (; (pgt_num.num_PDPTE > 0) && pdpte_id < 512; ++pdpte_id)
  498. {
  499. --pgt_num.num_PDPTE;
  500. uint64_t *pdpte_ptr = (pdpt_ptr + pdpte_id);
  501. // kdebug("pgt_num.num_PDPTE=%ld pdpte_ptr=%#018lx", pgt_num.num_PDPTE, pdpte_ptr);
  502. // 创建新的三级页表
  503. if (*pdpte_ptr == 0)
  504. {
  505. ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
  506. memset(virt_addr, 0, PAGE_4K_SIZE);
  507. set_pdpt(pdpte_ptr, mk_pdpt(virt_2_phys(virt_addr), (user ? PAGE_USER_DIR : PAGE_KERNEL_DIR)));
  508. // kdebug("created new pdt, *pdpte_ptr=%#018lx, virt_addr=%#018lx", *pdpte_ptr, virt_addr);
  509. }
  510. uint64_t pde_id = (((virt_addr_start + length_mapped) >> PAGE_2M_SHIFT) & 0x1ff);
  511. uint64_t *pd_ptr = (uint64_t *)phys_2_virt(*pdpte_ptr & (~0xfffUL));
  512. // kdebug("pd_ptr=%#018lx, *pd_ptr=%#018lx", pd_ptr, *pd_ptr);
  513. // 循环填写三级页表,初始化2M物理页
  514. for (; (pgt_num.num_PDE > 0) && pde_id < 512; ++pde_id)
  515. {
  516. --pgt_num.num_PDE;
  517. // 计算当前2M物理页对应的pdt的页表项的物理地址
  518. ul *pde_ptr = pd_ptr + pde_id;
  519. // ====== 使用4k页 =======
  520. if (unlikely(use4k))
  521. {
  522. // kdebug("use 4k");
  523. if (*pde_ptr == 0)
  524. {
  525. // 创建四级页表
  526. // kdebug("create PT");
  527. uint64_t *vaddr = kmalloc(PAGE_4K_SIZE, 0);
  528. memset(vaddr, 0, PAGE_4K_SIZE);
  529. set_pdt(pde_ptr, mk_pdt(virt_2_phys(vaddr), (user ? PAGE_USER_PDE : PAGE_KERNEL_PDE)));
  530. }
  531. else if (unlikely(*pde_ptr & (1 << 7)))
  532. {
  533. // 当前页表项已经被映射了2MB物理页
  534. goto failed;
  535. }
  536. uint64_t pte_id = (((virt_addr_start + length_mapped) >> PAGE_4K_SHIFT) & 0x1ff);
  537. uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0x1fffUL));
  538. // 循环填写4级页表,初始化4K页
  539. for (; pgt_num.num_PTE > 0 && pte_id < 512; ++pte_id)
  540. {
  541. --pgt_num.num_PTE;
  542. uint64_t *pte_ptr = pt_ptr + pte_id;
  543. if (unlikely(*pte_ptr != 0))
  544. {
  545. kwarn("pte already exists.");
  546. length_mapped += PAGE_4K_SIZE;
  547. }
  548. set_pt(pte_ptr, mk_pt((ul)phys_addr_start + length_mapped, flags | (user ? PAGE_USER_4K_PAGE : PAGE_KERNEL_4K_PAGE)));
  549. }
  550. }
  551. // ======= 使用2M页 ========
  552. else
  553. {
  554. if (unlikely(*pde_ptr != 0 && user))
  555. {
  556. // kwarn("page already mapped!");
  557. // 如果是用户态可访问的页,则释放当前新获取的物理页
  558. if (likely(((ul)phys_addr_start + length_mapped) < total_2M_pages)) // 校验是否为内存中的物理页
  559. free_pages(Phy_to_2M_Page((ul)phys_addr_start + length_mapped), 1);
  560. length_mapped += PAGE_2M_SIZE;
  561. continue;
  562. }
  563. // 页面写穿,禁止缓存
  564. set_pdt(pde_ptr, mk_pdt((ul)phys_addr_start + length_mapped, flags | (user ? PAGE_USER_PAGE : PAGE_KERNEL_PAGE)));
  565. length_mapped += PAGE_2M_SIZE;
  566. }
  567. }
  568. }
  569. }
  570. if (likely(flush))
  571. flush_tlb();
  572. return 0;
  573. failed:;
  574. kerror("Map memory failed. use4k=%d, vaddr=%#018lx, paddr=%#018lx", use4k, virt_addr_start, phys_addr_start);
  575. return -EFAULT;
  576. }
  577. /**
  578. * @brief 从页表中获取pdt页表项的内容
  579. *
  580. * @param proc_page_table_addr 页表的地址
  581. * @param is_phys 页表地址是否为物理地址
  582. * @param virt_addr_start 要清除的虚拟地址的起始地址
  583. * @param length 要清除的区域的长度
  584. * @param clear 是否清除标志位
  585. */
  586. uint64_t mm_get_PDE(ul proc_page_table_addr, bool is_phys, ul virt_addr, bool clear)
  587. {
  588. ul *tmp;
  589. if (is_phys)
  590. tmp = phys_2_virt((ul *)((ul)proc_page_table_addr & (~0xfffUL)) + ((virt_addr >> PAGE_GDT_SHIFT) & 0x1ff));
  591. else
  592. tmp = (ul *)((ul)proc_page_table_addr & (~0xfffUL)) + ((virt_addr >> PAGE_GDT_SHIFT) & 0x1ff);
  593. // pml4页表项为0
  594. if (*tmp == 0)
  595. return 0;
  596. tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((virt_addr >> PAGE_1G_SHIFT) & 0x1ff));
  597. // pdpt页表项为0
  598. if (*tmp == 0)
  599. return 0;
  600. // 读取pdt页表项
  601. tmp = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr) >> PAGE_2M_SHIFT) & 0x1ff)));
  602. if (clear) // 清除页表项的标志位
  603. return *tmp & (~0x1fff);
  604. else
  605. return *tmp;
  606. }
  607. /**
  608. * @brief 从页表中清除虚拟地址的映射
  609. *
  610. * @param proc_page_table_addr 页表的地址
  611. * @param is_phys 页表地址是否为物理地址
  612. * @param virt_addr_start 要清除的虚拟地址的起始地址
  613. * @param length 要清除的区域的长度
  614. */
  615. void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_start, ul length)
  616. {
  617. // 计算线性地址对应的pml4页表项的地址
  618. mm_pgt_entry_num_t pgt_num;
  619. mm_calculate_entry_num(length, &pgt_num);
  620. // kdebug("ent1=%d ent2=%d ent3=%d, ent4=%d", pgt_num.num_PML4E, pgt_num.num_PDPTE, pgt_num.num_PDE, pgt_num.num_PTE);
  621. // 已取消映射的内存大小
  622. uint64_t length_unmapped = 0;
  623. uint64_t pml4e_id = ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff);
  624. uint64_t *pml4_ptr;
  625. if (is_phys)
  626. pml4_ptr = phys_2_virt((ul *)((ul)proc_page_table_addr & (~0xfffUL)));
  627. else
  628. pml4_ptr = (ul *)((ul)proc_page_table_addr & (~0xfffUL));
  629. // 循环填写顶层页表
  630. for (; (pgt_num.num_PML4E > 0) && pml4e_id < 512; ++pml4e_id)
  631. {
  632. // 剩余需要处理的pml4E -1
  633. --(pgt_num.num_PML4E);
  634. ul *pml4e_ptr = NULL;
  635. pml4e_ptr = pml4_ptr + pml4e_id;
  636. // 二级页表不存在
  637. if (*pml4e_ptr == 0)
  638. {
  639. continue;
  640. }
  641. uint64_t pdpte_id = (((virt_addr_start + length_unmapped) >> PAGE_1G_SHIFT) & 0x1ff);
  642. uint64_t *pdpt_ptr = (uint64_t *)phys_2_virt(*pml4e_ptr & (~0xfffUL));
  643. // kdebug("pdpt_ptr=%#018lx", pdpt_ptr);
  644. // 循环处理二级页表
  645. for (; (pgt_num.num_PDPTE > 0) && pdpte_id < 512; ++pdpte_id)
  646. {
  647. --pgt_num.num_PDPTE;
  648. uint64_t *pdpte_ptr = (pdpt_ptr + pdpte_id);
  649. // kdebug("pgt_num.num_PDPTE=%ld pdpte_ptr=%#018lx", pgt_num.num_PDPTE, pdpte_ptr);
  650. // 三级页表为空
  651. if (*pdpte_ptr == 0)
  652. {
  653. continue;
  654. }
  655. uint64_t pde_id = (((virt_addr_start + length_unmapped) >> PAGE_2M_SHIFT) & 0x1ff);
  656. uint64_t *pd_ptr = (uint64_t *)phys_2_virt(*pdpte_ptr & (~0xfffUL));
  657. // kdebug("pd_ptr=%#018lx, *pd_ptr=%#018lx", pd_ptr, *pd_ptr);
  658. // 循环处理三级页表
  659. for (; (pgt_num.num_PDE > 0) && pde_id < 512; ++pde_id)
  660. {
  661. --pgt_num.num_PDE;
  662. // 计算当前2M物理页对应的pdt的页表项的物理地址
  663. ul *pde_ptr = pd_ptr + pde_id;
  664. // 存在4级页表
  665. if (unlikely(((*pde_ptr) & (1 << 7)) == 0))
  666. {
  667. // 存在4K页
  668. uint64_t pte_id = (((virt_addr_start + length_unmapped) >> PAGE_4K_SHIFT) & 0x1ff);
  669. uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0x1fffUL));
  670. uint64_t *pte_ptr = pt_ptr + pte_id;
  671. // 循环处理4K页表
  672. for (; pgt_num.num_PTE > 0 && pte_id < 512; ++pte_id, ++pte_ptr)
  673. {
  674. --pgt_num.num_PTE;
  675. // todo: 当支持使用slab分配4K内存作为进程的4K页之后,在这里需要释放这些4K对象
  676. *pte_ptr = 0;
  677. length_unmapped += PAGE_4K_SIZE;
  678. }
  679. // 4级页表已经空了,释放页表
  680. if (unlikely(mm_check_page_table(pt_ptr)) == 0)
  681. kfree(pt_ptr);
  682. }
  683. else
  684. {
  685. *pde_ptr = 0;
  686. length_unmapped += PAGE_2M_SIZE;
  687. }
  688. }
  689. // 3级页表已经空了,释放页表
  690. if (unlikely(mm_check_page_table(pd_ptr)) == 0)
  691. kfree(pd_ptr);
  692. }
  693. // 2级页表已经空了,释放页表
  694. if (unlikely(mm_check_page_table(pdpt_ptr)) == 0)
  695. kfree(pdpt_ptr);
  696. }
  697. flush_tlb();
  698. }
  699. /**
  700. * @brief 从mms中寻找Page结构体
  701. *
  702. * @param phys_addr
  703. * @return struct Page*
  704. */
  705. static struct Page *mm_find_page(uint64_t phys_addr, uint32_t zone_select)
  706. {
  707. uint32_t zone_start, zone_end;
  708. switch (zone_select)
  709. {
  710. case ZONE_DMA:
  711. // DMA区域
  712. zone_start = 0;
  713. zone_end = ZONE_DMA_INDEX;
  714. break;
  715. case ZONE_NORMAL:
  716. zone_start = ZONE_DMA_INDEX;
  717. zone_end = ZONE_NORMAL_INDEX;
  718. break;
  719. case ZONE_UNMAPPED_IN_PGT:
  720. zone_start = ZONE_NORMAL_INDEX;
  721. zone_end = ZONE_UNMAPPED_INDEX;
  722. break;
  723. default:
  724. kerror("In mm_find_page: param: zone_select incorrect.");
  725. // 返回空
  726. return NULL;
  727. break;
  728. }
  729. for (int i = zone_start; i <= zone_end; ++i)
  730. {
  731. if ((memory_management_struct.zones_struct + i)->count_pages_using == 0)
  732. continue;
  733. struct Zone *z = memory_management_struct.zones_struct + i;
  734. // 区域对应的起止页号
  735. ul page_start = (z->zone_addr_start >> PAGE_2M_SHIFT);
  736. ul page_end = (z->zone_addr_end >> PAGE_2M_SHIFT);
  737. ul tmp = 64 - page_start % 64;
  738. for (ul j = page_start; j < page_end; j += ((j % 64) ? tmp : 64))
  739. {
  740. // 按照bmp中的每一个元素进行查找
  741. // 先将p定位到bmp的起始元素
  742. ul *p = memory_management_struct.bmp + (j >> 6);
  743. ul shift = j % 64;
  744. for (ul k = shift; k < 64; ++k)
  745. {
  746. if ((*p >> k) & 1) // 若当前页已分配
  747. {
  748. uint64_t page_num = j + k - shift;
  749. struct Page *x = memory_management_struct.pages_struct + page_num;
  750. if (x->addr_phys == phys_addr) // 找到对应的页
  751. return x;
  752. }
  753. }
  754. }
  755. }
  756. return NULL;
  757. }
  758. /**
  759. * @brief 调整堆区域的大小(暂时只能增加堆区域)
  760. *
  761. * @todo 缩小堆区域
  762. * @param old_brk_end_addr 原本的堆内存区域的结束地址
  763. * @param offset 新的地址相对于原地址的偏移量
  764. * @return uint64_t
  765. */
  766. uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset)
  767. {
  768. uint64_t end_addr = PAGE_2M_ALIGN(old_brk_end_addr + offset);
  769. if (offset >= 0)
  770. {
  771. for (uint64_t i = old_brk_end_addr; i < end_addr; i += PAGE_2M_SIZE)
  772. {
  773. // kdebug("map [%#018lx]", i);
  774. mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, i, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true, true, false);
  775. }
  776. current_pcb->mm->brk_end = end_addr;
  777. }
  778. else
  779. {
  780. // 释放堆内存
  781. for (uint64_t i = end_addr; i < old_brk_end_addr; i += PAGE_2M_SIZE)
  782. {
  783. uint64_t phys = mm_get_PDE((uint64_t)phys_2_virt((uint64_t)current_pcb->mm->pgd), false, i, true);
  784. // 找到对应的页
  785. struct Page *p = mm_find_page(phys, ZONE_NORMAL);
  786. if (p == NULL)
  787. {
  788. kerror("cannot find page addr=%#018lx", phys);
  789. return end_addr;
  790. }
  791. free_pages(p, 1);
  792. }
  793. mm_unmap_proc_table((uint64_t)phys_2_virt((uint64_t)current_pcb->mm->pgd), false, end_addr, PAGE_2M_ALIGN(ABS(offset)));
  794. // 在页表中取消映射
  795. }
  796. return end_addr;
  797. }
  798. /**
  799. * @brief 检测指定地址是否已经被映射
  800. *
  801. * @param page_table_phys_addr 页表的物理地址
  802. * @param virt_addr 要检测的地址
  803. * @return true 已经被映射
  804. * @return false
  805. */
  806. bool mm_check_mapped(ul page_table_phys_addr, uint64_t virt_addr)
  807. {
  808. ul *tmp;
  809. tmp = phys_2_virt((ul *)((ul)page_table_phys_addr & (~0xfffUL)) + ((virt_addr >> PAGE_GDT_SHIFT) & 0x1ff));
  810. // pml4页表项为0
  811. if (*tmp == 0)
  812. return 0;
  813. tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((virt_addr >> PAGE_1G_SHIFT) & 0x1ff));
  814. // pdpt页表项为0
  815. if (*tmp == 0)
  816. return 0;
  817. // 读取pdt页表项
  818. tmp = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr) >> PAGE_2M_SHIFT) & 0x1ff)));
  819. // pde页表项为0
  820. if (*tmp == 0)
  821. return 0;
  822. if (*tmp & (1 << 7))
  823. {
  824. // 当前为2M物理页
  825. return true;
  826. }
  827. else
  828. {
  829. // 存在4级页表
  830. tmp = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr) >> PAGE_4K_SHIFT) & 0x1ff)));
  831. if (*tmp != 0)
  832. return true;
  833. else
  834. return false;
  835. }
  836. }
  837. /**
  838. * @brief 检测是否为有效的2M页(物理内存页)
  839. *
  840. * @param paddr 物理地址
  841. * @return int8_t 是 -> 1
  842. * 否 -> 0
  843. */
  844. int8_t mm_is_2M_page(uint64_t paddr)
  845. {
  846. if(likely((paddr >> PAGE_2M_SHIFT)<total_2M_pages))
  847. return 1;
  848. else return 0;
  849. }
  850. #pragma GCC pop_options