--- i386/i386at/acpi_parse_apic.c | 203 ++++++++++++++++++++++++---------- i386/i386at/acpi_parse_apic.h | 18 ++- i386/i386at/model_dep.c | 8 +- 3 files changed, 169 insertions(+), 60 deletions(-)
diff --git a/i386/i386at/acpi_parse_apic.c b/i386/i386at/acpi_parse_apic.c index 9cd861ed..7b377d33 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,33 @@ 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; /* 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 (checksum != 0) - return ACPI_BAD_CHECKSUM; + if (rsdp->v1.revision == 0) { + // ACPI 1.0 + *sdt_base = rsdp->v1.rsdt_addr; + printf("ACPI v1.0\n"); + return 1; + } else if (rsdp->v1.revision == 2) { + // ACPI >= 2.0 + *sdt_base = rsdp->xsdt_addr; + printf("ACPI >= v2.0\n"); + return 2; + } - return ACPI_SUCCESS; + return ACPI_NO_RSDP; } /* @@ -147,38 +152,43 @@ 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 = 0; + if (version == 2) + *is_64bit = 1; + 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,12 +196,12 @@ 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; @@ -229,16 +239,13 @@ 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) @@ -264,6 +271,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 +336,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. @@ -379,6 +451,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(); @@ -388,6 +462,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) { @@ -418,6 +493,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. */ @@ -449,16 +527,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), @@ -499,29 +570,47 @@ 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; - /* 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; + + /* 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); + + } else { + /* Try to get the XSDT pointer. */ + xsdt = acpi_get_xsdt(rsdp, &acpi_rsdt_n); + if (xsdt == NULL) + return ACPI_NO_RSDT; + + /* Try to get the APIC table pointer. */ + apic_madt = acpi_get_apic2(xsdt, acpi_rsdt_n); + if (apic_madt == NULL) + return ACPI_NO_APIC; + + /* 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 b0a55754..7a8aa6ee 100644 --- a/i386/i386at/model_dep.c +++ b/i386/i386at/model_dep.c @@ -159,7 +159,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