mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 19:36:47 +00:00
使mm支持4K虚拟地址映射
This commit is contained in:
parent
8b6489dac3
commit
aa3f433cd5
@ -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
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
@ -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; // 指向端口信息数组的指针
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
161
kernel/mm/mm.c
161
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,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;
|
||||
}
|
@ -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 调整堆区域的大小(暂时只能增加堆区域)
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user