Browse Source

:bug: 修复了需要映射的物理地址跨越页表时,产生内存越界的问题

fslongjin 2 years ago
parent
commit
8d8fd391fb
7 changed files with 127 additions and 159 deletions
  1. 1 1
      README.md
  2. 1 1
      README_EN.md
  3. 1 1
      kernel/common/printk.c
  4. 116 148
      kernel/mm/mm.c
  5. 0 1
      kernel/mm/mm.h
  6. 1 1
      kernel/process/process.c
  7. 7 6
      kernel/smp/smp.c

+ 1 - 1
README.md

@@ -68,7 +68,7 @@ grub==2.06
 
 - [x] VFS虚拟文件系统
 
-- [ ] 解析ELF文件格式
+- [x] 解析ELF文件格式
 
 - [x] 浮点数支持
 

+ 1 - 1
README_EN.md

@@ -68,7 +68,7 @@ grub==2.06
 
 - [x] virtual file system
 
-- [ ] Parsing ELF file format
+- [x] Parsing ELF file format
 
 - [x] Floating point support
 

+ 1 - 1
kernel/common/printk.c

@@ -50,7 +50,7 @@ int printk_init(const int char_size_x, const int char_size_y)
 
     // ======== 临时的将物理地址填写到0x0000000003000000处 之后会在mm内将帧缓存区重新映射=====
 
-    global_CR3 = get_CR3();
+    ul global_CR3 = (ul)get_CR3();
     ul fb_virt_addr = (ul)pos.FB_address;
     ul fb_phys_addr = VBE_FB_phys_addr;
 

+ 116 - 148
kernel/mm/mm.c

@@ -15,10 +15,10 @@ static ul root_page_table_phys_addr = 0; // 内核层根页表的物理地址
  */
 typedef struct
 {
-    uint64_t num_PML4E;
-    uint64_t *num_PDPTE;
-    uint64_t *num_PDE;
-    uint64_t num_PTE;
+    int64_t num_PML4E;
+    int64_t num_PDPTE;
+    int64_t num_PDE;
+    int64_t num_PTE;
 } mm_pgt_entry_num_t;
 
 /**
@@ -230,7 +230,6 @@ void mm_init()
         --tmp_page->zone->count_pages_free;
     }
 
-    global_CR3 = get_CR3();
     // root_page_table_phys_addr = global_CR3;
     // kdebug("global_CR3\t:%#018lx", global_CR3);
     // kdebug("*global_CR3\t:%#018lx", *phys_2_virt(global_CR3) & (~0xff));
@@ -460,7 +459,7 @@ void free_pages(struct Page *page, int number)
 void page_table_init()
 {
     kinfo("Re-Initializing page table...");
-    global_CR3 = get_CR3();
+    ul *global_CR3 = get_CR3();
     /*
     // 由于CR3寄存器的[11..0]位是PCID标志位,因此将低12位置0后,就是PML4页表的基地址
     ul *pml4_addr = (ul *)((ul)phys_2_virt((ul)global_CR3 & (~0xfffUL)));
@@ -499,39 +498,11 @@ void page_table_init()
 void init_frame_buffer()
 {
     kinfo("Re-mapping VBE frame buffer...");
-    global_CR3 = get_CR3();
+    uint64_t global_CR3 = (uint64_t)get_CR3();
     ul fb_virt_addr = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + FRAME_BUFFER_MAPPING_OFFSET;
     ul fb_phys_addr = get_VBE_FB_phys_addr();
-
-    // 计算帧缓冲区的线性地址对应的pml4页表项的地址
-    ul *tmp = phys_2_virt((ul *)((ul)global_CR3 & (~0xfffUL)) + ((fb_virt_addr >> PAGE_GDT_SHIFT) & 0x1ff));
-    if (*tmp == 0)
-    {
-        ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
-        memset(virt_addr, 0, PAGE_4K_SIZE);
-        set_pml4t(tmp, mk_pml4t(virt_2_phys(virt_addr), PAGE_KERNEL_PGT));
-    }
-
-    tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((fb_virt_addr >> PAGE_1G_SHIFT) & 0x1ff));
-
-    if (*tmp == 0)
-    {
-        ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
-        memset(virt_addr, 0, PAGE_4K_SIZE);
-        set_pdpt(tmp, mk_pdpt(virt_2_phys(virt_addr), PAGE_KERNEL_DIR));
-    }
-
-    ul vbe_fb_length = get_VBE_FB_length();
-    ul *tmp1;
-    // 初始化2M物理页
-    for (ul i = 0; i < (vbe_fb_length << 2); i += PAGE_2M_SIZE)
-    {
-        // 计算当前2M物理页对应的pdt的页表项的物理地址
-        tmp1 = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + (((ul)(fb_virt_addr + i) >> PAGE_2M_SHIFT) & 0x1ff));
-
-        // 页面写穿,禁止缓存
-        set_pdt(tmp1, mk_pdt((ul)fb_phys_addr + i, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD));
-    }
+    // mm_map_phys_addr(fb_virt_addr, fb_phys_addr, get_VBE_FB_length(), PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+    mm_map_proc_page_table(global_CR3, true, fb_virt_addr, fb_phys_addr, get_VBE_FB_length() << 2, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
 
     set_pos_VBE_FB_addr((uint *)fb_virt_addr);
     flush_tlb();
@@ -547,78 +518,15 @@ void init_frame_buffer()
  */
 void mm_map_phys_addr(ul virt_addr_start, ul phys_addr_start, ul length, ul flags)
 {
-    global_CR3 = get_CR3();
-
-    // 计算线性地址对应的pml4页表项的地址
-    ul *tmp = phys_2_virt((ul *)((ul)global_CR3 & (~0xfffUL)) + ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff));
-    if (*tmp == 0)
-    {
-        ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
-        memset(virt_addr, 0, PAGE_4K_SIZE);
-        set_pml4t(tmp, mk_pml4t(virt_2_phys(virt_addr), PAGE_KERNEL_PGT));
-    }
-
-    tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((virt_addr_start >> PAGE_1G_SHIFT) & 0x1ff));
-
-    if (*tmp == 0)
-    {
-        ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
-        memset(virt_addr, 0, PAGE_4K_SIZE);
-        set_pdpt(tmp, mk_pdpt(virt_2_phys(virt_addr), PAGE_KERNEL_DIR));
-    }
+    uint64_t global_CR3 = (uint64_t)get_CR3();
 
