From aa3f433cd5b78f5c29c3b690f4ff299c012d1473 Mon Sep 17 00:00:00 2001 From: fslongjin Date: Mon, 18 Jul 2022 16:07:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BFmm=E6=94=AF=E6=8C=814K=E8=99=9A?= =?UTF-8?q?=E6=8B=9F=E5=9C=B0=E5=9D=80=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/common/kprint.h | 72 +++++------ kernel/driver/acpi/acpi.c | 20 +-- kernel/driver/disk/ahci/ahci.c | 2 +- kernel/driver/interrupt/apic/apic.c | 4 +- kernel/driver/usb/xhci/xhci.c | 37 +++++- kernel/driver/usb/xhci/xhci.h | 6 +- kernel/driver/video/video.c | 4 +- kernel/mm/mm.c | 181 +++++++++++++++++++++++----- kernel/mm/mm.h | 71 +++++++++-- kernel/process/process.c | 49 +++++--- 10 files changed, 335 insertions(+), 111 deletions(-) diff --git a/kernel/common/kprint.h b/kernel/common/kprint.h index 62790801..25100c5b 100644 --- a/kernel/common/kprint.h +++ b/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); diff --git a/kernel/driver/acpi/acpi.c b/kernel/driver/acpi/acpi.c index 7335d8c7..10dcf9b0 100644 --- a/kernel/driver/acpi/acpi.c +++ b/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 { diff --git a/kernel/driver/disk/ahci/ahci.c b/kernel/driver/disk/ahci/ahci.c index 8d5a07b9..46b23b55 100644 --- a/kernel/driver/disk/ahci/ahci.c +++ b/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) { diff --git a/kernel/driver/interrupt/apic/apic.c b/kernel/driver/interrupt/apic/apic.c index ab8b4daf..ded669d3 100644 --- a/kernel/driver/interrupt/apic/apic.c +++ b/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); diff --git a/kernel/driver/usb/xhci/xhci.c b/kernel/driver/usb/xhci/xhci.c index d20cbc96..1b88ec37 100644 --- a/kernel/driver/usb/xhci/xhci.c +++ b/kernel/driver/usb/xhci/xhci.c @@ -2,12 +2,14 @@ #include #include #include +#include +#include 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); } \ No newline at end of file diff --git a/kernel/driver/usb/xhci/xhci.h b/kernel/driver/usb/xhci/xhci.h index 2b86752d..5f1981b5 100644 --- a/kernel/driver/usb/xhci/xhci.h +++ b/kernel/driver/usb/xhci/xhci.h @@ -2,6 +2,8 @@ #include #include +#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; // 指向端口信息数组的指针 }; diff --git a/kernel/driver/video/video.c b/kernel/driver/video/video.c index b85d9d08..60657d02 100644 --- a/kernel/driver/video/video.c +++ b/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); diff --git a/kernel/mm/mm.c b/kernel/mm/mm.c index 3b82c58b..a487729c 100644 --- a/kernel/mm/mm.c +++ b/kernel/mm/mm.c @@ -4,9 +4,12 @@ #include #include #include +#include +#include +#include -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)) { - // kwarn("page already mapped!"); - // 如果是用户态可访问的页,则释放当前新获取的物理页 - free_pages(Phy_to_2M_Page((ul)phys_addr_start + length_mapped), 1); - length_mapped += PAGE_2M_SIZE; - continue; + // 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 + { + 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; } - // 页面写穿,禁止缓存 - 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; - length_unmapped += PAGE_2M_SIZE; + // 循环处理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; + } + + // 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) 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); \ No newline at end of file diff --git a/kernel/process/process.c b/kernel/process/process.c index 3ef763d5..df28cba0 100644 --- a/kernel/process/process.c +++ b/kernel/process/process.c @@ -1,17 +1,19 @@ #include "process.h" -#include #include #include -#include -#include -#include -#include -#include #include -#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include + 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);