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 7169f786fSAlexandru Elisei void set_efi_rsdp(struct acpi_table_rsdp *rsdp) 8b4e8c300SZixuan Wang { 9f20589d6SZixuan Wang efi_rsdp = rsdp; 10f20589d6SZixuan Wang } 11f20589d6SZixuan Wang 12169f786fSAlexandru Elisei static 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 20169f786fSAlexandru Elisei static 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 38372e3528SPaolo Bonzini void *find_acpi_table_addr(u32 sig) 39372e3528SPaolo Bonzini { 40*74e927c7SNikos Nikoleris struct acpi_table_rsdt_rev1 *rsdt = NULL; 41*74e927c7SNikos 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) { 48169f786fSAlexandru Elisei struct acpi_table_fadt_rev1 *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; 66*74e927c7SNikos Nikoleris if (rsdt && rsdt->signature != RSDT_SIGNATURE) 67*74e927c7SNikos Nikoleris rsdt = NULL; 68372e3528SPaolo Bonzini 69b3e76d57SNikos Nikoleris if (sig == RSDT_SIGNATURE) 70372e3528SPaolo Bonzini return rsdt; 71372e3528SPaolo Bonzini 72*74e927c7SNikos Nikoleris if (rsdp->revision >= 2) { 73*74e927c7SNikos Nikoleris xsdt = (void *)(ulong) rsdp->xsdt_physical_address; 74*74e927c7SNikos Nikoleris if (xsdt && xsdt->signature != XSDT_SIGNATURE) 75*74e927c7SNikos Nikoleris xsdt = NULL; 76*74e927c7SNikos Nikoleris } 77*74e927c7SNikos Nikoleris 78*74e927c7SNikos Nikoleris if (sig == XSDT_SIGNATURE) 79*74e927c7SNikos Nikoleris return xsdt; 80*74e927c7SNikos Nikoleris 81*74e927c7SNikos Nikoleris /* 82*74e927c7SNikos Nikoleris * When the system implements APCI 2.0 and above and XSDT is valid we 83*74e927c7SNikos Nikoleris * have use XSDT to find other ACPI tables, otherwise, we use RSDT. 84*74e927c7SNikos Nikoleris */ 85*74e927c7SNikos Nikoleris if (xsdt) { 86*74e927c7SNikos Nikoleris end = (void *)xsdt + xsdt->length; 87*74e927c7SNikos Nikoleris for (i = 0; (void *)&xsdt->table_offset_entry[i] < end; i++) { 88*74e927c7SNikos Nikoleris struct acpi_table *t = (void *)(ulong) xsdt->table_offset_entry[i]; 89*74e927c7SNikos Nikoleris 90*74e927c7SNikos Nikoleris if (t && t->signature == sig) 91*74e927c7SNikos Nikoleris return t; 92*74e927c7SNikos Nikoleris } 93*74e927c7SNikos 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 } 101*74e927c7SNikos Nikoleris } 102e2ad9858SNikos Nikoleris 103372e3528SPaolo Bonzini return NULL; 104372e3528SPaolo Bonzini } 105