-    ul *tmp1;
-    // 初始化2M物理页
-    for (ul i = 0; i < (length); i += PAGE_2M_SIZE)
-    {
-        // 计算当前2M物理页对应的pdt的页表项的物理地址
-        tmp1 = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr_start + i) >> PAGE_2M_SHIFT) & 0x1ff));
-
-        // 页面写穿,禁止缓存
-        set_pdt(tmp1, mk_pdt((ul)phys_addr_start + i, flags));
-    }
-
-    flush_tlb();
+    mm_map_proc_page_table(global_CR3, true, virt_addr_start, phys_addr_start, length, flags, false);
 }
 
 void mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul flags)
 {
-    global_CR3 = get_CR3();
-
-    // 计算线性地址对应的pml4页表项的地址
-    ul *tmp = phys_2_virt((ul *)((ul)global_CR3 & (~0xfffUL)) + ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff));
-    if (*tmp == 0)
-    {
-        ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
-        memset(virt_addr, 0, PAGE_4K_SIZE);
-        set_pml4t(tmp, mk_pml4t(virt_2_phys(virt_addr), PAGE_USER_PGT));
-    }
-    else
-        kdebug("*tmp != 0!!!    \t tmp = %#018lx\t *tmp = %#018lx", tmp, *tmp);
-
-    tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((virt_addr_start >> PAGE_1G_SHIFT) & 0x1ff));
-
-    if (*tmp == 0)
-    {
-        ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
-        memset(virt_addr, 0, PAGE_4K_SIZE);
-        set_pdpt(tmp, mk_pdpt(virt_2_phys(virt_addr), PAGE_USER_DIR));
-    }
-    else
-        kdebug("*tmp != 0!!!    \t tmp = %#018lx\t *tmp = %#018lx", tmp, *tmp);
-
-    ul *tmp1;
-    // 初始化2M物理页
-    for (ul i = 0; i < (length); i += PAGE_2M_SIZE)
-    {
-        // 计算当前2M物理页对应的pdt的页表项的物理地址
-        tmp1 = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr_start + i) >> PAGE_2M_SHIFT) & 0x1ff));
-
-        // 页面写穿,禁止缓存
-        set_pdt(tmp1, mk_pdt((ul)phys_addr_start + i, flags | PAGE_USER_PAGE));
-    }
-
-    flush_tlb();
+    uint64_t global_CR3 = (uint64_t)get_CR3();
+    mm_map_proc_page_table(global_CR3, true, virt_addr_start, phys_addr_start, length, flags, true);
 }
 
 /**
@@ -634,51 +542,73 @@ void mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul
 void 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)
 {
 
-    // kdebug("proc_page_table_addr=%#018lx", proc_page_table_addr);
     // 计算线性地址对应的pml4页表项的地址
     mm_pgt_entry_num_t pgt_num;
     mm_calculate_entry_num(length, &pgt_num);
-    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);
+    // 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);
+    // 已映射的内存大小
+    uint64_t length_mapped = 0;
 
     uint64_t pml4e_id = ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff);
+    uint64_t *pml4_ptr;
+    if (is_phys)
+        pml4_ptr = phys_2_virt((ul *)((ul)proc_page_table_addr & (~0xfffUL)));
+    else
+        pml4_ptr = (ul *)((ul)proc_page_table_addr & (~0xfffUL));
+
     // 循环填写顶层页表
-    for (int num_pml4e = 0; num_pml4e < pgt_num.num_PML4E && pml4e_id < 512; ++num_pml4e, ++pml4e_id)
+    for (; (pgt_num.num_PML4E > 0) && pml4e_id < 512; ++pml4e_id)
     {
-        ul *tmp;
-        if (is_phys)
-            tmp = phys_2_virt((ul *)((ul)proc_page_table_addr & (~0xfffUL)) + pml4e_id);
-        else
-            tmp = (ul *)((ul)proc_page_table_addr & (~0xfffUL) + pml4e_id);
+        // 剩余需要处理的pml4E -1
+        --(pgt_num.num_PML4E);
 
-        if (*tmp == 0)
+        ul *pml4e_ptr = pml4_ptr + pml4e_id;
+
+        // 创建新的二级页表
+        if (*pml4e_ptr == 0)
         {
             ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
             memset(virt_addr, 0, PAGE_4K_SIZE);
-            set_pml4t(tmp, mk_pml4t(virt_2_phys(virt_addr), (user ? PAGE_USER_PGT : PAGE_KERNEL_PGT)));
+            set_pml4t(pml4e_ptr, mk_pml4t(virt_2_phys(virt_addr), (user ? PAGE_USER_PGT : PAGE_KERNEL_PGT)));
         }
 
-        tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((virt_addr_start >> PAGE_1G_SHIFT) & 0x1ff));
+        uint64_t pdpte_id = (((virt_addr_start + length_mapped) >> PAGE_1G_SHIFT) & 0x1ff);
+        uint64_t *pdpt_ptr = (uint64_t *)phys_2_virt(*pml4e_ptr & (~0xfffUL));
+        // kdebug("pdpt_ptr=%#018lx", pdpt_ptr);
 
-        if (*tmp == 0)
+        // 循环填写二级页表
+        for (; (pgt_num.num_PDPTE > 0) && pdpte_id < 512; ++pdpte_id)
         {
-            ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
-            memset(virt_addr, 0, PAGE_4K_SIZE);
-            set_pdpt(tmp, mk_pdpt(virt_2_phys(virt_addr), (user ? PAGE_USER_DIR : PAGE_KERNEL_DIR)));
-        }
+            --pgt_num.num_PDPTE;
+            uint64_t *pdpte_ptr = (pdpt_ptr + pdpte_id);
+            // kdebug("pgt_num.num_PDPTE=%ld pdpte_ptr=%#018lx", pgt_num.num_PDPTE, pdpte_ptr);
 
-        ul *tmp1;
-        // 初始化2M物理页
-        for (ul i = 0; i < (length); i += PAGE_2M_SIZE)
-        {
-            // 计算当前2M物理页对应的pdt的页表项的物理地址
+            // 创建新的三级页表
+            if (*pdpte_ptr == 0)
+            {
+                ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
+                memset(virt_addr, 0, PAGE_4K_SIZE);
+                set_pdpt(pdpte_ptr, mk_pdpt(virt_2_phys(virt_addr), (user ? PAGE_USER_DIR : PAGE_KERNEL_DIR)));
+                // kdebug("created new pdt, *pdpte_ptr=%#018lx, virt_addr=%#018lx", *pdpte_ptr, virt_addr);
+            }
+
+            uint64_t pde_id = (((virt_addr_start + length_mapped) >> PAGE_2M_SHIFT) & 0x1ff);
+            uint64_t *pd_ptr = (uint64_t *)phys_2_virt(*pdpte_ptr & (~0xfffUL));
+            // kdebug("pd_ptr=%#018lx, *pd_ptr=%#018lx", pd_ptr, *pd_ptr);
 
-            tmp1 = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr_start + i) >> PAGE_2M_SHIFT) & 0x1ff)));
+            // 循环填写三级页表,初始化2M物理页
+            for (; (pgt_num.num_PDE > 0) && pde_id < 512; ++pde_id)
+            {
+                --pgt_num.num_PDE;
+                // 计算当前2M物理页对应的pdt的页表项的物理地址
+                ul *pde_ptr = pd_ptr + pde_id;
 
-            // 页面写穿,禁止缓存
-            set_pdt(tmp1, mk_pdt((ul)phys_addr_start + i, flags | (user ? PAGE_USER_PAGE : PAGE_KERNEL_PAGE)));
+                // 页面写穿,禁止缓存
+                set_pdt(pde_ptr, mk_pdt((ul)phys_addr_start + length_mapped, flags | (user ? PAGE_USER_PAGE : PAGE_KERNEL_PAGE)));
+                length_mapped += PAGE_2M_SIZE;
+            }
         }
     }
-
     flush_tlb();
 }
 
@@ -728,32 +658,70 @@ uint64_t mm_get_PDE(ul proc_page_table_addr, bool is_phys, ul virt_addr, bool cl
  */
 void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_start, ul length)
 {
-    ul *tmp;
+
+    // 计算线性地址对应的pml4页表项的地址
+    mm_pgt_entry_num_t pgt_num;
+    mm_calculate_entry_num(length, &pgt_num);
+    // 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);
+    // 已取消映射的内存大小
+    uint64_t length_unmapped = 0;
+
+    uint64_t pml4e_id = ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff);
+    uint64_t *pml4_ptr;
     if (is_phys)
