]> xenbits.xensource.com Git - unikraft/unikraft.git/commitdiff
plat/common/acpi: Generalize `ACPI` initialization code
authorSergiu Moga <sergiu.moga@protonmail.com>
Mon, 24 Apr 2023 13:25:05 +0000 (16:25 +0300)
committerUnikraft <monkey@unikraft.io>
Fri, 11 Aug 2023 15:57:48 +0000 (15:57 +0000)
Write the code in such a manner that the same set of functions can
accommodate any version of ACPI. Thus, remove `acpi10_*` functions
and define an ACPI table generic fetching function `acpi_get_table`.

Signed-off-by: Sergiu Moga <sergiu.moga@protonmail.com>
Reviewed-by: Dragos Petre <dragos.petre27@gmail.com>
Reviewed-by: Marco Schlumpp <marco@unikraft.io>
Approved-by: Razvan Deaconescu <razvand@unikraft.io>
Tested-by: Unikraft CI <monkey@unikraft.io>
GitHub-Closes: #911

plat/common/include/x86/acpi/acpi.h
plat/common/x86/acpi.c
plat/common/x86/lcpu.c

index 336b6091a4de7004ef8610191f0809d460819072..a23fdfbf1240efb936762795a8292cff0bab03e3 100644 (file)
@@ -54,18 +54,17 @@ struct acpi_rsdp {
 } __packed;
 
 /**
- * Detect ACPI version and fetch ACPI tables.
+ * Get the Multiple APIC Descriptor Table (MADT).
  *
- * @return 0 on success, -errno otherwise.
+ * @return ACPI table pointer on success, NULL otherwise.
  */
-int acpi_init(void);
+struct acpi_madt *acpi_get_madt(void);
 
 /**
- * Return the detected ACPI version.
+ * Detect ACPI version and fetch ACPI tables.
  *
- * @return 0 if ACPI is not initialized or initialization failed, ACPI version
- *    otherwise.
+ * @return 0 on success, -errno otherwise.
  */
-int acpi_get_version(void);
+int acpi_init(void);
 
 #endif /* __PLAT_CMN_X86_ACPI_H__ */
index 3b90f587d6d04765f169ba4d6d5e00d124657193..a9648e5dae520075833d7a7e60e4c1147708c507 100644 (file)
@@ -1,8 +1,9 @@
 /* SPDX-License-Identifier: BSD-3-Clause */
 /*
  * Authors: Cristian Vijelie <cristianvijelie@gmail.com>
+ *          Sergiu Moga <sergiu.moga@protonmail.com>
  *
- * Copyright (c) 2021, University POLITEHNICA of Bucharest. All rights reserved.
+ * Copyright (c) 2023, University POLITEHNICA of Bucharest. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include <uk/print.h>
 #include <uk/assert.h>
 #include <x86/acpi/acpi.h>
-
 #include <string.h>
 #include <errno.h>
+#include <uk/plat/common/bootinfo.h>
 
-#define RSDT_ENTRIES(rsdt) (((rsdt)->hdr.tab_len - sizeof((rsdt)->hdr)) / 4)
 #define RSDP10_LEN             20
+#define BIOS_ROM_START         0xE0000UL
+#define BIOS_ROM_END           0xFFFFFUL
+#define BIOS_ROM_STEP          16
 
-static __u8 acpi_version;
-static struct acpi_rsdp *acpi_rsdp;
-static struct acpi_rsdt *acpi_rsdt;
 static struct acpi_madt *acpi_madt;
+static __u8 acpi_rsdt_entries;
+static void *acpi_rsdt;
+static __u8 acpi10;
+
+static struct {
+       struct acpi_sdt_hdr **sdt;
+       const char *sig;
+} acpi_sdts[] = {
+       {
+               .sdt = (struct acpi_sdt_hdr **)&acpi_madt,
+               .sig = ACPI_MADT_SIG,
+       },
+};
+
+static inline __paddr_t get_rsdt_entry(int idx)
+{
+       __u8 *entryp = (__u8 *)acpi_rsdt + sizeof(struct acpi_sdt_hdr);
+
+       if (acpi10)
+               return ((__u32 *)entryp)[idx];
+
+       return ((__u64 *)entryp)[idx];
+}
 
 static __u8 get_acpi_checksum(void __maybe_unused *buf, __sz __maybe_unused len)
 {
@@ -62,216 +85,136 @@ static __u8 get_acpi_checksum(void __maybe_unused *buf, __sz __maybe_unused len)
 #endif
 }
 
-/**
- * Find the Root System Descriptor Pointer (RSDP) in the physical memory area
- * 0xe0000 -> 0xfffff and determine ACPI version.
- *
- * @return 0 on success, -ENOENT if the table is not found, or invalid,
- * -ENOTSUP if the ACPI version is not supported.
- */
-
-static int detect_acpi_version(void)
+static void acpi_init_tables(void)
 {
-       __u8 *start_addr = (__u8 *)0xe0000; /* BIOS read-only memory space */
-       __u8 *end_addr = (__u8 *)0xfffff;
-       __u8 *ptr;
-
-       UK_ASSERT(!acpi_rsdp);
-       UK_ASSERT(!acpi_version);
-
-       for (ptr = start_addr; ptr < end_addr; ptr += 16) {
-               if (!memcmp(ptr, "RSD PTR ", 8)) {
-                       acpi_rsdp = (struct acpi_rsdp *)ptr;
-                       uk_pr_debug("ACPI RSDP present at %p\n", ptr);
-                       break;
-               }
-       }
-
-       if (!acpi_rsdp) {
-               uk_pr_debug("ACPI RSDP not found\n");
-               return -ENOENT;
-       }
+       struct acpi_sdt_hdr *h;
+       const char *sig;
+       __sz i, j;
 
-       if (unlikely(!get_acpi_checksum(acpi_rsdp, RSDP10_LEN))) {
-               uk_pr_err("ACPI RSDP corrupted\n");
+       UK_ASSERT(acpi_rsdt);
 
-               acpi_rsdp = NULL;
-               return -ENOENT;
-       }
+       for (i = 0; i < acpi_rsdt_entries; i++)
+               for (j = 0; j < ARRAY_SIZE(acpi_sdts); j++) {
+                       if (*acpi_sdts[j].sdt)
+                               continue;
 
-       uk_pr_info("ACPI version detected: ");
-       if (acpi_rsdp->revision == 0) {
-               uk_pr_info("1.0\n");
+                       h = (struct acpi_sdt_hdr *)get_rsdt_entry(i);
+                       sig = acpi_sdts[j].sig;
 
-               acpi_version = 1;
-       } else {
-               uk_pr_info(">= 2\n");
+                       if (!memcmp(h->sig, sig, ACPI_SDT_SIG_LEN)) {
+                               if (unlikely(get_acpi_checksum(h,
+                                                              h->tab_len))) {
+                                       uk_pr_warn("ACPI %s corrupted\n", sig);
 
-               /*
-                * TODO: add support for ACPI version 2 and greater
-                */
-               uk_pr_err("ACPI version not supported\n");
+                                       continue;
+                               }
 
-               return -ENOTSUP;
-       }
+                               *acpi_sdts[j].sdt = h;
 
-       return 0;
+                               continue;
+                       }
+               }
 }
 
 /*
- * Find the ACPI Root System Descriptor Table (RSDT) and check if it's valid.
+ * Print the detected ACPI tables to the debug output.
  */
