在acpi中使用mmio来映射rsdt表(#40)

* 在acpi中使用mmio来映射rsdt表

* bugfix: 修复page fault的问题

Co-authored-by: fslongjin <longjin@RinGoTek.cn>
This commit is contained in:
houmkh 2022-09-09 00:21:46 +08:00 committed by GitHub
parent 55e63fcb63
commit 6db92c86b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 85 additions and 48 deletions

View File

@ -3,8 +3,9 @@
#include <common/kprint.h> #include <common/kprint.h>
#include <driver/multiboot2/multiboot2.h> #include <driver/multiboot2/multiboot2.h>
#include <mm/mm.h> #include <mm/mm.h>
#include <mm/mmio.h>
#define acpi_get_RSDT_entry_vaddr(phys_addr) (ACPI_DESCRIPTION_HEDERS_BASE + (phys_addr)-acpi_RSDT_entry_phys_base) // 获取RSDT entry的虚拟地址 #define acpi_get_RSDT_entry_vaddr(phys_addr) (acpi_description_header_base + (phys_addr)-acpi_RSDT_entry_phys_base) // 获取RSDT entry的虚拟地址
// #define acpi_get_XSDT_entry_vaddr(phys_addr) (ACPI_DESCRIPTION_HEDERS_BASE + (phys_addr)-acpi_XSDT_entry_phys_base) // 获取XSDT entry的虚拟地址 // #define acpi_get_XSDT_entry_vaddr(phys_addr) (ACPI_DESCRIPTION_HEDERS_BASE + (phys_addr)-acpi_XSDT_entry_phys_base) // 获取XSDT entry的虚拟地址
static struct acpi_RSDP_t *rsdpv1; static struct acpi_RSDP_t *rsdpv1;
@ -23,6 +24,8 @@ static uint acpi_XSDT_Entry_num = 0;
static ul acpi_RSDT_entry_phys_base = 0; // RSDT中的第一个entry所在物理页的基地址 static ul acpi_RSDT_entry_phys_base = 0; // RSDT中的第一个entry所在物理页的基地址
static uint64_t acpi_madt_vaddr = 0; // MADT的虚拟地址 static uint64_t acpi_madt_vaddr = 0; // MADT的虚拟地址
static uint64_t acpi_rsdt_virt_addr_base = 0; // RSDT的虚拟地址
static uint64_t acpi_description_header_base = 0; // RSDT中的第一个entry所在虚拟地址
// static ul acpi_XSDT_entry_phys_base = 0; // XSDT中的第一个entry所在物理页的基地址 // static ul acpi_XSDT_entry_phys_base = 0; // XSDT中的第一个entry所在物理页的基地址
@ -41,8 +44,8 @@ void acpi_iter_SDT(bool (*_fun)(const struct acpi_system_description_table_heade
ul *ent = &(xsdt->Entry); ul *ent = &(xsdt->Entry);
for (int i = 0; i < acpi_XSDT_Entry_num; ++i) 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, false); mm_map_phys_addr(acpi_description_header_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)); sdt_header = (struct acpi_system_description_table_header_t *)((ul)(acpi_description_header_base + PAGE_2M_SIZE * i));
if (_fun(sdt_header, _data) == true) if (_fun(sdt_header, _data) == true)
return; return;
@ -100,7 +103,6 @@ bool acpi_get_HPET(const struct acpi_system_description_table_header_t *_iter_da
return true; return true;
} }
/** /**
* @brief acpi模块 * @brief acpi模块
* *
@ -110,26 +112,20 @@ void acpi_init()
{ {
kinfo("Initializing ACPI..."); kinfo("Initializing ACPI...");
// 获取rsdp // 获取物理地址
int reserved; int reserved;
multiboot2_iter(multiboot2_get_acpi_old_RSDP, &old_acpi, &reserved); multiboot2_iter(multiboot2_get_acpi_old_RSDP, &old_acpi, &reserved);
rsdpv1 = &(old_acpi.rsdp); rsdpv1 = &(old_acpi.rsdp);
kdebug("RSDT_phys_Address=%#018lx", rsdpv1->RsdtAddress);
kdebug("RSDP_Revision=%d", rsdpv1->Revision);
multiboot2_iter(multiboot2_get_acpi_new_RSDP, &new_acpi, &reserved); multiboot2_iter(multiboot2_get_acpi_new_RSDP, &new_acpi, &reserved);
rsdpv2 = &(new_acpi.rsdp); rsdpv2 = &(new_acpi.rsdp);
kdebug("Rsdt_v2_phys_Address=%#018lx", rsdpv2->rsdp1.RsdtAddress); uint64_t paddr = 0;
kdebug("Xsdt_phys_Address=%#018lx", rsdpv2->XsdtAddress);
kdebug("RSDP_v2_Revision=%d", rsdpv2->rsdp1.Revision);
// An ACPI-compatible OS must use the XSDT if present // An ACPI-compatible OS must use the XSDT if present
if (rsdpv2->XsdtAddress != 0x00UL) if (rsdpv2->XsdtAddress != 0x00UL)
{ {
// 不要删除这段注释因为还不确定是代码的bug还是真机的bug
/* /*
acpi_use_xsdt = true; acpi_use_xsdt = true;
ul xsdt_phys_base = rsdpv2->XsdtAddress & PAGE_2M_MASK; ul xsdt_phys_base = rsdpv2->XsdtAddress & PAGE_2M_MASK;
@ -156,12 +152,23 @@ void acpi_init()
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); 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规范的 // 由于解析XSDT出现问题。暂时只使用Rsdpv2的rsdt但是这是不符合ACPI规范的
ul rsdt_phys_base = rsdpv2->rsdp1.RsdtAddress & PAGE_2M_MASK; ul rsdt_phys_base = rsdpv2->rsdp1.RsdtAddress & PAGE_2M_MASK;
acpi_RSDT_offset = rsdpv2->rsdp1.RsdtAddress - rsdt_phys_base; 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, false);
//申请mmio空间
uint64_t size = 0;
mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_rsdt_virt_addr_base, &size);
//映射rsdt表
paddr = (uint64_t)rsdt_phys_base;
mm_map(&initial_mm, acpi_rsdt_virt_addr_base, PAGE_2M_SIZE, paddr);
// rsdt表虚拟地址
rsdt = (struct acpi_RSDT_Structure_t *)(acpi_rsdt_virt_addr_base + acpi_RSDT_offset);
kdebug("RSDT mapped!(v2)"); kdebug("RSDT mapped!(v2)");
rsdt = (struct acpi_RSDT_Structure_t *)(ACPI_RSDT_VIRT_ADDR_BASE + acpi_RSDT_offset);
// 计算RSDT Entry的数量 // 计算RSDT Entry的数量
kdebug("offset=%d", sizeof(rsdt->header)); kdebug("offset=%d", sizeof(rsdt->header));
acpi_RSDT_Entry_num = (rsdt->header.Length - 36) / 4; acpi_RSDT_Entry_num = (rsdt->header.Length - 36) / 4;
@ -169,43 +176,57 @@ void acpi_init()
printk_color(ORANGE, BLACK, "RSDT Length=%dbytes.\n", rsdt->header.Length); printk_color(ORANGE, BLACK, "RSDT Length=%dbytes.\n", rsdt->header.Length);
printk_color(ORANGE, BLACK, "RSDT Entry num=%d\n", acpi_RSDT_Entry_num); 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, false); //申请mmio空间
mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_description_header_base, &size);
// 映射所有的Entry的物理地址 // 映射所有的Entry的物理地址
acpi_RSDT_entry_phys_base = ((ul)(rsdt->Entry)) & PAGE_2M_MASK; acpi_RSDT_entry_phys_base = ((ul)(rsdt->Entry)) & PAGE_2M_MASK;
// 由于地址只是32bit的并且存在脏数据这里需要手动清除高32bit否则会触发#GP // 由于地址只是32bit的并且存在脏数据这里需要手动清除高32bit否则会触发#GP
acpi_RSDT_entry_phys_base = MASK_HIGH_32bit(acpi_RSDT_entry_phys_base); acpi_RSDT_entry_phys_base = MASK_HIGH_32bit(acpi_RSDT_entry_phys_base);
kdebug("entry=%#018lx", rsdt->Entry); paddr = (uint64_t)acpi_RSDT_entry_phys_base;
kdebug("acpi_RSDT_entry_phys_base=%#018lx", acpi_RSDT_entry_phys_base); mm_map(&initial_mm, acpi_description_header_base, PAGE_2M_SIZE, paddr);
// 映射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, false);
} }
else if (rsdpv1->RsdtAddress != (uint)0x00UL) else if (rsdpv1->RsdtAddress != (uint)0x00UL)
{ // 映射RSDT的物理地址到页表 {
// 暂定字节数为2MB // rsdt表物理地址
// 由于页表映射的原因需要清除低21位地址才能填入页表
ul rsdt_phys_base = rsdpv1->RsdtAddress & PAGE_2M_MASK; ul rsdt_phys_base = rsdpv1->RsdtAddress & PAGE_2M_MASK;
acpi_RSDT_offset = rsdpv1->RsdtAddress - rsdt_phys_base; 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, false);
kdebug("rsdpv1->RsdtAddress=%#018lx", rsdpv1->RsdtAddress);
//申请mmio空间
uint64_t size = 0;
mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_rsdt_virt_addr_base, &size);
// kdebug("acpi_rsdt_virt_addr_base = %#018lx,size= %#010lx", acpi_rsdt_virt_addr_base, size);
//映射rsdt表
paddr = (uint64_t)rsdt_phys_base;
mm_map(&initial_mm, acpi_rsdt_virt_addr_base, PAGE_2M_SIZE, paddr);
// rsdt表虚拟地址
rsdt = (struct acpi_RSDT_Structure_t *)(acpi_rsdt_virt_addr_base + acpi_RSDT_offset);
kdebug("RSDT mapped!"); kdebug("RSDT mapped!");
rsdt = (struct acpi_RSDT_Structure_t *)(ACPI_RSDT_VIRT_ADDR_BASE + acpi_RSDT_offset);
// kdebug("length = %d",rsdt->header.Length);
// 计算RSDT Entry的数量 // 计算RSDT Entry的数量
kdebug("offset=%d", sizeof(rsdt->header)); // kdebug("offset=%d", sizeof(rsdt->header));
acpi_RSDT_Entry_num = (rsdt->header.Length - 36) / 4; acpi_RSDT_Entry_num = (rsdt->header.Length - 36) / 4;
printk_color(ORANGE, BLACK, "RSDT Length=%dbytes.\n", rsdt->header.Length); printk_color(ORANGE, BLACK, "RSDT Length=%dbytes.\n", rsdt->header.Length);
printk_color(ORANGE, BLACK, "RSDT Entry num=%d\n", acpi_RSDT_Entry_num); 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, false); //申请mmio空间
mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_description_header_base, &size);
// 映射所有的Entry的物理地址 // 映射所有的Entry的物理地址
acpi_RSDT_entry_phys_base = ((ul)(rsdt->Entry)) & PAGE_2M_MASK; acpi_RSDT_entry_phys_base = ((ul)(rsdt->Entry)) & PAGE_2M_MASK;
// 由于地址只是32bit的并且存在脏数据这里需要手动清除高32bit否则会触发#GP // 由于地址只是32bit的并且存在脏数据这里需要手动清除高32bit否则会触发#GP
acpi_RSDT_entry_phys_base = MASK_HIGH_32bit(acpi_RSDT_entry_phys_base); acpi_RSDT_entry_phys_base = MASK_HIGH_32bit(acpi_RSDT_entry_phys_base);
kdebug("entry=%#018lx", rsdt->Entry); paddr = (uint64_t)acpi_RSDT_entry_phys_base;
kdebug("acpi_RSDT_entry_phys_base=%#018lx", acpi_RSDT_entry_phys_base); mm_map(&initial_mm, acpi_description_header_base, PAGE_2M_SIZE, paddr);
// 映射RSDT ENTRY的物理地址 // kinfo("entry mapped!");
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 else
{ {
@ -216,4 +237,5 @@ void acpi_init()
} }
kinfo("ACPI module initialized!"); kinfo("ACPI module initialized!");
return;
} }

View File

@ -25,11 +25,8 @@
#define ACPI_ICS_TYPE_PROCESSOR_GIC_ITS 0xF #define ACPI_ICS_TYPE_PROCESSOR_GIC_ITS 0xF
// 0x10-0x7f Reserved. OSPM skips structures of the reserved type. // 0x10-0x7f Reserved. OSPM skips structures of the reserved type.
// 0x80-0xff Reserved for OEM use // 0x80-0xff Reserved for OEM use
// extern const uint64_t acpi_rsdt_virt_addr_base ; // RSDT的虚拟地址
#define ACPI_RSDT_VIRT_ADDR_BASE SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + ACPI_RSDT_MAPPING_OFFSET // extern const uint64_t acpi_description_header_base ; // RSDT中的第一个entry所在虚拟地址
#define ACPI_XSDT_VIRT_ADDR_BASE SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + ACPI_XSDT_MAPPING_OFFSET
#define ACPI_DESCRIPTION_HEDERS_BASE ACPI_RSDT_VIRT_ADDR_BASE + (PAGE_2M_SIZE)
#define ACPI_XSDT_DESCRIPTION_HEDERS_BASE ACPI_XSDT_VIRT_ADDR_BASE + (PAGE_2M_SIZE)
bool acpi_use_xsdt = false; bool acpi_use_xsdt = false;
struct acpi_RSDP_t struct acpi_RSDP_t

View File

@ -229,6 +229,26 @@ void mm_init()
// 初始化slab内存池 // 初始化slab内存池
slab_init(); slab_init();
page_table_init(); page_table_init();
initial_mm.pgd = (pml4t_t *)get_CR3();
initial_mm.code_addr_start = memory_management_struct.kernel_code_start;
initial_mm.code_addr_end = memory_management_struct.kernel_code_end;
initial_mm.data_addr_start = (ul)&_data;
initial_mm.data_addr_end = memory_management_struct.kernel_data_end;
initial_mm.rodata_addr_start = (ul)&_rodata;
initial_mm.rodata_addr_end = (ul)&_erodata;
initial_mm.bss_start = (uint64_t)&_bss;
initial_mm.bss_end = (uint64_t)&_ebss;
initial_mm.brk_start = memory_management_struct.start_brk;
initial_mm.brk_end = current_pcb->addr_limit;
initial_mm.stack_start = _stack_start;
initial_mm.vmas = NULL;
mmio_init(); mmio_init();
} }

View File

@ -45,8 +45,6 @@
// 在这个地址以上的虚拟空间,用来进行特殊的映射 // 在这个地址以上的虚拟空间,用来进行特殊的映射
#define SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE 0xffffa00000000000UL #define SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE 0xffffa00000000000UL
#define FRAME_BUFFER_MAPPING_OFFSET 0x3000000UL #define FRAME_BUFFER_MAPPING_OFFSET 0x3000000UL
#define ACPI_RSDT_MAPPING_OFFSET 0x7000000UL
#define ACPI_XSDT_MAPPING_OFFSET 0x9000000UL
#define IO_APIC_MAPPING_OFFSET 0xfec00000UL #define IO_APIC_MAPPING_OFFSET 0xfec00000UL
#define LOCAL_APIC_MAPPING_OFFSET 0xfee00000UL #define LOCAL_APIC_MAPPING_OFFSET 0xfee00000UL
#define AHCI_MAPPING_OFFSET 0xff200000UL // AHCI 映射偏移量,之后使用了4M的地址 #define AHCI_MAPPING_OFFSET 0xff200000UL // AHCI 映射偏移量,之后使用了4M的地址

View File

@ -351,8 +351,10 @@ int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr)
int retval = 0; int retval = 0;
// 获取物理地址对应的页面 // 获取物理地址对应的页面
struct Page *pg; struct Page *pg;
uint64_t page_flags = 0;
if (vma->vm_flags & VM_IO) // 对于mmio的内存创建新的page结构体 if (vma->vm_flags & VM_IO) // 对于mmio的内存创建新的page结构体
{ {
page_flags = PAGE_PWT | PAGE_PCD;
if (unlikely(vma->anon_vma == NULL || vma->anon_vma->page == NULL)) if (unlikely(vma->anon_vma == NULL || vma->anon_vma->page == NULL))
pg = __create_mmio_page_struct(paddr); pg = __create_mmio_page_struct(paddr);
else else
@ -381,15 +383,14 @@ int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr)
/* /*
todo: todo:
*/ */
// kdebug("len2m=%d", len_2m);
// 先映射2M页 // 先映射2M页
if (likely(len_2m > 0)) if (likely(len_2m > 0))
{ {
uint64_t page_flags = 0;
if (vma->vm_flags & VM_USER) if (vma->vm_flags & VM_USER)
page_flags = PAGE_USER_PAGE; page_flags |= PAGE_USER_PAGE;
else else
page_flags = PAGE_KERNEL_PAGE; page_flags |= PAGE_KERNEL_PAGE;
// 这里直接设置user标志位为false因为该函数内部会对其进行自动校正 // 这里直接设置user标志位为false因为该函数内部会对其进行自动校正
retval = mm_map_proc_page_table((uint64_t)vma->vm_mm->pgd, true, vma->vm_start, paddr, len_2m, page_flags, false, false, false); retval = mm_map_proc_page_table((uint64_t)vma->vm_mm->pgd, true, vma->vm_start, paddr, len_2m, page_flags, false, false, false);
if (unlikely(retval != 0)) if (unlikely(retval != 0))
@ -400,11 +401,10 @@ int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr)
{ {
len_4k = ALIGN(len_4k, PAGE_4K_SIZE); len_4k = ALIGN(len_4k, PAGE_4K_SIZE);
uint64_t page_flags = 0;
if (vma->vm_flags & VM_USER) if (vma->vm_flags & VM_USER)
page_flags = PAGE_USER_4K_PAGE; page_flags |= PAGE_USER_4K_PAGE;
else else
page_flags = PAGE_KERNEL_4K_PAGE; page_flags |= PAGE_KERNEL_4K_PAGE;
// 这里直接设置user标志位为false因为该函数内部会对其进行自动校正 // 这里直接设置user标志位为false因为该函数内部会对其进行自动校正
retval = mm_map_proc_page_table((uint64_t)vma->vm_mm->pgd, true, vma->vm_start + len_2m, paddr + len_2m, len_4k, page_flags, false, false, true); retval = mm_map_proc_page_table((uint64_t)vma->vm_mm->pgd, true, vma->vm_start + len_2m, paddr + len_2m, len_4k, page_flags, false, false, true);
if (unlikely(retval != 0)) if (unlikely(retval != 0))