:: commit 2786666b0add6f7eb48ecce6dff3587470c90ff0

Andy-Python-Programmer <andypythonappdeveloper@gmail.com> — 2021-10-05 01:07

parents: 05d5518713

multiboot2: add the ACPI old tag

Signed-off-by: Andy-Python-Programmer <andypythonappdeveloper@gmail.com>
diff --git a/stage23/lib/acpi.c b/stage23/lib/acpi.c
index 65589f5d..5f02cc91 100644
--- a/stage23/lib/acpi.c
+++ b/stage23/lib/acpi.c
@@ -34,6 +34,21 @@ void *acpi_get_rsdp(void) {
     return NULL;
 }
 
+/// Returns the RSDP v1 pointer if avaliable or else NULL.
+void *acpi_get_rsdp_v1(void) {
+    // In BIOS according to the ACPI spec (see ACPI 6.2 section 
+    // 5.2.5.1 'Finding the RSDP on IA-PC Systems') it either contains
+    // the RSDP or the XSDP and it cannot contain both. So, we directly
+    // use acpi_get_rsdp function to find the RSDP and if it has the correct
+    // revision, return it.
+    struct rsdp *rsdp = acpi_get_rsdp();
+
+    if (rsdp != NULL && rsdp->rev == 1)
+        return rsdp;
+    
+    return NULL;
+}
+
 void acpi_get_smbios(void **smbios32, void **smbios64) {
     *smbios32 = NULL;
     *smbios64 = NULL;
@@ -67,18 +82,56 @@ void *acpi_get_rsdp(void) {
     EFI_GUID acpi_2_guid = ACPI_20_TABLE_GUID;
     EFI_GUID acpi_1_guid = ACPI_TABLE_GUID;
 
+    void *rsdp = NULL;
+
     for (size_t i = 0; i < gST->NumberOfTableEntries; i++) {
         EFI_CONFIGURATION_TABLE *cur_table = &gST->ConfigurationTable[i];
 
-        if (memcmp(&cur_table->VendorGuid, &acpi_2_guid, sizeof(EFI_GUID)) != 0 || // XSDP
-            memcmp(&cur_table->VendorGuid, &acpi_1_guid, sizeof(EFI_GUID)) != 0)   // RSDP
-            continue;
+        bool is_xsdp = memcmp(&cur_table->VendorGuid, &acpi_2_guid, sizeof(EFI_GUID)) == 0;
+        bool is_rsdp = memcmp(&cur_table->VendorGuid, &acpi_1_guid, sizeof(EFI_GUID)) == 0;
 
-        if (acpi_checksum(cur_table->VendorTable, sizeof(struct rsdp)) != 0 || // XSDP is 36 bytes wide
-            acpi_checksum(cur_table->VendorTable, 20) != 0)                   // RSDP is 20 bytes wide
+        if (!is_xsdp && !is_rsdp)
             continue;
+        
+        if ((is_xsdp && acpi_checksum(cur_table->VendorTable, sizeof(struct rsdp)) != 0) || // XSDP is 36 bytes wide
+            (is_rsdp && acpi_checksum(cur_table->VendorTable, 20) != 0)) // RSDP is 20 bytes wide
+            continue;
+
+        printv("acpi: Found %s at %X\n", is_xsdp ? "XSDP" : "RSDP", cur_table->VendorTable);
+
+        // We want to return the XSDP if it exists rather then returning
+        // the RSDP. We need to add a check for that since the table entries
+        // are not in the same order for all EFI systems since it might be the
+        // case where the RSDP ocurs before the XSDP.
+        if (rsdp != NULL && is_xsdp) {
+            rsdp = (void *)cur_table->VendorTable;
+            break; // Found it!.
+        } else {
+            // Found the RSDP but we continue to loop since we might
+            // find the XSDP.
+            rsdp = (void *)cur_table->VendorTable;
+        }
+    }
+
+    return rsdp;
+}
 
-        printv("acpi: Found RSDP at %X\n", cur_table->VendorTable);
+/// Returns the RSDP v1 pointer if avaliable or else NULL.
+void *acpi_get_rsdp_v1(void) {
+    // To maintain GRUB compatibility we will need to probe for the RSDP
+    // again since UEFI can contain both XSDP and RSDP (see ACPI 6.2 section 
+    // 5.2.5.2 'Finding the RSDP on UEFI Enabled Systems') and in the acpi_get_rsdp
+    // function we look for the RSDP with the latest revision.
+    EFI_GUID acpi_1_guid = ACPI_TABLE_GUID;
+
+    for (size_t i = 0; i < gST->NumberOfTableEntries; i++) {
+        EFI_CONFIGURATION_TABLE *cur_table = &gST->ConfigurationTable[i];
+
+        if (memcmp(&cur_table->VendorGuid, &acpi_1_guid, sizeof(EFI_GUID)) != 0)
+            continue;
+        
+        if (acpi_checksum(cur_table->VendorTable, 20) != 0)
+            continue;
 
         return (void *)cur_table->VendorTable;
     }
@@ -129,6 +182,18 @@ void acpi_get_smbios(void **smbios32, void **smbios64) {
 
 #endif
 
+/// Returns the RSDP v2 pointer if avaliable or else NULL.
+void *acpi_get_rsdp_v2(void) {
+    // Since the acpi_get_rsdp function already looks for the XSDP we can
+    // just check if it has the correct revision and return the pointer :^)
+    struct rsdp *rsdp = acpi_get_rsdp();
+
+    if (rsdp != NULL && rsdp->rev >= 2)
+        return rsdp;
+
+    return NULL;
+}
+
 void *acpi_get_table(const char *signature, int index) {
     int cnt = 0;
 
diff --git a/stage23/lib/acpi.h b/stage23/lib/acpi.h
index 26c64876..0638344f 100644
--- a/stage23/lib/acpi.h
+++ b/stage23/lib/acpi.h
@@ -38,6 +38,10 @@ struct rsdt {
 
 uint8_t acpi_checksum(void *ptr, size_t size);
 void   *acpi_get_rsdp(void);
+
+void   *acpi_get_rsdp_v1(void);
+void   *acpi_get_rsdp_v2(void);
+
 void   *acpi_get_table(const char *signature, int index);
 void    acpi_get_smbios(void **smbios32, void **smbios64);
 
diff --git a/stage23/protos/multiboot2.c b/stage23/protos/multiboot2.c
index e082ea60..a03b1a45 100644
--- a/stage23/protos/multiboot2.c
+++ b/stage23/protos/multiboot2.c
@@ -55,7 +55,8 @@ static size_t get_multiboot2_info_size(
         ALIGN_UP(strlen(cmdline) + 1 + offsetof(struct multiboot_tag_string, string), MULTIBOOT_TAG_ALIGN) +            // cmdline
         ALIGN_UP(8 + offsetof(struct multiboot_tag_string, string), MULTIBOOT_TAG_ALIGN) +                              // bootloader brand
         ALIGN_UP(sizeof(struct multiboot_tag_framebuffer), MULTIBOOT_TAG_ALIGN) +                                       // framebuffer
-        ALIGN_UP(sizeof(struct multiboot_tag_new_acpi) + 36, MULTIBOOT_TAG_ALIGN) +                                     // new ACPI info
+        ALIGN_UP(sizeof(struct multiboot_tag_new_acpi) + sizeof(struct rsdp), MULTIBOOT_TAG_ALIGN) +                    // new ACPI info
+        ALIGN_UP(sizeof(struct multiboot_tag_old_acpi) + 20, MULTIBOOT_TAG_ALIGN) +                                     // old ACPI info
         ALIGN_UP(sizeof(struct multiboot_tag_elf_sections) + section_hdr_size, MULTIBOOT_TAG_ALIGN) +                   // ELF info
         ALIGN_UP(modules_size, MULTIBOOT_TAG_ALIGN) +                                                                   // modules
         ALIGN_UP(sizeof(struct multiboot_tag_mmap) + sizeof(struct multiboot_mmap_entry) * 256, MULTIBOOT_TAG_ALIGN) +  // MMAP
@@ -91,7 +92,10 @@ void multiboot2_load(char *config, char* cmdline) {
 
     struct multiboot_header_tag_address *addresstag = NULL;
     struct multiboot_header_tag_framebuffer *fbtag = NULL;
+
     bool is_new_acpi_required = false;
+    bool is_old_acpi_required = false;
+
     bool is_elf_info_requested = false;
 
     uint32_t entry_point = 0xffffffff;
@@ -129,6 +133,9 @@ void multiboot2_load(char *config, char* cmdline) {
                         case MULTIBOOT_TAG_TYPE_ACPI_NEW:
                             is_new_acpi_required = is_required;
                             break;
+                        case MULTIBOOT_TAG_TYPE_ACPI_OLD:
+                            is_old_acpi_required = is_required;
+                            break;
                         case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
                             is_elf_info_requested = is_required;
                             break;
@@ -426,15 +433,35 @@ void multiboot2_load(char *config, char* cmdline) {
         void *new_rsdp = acpi_get_rsdp();
 
         if (new_rsdp != NULL) {
-            uint32_t size = sizeof(struct multiboot_tag_new_acpi) + 36; // XSDP is 36 bytes wide
+            uint32_t size = sizeof(struct multiboot_tag_new_acpi) + sizeof(struct rsdp); // XSDP is 36 bytes wide
             struct multiboot_tag_new_acpi *tag = (struct multiboot_tag_new_acpi *)(mb2_info + info_idx);
 
             tag->type = MULTIBOOT_TAG_TYPE_ACPI_NEW;
             tag->size = size;
 
-            memcpy(tag->rsdp, new_rsdp, 36);
+            memcpy(tag->rsdp, new_rsdp, sizeof(struct rsdp));
             append_tag(info_idx, tag);
         } else if (is_new_acpi_required) {
+            panic("multiboot2: XSDP requested but not found");
+        }
+    }
+
+    //////////////////////////////////////////////
+    // Create old ACPI info tag
+    //////////////////////////////////////////////
+    {
+        void *old_rsdp = acpi_get_rsdp_v1();
+
+        if (old_rsdp != NULL) {
+            uint32_t size = sizeof(struct multiboot_tag_old_acpi) + 20; // RSDP is 20 bytes wide
+            struct multiboot_tag_old_acpi *tag = (struct multiboot_tag_old_acpi *)(mb2_info + info_idx);
+
+            tag->type = MULTIBOOT_TAG_TYPE_ACPI_OLD;
+            tag->size = size;
+
+            memcpy(tag->rsdp, old_rsdp, 20);
+            append_tag(info_idx, tag);
+        } else if (is_old_acpi_required) {
             panic("multiboot2: RSDP requested but not found");
         }
     }
tab: 248 wrap: offon