-
-static int acpi10_find_rsdt(void)
+#ifdef UK_DEBUG
+static void acpi_list_tables(void)
 {
-       UK_ASSERT(acpi_version == 1);
-       UK_ASSERT(acpi_rsdp);
+       int i;
 
-       acpi_rsdt = (struct acpi_rsdt *)((__uptr)acpi_rsdp->rsdt_paddr);
-       uk_pr_debug("ACPI RSDT present at %p\n", acpi_rsdt);
+       UK_ASSERT(acpi_rsdt);
 
-       if (unlikely(!get_acpi_checksum(&acpi_rsdt->hdr,
-                    acpi_rsdt->hdr.tab_len))) {
-               uk_pr_err("ACPI RSDT corrupted\n");
+       uk_pr_debug("%d ACPI tables found from %.4s\n", acpi_rsdt_entries,
+                   acpi10 ? ACPI_RSDT_SIG : ACPI_XSDT_SIG);
+       for (i = 0; i < ARRAY_SIZE(acpi_sdts); i++) {
+               if (!acpi_sdts[i].sdt)
+                       continue;
 
-               acpi_rsdt = NULL;
-               return -ENOENT;
+               uk_pr_debug("%p: %.4s\n", acpi_sdts[i].sdt, acpi_sdts[i].sig);
        }
-
-       return 0;
 }
+#endif /* UK_DEBUG */
 
-/*
- * Find the Multiple APIC Descriptor Table (MADT) in the RSDT and check if
- * it's valid. MADT can be found by searching for the string "APIC" in the
- * first 4 bytes of each table entry.
- */
-
-static int acpi10_find_madt(void)
+#if defined(__X86_64__)
+static struct acpi_rsdp *acpi_get_bios_rom_rsdp(void)
 {
-       int entries, i;
-       struct acpi_sdt_hdr *h;
+       __paddr_t ptr;
 
-       UK_ASSERT(acpi_version == 1);
-       UK_ASSERT(acpi_rsdt);
-       UK_ASSERT(!acpi_madt);
-
-       entries = RSDT_ENTRIES(acpi_rsdt);
-
-       for (i = 0; i < entries; i++) {
-               h = (struct acpi_sdt_hdr *)((__uptr)acpi_rsdt->entry[i]);
+       for (ptr = BIOS_ROM_START; ptr < BIOS_ROM_END; ptr += BIOS_ROM_STEP)
+               if (!memcmp((void *)ptr, RSDP_SIG, sizeof(RSDP_SIG) - 1)) {
+                       uk_pr_debug("ACPI RSDP present at %lx\n", ptr);
 
-               if (memcmp(h->sig, "APIC", 4) != 0)
-                       continue; /* Not an APIC entry */
-
-               uk_pr_debug("ACPI MADT present at %p\n", h);
-
-               if (unlikely(!get_acpi_checksum(h, h->tab_len))) {
-                       uk_pr_err("ACPI MADT corrupted\n");
-                       return -ENOENT;
+                       return (struct acpi_rsdp *)ptr;
                }
 
-               acpi_madt = (struct acpi_madt *)h;
-               return 0;
-       }
+       return NULL;
+}
+#endif
 
-       /* no MADT was found */
-       return -ENOENT;
+static struct acpi_rsdp *acpi_get_rsdp(void)
+{
+       return acpi_get_bios_rom_rsdp();
 }
 
 /*
- * Print the detected ACPI tables to the debug output.
+ * Detect ACPI version and discover ACPI tables.
  */
-
-#ifdef UK_DEBUG
-static void acpi10_list_tables(void)
+int acpi_init(void)
 {
-       int entries, i;
+       struct acpi_rsdp *rsdp;
        struct acpi_sdt_hdr *h;
 
-       UK_ASSERT(acpi_version == 1);
-       UK_ASSERT(acpi_rsdt);
-
-       entries = RSDT_ENTRIES(acpi_rsdt);
+       rsdp = acpi_get_rsdp();
+       if (unlikely(!rsdp))
+               return -ENOENT;
 
-       uk_pr_debug("%d ACPI tables found\n", entries);
+       if (unlikely(get_acpi_checksum(rsdp, RSDP10_LEN))) {
+               uk_pr_err("ACPI 1.0 RSDP corrupted\n");
 
-       for (i = 0; i < entries; i++) {
-               h = (struct acpi_sdt_hdr *)((__uptr)acpi_rsdt->entry[i]);
-               uk_pr_debug("%p: %.4s\n", h, h->sig);
+               return -ENOENT;
        }
-}
-#endif /* UK_DEBUG */
-
-/*
- * Initialize ACPI 1.0 data structures.
- */
-
-static int acpi10_init(void)
-{
-       int ret;
-
-       UK_ASSERT(acpi_version == 1);
 
-       if ((ret = acpi10_find_rsdt()) != 0)
-               return ret;
+       if (rsdp->revision == 0) {
+               h = (struct acpi_sdt_hdr *)((__uptr)rsdp->rsdt_paddr);
+               acpi_rsdt_entries = (h->tab_len - sizeof(*h)) / 4;
+               acpi10 = 1;
+       } else {
+               if (unlikely(get_acpi_checksum(rsdp, sizeof(*rsdp)))) {
+                       uk_pr_err("ACPI 1.0 RSDP corrupted\n");
 
-#ifdef UK_DEBUG
-       acpi10_list_tables();
-#endif
+                       return -ENOENT;
+               }
 
-       if ((ret = acpi10_find_madt()) != 0)
-               return ret;
+               h = (struct acpi_sdt_hdr *)rsdp->xsdt_paddr;
+               acpi_rsdt_entries = (h->tab_len - sizeof(*h)) / 8;
+       }
 
-       return 0;
-}
+       UK_ASSERT(h);
 
-/*
- * Detect ACPI version and discover ACPI tables.
- */
+       if (unlikely(get_acpi_checksum(h, h->tab_len))) {
+               uk_pr_err("ACPI RSDT corrupted\n");
 
-int acpi_init(void)
-{
-       int ret;
+               return -ENOENT;
+       }
 
-       UK_ASSERT(!acpi_version);
+       acpi_rsdt = h;
 
-       if ((ret = detect_acpi_version()) != 0)
-               return ret;
+       acpi_init_tables();
 
-       /* Try to initialize the respective ACPI support. If it fails, we reset
-        * acpi_version to indicate that ACPI support is not provided.
-        */
-       if (acpi_version == 1) {
-               if ((ret = acpi10_init()) != 0) {
-                       acpi_version = 0;
-                       return ret;
-               }
-       } else {
-               UK_ASSERT(!acpi_version);
-               return -ENOTSUP;
-       }
+#ifdef UK_DEBUG
+       acpi_list_tables();
+#endif
 
        return 0;
 }
 
-/*
- * Return detected ACPI version.
- */
-
-int acpi_get_version(void)
-{
-       return acpi_version;
-}
 
 /*
  * Return the Multiple APIC Descriptor Table (MADT).
  */
-
 struct acpi_madt *acpi_get_madt(void)
 {
-       UK_ASSERT(acpi_version);
-       UK_ASSERT(acpi_madt);
-
        return acpi_madt;
 }
index f2f921b5e0f66079636c5df6c11accad0e69315f..80226f9ad5e8d67460a487912c55a6ea7687c75f 100644 (file)
@@ -42,7 +42,7 @@
 #include <x86/cpu.h>
 #include <x86/traps.h>
 #include <x86/delay.h>
-#include <x86/acpi/madt.h>
+#include <x86/acpi/acpi.h>
 
 #include <uk/plat/lcpu.h>
 #include <uk/plat/common/lcpu.h>