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

This commit is contained in:
fslongjin 2022-07-18 16:07:34 +08:00
parent 8b6489dac3
commit aa3f433cd5
10 changed files with 335 additions and 111 deletions

View File

@ -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
{

View File

@ -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)
{

View File

@ -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);

View File

@ -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 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);
}

View File

@ -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; // 虚拟地址basebar0映射到的虚拟地址
uint64_t vbase; // 虚拟地址basebar0映射到的虚拟地址
struct xhci_port_info_t *ports; // 指向端口信息数组的指针
};

View File

@ -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);

View File

@ -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,10 +599,51 @@ 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!");
// 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;
@ -593,8 +654,13 @@ void mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_
}
}
}
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;
}
// 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页的页表的检测
// pde页表项为0
if (*tmp == 0)
return 0;
if (*tmp & (1 << 7))
{
// 当前为2M物理页
return true;
}
else
{
// 存在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;
}

View File

@ -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
@ -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,11 +380,31 @@ 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);
void 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);
/**
* @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
@ -383,6 +415,25 @@ void mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul
* @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
*

View File

@ -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,9 +919,29 @@ uint64_t process_exit_mm(struct process_control_block *pcb)
{
if ((current_pdt + k)->pdt == 0)
continue;
// 存在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);
}