-        tmp = phys_2_virt((ul *)((ul)proc_page_table_addr & (~0xfffUL)) + ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff));
+        pml4_ptr = phys_2_virt((ul *)((ul)proc_page_table_addr & (~0xfffUL)));
     else
-        tmp = (ul *)((ul)proc_page_table_addr & (~0xfffUL)) + ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff);
+        pml4_ptr = (ul *)((ul)proc_page_table_addr & (~0xfffUL));
 
-    // pml4页表项为0
-    if (*tmp == 0)
-        return;
+    // 循环填写顶层页表
+    for (; (pgt_num.num_PML4E > 0) && pml4e_id < 512; ++pml4e_id)
+    {
+        // 剩余需要处理的pml4E -1
+        --(pgt_num.num_PML4E);
 
-    tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((virt_addr_start >> PAGE_1G_SHIFT) & 0x1ff));
+        ul *pml4e_ptr = NULL;
+        pml4e_ptr = pml4_ptr + pml4e_id;
 
-    // pdpt页表项为0
-    if (*tmp == 0)
-        return;
+        // 二级页表不存在
+        if (*pml4e_ptr == 0)
+        {
+            continue;
+        }
 
-    ul *tmp1;
+        uint64_t pdpte_id = (((virt_addr_start + length_unmapped) >> PAGE_1G_SHIFT) & 0x1ff);
+        uint64_t *pdpt_ptr = (uint64_t *)phys_2_virt(*pml4e_ptr & (~0xfffUL));
+        // kdebug("pdpt_ptr=%#018lx", pdpt_ptr);
 
