From 725393b26be977ec5a2d75728363817cf7703359 Mon Sep 17 00:00:00 2001 From: Andy-Python-Programmer Date: Tue, 5 Oct 2021 12:07:52 +1100 Subject: [PATCH] multiboot2: add the ACPI old tag Signed-off-by: Andy-Python-Programmer --- stage23/lib/acpi.c | 77 ++++++++++++++++++++++++++++++++++--- stage23/lib/acpi.h | 4 ++ stage23/protos/multiboot2.c | 33 ++++++++++++++-- 3 files changed, 105 insertions(+), 9 deletions(-) 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 + 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 (!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; - 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 - continue; + printv("acpi: Found %s at %X\n", is_xsdp ? "XSDP" : "RSDP", cur_table->VendorTable); - printv("acpi: Found RSDP at %X\n", 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; +} + +/// 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"); } }