diff options
author | Bin Meng <bmeng.cn@gmail.com> | 2017-04-21 07:24:36 -0700 |
---|---|---|
committer | Bin Meng <bmeng.cn@gmail.com> | 2017-05-17 17:11:46 +0800 |
commit | e76bf38f180b0c9325b17506f1518329d82cbed8 (patch) | |
tree | 8ce67b116d477a575794a7d391d71ba8085571fd /arch/x86/lib/acpi_table.c | |
parent | 2b2d666f9caca189e4014f8e23088b0afc360e22 (diff) |
x86: acpi: Add one API to find OS wakeup vector
This adds one API acpi_find_wakeup_vector() to locate OS wakeup
vector from the ACPI FACS table, to be used in the S3 boot path.
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Tested-by: Stefan Roese <sr@denx.de>
Diffstat (limited to 'arch/x86/lib/acpi_table.c')
-rw-r--r-- | arch/x86/lib/acpi_table.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index 355456dc19..f1183452f8 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -438,3 +438,75 @@ ulong write_acpi_tables(ulong start) return current; } + +static struct acpi_rsdp *acpi_valid_rsdp(struct acpi_rsdp *rsdp) +{ + if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) + return NULL; + + debug("Looking on %p for valid checksum\n", rsdp); + + if (table_compute_checksum((void *)rsdp, 20) != 0) + return NULL; + debug("acpi rsdp checksum 1 passed\n"); + + if ((rsdp->revision > 1) && + (table_compute_checksum((void *)rsdp, rsdp->length) != 0)) + return NULL; + debug("acpi rsdp checksum 2 passed\n"); + + return rsdp; +} + +void *acpi_find_wakeup_vector(void) +{ + char *p, *end; + struct acpi_rsdp *rsdp = NULL; + struct acpi_rsdt *rsdt; + struct acpi_fadt *fadt = NULL; + struct acpi_facs *facs; + void *wake_vec; + int i; + + debug("Trying to find the wakeup vector...\n"); + + /* Find RSDP */ + for (p = (char *)ROM_TABLE_ADDR; p < (char *)ROM_TABLE_END; p += 16) { + rsdp = acpi_valid_rsdp((struct acpi_rsdp *)p); + if (rsdp) + break; + } + + if (rsdp == NULL) + return NULL; + + debug("RSDP found at %p\n", rsdp); + rsdt = (struct acpi_rsdt *)rsdp->rsdt_address; + + end = (char *)rsdt + rsdt->header.length; + debug("RSDT found at %p ends at %p\n", rsdt, end); + + for (i = 0; ((char *)&rsdt->entry[i]) < end; i++) { + fadt = (struct acpi_fadt *)rsdt->entry[i]; + if (strncmp((char *)fadt, "FACP", 4) == 0) + break; + fadt = NULL; + } + + if (fadt == NULL) + return NULL; + + debug("FADT found at %p\n", fadt); + facs = (struct acpi_facs *)fadt->firmware_ctrl; + + if (facs == NULL) { + debug("No FACS found, wake up from S3 not possible.\n"); + return NULL; + } + + debug("FACS found at %p\n", facs); + wake_vec = (void *)facs->firmware_waking_vector; + debug("OS waking vector is %p\n", wake_vec); + + return wake_vec; +} |