Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bugfix: 修复因rsdp v1 v2版本问题,导致ACPI无法正常初始化的bug #454

Merged
merged 8 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 13 additions & 27 deletions kernel/src/arch/x86_64/pci/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ use crate::driver::pci::pci::{
BusDeviceFunction, PciAddr, PciError, PciRoot, SegmentGroupNumber, PORT_PCI_CONFIG_ADDRESS,
PORT_PCI_CONFIG_DATA,
};
use crate::include::bindings::bindings::{acpi_get_MCFG, acpi_iter_SDT, io_in32, io_out32};
use crate::include::bindings::bindings::{io_in32, io_out32};
use crate::mm::PhysAddr;

use acpi::mcfg::Mcfg;
use core::ffi::c_void;

pub struct X86_64PciArch;
impl TraitPciArch for X86_64PciArch {
Expand Down Expand Up @@ -45,33 +44,20 @@ impl TraitPciArch for X86_64PciArch {
}

fn ecam_root(segement: SegmentGroupNumber) -> Result<PciRoot, PciError> {
let mut data: usize = 0;
let data_point = &mut data;
unsafe {
acpi_iter_SDT(Some(acpi_get_MCFG), data_point as *mut usize as *mut c_void);
};
// 防止无PCIE的机器找不到MCFG Table导致的错误
if data == 0 {
return Err(PciError::McfgTableNotFound);
}
//kdebug!("{}",data);
//loop{}

let binding = acpi_manager()
let mcfg = acpi_manager()
.tables()
.expect("get acpi_manager table error")
.find_table::<Mcfg>();
if let Ok(mcfg) = binding {
for mcfg_entry in mcfg.entries() {
if mcfg_entry.pci_segment_group == segement {
return Ok(PciRoot {
physical_address_base: PhysAddr::new(mcfg_entry.base_address as usize),
mmio_guard: None,
segement_group_number: segement,
bus_begin: mcfg_entry.bus_number_start,
bus_end: mcfg_entry.bus_number_end,
});
}
.find_table::<Mcfg>()
.map_err(|_| PciError::McfgTableNotFound)?;
for mcfg_entry in mcfg.entries() {
if mcfg_entry.pci_segment_group == segement {
return Ok(PciRoot {
physical_address_base: PhysAddr::new(mcfg_entry.base_address as usize),
mmio_guard: None,
segement_group_number: segement,
bus_begin: mcfg_entry.bus_number_start,
bus_end: mcfg_entry.bus_number_end,
});
}
}
return Err(PciError::SegmentNotFound);
Expand Down
243 changes: 5 additions & 238 deletions kernel/src/driver/acpi/acpi.c
Original file line number Diff line number Diff line change
@@ -1,132 +1,19 @@
#include "acpi.h"
#include <common/printk.h>
#include <common/kprint.h>
#include <driver/multiboot2/multiboot2.h>
#include <mm/mm.h>
#include <mm/mmio.h>

extern void rs_acpi_init(uint64_t rsdp_paddr);

#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的虚拟地址
extern void rs_acpi_init(uint64_t rsdp_paddr1, uint64_t rsdp_paddr2);

static struct acpi_RSDP_t *rsdpv1;
static struct acpi_RSDP_2_t *rsdpv2;
static struct acpi_RSDT_Structure_t *rsdt;
static struct acpi_XSDT_Structure_t *xsdt;

static struct multiboot_tag_old_acpi_t old_acpi;
static struct multiboot_tag_new_acpi_t new_acpi;

static ul acpi_RSDT_offset = 0;
static ul acpi_XSDT_offset = 0;
static uint acpi_RSDT_Entry_num = 0;
static uint acpi_XSDT_Entry_num = 0;

static ul acpi_RSDT_entry_phys_base = 0; // RSDT中的第一个entry所在物理页的基地址

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所在物理页的基地址

/**
* @brief 迭代器,用于迭代描述符头(位于ACPI标准文件的Table 5-29)
* @param _fun 迭代操作调用的函数
* @param _data 数据
*/
void acpi_iter_SDT(bool (*_fun)(const struct acpi_system_description_table_header_t *, void *),
void *_data)
{

struct acpi_system_description_table_header_t *sdt_header;
if (acpi_use_xsdt)
{
ul *ent = &(xsdt->Entry);
for (int i = 0; i < acpi_XSDT_Entry_num; ++i)
{
// 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);
rs_map_phys(acpi_description_header_base + PAGE_2M_SIZE * i, (*(ent + i)) & PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE);
sdt_header = (struct acpi_system_description_table_header_t *)((ul)(acpi_description_header_base + PAGE_2M_SIZE * i));

if (_fun(sdt_header, _data) == true)
return;
}
}
else
{
uint *ent = &(rsdt->Entry);
for (int i = 0; i < acpi_RSDT_Entry_num; ++i)
{

sdt_header = (struct acpi_system_description_table_header_t *)(acpi_get_RSDT_entry_vaddr((ul)(*(ent + i))));

if (_fun(sdt_header, _data) == true)
return;
}
}

return;
}

/**
* @brief 获取MADT信息 Multiple APIC Description Table
*
* @param _iter_data 要被迭代的信息的结构体
* @param _data 返回的MADT的虚拟地址
* @param count 返回数组的长度
* @return true
* @return false
*/
bool acpi_get_MADT(const struct acpi_system_description_table_header_t *_iter_data, void *_data)
{
if (!(_iter_data->Signature[0] == 'A' && _iter_data->Signature[1] == 'P' && _iter_data->Signature[2] == 'I' && _iter_data->Signature[3] == 'C'))
return false;
//*(struct acpi_Multiple_APIC_Description_Table_t *)_data = *(struct acpi_Multiple_APIC_Description_Table_t *)_iter_data;
// 返回MADT的虚拟地址
*(ul *)_data = (ul)_iter_data;
acpi_madt_vaddr = (ul)_iter_data;
return true;
}

/**
* @brief 获取HPET HPET_description_table
*
* @param _iter_data 要被迭代的信息的结构体
* @param _data 返回的HPET表的虚拟地址
* @return true
* @return false
*/
bool acpi_get_HPET(const struct acpi_system_description_table_header_t *_iter_data, void *_data)
{
if (!(_iter_data->Signature[0] == 'H' && _iter_data->Signature[1] == 'P' && _iter_data->Signature[2] == 'E' && _iter_data->Signature[3] == 'T'))
return false;
*(ul *)_data = (ul)_iter_data;
return true;
}

/**
* @brief 获取MCFG MCFG_description_table
*
* @param _iter_data 要被迭代的信息的结构体
* @param _data 返回的MCFG表的虚拟地址
* @return true
* @return false
*/
bool acpi_get_MCFG(const struct acpi_system_description_table_header_t *_iter_data, void *_data)
{
if (!(_iter_data->Signature[0] == 'M' && _iter_data->Signature[1] == 'C' && _iter_data->Signature[2] == 'F' && _iter_data->Signature[3] == 'G'))
return false;
*(ul *)_data = (ul)_iter_data;
return true;
}

/**
* @brief 初始化acpi模块
*
*/
// todo: 修复bug:当物理机上提供了rsdpv2之后,rsdpv1是不提供的(物理地址为0),因此需要手动判断rsdp的版本信息,然后做对应的解析。
void acpi_init()
{
kinfo("Initializing ACPI...");
Expand All @@ -137,131 +24,11 @@ void acpi_init()
multiboot2_iter(multiboot2_get_acpi_old_RSDP, &old_acpi, &reserved);
rsdpv1 = &(old_acpi.rsdp);

// 这里有bug:当multiboot2不存在rsdpv2的时候,会导致错误
// multiboot2_iter(multiboot2_get_acpi_new_RSDP, &new_acpi, &reserved);
// rsdpv2 = &(new_acpi.rsdp);
rsdpv2 = NULL;
rs_acpi_init((uint64_t)rsdpv1);

uint64_t paddr = 0;
// An ACPI-compatible OS must use the XSDT if present
if (rsdpv2 && rsdpv2->XsdtAddress != 0x00UL)
{
// 不要删除这段注释(因为还不确定是代码的bug,还是真机的bug)
/*
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, false);
kdebug("XSDT mapped!");

xsdt = (struct acpi_XSDT_Structure_t *)(ACPI_XSDT_VIRT_ADDR_BASE + acpi_XSDT_offset);
// 计算RSDT Entry的数量
kdebug("offset=%d", sizeof(xsdt->header));
kdebug("xsdt sign=%s", xsdt->header.Signature);
acpi_XSDT_Entry_num = (xsdt->header.Length - sizeof(xsdt->header)) / 8;

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, 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, false);
}
*/

// 由于解析XSDT出现问题。暂时只使用Rsdpv2的rsdt,但是这是不符合ACPI规范的!!!
ul rsdt_phys_base = rsdpv2->rsdp1.RsdtAddress & PAGE_2M_MASK;
acpi_RSDT_offset = rsdpv2->rsdp1.RsdtAddress - rsdt_phys_base;

// 申请mmio空间
uint64_t size = 0;
rs_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);
rs_map_phys(acpi_rsdt_virt_addr_base, paddr, PAGE_2M_SIZE, PAGE_KERNEL_PAGE);

// rsdt表虚拟地址
rsdt = (struct acpi_RSDT_Structure_t *)(acpi_rsdt_virt_addr_base + acpi_RSDT_offset);
kdebug("RSDT mapped!(v2)");

// 计算RSDT Entry的数量
kdebug("offset=%d", sizeof(rsdt->header));
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 Entry num=%d\n", acpi_RSDT_Entry_num);

// 申请mmio空间
rs_mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_description_header_base, &size);

// 映射所有的Entry的物理地址
acpi_RSDT_entry_phys_base = ((ul)(rsdt->Entry)) & PAGE_2M_MASK;
// 由于地址只是32bit的,并且存在脏数据,这里需要手动清除高32bit,否则会触发#GP
acpi_RSDT_entry_phys_base = MASK_HIGH_32bit(acpi_RSDT_entry_phys_base);

paddr = (uint64_t)acpi_RSDT_entry_phys_base;
// mm_map(&initial_mm, acpi_description_header_base, PAGE_2M_SIZE, paddr);
rs_map_phys(acpi_description_header_base, paddr, PAGE_2M_SIZE, PAGE_KERNEL_PAGE);
}
else if (rsdpv1->RsdtAddress != (uint)0x00UL)
{
// rsdt表物理地址
ul rsdt_phys_base = rsdpv1->RsdtAddress & PAGE_2M_MASK;
acpi_RSDT_offset = rsdpv1->RsdtAddress - rsdt_phys_base;

kdebug("rsdpv1->RsdtAddress=%#018lx", rsdpv1->RsdtAddress);
// 申请mmio空间
uint64_t size = 0;
rs_mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_rsdt_virt_addr_base, &size);
// acpi_rsdt_virt_addr_base = 0xffffb00000000000UL;
kdebug("ACPI: mmio created. acpi_rsdt_virt_addr_base = %#018lx,size= %#010lx", 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);
rs_map_phys(acpi_rsdt_virt_addr_base, paddr, PAGE_2M_SIZE, PAGE_KERNEL_PAGE);
// rsdt表虚拟地址
rsdt = (struct acpi_RSDT_Structure_t *)(acpi_rsdt_virt_addr_base + acpi_RSDT_offset);
kdebug("RSDT mapped!");

// kdebug("length = %d",rsdt->header.Length);
// 计算RSDT Entry的数量
// kdebug("offset=%d", sizeof(rsdt->header));

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 Entry num=%d\n", acpi_RSDT_Entry_num);

// 申请mmio空间
rs_mmio_create(PAGE_2M_SIZE, VM_IO | VM_DONTCOPY, &acpi_description_header_base, &size);

// 映射所有的Entry的物理地址
acpi_RSDT_entry_phys_base = ((ul)(rsdt->Entry)) & PAGE_2M_MASK;
// 由于地址只是32bit的,并且存在脏数据,这里需要手动清除高32bit,否则会触发#GP
acpi_RSDT_entry_phys_base = MASK_HIGH_32bit(acpi_RSDT_entry_phys_base);
multiboot2_iter(multiboot2_get_acpi_new_RSDP, &new_acpi, &reserved);
rsdpv2 = &(new_acpi.rsdp);

paddr = (uint64_t)acpi_RSDT_entry_phys_base;
// mm_map(&initial_mm, acpi_description_header_base, PAGE_2M_SIZE, paddr);
rs_map_phys(acpi_description_header_base, paddr, PAGE_2M_SIZE, PAGE_KERNEL_PAGE);
kinfo("entry mapped!");
}
else
{
// should not reach here!
kBUG("At acpi_init(): Cannot get right SDT!");
while (1)
;
}
// rsdpv1、rsdpv2,二者有一个能成功即可
rs_acpi_init((uint64_t)rsdpv1, (uint64_t)rsdpv2);

kinfo("ACPI module initialized!");
return;
Expand Down
Loading