Improve and fix scanning for ACPI tables.

This commit is contained in:
Martin Whitaker 2020-12-11 13:27:05 +00:00
parent 27c5fe363f
commit 1d2bf57403
1 changed files with 43 additions and 28 deletions

View File

@ -89,7 +89,8 @@
#define MPCSignature ('P' | ('C' << 8) | ('M' << 16) | ('P' << 24))
#define RSDPSignature ('R' | ('S' << 8) | ('D' << 16) | (' ' << 24))
#define RSDPSignature1 ('R' | ('S' << 8) | ('D' << 16) | (' ' << 24))
#define RSDPSignature2 ('P' | ('T' << 8) | ('R' << 16) | (' ' << 24))
#define RSDTSignature ('R' | ('S' << 8) | ('D' << 16) | ('T' << 24))
@ -207,7 +208,7 @@ typedef struct {
} rsdp_t;
typedef struct {
char signature[4]; // "RSDT"
char signature[4]; // "RSDT" or "XSDT"
uint32_t length;
uint8_t revision;
uint8_t checksum;
@ -216,7 +217,7 @@ typedef struct {
char oem_revision[4];
char creator_id[4];
char creator_revision[4];
} rsdt_t;
} rsdt_header_t;
typedef struct {
uint8_t type;
@ -382,7 +383,7 @@ static bool find_cpus_in_floating_mp_struct(void)
fp = scan_for_floating_ptr_struct(0xf0000, 0x10000);
}
if (fp == NULL) {
// Search the BIOS ESDS area.
// Search the BIOS EBDA area.
uintptr_t address = *(uint16_t *)0x40E << 4;
if (address) {
fp = scan_for_floating_ptr_struct(address, 0x400);
@ -420,10 +421,12 @@ static rsdp_t *scan_for_rsdp(uintptr_t addr, int length)
while (ptr < end) {
rsdp_t *rp = (rsdp_t *)ptr;
if (*ptr == RSDPSignature && checksum(ptr, rp->length) == 0) {
return rp;
if (*ptr == RSDPSignature1 && *(ptr+1) == RSDPSignature2 && checksum(ptr, 20) == 0) {
if (rp->revision < 2 || (rp->length < 1024 && checksum(ptr, rp->length) == 0)) {
return rp;
}
}
ptr++;
ptr += 4;
}
return NULL;
}
@ -516,25 +519,25 @@ static bool find_cpus_in_rsdp(void)
}
#endif
if (rp == NULL) {
// Search the BIOS reserved area.
rp = scan_for_rsdp(0xE0000, 0x20000);
}
if (rp == NULL) {
// Search the BIOS ESDS area.
// Search the BIOS EBDA area.
uintptr_t address = *(uint16_t *)0x40E << 4;
if (address) {
rp = scan_for_rsdp(address, 0x400);
}
}
if (rp == NULL) {
// Search the BIOS reserved area.
rp = scan_for_rsdp(0xE0000, 0x20000);
}
if (rp == NULL) {
// RSDP not found, give up.
return false;
}
// Found the RSDP, now get either the RSDT or XSDT.
rsdt_t *rt;
// Found the RSDP, now get either the RSDT or XSDT and scan it for a pointer to the MADT.
rsdt_header_t *rt;
if (rp->revision >= 2) {
rt = (rsdt_t *)((uintptr_t)rp->xsdt_addr);
rt = (rsdt_header_t *)((uintptr_t)rp->xsdt_addr);
if (rt == 0) {
return false;
}
@ -542,11 +545,24 @@ static bool find_cpus_in_rsdp(void)
if (*(uint32_t *)rt != XSDTSignature) {
return false;
}
if (checksum((uint8_t *)rt, rt->length) != 0) {
if (checksum(rt, rt->length) != 0) {
return false;
}
// Scan the XSDT for a pointer to the MADT.
uint64_t *tab_ptr = (uint64_t *)((uint8_t *)rt + sizeof(rsdt_header_t));
uint64_t *tab_end = (uint64_t *)((uint8_t *)rt + rt->length);
while (tab_ptr < tab_end) {
uint32_t *ptr = (uint32_t *)((uintptr_t)(*tab_ptr++)); // read the next table entry
if (ptr && *ptr == MADTSignature) {
if (parse_madt(ptr)) {
return true;
}
}
}
} else {
rt = (rsdt_t *)((uintptr_t)rp->rsdt_addr);
rt = (rsdt_header_t *)((uintptr_t)rp->rsdt_addr);
if (rt == 0) {
return false;
}
@ -554,21 +570,20 @@ static bool find_cpus_in_rsdp(void)
if (*(uint32_t *)rt != RSDTSignature) {
return false;
}
if (checksum((uint8_t *)rt, rt->length) != 0) {
if (checksum(rt, rt->length) != 0) {
return false;
}
}
// Scan the RSDT for a pointer to the MADT.
uint32_t *tab_ptr = (uint32_t *)((uint8_t *)rt + sizeof(rsdt_header_t));
uint32_t *tab_end = (uint32_t *)((uint8_t *)rt + rt->length);
// Scan the RSDT or XSDT for a pointer to the MADT.
uint32_t *tab_ptr = (uint32_t *)(rt + 1); // immediately follows the RSDT/XSDT
uint32_t *tab_end = tab_ptr + (rt->length / sizeof(uint32_t));
while (tab_ptr < tab_end) {
uint32_t *ptr = (uint32_t *)((uintptr_t)(*tab_ptr++)); // read the next table entry
while (tab_ptr < tab_end) {
uint32_t *ptr = (uint32_t *)((uintptr_t)(*tab_ptr++)); // read the next table entry
if (ptr && *ptr == MADTSignature) {
if (parse_madt(ptr)) {
return true;
if (ptr && *ptr == MADTSignature) {
if (parse_madt(ptr)) {
return true;
}
}
}
}