Browse Source

使mm支持4K虚拟地址映射

fslongjin 2 years ago
parent
commit
aa3f433cd5

+ 36 - 36
kernel/common/kprint.h

@@ -3,22 +3,22 @@
  * @author longjin
  * @brief 内核日志打印程序
  * @date 2022-01-28
- * 
+ *
  * @copyright Copyright (c) 2022 longjin
- * 
+ *
  */
 
 #pragma once
 #include "printk.h"
 
-#define ksuccess(...)                           \
-    do                                       \
-    {                                        \
-        printk("[ ");                        \
+#define ksuccess(...)                          \
+    do                                         \
+    {                                          \
+        printk("[ ");                          \
         printk_color(GREEN, BLACK, "SUCCESS"); \
-        printk(" ] ");                       \
-        printk(__VA_ARGS__);                 \
-        printk("\n");                        \
+        printk(" ] ");                         \
+        printk(__VA_ARGS__);                   \
+        printk("\n");                          \
     } while (0);
 
 #define kinfo(...)           \
@@ -29,22 +29,22 @@
         printk("\n");        \
     } while (0);
 
-#define kdebug(...)           \
-    do                        \
-    {                         \
+#define kdebug(...)                                        \
+    do                                                     \
+    {                                                      \
         printk("[ DEBUG ] (%s:%d)\t", __FILE__, __LINE__); \
-        printk(__VA_ARGS__);  \
-        printk("\n");         \
+        printk(__VA_ARGS__);                               \
+        printk("\n");                                      \
     } while (0);
 
-#define kwarn(...)                           \
-    do                                       \
-    {                                        \
-        printk("[ ");                        \
-        printk_color(YELLOW, BLACK, "WARN"); \
-        printk(" ] ");                       \
-        printk(__VA_ARGS__);                 \
-        printk("\n");                        \
+#define kwarn(...)                                 \
+    do                                             \
+    {                                              \
+        printk("[ ");                              \
+        printk_color(YELLOW, BLACK, "WARN");       \
+        printk(" ] "); \
+        printk(__VA_ARGS__);                       \
+        printk("\n");                              \
     } while (0);
 
 #define kerror(...)                        \
@@ -58,21 +58,21 @@
     } while (0);
 
 #define kterminated(...)                        \
-    do                                     \
-    {                                      \
-        printk("[ ");                      \
+    do                                          \
+    {                                           \
+        printk("[ ");                           \
         printk_color(RED, BLACK, "TERMINATED"); \
-        printk(" ] ");                     \
-        printk(__VA_ARGS__);               \
-        printk("\n");                      \
+        printk(" ] ");                          \
+        printk(__VA_ARGS__);                    \
+        printk("\n");                           \
     } while (0);
 
-#define kBUG(...)                        \
-    do                                     \
-    {                                      \
-        printk("[ ");                      \
-        printk_color(RED, BLACK, "BUG"); \
-        printk(" ] (%s:%d)\t", __FILE__, __LINE__);                     \
-        printk(__VA_ARGS__);               \
-        printk("\n");                      \
+#define kBUG(...)                                   \
+    do                                              \
+    {                                               \
+        printk("[ ");                               \
+        printk_color(RED, BLACK, "BUG");            \
+        printk(" ] (%s:%d)\t", __FILE__, __LINE__); \
+        printk(__VA_ARGS__);                        \
+        printk("\n");                               \
     } while (0);

+ 10 - 10
kernel/driver/acpi/acpi.c

@@ -41,7 +41,7 @@ void acpi_iter_SDT(bool (*_fun)(const struct acpi_system_description_table_heade
         ul *ent = &(xsdt->Entry);
         for (int i = 0; i < acpi_XSDT_Entry_num; ++i)
         {
-            mm_map_phys_addr(ACPI_XSDT_DESCRIPTION_HEDERS_BASE + PAGE_2M_SIZE * i, (*(ent + i)) & PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+            mm_map_phys_addr(ACPI_XSDT_DESCRIPTION_HEDERS_BASE + PAGE_2M_SIZE * i, (*(ent + i)) & PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
             sdt_header = (struct acpi_system_description_table_header_t *)((ul)(ACPI_XSDT_DESCRIPTION_HEDERS_BASE + PAGE_2M_SIZE * i));
 
             if (_fun(sdt_header, _data) == true)
@@ -134,7 +134,7 @@ void acpi_init()
         acpi_use_xsdt = true;
         ul xsdt_phys_base = rsdpv2->XsdtAddress & PAGE_2M_MASK;
         acpi_XSDT_offset = rsdpv2->XsdtAddress - xsdt_phys_base;
-        mm_map_phys_addr(ACPI_XSDT_VIRT_ADDR_BASE, xsdt_phys_base, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+        mm_map_phys_addr(ACPI_XSDT_VIRT_ADDR_BASE, xsdt_phys_base, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
         kdebug("XSDT mapped!");
 
         xsdt = (struct acpi_XSDT_Structure_t *)(ACPI_XSDT_VIRT_ADDR_BASE + acpi_XSDT_offset);
@@ -146,20 +146,20 @@ void acpi_init()
         printk_color(ORANGE, BLACK, "XSDT Length=%dbytes.\n", xsdt->header.Length);
         printk_color(ORANGE, BLACK, "XSDT Entry num=%d\n", acpi_XSDT_Entry_num);
 
-        mm_map_phys_addr(ACPI_XSDT_VIRT_ADDR_BASE, xsdt_phys_base, xsdt->header.Length + PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+        mm_map_phys_addr(ACPI_XSDT_VIRT_ADDR_BASE, xsdt_phys_base, xsdt->header.Length + PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
         // 映射所有的Entry的物理地址
         ul *ent = &(xsdt->Entry);
         for (int j = 0; j < acpi_XSDT_Entry_num; ++j)
         {
             kdebug("entry=%#018lx, virt=%#018lx", (*(ent + j)) & PAGE_2M_MASK, ACPI_XSDT_DESCRIPTION_HEDERS_BASE + PAGE_2M_SIZE * j);
             // 映射RSDT ENTRY的物理地址
-            mm_map_phys_addr(ACPI_XSDT_DESCRIPTION_HEDERS_BASE + PAGE_2M_SIZE * j, (*(ent + j)) & PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+            mm_map_phys_addr(ACPI_XSDT_DESCRIPTION_HEDERS_BASE + PAGE_2M_SIZE * j, (*(ent + j)) & PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
         }
         */
         // 由于解析XSDT出现问题。暂时只使用Rsdpv2的rsdt,但是这是不符合ACPI规范的!!!
         ul rsdt_phys_base = rsdpv2->rsdp1.RsdtAddress & PAGE_2M_MASK;
         acpi_RSDT_offset = rsdpv2->rsdp1.RsdtAddress - rsdt_phys_base;
-        mm_map_phys_addr(ACPI_RSDT_VIRT_ADDR_BASE, rsdt_phys_base, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+        mm_map_phys_addr(ACPI_RSDT_VIRT_ADDR_BASE, rsdt_phys_base, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
         kdebug("RSDT mapped!(v2)");
         rsdt = (struct acpi_RSDT_Structure_t *)(ACPI_RSDT_VIRT_ADDR_BASE + acpi_RSDT_offset);
         // 计算RSDT Entry的数量
@@ -169,7 +169,7 @@ void acpi_init()
         printk_color(ORANGE, BLACK, "RSDT Length=%dbytes.\n", rsdt->header.Length);
         printk_color(ORANGE, BLACK, "RSDT Entry num=%d\n", acpi_RSDT_Entry_num);
 
-        mm_map_phys_addr(ACPI_RSDT_VIRT_ADDR_BASE, rsdt_phys_base, rsdt->header.Length + PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+        mm_map_phys_addr(ACPI_RSDT_VIRT_ADDR_BASE, rsdt_phys_base, rsdt->header.Length + PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
         // 映射所有的Entry的物理地址
         acpi_RSDT_entry_phys_base = ((ul)(rsdt->Entry)) & PAGE_2M_MASK;
         // 由于地址只是32bit的,并且存在脏数据,这里需要手动清除高32bit,否则会触发#GP
@@ -178,7 +178,7 @@ void acpi_init()
         kdebug("entry=%#018lx", rsdt->Entry);
         kdebug("acpi_RSDT_entry_phys_base=%#018lx", acpi_RSDT_entry_phys_base);
         // 映射RSDT ENTRY的物理地址
-        mm_map_phys_addr(ACPI_DESCRIPTION_HEDERS_BASE, acpi_RSDT_entry_phys_base, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+        mm_map_phys_addr(ACPI_DESCRIPTION_HEDERS_BASE, acpi_RSDT_entry_phys_base, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
     }
     else if (rsdpv1->RsdtAddress != (uint)0x00UL)
     { // 映射RSDT的物理地址到页表
@@ -186,7 +186,7 @@ void acpi_init()
         // 由于页表映射的原因,需要清除低21位地址,才能填入页表
         ul rsdt_phys_base = rsdpv1->RsdtAddress & PAGE_2M_MASK;
         acpi_RSDT_offset = rsdpv1->RsdtAddress - rsdt_phys_base;
-        mm_map_phys_addr(ACPI_RSDT_VIRT_ADDR_BASE, rsdt_phys_base, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+        mm_map_phys_addr(ACPI_RSDT_VIRT_ADDR_BASE, rsdt_phys_base, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
         kdebug("RSDT mapped!");
         rsdt = (struct acpi_RSDT_Structure_t *)(ACPI_RSDT_VIRT_ADDR_BASE + acpi_RSDT_offset);
         // 计算RSDT Entry的数量
@@ -196,7 +196,7 @@ void acpi_init()
         printk_color(ORANGE, BLACK, "RSDT Length=%dbytes.\n", rsdt->header.Length);
         printk_color(ORANGE, BLACK, "RSDT Entry num=%d\n", acpi_RSDT_Entry_num);
 
-        mm_map_phys_addr(ACPI_RSDT_VIRT_ADDR_BASE, rsdt_phys_base, rsdt->header.Length + PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+        mm_map_phys_addr(ACPI_RSDT_VIRT_ADDR_BASE, rsdt_phys_base, rsdt->header.Length + PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
         // 映射所有的Entry的物理地址
         acpi_RSDT_entry_phys_base = ((ul)(rsdt->Entry)) & PAGE_2M_MASK;
         // 由于地址只是32bit的,并且存在脏数据,这里需要手动清除高32bit,否则会触发#GP
@@ -205,7 +205,7 @@ void acpi_init()
         kdebug("entry=%#018lx", rsdt->Entry);
         kdebug("acpi_RSDT_entry_phys_base=%#018lx", acpi_RSDT_entry_phys_base);
         // 映射RSDT ENTRY的物理地址
-        mm_map_phys_addr(ACPI_DESCRIPTION_HEDERS_BASE, acpi_RSDT_entry_phys_base, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+        mm_map_phys_addr(ACPI_DESCRIPTION_HEDERS_BASE, acpi_RSDT_entry_phys_base, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
     }
     else
     {

+ 1 - 1
kernel/driver/disk/ahci/ahci.c

@@ -43,7 +43,7 @@ void ahci_init()
     kdebug("((struct pci_device_structure_general_device_t *)phys_2_virt(ahci_devs[0])))->BAR5= %#018lx", ((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5);
     uint32_t bar5 = ((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5;
 
-    mm_map_phys_addr(AHCI_MAPPING_BASE, (ul)(bar5)&PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+    mm_map_phys_addr(AHCI_MAPPING_BASE, (ul)(bar5)&PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
     kdebug("ABAR mapped!");
     for (int i = 0; i < count_ahci_devices; ++i)
     {

+ 2 - 2
kernel/driver/interrupt/apic/apic.c

@@ -69,7 +69,7 @@ void apic_io_apic_init()
 
     // kdebug("(ul)apic_ioapic_map.virtual_index_addr=%#018lx", (ul)apic_ioapic_map.virtual_index_addr);
     // 填写页表,完成地址映射
-    mm_map_phys_addr((ul)apic_ioapic_map.virtual_index_addr, apic_ioapic_map.addr_phys, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+    mm_map_phys_addr((ul)apic_ioapic_map.virtual_index_addr, apic_ioapic_map.addr_phys, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
 
     // 设置IO APIC ID 为0x0f000000
     *apic_ioapic_map.virtual_index_addr = 0x00;
@@ -198,7 +198,7 @@ void apic_init_ap_core_local_apic()
 void apic_local_apic_init()
 {
     // 映射Local APIC 寄存器地址
-    mm_map_phys_addr(APIC_LOCAL_APIC_VIRT_BASE_ADDR, 0xfee00000UL, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+    mm_map_phys_addr(APIC_LOCAL_APIC_VIRT_BASE_ADDR, 0xfee00000UL, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false);
     uint a, b, c, d;
 
     cpu_cpuid(1, 0, &a, &b, &c, &d);

+ 34 - 3
kernel/driver/usb/xhci/xhci.c

@@ -2,12 +2,14 @@
 #include <common/kprint.h>
 #include <debug/bug.h>
 #include <process/spinlock.h>
+#include <mm/mm.h>
+#include <debug/traceback/traceback.h>
 
 spinlock_t xhci_controller_init_lock; // xhci控制器初始化锁(在usb_init中被初始化)
 
-static int xhci_ctrl_count = 0;    // xhci控制器计数
-
+static int xhci_ctrl_count = 0; // xhci控制器计数
 
+static struct xhci_host_controller_t xhci_hc[MAX_XHCI_HOST_CONTROLLERS] = {0};
 
 /**
  * @brief 初始化xhci控制器
@@ -17,12 +19,41 @@ static int xhci_ctrl_count = 0;    // xhci控制器计数
 void xhci_init(struct pci_device_structure_general_device_t *dev_hdr)
 {
     spin_lock(&xhci_controller_init_lock);
-    kinfo("Initializing xhci host controller: bus=%#02x, device=%#02x, func=%#02x, VendorID=%#04x, irq_line=%d, irq_pin=%d", dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, dev_hdr->header.Vendor_ID, dev_hdr->Interrupt_Line, dev_hdr->Interrupt_PIN );
+    kinfo("Initializing xhci host controller: bus=%#02x, device=%#02x, func=%#02x, VendorID=%#04x, irq_line=%d, irq_pin=%d", dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, dev_hdr->header.Vendor_ID, dev_hdr->Interrupt_Line, dev_hdr->Interrupt_PIN);
 
+    xhci_hc[xhci_ctrl_count].controller_id = xhci_ctrl_count;
+    xhci_hc[xhci_ctrl_count].pci_dev_hdr = dev_hdr;
     pci_write_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 0x4, 0x0006); // mem I/O access enable and bus master enable
 
+    // 为当前控制器映射寄存器地址空间
+    xhci_hc[xhci_ctrl_count].vbase = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + XHCI_MAPPING_OFFSET + PAGE_2M_SIZE * xhci_hc[xhci_ctrl_count].controller_id;
+    kdebug("dev_hdr->BAR0 & (~0xf)=%#018lx", dev_hdr->BAR0 & (~0xf));
+    mm_map_phys_addr(xhci_hc[xhci_ctrl_count].vbase, dev_hdr->BAR0 & (~0xf), 65536, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, true);
 
+    // 读取xhci控制寄存器
+    uint16_t iversion = *(uint16_t *)(xhci_hc[xhci_ctrl_count].vbase + XHCI_CAPS_HCIVERSION);
+    uint32_t dboff = *(uint16_t *)(xhci_hc[xhci_ctrl_count].vbase + XHCI_CAPS_DBOFF);
     
+    // kdebug("dboff=%ld", dboff);
+    // struct xhci_caps_HCSPARAMS1_reg_t hcs1 = *(struct xhci_caps_HCSPARAMS1_reg_t *)(xhci_hc[xhci_ctrl_count].vbase + XHCI_CAPS_HCSPARAMS1);
+
+    // kdebug("hcs1.max_ports=%d, hcs1.max_slots=%d, hcs1.max_intrs=%d", hcs1.max_ports, hcs1.max_slots, hcs1.max_intrs);
+    // kdebug("caps size=%d", *(uint8_t *)xhci_hc[xhci_ctrl_count].vbase);
+    // kdebug("iversion=%#06x", iversion);
+    if (iversion < 0x95)
+    {
+        kwarn("Unsupported/Unknowned xHCI controller version: %#06x. This may cause unexpected behavior.", iversion);
+    }
+
     ++xhci_ctrl_count;
     spin_unlock(&xhci_controller_init_lock);
+    return;
+failed:;
+    // 取消地址映射
+    mm_unmap(xhci_hc[xhci_ctrl_count].vbase, 65536);
+
+    // 清空数组
+    memset((void *)&xhci_hc[xhci_ctrl_count], 0, sizeof(struct xhci_host_controller_t));
+
+    spin_unlock(&xhci_controller_init_lock);
 }

+ 4 - 2
kernel/driver/usb/xhci/xhci.h

@@ -2,6 +2,8 @@
 #include <driver/usb/usb.h>
 #include <driver/pci/pci.h>
 
+#define MAX_XHCI_HOST_CONTROLLERS 8
+
 // xhci Capability Registers offset
 #define XHCI_CAPS_CAPLENGTH 0x00 // Cap 寄存器组的长度
 #define XHCI_CAPS_RESERVED 0x01
@@ -85,11 +87,11 @@ struct xhci_port_info_t
     uint8_t reserved;
 } __attribute__((packed));
 
-struct xhci_controller_t
+struct xhci_host_controller_t
 {
     struct pci_device_structure_general_device_t *pci_dev_hdr; // 指向pci header结构体的指针
     int controller_id;                                         // 操作系统给controller的编号
-    int vbase;                                                 // 虚拟地址base(bar0映射到的虚拟地址)
+    uint64_t vbase;                                                 // 虚拟地址base(bar0映射到的虚拟地址)
     struct xhci_port_info_t *ports;                            // 指向端口信息数组的指针
 };
 

+ 2 - 2
kernel/driver/video/video.c

@@ -50,7 +50,7 @@ void init_frame_buffer(bool level)
         sc_info.height = info.framebuffer_height;
 
         sc_info.length = 1UL * sc_info.width * sc_info.height;
-        mm_map_proc_page_table(global_CR3, true, sc_info.fb_vaddr, sc_info.fb_paddr, get_VBE_FB_length() << 2, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false, true);
+        mm_map_proc_page_table(global_CR3, true, sc_info.fb_vaddr, sc_info.fb_paddr, get_VBE_FB_length() << 2, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false, true, false);
         set_pos_VBE_FB_addr((uint *)sc_info.fb_vaddr);
     }
     else // 高级初始化,增加双缓冲区的支持
@@ -58,7 +58,7 @@ void init_frame_buffer(bool level)
         // 申请双重缓冲区
         struct Page *p = alloc_pages(ZONE_NORMAL, PAGE_2M_ALIGN(sc_info.length << 2) / PAGE_2M_SIZE, 0);
         sc_info.double_fb_vaddr = (uint64_t)phys_2_virt(p->addr_phys);
-        mm_map_proc_page_table(global_CR3, true, sc_info.double_fb_vaddr, p->addr_phys, PAGE_2M_ALIGN(sc_info.length << 2), PAGE_KERNEL_PAGE, false, true);
+        mm_map_proc_page_table(global_CR3, true, sc_info.double_fb_vaddr, p->addr_phys, PAGE_2M_ALIGN(sc_info.length << 2), PAGE_KERNEL_PAGE, false, true, false);
 
         // 将原有的数据拷贝到double buffer里面
         memcpy((void *)sc_info.double_fb_vaddr, (void *)sc_info.fb_vaddr, sc_info.length << 2);

+ 151 - 28
kernel/mm/mm.c

@@ -4,9 +4,12 @@
 #include <common/kprint.h>
 #include <driver/multiboot2/multiboot2.h>
 #include <process/process.h>
+#include <common/compiler.h>
+#include <common/errno.h>
+#include <debug/traceback/traceback.h>
 
-ul Total_Memory = 0;
-ul total_2M_pages = 0;
+static ul Total_Memory = 0;
+static ul total_2M_pages = 0;
 static ul root_page_table_phys_addr = 0; // 内核层根页表的物理地址
 
 /**
@@ -48,6 +51,23 @@ static void mm_calculate_entry_num(uint64_t length, mm_pgt_entry_num_t *ent)
  */
 uint64_t mm_get_PDE(ul proc_page_table_addr, bool is_phys, ul virt_addr, bool clear);
 
+/**
+ * @brief 检查页表是否存在不为0的页表项
+ *
+ * @param ptr 页表基指针
+ * @return int8_t 存在 -> 1
+ *                不存在 -> 0
+ */
+int8_t mm_check_page_table(uint64_t *ptr)
+{
+    for (int i = 0; i < 512; ++i, ++ptr)
+    {
+        if (*ptr != 0)
+            return 1;
+    }
+    return 0;
+}
+
 void mm_init()
 {
     kinfo("Initializing memory management unit...");
@@ -451,7 +471,7 @@ void free_pages(struct Page *page, int number)
 
 /**
  * @brief 重新初始化页表的函数
- * 将0~4GB的物理页映射到线性地址空间
+ * 将所有物理页映射到线性地址空间
  */
 void page_table_init()
 {
@@ -470,10 +490,7 @@ void page_table_init()
 
         for (int j = 0; j < z->count_pages; ++j)
         {
-            // if (p->addr_phys)
-            //     kdebug("(ul)phys_2_virt(p->addr_phys)=%#018lx",(ul)phys_2_virt(p->addr_phys));
-            // mm_map_phys_addr((ul)phys_2_virt(p->addr_phys), p->addr_phys, PAGE_2M_SIZE, PAGE_KERNEL_PAGE);
-            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);
+            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);
 
             ++p;
             ++js;
@@ -491,18 +508,20 @@ void page_table_init()
  * @param virt_addr_start 要映射到的虚拟地址的起始位置
  * @param phys_addr_start 物理地址的起始位置
  * @param length 要映射的区域的长度(字节)
+ * @param flags 标志位
+ * @param use4k 是否使用4k页
  */
-void mm_map_phys_addr(ul virt_addr_start, ul phys_addr_start, ul length, ul flags)
+int mm_map_phys_addr(ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool use4k)
 {
     uint64_t global_CR3 = (uint64_t)get_CR3();
 
-    mm_map_proc_page_table(global_CR3, true, virt_addr_start, phys_addr_start, length, flags, false, true);
+    return mm_map_proc_page_table(global_CR3, true, virt_addr_start, phys_addr_start, length, flags, false, true, use4k);
 }
 
-void mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul flags)
+int mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul flags)
 {
     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, true);
+    return mm_map_proc_page_table(global_CR3, true, virt_addr_start, phys_addr_start, length, flags, true, true, false);
 }
 
 /**
@@ -515,8 +534,9 @@ void mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul
  * @param length 要映射的区域的长度(字节)
  * @param user 用户态是否可访问
  * @param flush 是否刷新tlb
+ * @param use4k 是否使用4k页
  */
-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, bool flush)
+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)
 {
 
     // 计算线性地址对应的pml4页表项的地址
@@ -579,22 +599,68 @@ void mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_
                 --pgt_num.num_PDE;
                 // 计算当前2M物理页对应的pdt的页表项的物理地址
                 ul *pde_ptr = pd_ptr + pde_id;
-                if (*pde_ptr != 0 && user)
+
+                // ====== 使用4k页 =======
+                if (unlikely(use4k))
+                {
+                    // kdebug("use 4k");
+                    if (*pde_ptr == 0)
+                    {
+                        // 创建四级页表
+                        // kdebug("create PT");
+                        uint64_t *vaddr = kmalloc(PAGE_4K_SIZE, 0);
+                        memset(vaddr, 0, PAGE_4K_SIZE);
+                        set_pdt(pde_ptr, mk_pdt(virt_2_phys(vaddr), (user ? PAGE_USER_PDE : PAGE_KERNEL_PDE)));
+                    }
+                    else if (unlikely(*pde_ptr & (1 << 7)))
+                    {
+                        // 当前页表项已经被映射了2MB物理页
+                        goto failed;
+                    }
+
+                    uint64_t pte_id = (((virt_addr_start + length_mapped) >> PAGE_4K_SHIFT) & 0x1ff);
+                    uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0x1fffUL));
+
+                    // 循环填写4级页表,初始化4K页
+                    for (; pgt_num.num_PTE > 0 && pte_id < 512; ++pte_id)
+                    {
+                        --pgt_num.num_PTE;
+                        uint64_t *pte_ptr = pt_ptr + pte_id;
+
+                        if (unlikely(*pte_ptr != 0))
+                        {
+                            kwarn("pte already exists.");
+                            length_mapped += PAGE_4K_SIZE;
+                        }
+
+                        set_pt(pte_ptr, mk_pt((ul)phys_addr_start + length_mapped, flags | (user ? PAGE_USER_4K_PAGE : PAGE_KERNEL_4K_PAGE)));
+                    }
+                }
+                // ======= 使用2M页 ========
+                else
                 {
-                    // kwarn("page already mapped!");
-                    // 如果是用户态可访问的页,则释放当前新获取的物理页
-                    free_pages(Phy_to_2M_Page((ul)phys_addr_start + length_mapped), 1);
+                    if (unlikely(*pde_ptr != 0 && user))
+                    {
+                        kwarn("page already mapped!");
+                        // 如果是用户态可访问的页,则释放当前新获取的物理页
+                        if (likely(((ul)phys_addr_start + length_mapped) < total_2M_pages)) // 校验是否为内存中的物理页
+                            free_pages(Phy_to_2M_Page((ul)phys_addr_start + length_mapped), 1);
+                        length_mapped += PAGE_2M_SIZE;
+                        continue;
+                    }
+                    // 页面写穿,禁止缓存
+                    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;
-                    continue;
                 }
-                // 页面写穿,禁止缓存
-                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;
             }
         }
     }
-    if (flush)
+    if (likely(flush))
         flush_tlb();
+    return 0;
+failed:;
+    kerror("Map memory failed. use4k=%d, vaddr=%#018lx, paddr=%#018lx", use4k, virt_addr_start, phys_addr_start);
+    return -EFAULT;
 }
 
 /**
@@ -701,11 +767,41 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta
                 // 计算当前2M物理页对应的pdt的页表项的物理地址
                 ul *pde_ptr = pd_ptr + pde_id;
 
-                *pde_ptr = 0;
+                // 存在4级页表
+                if (unlikely(((*pde_ptr) & (1 << 7)) == 0))
+                {
+                    // 存在4K页
+                    uint64_t pte_id = (((virt_addr_start + length_unmapped) >> PAGE_4K_SHIFT) & 0x1ff);
+                    uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0x1fffUL));
+                    uint64_t *pte_ptr = pt_ptr + pte_id;
+
+                    // 循环处理4K页表
+                    for (; pgt_num.num_PTE > 0 && pte_id < 512; ++pte_id, ++pte_ptr)
+                    {
+                        --pgt_num.num_PTE;
+                        // todo: 当支持使用slab分配4K内存作为进程的4K页之后,在这里需要释放这些4K对象
+                        *pte_ptr = 0;
+                        length_unmapped += PAGE_4K_SIZE;
+                    }
 
-                length_unmapped += PAGE_2M_SIZE;
+                    // 4级页表已经空了,释放页表
+                    if (unlikely(mm_check_page_table(pt_ptr)) == 0)
+                        kfree(pt_ptr);
+                }
+                else
+                {
+                    *pde_ptr = 0;
+                    length_unmapped += PAGE_2M_SIZE;
+                }
             }
+
+            // 3级页表已经空了,释放页表
+            if (unlikely(mm_check_page_table(pd_ptr)) == 0)
+                kfree(pd_ptr);
         }
+        // 2级页表已经空了,释放页表
+        if (unlikely(mm_check_page_table(pdpt_ptr)) == 0)
+            kfree(pdpt_ptr);
     }
     flush_tlb();
 }
@@ -793,8 +889,8 @@ 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);
-            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);
+            // 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, true, false);
         }
         current_pcb->mm->brk_end = end_addr;
     }
@@ -850,9 +946,36 @@ bool mm_check_mapped(ul page_table_phys_addr, uint64_t virt_addr)
     // 读取pdt页表项
     tmp = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr) >> PAGE_2M_SHIFT) & 0x1ff)));
 
-    // todo: 增加对使用了4K页的页表的检测
-    if (*tmp != 0)
+    // pde页表项为0
+    if (*tmp == 0)
+        return 0;
+
+    if (*tmp & (1 << 7))
+    {
+        // 当前为2M物理页
         return true;
+    }
     else
-        return false;
+    {
+        // 存在4级页表
+        tmp = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr) >> PAGE_4K_SHIFT) & 0x1ff)));
+        if (*tmp != 0)
+            return true;
+        else
+            return false;
+    }
+}
+
+/**
+ * @brief 检测是否为有效的2M页(物理内存页)
+ * 
+ * @param paddr 物理地址
+ * @return int8_t 是 -> 1
+ *                 否 -> 0
+ */
+int8_t mm_is_2M_page(uint64_t paddr)
+{
+    if(likely((paddr >> PAGE_2M_SHIFT)<total_2M_pages))
+        return 1;
+    else return 0;
 }

+ 61 - 10
kernel/mm/mm.h

@@ -77,6 +77,8 @@
 
 //	bit 12	Page Attribute Table
 #define PAGE_PAT (1UL << 12)
+// 对于PTE而言,第7位是PAT
+#define PAGE_4K_PAT (1UL << 7)
 
 //	bit 8	Global Page:1,global;0,part
 #define PAGE_GLOBAL (1UL << 8)
@@ -111,17 +113,26 @@
 // 1,0
 #define PAGE_KERNEL_DIR (PAGE_R_W | PAGE_PRESENT)
 
+// 1,0 (4级页表在3级页表中的页表项的属性)
+#define PAGE_KERNEL_PDE (PAGE_R_W | PAGE_PRESENT)
+
 // 7,1,0
 #define PAGE_KERNEL_PAGE (PAGE_PS | PAGE_R_W | PAGE_PRESENT)
 
+#define PAGE_KERNEL_4K_PAGE (PAGE_R_W | PAGE_PRESENT)
+
 #define PAGE_USER_PGT (PAGE_U_S | PAGE_R_W | PAGE_PRESENT)
 
 // 2,1,0
 #define PAGE_USER_DIR (PAGE_U_S | PAGE_R_W | PAGE_PRESENT)
 
+// 1,0 (4级页表在3级页表中的页表项的属性)
+#define PAGE_USER_PDE (PAGE_U_S | PAGE_R_W | PAGE_PRESENT)
 // 7,2,1,0
 #define PAGE_USER_PAGE (PAGE_PS | PAGE_U_S | PAGE_R_W | PAGE_PRESENT)
 
+#define PAGE_USER_4K_PAGE (PAGE_U_S | PAGE_R_W | PAGE_PRESENT)
+
 // ===== 错误码定义 ====
 // 物理页结构体为空
 #define EPAGE_NULL 1
@@ -172,7 +183,7 @@ struct memory_desc
 
     ul kernel_code_start, kernel_code_end; // 内核程序代码段起始地址、结束地址
     ul kernel_data_end, rodata_end;        // 内核程序数据段结束地址、 内核程序只读段结束地址
-    uint64_t start_brk; // 堆地址的起始位置
+    uint64_t start_brk;                    // 堆地址的起始位置
 
     ul end_of_struct; // 内存页管理结构的结束地址
 };
@@ -234,7 +245,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
 
-
 // 初始化内存管理单元
 void mm_init();
 
@@ -345,7 +355,7 @@ typedef struct
 
 /**
  * @brief 重新初始化页表的函数
- * 将0~4GB的物理页映射到线性地址空间
+ * 将所有物理页映射到线性地址空间
  */
 void page_table_init();
 
@@ -355,8 +365,10 @@ void page_table_init();
  * @param virt_addr_start 要映射到的虚拟地址的起始位置
  * @param phys_addr_start 物理地址的起始位置
  * @param length 要映射的区域的长度(字节)
+ * @param flags 标志位
+ * @param use4k 是否使用4k页
  */
-void mm_map_phys_addr(ul virt_addr_start, ul phys_addr_start, ul length, ul flags);
+int mm_map_phys_addr(ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool use4k);
 
 /**
  * @brief 将将物理地址填写到进程的页表的函数
@@ -368,27 +380,66 @@ void mm_map_phys_addr(ul virt_addr_start, ul phys_addr_start, ul length, ul flag
  * @param length 要映射的区域的长度(字节)
  * @param user 用户态是否可访问
  * @param flush 是否刷新tlb
+ * @param use4k 是否使用4k页
  */
-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, bool flush);
+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);
+
+int mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul flags);
 
+/**
+ * @brief 从页表中清除虚拟地址的映射
+ *
+ * @param proc_page_table_addr 页表的地址
+ * @param is_phys 页表地址是否为物理地址
+ * @param virt_addr_start 要清除的虚拟地址的起始地址
+ * @param length 要清除的区域的长度
+ */
+void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_start, ul length);
 
-void mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul flags);
+/**
+ * @brief 取消当前进程的页表中的虚拟地址映射
+ *
+ * @param virt_addr 虚拟地址
+ * @param length 地址长度
+ */
+#define mm_unmap(virt_addr, length) ({                                 \
+    mm_unmap_proc_table((uint64_t)get_CR3(), true, virt_addr, length); \
+})
 
 /**
  * @brief 检测指定地址是否已经被映射
- * 
+ *
  * @param page_table_phys_addr 页表的物理地址
  * @param virt_addr 要检测的地址
  * @return true 已经被映射
- * @return false 
+ * @return false
  */
 bool mm_check_mapped(ul page_table_phys_addr, uint64_t virt_addr);
+
+/**
+ * @brief 检测是否为有效的2M页(物理内存页)
+ *
+ * @param paddr 物理地址
+ * @return int8_t 是 -> 1
+ *                 否 -> 0
+ */
+int8_t mm_is_2M_page(uint64_t paddr);
+
+/**
+ * @brief 检查页表是否存在不为0的页表项
+ *
+ * @param ptr 页表基指针
+ * @return int8_t 存在 -> 1
+ *                不存在 -> 0
+ */
+int8_t mm_check_page_table(uint64_t *ptr);
+
 /**
  * @brief 调整堆区域的大小(暂时只能增加堆区域)
- * 
+ *
  * @todo 缩小堆区域
  * @param old_brk_end_addr 原本的堆内存区域的结束地址
  * @param offset 新的地址相对于原地址的偏移量
- * @return uint64_t 
+ * @return uint64_t
  */
 uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset);

+ 33 - 16
kernel/process/process.c

@@ -1,17 +1,19 @@
 #include "process.h"
 
-#include <exception/gate.h>
 #include <common/printk.h>
 #include <common/kprint.h>
-#include <syscall/syscall.h>
-#include <syscall/syscall_num.h>
-#include <mm/slab.h>
-#include <sched/sched.h>
-#include <filesystem/fat32/fat32.h>
 #include <common/stdio.h>
-#include <process/spinlock.h>
+#include <common/compiler.h>
 #include <common/libELF/elf.h>
 #include <driver/video/video.h>
+#include <exception/gate.h>
+#include <filesystem/fat32/fat32.h>
+#include <mm/slab.h>
+#include <process/spinlock.h>
+#include <syscall/syscall.h>
+#include <syscall/syscall_num.h>
+#include <sched/sched.h>
+
 
 spinlock_t process_global_pid_write_lock; // 增加pid的写锁
 long process_global_pid = 1;              // 系统中最大的pid
@@ -246,7 +248,7 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
             // todo: 改用slab分配4K大小内存块并映射到4K页
             if (!mm_check_mapped((uint64_t)current_pcb->mm->pgd, virt_base)) // 未映射,则新增物理页
             {
-                mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, virt_base, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true, true);
+                mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, virt_base, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true, true, false);
 
                 memset((void *)virt_base, 0, PAGE_2M_SIZE);
             }
@@ -273,7 +275,7 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
 
     uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
 
-    mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, current_pcb->mm->stack_start - PAGE_2M_SIZE, pa, PAGE_2M_SIZE, PAGE_USER_PAGE, true, true);
+    mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, current_pcb->mm->stack_start - PAGE_2M_SIZE, pa, PAGE_2M_SIZE, PAGE_USER_PAGE, true, true, false);
 
     // 清空栈空间
     memset((void *)(current_pcb->mm->stack_start - PAGE_2M_SIZE), 0, PAGE_2M_SIZE);
@@ -651,11 +653,6 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
     // 拷贝成功
     retval = tsk->pid;
 
-    // kdebug("fork done: tsk->pid=%d", tsk->pid);
-
-    // kdebug("current_pcb->mm->brk_end=%#018lx", current_pcb->mm->brk_end);
-    // mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, 0x0000500000000000, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true);
-
     // 唤醒进程
     process_wakeup(tsk);
 
@@ -922,8 +919,28 @@ uint64_t process_exit_mm(struct process_control_block *pcb)
             {
                 if ((current_pdt + k)->pdt == 0)
                     continue;
-                // 释放内存页
-                free_pages(Phy_to_2M_Page((current_pdt + k)->pdt & (~0x1fffUL)), 1);
+                // 存在4级页表
+                if (unlikely(((current_pdt + k)->pdt & (1 << 7)) == 0))
+                {
+                    // 存在4K页
+                    uint64_t *pt_ptr = (uint64_t *)phys_2_virt((current_pdt + k)->pdt & (~0x1fffUL));
+                    uint64_t *pte_ptr = pt_ptr;
+
+                    // 循环处理4K页表, 直接清空
+                    // todo: 当支持使用slab分配4K内存作为进程的4K页之后,在这里需要释放这些4K对象
+                    for (int16_t g = 0; g < 512; ++g, ++pte_ptr)
+                        *pte_ptr = 0;
+
+                    // 4级页表已经空了,释放页表
+                    if (unlikely(mm_check_page_table(pt_ptr)) == 0)
+                        kfree(pt_ptr);
+                }
+                else
+                {
+                    // 释放内存页
+                    if (mm_is_2M_page((current_pdt + k)->pdt & (~0x1fffUL))) // 校验是否为内存中的物理页
+                        free_pages(Phy_to_2M_Page((current_pdt + k)->pdt & (~0x1fffUL)), 1);
+                }
             }
             // 释放三级页表
             kfree(current_pdt);