-    for (ul i = 0; i < (length); i += PAGE_2M_SIZE)
-    {
-        // 计算当前2M物理页对应的pdt的页表项的物理地址
-        tmp1 = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr_start + i) >> PAGE_2M_SHIFT) & 0x1ff)));
-        // 清除映射
-        *tmp1 = 0;
-    }
+        // 循环处理二级页表
+        for (; (pgt_num.num_PDPTE > 0) && pdpte_id < 512; ++pdpte_id)
+        {
+            --pgt_num.num_PDPTE;
+            uint64_t *pdpte_ptr = (pdpt_ptr + pdpte_id);
+            // kdebug("pgt_num.num_PDPTE=%ld pdpte_ptr=%#018lx", pgt_num.num_PDPTE, pdpte_ptr);
+
+            // 三级页表为空
+            if (*pdpte_ptr == 0)
+            {
+                continue;
+            }
+
+            uint64_t pde_id = (((virt_addr_start + length_unmapped) >> PAGE_2M_SHIFT) & 0x1ff);
+            uint64_t *pd_ptr = (uint64_t *)phys_2_virt(*pdpte_ptr & (~0xfffUL));
+            // kdebug("pd_ptr=%#018lx, *pd_ptr=%#018lx", pd_ptr, *pd_ptr);
 
+            // 循环处理三级页表
+            for (; (pgt_num.num_PDE > 0) && pde_id < 512; ++pde_id)
+            {
+                --pgt_num.num_PDE;
+                // 计算当前2M物理页对应的pdt的页表项的物理地址
+                ul *pde_ptr = pd_ptr + pde_id;
+
+                *pde_ptr = 0;
+
+                length_unmapped += PAGE_2M_SIZE;
+            }
+        }
+    }
     flush_tlb();
 }
 
