1372e3528SPaolo Bonzini #include "libcflat.h" 2372e3528SPaolo Bonzini #include "acpi.h" 3372e3528SPaolo Bonzini 4c98ce6e0SAlexandru Elisei #ifdef CONFIG_EFI 5169f786fSAlexandru Elisei struct acpi_table_rsdp *efi_rsdp = NULL; 6f20589d6SZixuan Wang set_efi_rsdp(struct acpi_table_rsdp * rsdp)7169f786fSAlexandru Eliseivoid set_efi_rsdp(struct acpi_table_rsdp *rsdp) 8b4e8c300SZixuan Wang { 9f20589d6SZixuan Wang efi_rsdp = rsdp; 10f20589d6SZixuan Wang } 11f20589d6SZixuan Wang get_rsdp(void)12169f786fSAlexandru Eliseistatic struct acpi_table_rsdp *get_rsdp(void) 13b4e8c300SZixuan Wang { 14e2ad9858SNikos Nikoleris if (efi_rsdp == NULL) 15b4e8c300SZixuan Wang printf("Can't find RSDP from UEFI, maybe set_efi_rsdp() was not called\n"); 16e2ad9858SNikos Nikoleris 17f20589d6SZixuan Wang return efi_rsdp; 18f20589d6SZixuan Wang } 19f20589d6SZixuan Wang #else get_rsdp(void)20169f786fSAlexandru Eliseistatic struct acpi_table_rsdp *get_rsdp(void) 21b4e8c300SZixuan Wang { 22169f786fSAlexandru Elisei struct acpi_table_rsdp *rsdp; 23f20589d6SZixuan Wang unsigned long addr; 24b4e8c300SZixuan Wang 2592a6c9b9SPaolo Bonzini for (addr = 0xe0000; addr < 0x100000; addr += 16) { 26f20589d6SZixuan Wang rsdp = (void *)addr; 27f20589d6SZixuan Wang if (rsdp->signature == RSDP_SIGNATURE_8BYTE) 28f20589d6SZixuan Wang break; 29f20589d6SZixuan Wang } 30b4e8c300SZixuan Wang 31e2ad9858SNikos Nikoleris if (addr == 0x100000) 32f20589d6SZixuan Wang return NULL; 33b4e8c300SZixuan Wang 34f20589d6SZixuan Wang return rsdp; 35f20589d6SZixuan Wang } 36c98ce6e0SAlexandru Elisei #endif /* CONFIG_EFI */ 37f20589d6SZixuan Wang find_acpi_table_addr(u32 sig)38372e3528SPaolo Bonzinivoid *find_acpi_table_addr(u32 sig) 39372e3528SPaolo Bonzini { 4074e927c7SNikos Nikoleris struct acpi_table_rsdt_rev1 *rsdt = NULL; 4174e927c7SNikos Nikoleris struct acpi_table_xsdt *xsdt = NULL; 42169f786fSAlexandru Elisei struct acpi_table_rsdp *rsdp; 43372e3528SPaolo Bonzini void *end; 44372e3528SPaolo Bonzini int i; 45372e3528SPaolo Bonzini 46372e3528SPaolo Bonzini /* FACS is special... */ 47372e3528SPaolo Bonzini if (sig == FACS_SIGNATURE) { 4864cd0cc1SNikos Nikoleris struct acpi_table_fadt *fadt; 49e2ad9858SNikos Nikoleris 50372e3528SPaolo Bonzini fadt = find_acpi_table_addr(FACP_SIGNATURE); 51b3e76d57SNikos Nikoleris if (!fadt) 52372e3528SPaolo Bonzini return NULL; 53372e3528SPaolo Bonzini return (void *)(ulong) fadt->firmware_ctrl; 54372e3528SPaolo Bonzini } 55372e3528SPaolo Bonzini 56f20589d6SZixuan Wang rsdp = get_rsdp(); 57f20589d6SZixuan Wang if (rsdp == NULL) { 58372e3528SPaolo Bonzini printf("Can't find RSDP\n"); 59b3e76d57SNikos Nikoleris return NULL; 60372e3528SPaolo Bonzini } 61372e3528SPaolo Bonzini 62b3e76d57SNikos Nikoleris if (sig == RSDP_SIGNATURE) 63372e3528SPaolo Bonzini return rsdp; 64372e3528SPaolo Bonzini 65372e3528SPaolo Bonzini rsdt = (void *)(ulong) rsdp->rsdt_physical_address; 6674e927c7SNikos Nikoleris if (rsdt && rsdt->signature != RSDT_SIGNATURE) 6774e927c7SNikos Nikoleris rsdt = NULL; 68372e3528SPaolo Bonzini 69b3e76d57SNikos Nikoleris if (sig == RSDT_SIGNATURE) 70372e3528SPaolo Bonzini return rsdt; 71372e3528SPaolo Bonzini 7274e927c7SNikos Nikoleris if (rsdp->revision >= 2) { 7374e927c7SNikos Nikoleris xsdt = (void *)(ulong) rsdp->xsdt_physical_address; 7474e927c7SNikos Nikoleris if (xsdt && xsdt->signature != XSDT_SIGNATURE) 7574e927c7SNikos Nikoleris xsdt = NULL; 7674e927c7SNikos Nikoleris } 7774e927c7SNikos Nikoleris 7874e927c7SNikos Nikoleris if (sig == XSDT_SIGNATURE) 7974e927c7SNikos Nikoleris return xsdt; 8074e927c7SNikos Nikoleris 8174e927c7SNikos Nikoleris /* 8274e927c7SNikos Nikoleris * When the system implements APCI 2.0 and above and XSDT is valid we 8374e927c7SNikos Nikoleris * have use XSDT to find other ACPI tables, otherwise, we use RSDT. 8474e927c7SNikos Nikoleris */ 8574e927c7SNikos Nikoleris if (xsdt) { 8674e927c7SNikos Nikoleris end = (void *)xsdt + xsdt->length; 8774e927c7SNikos Nikoleris for (i = 0; (void *)&xsdt->table_offset_entry[i] < end; i++) { 8874e927c7SNikos Nikoleris struct acpi_table *t = (void *)(ulong) xsdt->table_offset_entry[i]; 8974e927c7SNikos Nikoleris 9074e927c7SNikos Nikoleris if (t && t->signature == sig) 9174e927c7SNikos Nikoleris return t; 9274e927c7SNikos Nikoleris } 9374e927c7SNikos Nikoleris } else if (rsdt) { 94372e3528SPaolo Bonzini end = (void *)rsdt + rsdt->length; 95372e3528SPaolo Bonzini for (i = 0; (void *)&rsdt->table_offset_entry[i] < end; i++) { 96372e3528SPaolo Bonzini struct acpi_table *t = (void *)(ulong) rsdt->table_offset_entry[i]; 97e2ad9858SNikos Nikoleris 98e2ad9858SNikos Nikoleris if (t && t->signature == sig) 99372e3528SPaolo Bonzini return t; 100372e3528SPaolo Bonzini } 10174e927c7SNikos Nikoleris } 102e2ad9858SNikos Nikoleris 103372e3528SPaolo Bonzini return NULL; 104372e3528SPaolo Bonzini } 1053d29f825SNikos Nikoleris acpi_table_parse_madt(enum acpi_madt_type mtype,acpi_table_handler handler)106*13182cd7SNikos Nikolerisint acpi_table_parse_madt(enum acpi_madt_type mtype, acpi_table_handler handler) 1073d29f825SNikos Nikoleris { 1083d29f825SNikos Nikoleris struct acpi_table_madt *madt; 1093d29f825SNikos Nikoleris struct acpi_subtable_header *header; 1103d29f825SNikos Nikoleris void *end; 111*13182cd7SNikos Nikoleris int count = 0; 1123d29f825SNikos Nikoleris 1133d29f825SNikos Nikoleris madt = find_acpi_table_addr(MADT_SIGNATURE); 1143d29f825SNikos Nikoleris assert(madt); 1153d29f825SNikos Nikoleris 1163d29f825SNikos Nikoleris header = (void *)(ulong) madt + sizeof(struct acpi_table_madt); 1173d29f825SNikos Nikoleris end = (void *)((ulong) madt + madt->length); 1183d29f825SNikos Nikoleris 1193d29f825SNikos Nikoleris while ((void *)header < end) { 120*13182cd7SNikos Nikoleris if (header->type == mtype) { 1213d29f825SNikos Nikoleris handler(header); 122*13182cd7SNikos Nikoleris count++; 123*13182cd7SNikos Nikoleris } 1243d29f825SNikos Nikoleris 1253d29f825SNikos Nikoleris header = (void *)(ulong) header + header->length; 1263d29f825SNikos Nikoleris } 127*13182cd7SNikos Nikoleris 128*13182cd7SNikos Nikoleris return count; 1293d29f825SNikos Nikoleris } 130