[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v3 gnumach] ACPI: Support XSDT (ACPI >= v2.0)
From: |
Samuel Thibault |
Subject: |
Re: [PATCH v3 gnumach] ACPI: Support XSDT (ACPI >= v2.0) |
Date: |
Thu, 1 Feb 2024 02:22:52 +0100 |
User-agent: |
NeoMutt/20170609 (1.8.3) |
Applied, thanks!
Damien Zammit, le mer. 31 janv. 2024 02:12:26 +0000, a ecrit:
> This enables gnumach to additionally parse the XSDT table
> if the revision of ACPI is 2.
>
> TESTED: Still works on qemu (ACPI v1.0)
> TESTED: Works on a x86 board with XSDT (ACPI v2.0)
> ---
> i386/i386at/acpi_parse_apic.c | 258 ++++++++++++++++++++++------------
> i386/i386at/acpi_parse_apic.h | 18 ++-
> i386/i386at/model_dep.c | 8 +-
> 3 files changed, 195 insertions(+), 89 deletions(-)
>
> diff --git a/i386/i386at/acpi_parse_apic.c b/i386/i386at/acpi_parse_apic.c
> index 1aef53ed..dcd5da89 100644
> --- a/i386/i386at/acpi_parse_apic.c
> +++ b/i386/i386at/acpi_parse_apic.c
> @@ -43,13 +43,12 @@ unsigned lapic_addr;
> * and the number of entries stored in RSDT.
> */
> void
> -acpi_print_info(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, int
> acpi_rsdt_n)
> +acpi_print_info(phys_addr_t rsdp, void *rsdt, int acpi_rsdt_n)
> {
>
> printf("ACPI:\n");
> - printf(" rsdp = %p; rsdp->rsdt_addr = %x\n", rsdp, rsdp->rsdt_addr);
> - printf(" rsdt = %p; rsdt->length = %x (n = %x)\n", rsdt,
> rsdt->header.length,
> - acpi_rsdt_n);
> + printf(" rsdp = 0x%lx\n", rsdp);
> + printf(" rsdt/xsdt = 0x%p (n = %d)\n", rsdt, acpi_rsdt_n);
> }
>
> /*
> @@ -99,27 +98,45 @@ acpi_check_signature(const uint8_t table_signature[],
> const char *real_signature
> *
> * Preconditions: RSDP pointer must not be NULL.
> *
> - * Returns 0 if correct.
> + * Returns 1 if ACPI 1.0 and sets sdt_base
> + * Returns 2 if ACPI >= 2.0 and sets sdt_base
> */
> static int8_t
> -acpi_check_rsdp(struct acpi_rsdp *rsdp)
> +acpi_check_rsdp(struct acpi_rsdp2 *rsdp, phys_addr_t *sdt_base)
> {
> - uint32_t checksum;
> int is_rsdp;
> + uint8_t cksum;
>
> /* Check if rsdp signature match with the ACPI RSDP signature. */
> - is_rsdp = acpi_check_signature(rsdp->signature, ACPI_RSDP_SIG,
> 8*sizeof(uint8_t));
> + is_rsdp = acpi_check_signature(rsdp->v1.signature, ACPI_RSDP_SIG,
> 8*sizeof(uint8_t));
>
> if (is_rsdp != ACPI_SUCCESS)
> return ACPI_BAD_SIGNATURE;
>
> - /* If match, calculates rdsp checksum and check It. */
> - checksum = acpi_checksum(rsdp, sizeof(struct acpi_rsdp));
> + if (rsdp->v1.revision == 0) {
> + // ACPI 1.0
> + *sdt_base = rsdp->v1.rsdt_addr;
> + printf("ACPI v1.0\n");
> + cksum = acpi_checksum((void *)(&rsdp->v1), sizeof(struct acpi_rsdp));
>
> - if (checksum != 0)
> - return ACPI_BAD_CHECKSUM;
> + if (cksum != 0)
> + return ACPI_BAD_CHECKSUM;
>
> - return ACPI_SUCCESS;
> + return 1;
> +
> + } else if (rsdp->v1.revision == 2) {
> + // ACPI >= 2.0
> + *sdt_base = rsdp->xsdt_addr;
> + printf("ACPI >= v2.0\n");
> + cksum = acpi_checksum((void *)rsdp, sizeof(struct acpi_rsdp2));
> +
> + if (cksum != 0)
> + return ACPI_BAD_CHECKSUM;
> +
> + return 2;
> + }
> +
> + return ACPI_NO_RSDP;
> }
>
> /*
> @@ -147,38 +164,41 @@ acpi_check_rsdp_align(void *addr)
> *
> * Preconditions: The start address (addr) must be aligned.
> *
> - * Returns the reference to rsdp structure if success, NULL if failure.
> + * Returns the physical address of rsdp structure if success, 0 if failure.
> */
> -static struct acpi_rsdp*
> -acpi_search_rsdp(void *addr, uint32_t length)
> +static phys_addr_t
> +acpi_search_rsdp(void *addr, uint32_t length, int *is_64bit)
> {
> void *end;
> + int version = 0;
> + phys_addr_t sdt_base = 0;
>
> /* Search RDSP in memory space between addr and addr+lenght. */
> for (end = addr+length; addr < end; addr += ACPI_RSDP_ALIGN) {
>
> /* Check if the current memory block stores the RDSP. */
> - if ((addr != NULL) && (acpi_check_rsdp(addr) == ACPI_SUCCESS)) {
> - /* If yes, return RSDP address */
> - return (struct acpi_rsdp*) addr;
> + if ((addr != NULL) && ((version = acpi_check_rsdp(addr, &sdt_base))
> > 0)) {
> + /* If yes, return RSDT/XSDT address */
> + *is_64bit = (version == 2);
> + return sdt_base;
> }
> }
>
> - return NULL;
> + return 0;
> }
>
> /*
> * acpi_get_rsdp: tries to find the RSDP table,
> * searching It in many memory ranges, as It's written in ACPI Specification.
> *
> - * Returns the reference to RDSP structure if success, NULL if failure.
> + * Returns the reference to RDSP structure if success, 0 if failure.
> */
> -static struct acpi_rsdp*
> -acpi_get_rsdp(void)
> +static phys_addr_t
> +acpi_get_rsdp(int *is_64bit)
> {
> uint16_t *start = 0;
> phys_addr_t base = 0;
> - struct acpi_rsdp *rsdp = NULL;
> + phys_addr_t rsdp = 0;
>
> /* EDBA start address. */
> start = (uint16_t*) phystokv(0x040e);
> @@ -186,40 +206,17 @@ acpi_get_rsdp(void)
>
> /* check alignment. */
> if (acpi_check_rsdp_align((void *)base) == ACPI_BAD_ALIGN)
> - return NULL;
> - rsdp = acpi_search_rsdp((void *)base, 1024);
> + return 0;
> + rsdp = acpi_search_rsdp((void *)base, 1024, is_64bit);
>
> - if (rsdp == NULL) {
> + if (rsdp == 0) {
> /* If RSDP isn't in EDBA, search in the BIOS read-only memory space
> between 0E0000h and 0FFFFFh */
> - rsdp = acpi_search_rsdp((void *)phystokv(0xe0000), 0x100000 -
> 0x0e0000);
> + rsdp = acpi_search_rsdp((void *)phystokv(0xe0000), 0x100000 -
> 0x0e0000, is_64bit);
> }
>
> return rsdp;
> }
>
> -/*
> - * acpi_check_rsdt: check if the RSDT initial address is correct
> - * checking its checksum.
> - *
> - * Receives as input a reference for the RSDT "candidate" table.
> - * Returns 0 if success.
> - *
> - * Preconditions: rsdp must not be NULL.
> - *
> - */
> -static int
> -acpi_check_rsdt(struct acpi_rsdt *rsdt)
> -{
> - uint8_t checksum;
> -
> - checksum = acpi_checksum(rsdt, rsdt->header.length);
> -
> - if (checksum != 0)
> - return ACPI_BAD_CHECKSUM;
> -
> - return ACPI_SUCCESS;
> -}
> -
> /*
> * acpi_get_rsdt: Get RSDT table reference from RSDP entries.
> *
> @@ -229,16 +226,12 @@ acpi_check_rsdt(struct acpi_rsdt *rsdt)
> * Returns the reference to RSDT table if success, NULL if error.
> */
> static struct acpi_rsdt*
> -acpi_get_rsdt(struct acpi_rsdp *rsdp, int* acpi_rsdt_n)
> +acpi_get_rsdt(phys_addr_t rsdp_phys, int* acpi_rsdt_n)
> {
> - phys_addr_t rsdt_phys;
> struct acpi_rsdt *rsdt = NULL;
> - int acpi_check;
> int signature_check;
>
> - /* Get rsdt address from rsdp table. */
> - rsdt_phys = rsdp->rsdt_addr;
> - rsdt = (struct acpi_rsdt*) kmem_map_aligned_table(rsdt_phys,
> sizeof(struct acpi_rsdt), VM_PROT_READ);
> + rsdt = (struct acpi_rsdt*) kmem_map_aligned_table(rsdp_phys,
> sizeof(struct acpi_rsdt), VM_PROT_READ);
>
> /* Check if the RSDT mapping is fine. */
> if (rsdt == NULL)
> @@ -251,12 +244,6 @@ acpi_get_rsdt(struct acpi_rsdp *rsdp, int* acpi_rsdt_n)
> if (signature_check != ACPI_SUCCESS)
> return NULL;
>
> - /* Check if rsdt is correct. */
> - acpi_check = acpi_check_rsdt(rsdt);
> -
> - if (acpi_check != ACPI_SUCCESS)
> - return NULL;
> -
> /* Calculated number of elements stored in rsdt. */
> *acpi_rsdt_n = (rsdt->header.length - sizeof(rsdt->header))
> / sizeof(rsdt->entry[0]);
> @@ -264,6 +251,40 @@ acpi_get_rsdt(struct acpi_rsdp *rsdp, int* acpi_rsdt_n)
> return rsdt;
> }
>
> +/*
> + * acpi_get_xsdt: Get XSDT table reference from RSDPv2 entries.
> + *
> + * Receives as input a reference for RSDPv2 table
> + * and a reference to store the number of entries of XSDT.
> + *
> + * Returns the reference to XSDT table if success, NULL if error.
> + */
> +static struct acpi_xsdt*
> +acpi_get_xsdt(phys_addr_t rsdp_phys, int* acpi_xsdt_n)
> +{
> + struct acpi_xsdt *xsdt = NULL;
> + int signature_check;
> +
> + xsdt = (struct acpi_xsdt*) kmem_map_aligned_table(rsdp_phys,
> sizeof(struct acpi_xsdt), VM_PROT_READ);
> +
> + /* Check if the RSDT mapping is fine. */
> + if (xsdt == NULL)
> + return NULL;
> +
> + /* Check is rsdt signature is equals to ACPI RSDT signature. */
> + signature_check = acpi_check_signature(xsdt->header.signature,
> ACPI_XSDT_SIG,
> + 4*sizeof(uint8_t));
> +
> + if (signature_check != ACPI_SUCCESS)
> + return NULL;
> +
> + /* Calculated number of elements stored in rsdt. */
> + *acpi_xsdt_n = (xsdt->header.length - sizeof(xsdt->header))
> + / sizeof(xsdt->entry[0]);
> +
> + return xsdt;
> +}
> +
> /*
> * acpi_get_apic: get MADT/APIC table from RSDT entries.
> *
> @@ -295,6 +316,37 @@ acpi_get_apic(struct acpi_rsdt *rsdt, int acpi_rsdt_n)
> return NULL;
> }
>
> +/*
> + * acpi_get_apic2: get MADT/APIC table from XSDT entries.
> + *
> + * Receives as input the XSDT initial address,
> + * and the number of entries of XSDT table.
> + *
> + * Returns a reference to APIC/MADT table if success, NULL if failure.
> + */
> +static struct acpi_apic*
> +acpi_get_apic2(struct acpi_xsdt *xsdt, int acpi_xsdt_n)
> +{
> + struct acpi_dhdr *descr_header;
> + int check_signature;
> +
> + /* Search APIC entries in rsdt table. */
> + for (int i = 0; i < acpi_xsdt_n; i++) {
> + descr_header = (struct acpi_dhdr*)
> kmem_map_aligned_table(xsdt->entry[i], sizeof(struct acpi_dhdr),
> +
> VM_PROT_READ);
> +
> + /* Check if the entry contains an APIC. */
> + check_signature = acpi_check_signature(descr_header->signature,
> ACPI_APIC_SIG, 4*sizeof(uint8_t));
> +
> + if (check_signature == ACPI_SUCCESS) {
> + /* If yes, return the APIC. */
> + return (struct acpi_apic*) descr_header;
> + }
> + }
> +
> + return NULL;
> +}
> +
> /*
> * acpi_add_lapic: add a new Local APIC to cpu_to_lapic array
> * and increase the number of cpus.
> @@ -382,6 +434,8 @@ acpi_apic_parse_table(struct acpi_apic *apic)
> /* Get the end address of APIC table */
> end = (vm_offset_t) apic + apic->header.length;
>
> + printf("APIC entry=0x%p end=0x%x\n", apic_entry, end);
> +
> /* Initialize number of cpus */
> numcpus = apic_get_numcpus();
>
> @@ -391,6 +445,7 @@ acpi_apic_parse_table(struct acpi_apic *apic)
> struct acpi_apic_ioapic *ioapic_entry;
> struct acpi_apic_irq_override *irq_override_entry;
>
> + printf("APIC entry=0x%p end=0x%x\n", apic_entry, end);
> /* Check entry type. */
> switch(apic_entry->type) {
>
> @@ -421,6 +476,9 @@ acpi_apic_parse_table(struct acpi_apic *apic)
> break;
>
> /* FIXME: There is another unhandled case */
> + default:
> + printf("Unhandled APIC entry type 0x%x\n", apic_entry->type);
> + break;
> }
>
> /* Get next APIC entry. */
> @@ -452,16 +510,9 @@ acpi_apic_parse_table(struct acpi_apic *apic)
> static int
> acpi_apic_setup(struct acpi_apic *apic)
> {
> - int apic_checksum;
> ApicLocalUnit* lapic_unit;
> uint8_t ncpus, nioapics;
>
> - /* Check the checksum of the APIC */
> - apic_checksum = acpi_checksum(apic, apic->header.length);
> -
> - if(apic_checksum != 0)
> - return ACPI_BAD_CHECKSUM;
> -
> /* map common lapic address */
> lapic_addr = apic->lapic_addr;
> lapic_unit = kmem_map_aligned_table(apic->lapic_addr,
> sizeof(ApicLocalUnit),
> @@ -502,29 +553,64 @@ acpi_apic_setup(struct acpi_apic *apic)
> int
> acpi_apic_init(void)
> {
> - struct acpi_rsdp *rsdp = 0;
> + phys_addr_t rsdp = 0;
> struct acpi_rsdt *rsdt = 0;
> + struct acpi_xsdt *xsdt = 0;
> int acpi_rsdt_n;
> int ret_acpi_setup;
> int apic_init_success = 0;
> + int is_64bit = 0;
> + uint8_t checksum;
>
> - /* Try to get the RSDP pointer. */
> - rsdp = acpi_get_rsdp();
> - if (rsdp == NULL)
> + /* Try to get the RSDP physical address. */
> + rsdp = acpi_get_rsdp(&is_64bit);
> + if (rsdp == 0)
> return ACPI_NO_RSDP;
>
> - /* Try to get the RSDT pointer. */
> - rsdt = acpi_get_rsdt(rsdp, &acpi_rsdt_n);
> - if (rsdt == NULL)
> - return ACPI_NO_RSDT;
> -
> - /* Try to get the APIC table pointer. */
> - apic_madt = acpi_get_apic(rsdt, acpi_rsdt_n);
> - if (apic_madt == NULL)
> - return ACPI_NO_APIC;
> -
> - /* Print the ACPI tables addresses. */
> - acpi_print_info(rsdp, rsdt, acpi_rsdt_n);
> + if (!is_64bit) {
> + /* Try to get the RSDT pointer. */
> + rsdt = acpi_get_rsdt(rsdp, &acpi_rsdt_n);
> + if (rsdt == NULL)
> + return ACPI_NO_RSDT;
> +
> + checksum = acpi_checksum((void *)rsdt, rsdt->header.length);
> + if (checksum != 0)
> + return ACPI_BAD_CHECKSUM;
> +
> + /* Try to get the APIC table pointer. */
> + apic_madt = acpi_get_apic(rsdt, acpi_rsdt_n);
> + if (apic_madt == NULL)
> + return ACPI_NO_APIC;
> +
> + checksum = acpi_checksum((void *)apic_madt,
> apic_madt->header.length);
> + if (checksum != 0)
> + return ACPI_BAD_CHECKSUM;
> +
> + /* Print the ACPI tables addresses. */
> + acpi_print_info(rsdp, rsdt, acpi_rsdt_n);
> +
> + } else {
> + /* Try to get the XSDT pointer. */
> + xsdt = acpi_get_xsdt(rsdp, &acpi_rsdt_n);
> + if (xsdt == NULL)
> + return ACPI_NO_RSDT;
> +
> + checksum = acpi_checksum((void *)xsdt, xsdt->header.length);
> + if (checksum != 0)
> + return ACPI_BAD_CHECKSUM;
> +
> + /* Try to get the APIC table pointer. */
> + apic_madt = acpi_get_apic2(xsdt, acpi_rsdt_n);
> + if (apic_madt == NULL)
> + return ACPI_NO_APIC;
> +
> + checksum = acpi_checksum((void *)apic_madt,
> apic_madt->header.length);
> + if (checksum != 0)
> + return ACPI_BAD_CHECKSUM;
> +
> + /* Print the ACPI tables addresses. */
> + acpi_print_info(rsdp, xsdt, acpi_rsdt_n);
> + }
>
> apic_init_success = apic_data_init();
> if (apic_init_success != ACPI_SUCCESS)
> diff --git a/i386/i386at/acpi_parse_apic.h b/i386/i386at/acpi_parse_apic.h
> index bad10054..df36bb31 100644
> --- a/i386/i386at/acpi_parse_apic.h
> +++ b/i386/i386at/acpi_parse_apic.h
> @@ -44,10 +44,17 @@ struct acpi_rsdp {
> uint8_t signature[8];
> uint8_t checksum;
> uint8_t oem_id[6];
> - uint8_t revision[1];
> + uint8_t revision;
> uint32_t rsdt_addr;
> } __attribute__((__packed__));
>
> +struct acpi_rsdp2 {
> + struct acpi_rsdp v1;
> + uint32_t length;
> + uint64_t xsdt_addr;
> + uint8_t checksum;
> + uint8_t reserved[3];
> +} __attribute__((__packed__));
>
> /*
> * RSDT Entry Header
> @@ -77,6 +84,13 @@ struct acpi_rsdt {
> uint32_t entry[0];
> } __attribute__((__packed__));
>
> +#define ACPI_XSDT_SIG "XSDT"
> +
> +struct acpi_xsdt {
> + struct acpi_dhdr header;
> + uint64_t entry[0];
> +} __attribute__((__packed__));
> +
> /* APIC table signature. */
> #define ACPI_APIC_SIG "APIC"
>
> @@ -157,7 +171,7 @@ struct acpi_apic_irq_override {
> } __attribute__((__packed__));
>
> int acpi_apic_init(void);
> -void acpi_print_info(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, int
> acpi_rsdt_n);
> +void acpi_print_info(phys_addr_t rsdp, void *rsdt, int acpi_rsdt_n);
>
> extern unsigned lapic_addr;
>
> diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
> index fb95029f..a53556e7 100644
> --- a/i386/i386at/model_dep.c
> +++ b/i386/i386at/model_dep.c
> @@ -163,7 +163,13 @@ void machine_init(void)
> hyp_init();
> #else /* MACH_HYP */
> #if defined(APIC)
> - acpi_apic_init();
> + int err;
> +
> + err = acpi_apic_init();
> + if (err) {
> + printf("acpi_apic_init failed with %d\n", err);
> + for (;;);
> + }
> #endif
> #if (NCPUS > 1)
> smp_init();
> --
> 2.43.0
>
>
>
--
Samuel
---
Pour une évaluation indépendante, transparente et rigoureuse !
Je soutiens la Commission d'Évaluation de l'Inria.