@@ -840,7 +808,7 @@ uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset)
     {
         for (uint64_t i = old_brk_end_addr; i < end_addr; i += PAGE_2M_SIZE)
         {
-            kdebug("map [%#018lx]", i);
+            // kdebug("map [%#018lx]", i);
             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);
         }
         current_pcb->mm->brk_end = end_addr;

+ 0 - 1
kernel/mm/mm.h

@@ -233,7 +233,6 @@ int ZONE_DMA_INDEX = 0;
 int ZONE_NORMAL_INDEX = 0;   // low 1GB RAM ,was mapped in pagetable
 int ZONE_UNMAPPED_INDEX = 0; // above 1GB RAM,unmapped in pagetable
 
-ul *global_CR3 = NULL;
 
 // 初始化内存管理单元
 void mm_init();

+ 1 - 1
kernel/process/process.c

@@ -647,7 +647,7 @@ int kernel_thread(unsigned long (*fn)(unsigned long), unsigned long arg, unsigne
 void process_init()
 {
     kinfo("Initializing process...");
-    initial_mm.pgd = (pml4t_t *)global_CR3;
+    initial_mm.pgd = (pml4t_t *)get_CR3();
 
     initial_mm.code_addr_start = memory_management_struct.kernel_code_start;
     initial_mm.code_addr_end = memory_management_struct.kernel_code_end;

+ 7 - 6
kernel/smp/smp.c

@@ -41,7 +41,7 @@ void smp_init()
         set_intr_gate(i, 0, SMP_interrupt_table[i - 200]);
 
     memset((void *)SMP_IPI_desc, 0, sizeof(irq_desc_t) * SMP_IRQ_NUM);
-    
+
     // 注册接收bsp处理器的hpet中断转发的处理函数
     ipi_regiserIPI(0xc8, NULL, &ipi_0xc8_handler, NULL, NULL, "IPI 0xc8");
 
@@ -90,6 +90,7 @@ void smp_init()
     kinfo("Cleaning page table remapping...\n");
 
     // 由于ap处理器初始化过程需要用到0x00处的地址,因此初始化完毕后才取消内存地址的重映射
+    uint64_t *global_CR3 = get_CR3();
     for (int i = 0; i < 128; ++i)
     {
 
@@ -153,13 +154,13 @@ void smp_ap_start()
     current_pcb->preempt_count = 0;
     sti();
 
-    while(1)
+    while (1)
         hlt();
 
-/*
-    if (proc_current_cpu_id == 1)
-        process_init();
-        */
+    /*
+        if (proc_current_cpu_id == 1)
+            process_init();
+            */
     while (1)
     {
         printk_color(BLACK, WHITE, "CPU:%d IDLE process.\n", proc_current_cpu_id);