Searching for the RSDP in the BIOS memory region is already supported
by libacpica. libacpica might also have additional methods to find it,
for example use of EFI data.
---
acpi/acpi.c | 93 ++++++++++++++++++++++-------------------------------
1 file changed, 39 insertions(+), 54 deletions(-)
diff --git a/acpi/acpi.c b/acpi/acpi.c
index 736728ae2..0cae49e21 100644
--- a/acpi/acpi.c
+++ b/acpi/acpi.c
@@ -33,39 +33,51 @@
#define __KERNEL__
#include <acpi/acpi.h>
+static int
+acpi_get_rsdp(struct rsdp_descr2 *rsdp)
+{
+ acpi_physical_address rsdp_phys = acpi_os_get_root_pointer();
+
+ if (!rsdp_phys)
+ return ENODEV;
+
+ acpi_size map_sz = sizeof (struct rsdp_descr2);
+ void *virt_addr = acpi_os_map_memory (rsdp_phys, map_sz);
+
+ if (virt_addr == MAP_FAILED)
+ {
+ /* There is an extremely unlikely case that rsdp_phys is very
+ close to the maximum value possible and ACPI 1 is in use
+ which meant we were mapping more than necessary. */
+
+ map_sz = sizeof (struct rsdp_descr);
+ virt_addr = acpi_os_map_memory (rsdp_phys, map_sz);
+ }
+
+ if (virt_addr == MAP_FAILED)
+ return errno;
+
+ memcpy (rsdp, virt_addr, map_sz);
+ acpi_os_unmap_memory (virt_addr, map_sz);
+
+ if (memcmp (rsdp->v1.magic, RSDP_MAGIC, sizeof (rsdp->v1.magic)))
+ return ENODEV;
+
+ return 0;
+}
+
int
acpi_get_num_tables(size_t *num_tables)
{
- void *virt_addr;
- bool found = false;
struct rsdp_descr2 rsdp = { 0 };
uintptr_t sdt_base = (uintptr_t)0;
bool is_64bit = false;
- unsigned char *buf;
struct acpi_header *root_sdt;
struct acpi_header *next;
- virt_addr = acpi_os_map_memory(ESCD, ESCD_SIZE);
- if (virt_addr == MAP_FAILED)
- return errno;
-
- buf = (unsigned char *)virt_addr;
- found = false;
-
- /* RSDP magic string is 16 byte aligned */
- for (int i = 0; i < ESCD_SIZE; i += 16)
- {
- if (!memcmp(&buf[i], RSDP_MAGIC, 8)) {
- rsdp = *((struct rsdp_descr2 *)(&buf[i]));
- found = true;
- break;
- }
- }
-
- if (!found) {
- acpi_os_unmap_memory(virt_addr, ESCD_SIZE);
- return ENODEV;
- }
+ int err = acpi_get_rsdp (&rsdp);
+ if (err)
+ return err;
if (rsdp.v1.revision == 0) {
// ACPI 1.0
@@ -76,12 +88,9 @@ acpi_get_num_tables(size_t *num_tables)
sdt_base = rsdp.xsdt_addr;
is_64bit = true;
} else {
- acpi_os_unmap_memory(virt_addr, ESCD_SIZE);
return ENODEV;
}
- acpi_os_unmap_memory(virt_addr, ESCD_SIZE);
-
/* Now we have the sdt_base address and knowledge of 32/64 bit ACPI */
root_sdt = acpi_os_map_memory(sdt_base, ESCD_SIZE);
@@ -131,12 +140,9 @@ int
acpi_get_tables(struct acpi_table **tables)
{
int err;
- void *virt_addr;
- bool found = false;
struct rsdp_descr2 rsdp = { 0 };
uintptr_t sdt_base = (uintptr_t)0;
bool is_64bit = false;
- unsigned char *buf;
struct acpi_header *root_sdt;
struct acpi_header *next;
size_t ntables_actual;
@@ -150,27 +156,9 @@ acpi_get_tables(struct acpi_table **tables)
if (!*tables)
return ENOMEM;
- virt_addr = acpi_os_map_memory(ESCD, ESCD_SIZE);
- if (virt_addr == MAP_FAILED)
- return errno;
-
- buf = (unsigned char *)virt_addr;
- found = false;
-
- /* RSDP magic string is 16 byte aligned */
- for (int i = 0; i < ESCD_SIZE; i += 16)
- {
- if (!memcmp(&buf[i], RSDP_MAGIC, 8)) {
- rsdp = *((struct rsdp_descr2 *)(&buf[i]));
- found = true;
- break;
- }
- }
-
- if (!found) {
- acpi_os_unmap_memory(virt_addr, ESCD_SIZE);
- return ENODEV;
- }
+ err = acpi_get_rsdp (&rsdp);
+ if (err)
+ return err;
if (rsdp.v1.revision == 0) {
// ACPI 1.0
@@ -181,12 +169,9 @@ acpi_get_tables(struct acpi_table **tables)
sdt_base = rsdp.xsdt_addr;
is_64bit = true;
} else {
- acpi_os_unmap_memory(virt_addr, ESCD_SIZE);
return ENODEV;
}
- acpi_os_unmap_memory(virt_addr, ESCD_SIZE);
-
/* Now we have the sdt_base address and knowledge of 32/64 bit ACPI */
root_sdt = acpi_os_map_memory(sdt_base, ESCD_SIZE);
--
2.47.3