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.