123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791 |
- /* acpi.c - modify acpi tables. */
- /*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2009 Free Software Foundation, Inc.
- *
- * GRUB is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GRUB is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <grub/dl.h>
- #include <grub/extcmd.h>
- #include <grub/file.h>
- #include <grub/disk.h>
- #include <grub/term.h>
- #include <grub/misc.h>
- #include <grub/acpi.h>
- #include <grub/mm.h>
- #include <grub/memory.h>
- #include <grub/i18n.h>
- #ifdef GRUB_MACHINE_EFI
- #include <grub/efi/efi.h>
- #include <grub/efi/api.h>
- #endif
- #pragma GCC diagnostic ignored "-Wcast-align"
- GRUB_MOD_LICENSE ("GPLv3+");
- static const struct grub_arg_option options[] = {
- {"exclude", 'x', 0,
- N_("Don't load host tables specified by comma-separated list."),
- 0, ARG_TYPE_STRING},
- {"load-only", 'n', 0,
- N_("Load only tables specified by comma-separated list."), 0, ARG_TYPE_STRING},
- {"v1", '1', 0, N_("Export version 1 tables to the OS."), 0, ARG_TYPE_NONE},
- {"v2", '2', 0, N_("Export version 2 and version 3 tables to the OS."), 0, ARG_TYPE_NONE},
- {"oemid", 'o', 0, N_("Set OEMID of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING},
- {"oemtable", 't', 0,
- N_("Set OEMTABLE ID of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING},
- {"oemtablerev", 'r', 0,
- N_("Set OEMTABLE revision of RSDP, XSDT and RSDT."), 0, ARG_TYPE_INT},
- {"oemtablecreator", 'c', 0,
- N_("Set creator field of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING},
- {"oemtablecreatorrev", 'd', 0,
- N_("Set creator revision of RSDP, XSDT and RSDT."), 0, ARG_TYPE_INT},
- /* TRANSLATORS: "hangs" here is a noun, not a verb. */
- {"no-ebda", 'e', 0, N_("Don't update EBDA. May fix failures or hangs on some "
- "BIOSes but makes it ineffective with OS not receiving RSDP from GRUB."),
- 0, ARG_TYPE_NONE},
- {0, 0, 0, 0, 0, 0}
- };
- /* rev1 is 1 if ACPIv1 is to be generated, 0 otherwise.
- rev2 contains the revision of ACPIv2+ to generate or 0 if none. */
- static int rev1, rev2;
- /* OEMID of RSDP, RSDT and XSDT. */
- static char root_oemid[6];
- /* OEMTABLE of the same tables. */
- static char root_oemtable[8];
- /* OEMREVISION of the same tables. */
- static grub_uint32_t root_oemrev;
- /* CreatorID of the same tables. */
- static char root_creator_id[4];
- /* CreatorRevision of the same tables. */
- static grub_uint32_t root_creator_rev;
- static struct grub_acpi_rsdp_v10 *rsdpv1_new = 0;
- static struct grub_acpi_rsdp_v20 *rsdpv2_new = 0;
- static char *playground = 0, *playground_ptr = 0;
- static int playground_size = 0;
- /* Linked list of ACPI tables. */
- struct efiemu_acpi_table
- {
- void *addr;
- grub_size_t size;
- struct efiemu_acpi_table *next;
- };
- static struct efiemu_acpi_table *acpi_tables = 0;
- /* DSDT isn't in RSDT. So treat it specially. */
- static void *table_dsdt = 0;
- /* Pointer to recreated RSDT. */
- static void *rsdt_addr = 0;
- /* Allocation handles for different tables. */
- static grub_size_t dsdt_size = 0;
- /* Address of original FACS. */
- static grub_uint32_t facs_addr = 0;
- struct grub_acpi_rsdp_v20 *
- grub_acpi_get_rsdpv2 (void)
- {
- if (rsdpv2_new)
- return rsdpv2_new;
- if (rsdpv1_new)
- return 0;
- return grub_machine_acpi_get_rsdpv2 ();
- }
- struct grub_acpi_rsdp_v10 *
- grub_acpi_get_rsdpv1 (void)
- {
- if (rsdpv1_new)
- return rsdpv1_new;
- if (rsdpv2_new)
- return 0;
- return grub_machine_acpi_get_rsdpv1 ();
- }
- #if defined (__i386__) || defined (__x86_64__)
- static inline int
- iszero (grub_uint8_t *reg, int size)
- {
- int i;
- for (i = 0; i < size; i++)
- if (reg[i])
- return 0;
- return 1;
- }
- /* Context for grub_acpi_create_ebda. */
- struct grub_acpi_create_ebda_ctx {
- int ebda_len;
- grub_uint64_t highestlow;
- };
- /* Helper for grub_acpi_create_ebda. */
- static int
- find_hook (grub_uint64_t start, grub_uint64_t size, grub_memory_type_t type,
- void *data)
- {
- struct grub_acpi_create_ebda_ctx *ctx = data;
- grub_uint64_t end = start + size;
- if (type != GRUB_MEMORY_AVAILABLE)
- return 0;
- if (end > 0x100000)
- end = 0x100000;
- if (end > start + ctx->ebda_len
- && ctx->highestlow < ((end - ctx->ebda_len) & (~0xf)) )
- ctx->highestlow = (end - ctx->ebda_len) & (~0xf);
- return 0;
- }
- grub_err_t
- grub_acpi_create_ebda (void)
- {
- struct grub_acpi_create_ebda_ctx ctx = {
- .highestlow = 0
- };
- int ebda_kb_len = 0;
- int mmapregion = 0;
- grub_uint8_t *ebda, *v1inebda = 0, *v2inebda = 0;
- grub_uint8_t *targetebda, *target;
- struct grub_acpi_rsdp_v10 *v1;
- struct grub_acpi_rsdp_v20 *v2;
- ebda = (grub_uint8_t *) (grub_addr_t) ((*((grub_uint16_t *)0x40e)) << 4);
- grub_dprintf ("acpi", "EBDA @%p\n", ebda);
- if (ebda)
- ebda_kb_len = *(grub_uint16_t *) ebda;
- grub_dprintf ("acpi", "EBDA length 0x%x\n", ebda_kb_len);
- if (ebda_kb_len > 16)
- ebda_kb_len = 0;
- ctx.ebda_len = (ebda_kb_len + 1) << 10;
- /* FIXME: use low-memory mm allocation once it's available. */
- grub_mmap_iterate (find_hook, &ctx);
- targetebda = (grub_uint8_t *) (grub_addr_t) ctx.highestlow;
- grub_dprintf ("acpi", "creating ebda @%llx\n",
- (unsigned long long) ctx.highestlow);
- if (! ctx.highestlow)
- return grub_error (GRUB_ERR_OUT_OF_MEMORY,
- "couldn't find space for the new EBDA");
- mmapregion = grub_mmap_register ((grub_addr_t) targetebda, ctx.ebda_len,
- GRUB_MEMORY_RESERVED);
- if (! mmapregion)
- return grub_errno;
- /* XXX: EBDA is unstandardized, so this implementation is heuristical. */
- if (ebda_kb_len)
- grub_memcpy (targetebda, ebda, 0x400);
- else
- grub_memset (targetebda, 0, 0x400);
- *((grub_uint16_t *) targetebda) = ebda_kb_len + 1;
- target = targetebda;
- v1 = grub_acpi_get_rsdpv1 ();
- v2 = grub_acpi_get_rsdpv2 ();
- if (v2 && v2->length > 40)
- v2 = 0;
- /* First try to replace already existing rsdp. */
- if (v2)
- {
- grub_dprintf ("acpi", "Scanning EBDA for old rsdpv2\n");
- for (; target < targetebda + 0x400 - v2->length; target += 0x10)
- if (grub_memcmp (target, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
- && grub_byte_checksum (target,
- sizeof (struct grub_acpi_rsdp_v10)) == 0
- && ((struct grub_acpi_rsdp_v10 *) target)->revision != 0
- && ((struct grub_acpi_rsdp_v20 *) target)->length <= v2->length)
- {
- grub_memcpy (target, v2, v2->length);
- grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target);
- v2inebda = target;
- target += v2->length;
- target = (grub_uint8_t *) ALIGN_UP((grub_addr_t) target, 16);
- v2 = 0;
- break;
- }
- }
- if (v1)
- {
- grub_dprintf ("acpi", "Scanning EBDA for old rsdpv1\n");
- for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
- target += 0x10)
- if (grub_memcmp (target, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
- && grub_byte_checksum (target,
- sizeof (struct grub_acpi_rsdp_v10)) == 0)
- {
- grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10));
- grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target);
- v1inebda = target;
- target += sizeof (struct grub_acpi_rsdp_v10);
- target = (grub_uint8_t *) ALIGN_UP((grub_addr_t) target, 16);
- v1 = 0;
- break;
- }
- }
- target = targetebda + 0x100;
- /* Try contiguous zeros. */
- if (v2)
- {
- grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n");
- for (; target < targetebda + 0x400 - v2->length; target += 0x10)
- if (iszero (target, v2->length))
- {
- grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target);
- grub_memcpy (target, v2, v2->length);
- v2inebda = target;
- target += v2->length;
- target = (grub_uint8_t *) ALIGN_UP((grub_addr_t) target, 16);
- v2 = 0;
- break;
- }
- }
- if (v1)
- {
- grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n");
- for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
- target += 0x10)
- if (iszero (target, sizeof (struct grub_acpi_rsdp_v10)))
- {
- grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target);
- grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10));
- v1inebda = target;
- target += sizeof (struct grub_acpi_rsdp_v10);
- target = (grub_uint8_t *) ALIGN_UP((grub_addr_t) target, 16);
- v1 = 0;
- break;
- }
- }
- if (v1 || v2)
- {
- grub_mmap_unregister (mmapregion);
- return grub_error (GRUB_ERR_OUT_OF_MEMORY,
- "couldn't find suitable spot in EBDA");
- }
- /* Remove any other RSDT. */
- for (target = targetebda;
- target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
- target += 0x10)
- if (grub_memcmp (target, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
- && grub_byte_checksum (target,
- sizeof (struct grub_acpi_rsdp_v10)) == 0
- && target != v1inebda && target != v2inebda)
- *target = 0;
- grub_dprintf ("acpi", "Switching EBDA\n");
- (*((grub_uint16_t *) 0x40e)) = ((grub_addr_t) targetebda) >> 4;
- grub_dprintf ("acpi", "EBDA switched\n");
- return GRUB_ERR_NONE;
- }
- #endif
- /* Create tables common to ACPIv1 and ACPIv2+ */
- static void
- setup_common_tables (void)
- {
- struct efiemu_acpi_table *cur;
- struct grub_acpi_table_header *rsdt;
- grub_uint32_t *rsdt_entry;
- int numoftables;
- /* Treat DSDT. */
- grub_memcpy (playground_ptr, table_dsdt, dsdt_size);
- grub_free (table_dsdt);
- table_dsdt = playground_ptr;
- playground_ptr += dsdt_size;
- /* Treat other tables. */
- for (cur = acpi_tables; cur; cur = cur->next)
- {
- struct grub_acpi_fadt *fadt;
- grub_memcpy (playground_ptr, cur->addr, cur->size);
- grub_free (cur->addr);
- cur->addr = playground_ptr;
- playground_ptr += cur->size;
- /* If it's FADT correct DSDT and FACS addresses. */
- fadt = (struct grub_acpi_fadt *) cur->addr;
- if (grub_memcmp (fadt->hdr.signature, GRUB_ACPI_FADT_SIGNATURE,
- sizeof (fadt->hdr.signature)) == 0)
- {
- fadt->dsdt_addr = (grub_addr_t) table_dsdt;
- fadt->facs_addr = facs_addr;
- /* Does a revision 2 exist at all? */
- if (fadt->hdr.revision >= 3)
- {
- fadt->dsdt_xaddr = (grub_addr_t) table_dsdt;
- fadt->facs_xaddr = facs_addr;
- }
- /* Recompute checksum. */
- fadt->hdr.checksum = 0;
- fadt->hdr.checksum = 1 + ~grub_byte_checksum (fadt, fadt->hdr.length);
- }
- }
- /* Fill RSDT entries. */
- numoftables = 0;
- for (cur = acpi_tables; cur; cur = cur->next)
- numoftables++;
- rsdt_addr = rsdt = (struct grub_acpi_table_header *) playground_ptr;
- playground_ptr += sizeof (struct grub_acpi_table_header) + sizeof (grub_uint32_t) * numoftables;
- rsdt_entry = (grub_uint32_t *) (rsdt + 1);
- /* Fill RSDT header. */
- grub_memcpy (&(rsdt->signature), "RSDT", 4);
- rsdt->length = sizeof (struct grub_acpi_table_header) + sizeof (grub_uint32_t) * numoftables;
- rsdt->revision = 1;
- grub_memcpy (&(rsdt->oemid), root_oemid, sizeof (rsdt->oemid));
- grub_memcpy (&(rsdt->oemtable), root_oemtable, sizeof (rsdt->oemtable));
- rsdt->oemrev = root_oemrev;
- grub_memcpy (&(rsdt->creator_id), root_creator_id, sizeof (rsdt->creator_id));
- rsdt->creator_rev = root_creator_rev;
- for (cur = acpi_tables; cur; cur = cur->next)
- *(rsdt_entry++) = (grub_addr_t) cur->addr;
- /* Recompute checksum. */
- rsdt->checksum = 0;
- rsdt->checksum = 1 + ~grub_byte_checksum (rsdt, rsdt->length);
- }
- /* Regenerate ACPIv1 RSDP */
- static void
- setv1table (void)
- {
- /* Create RSDP. */
- rsdpv1_new = (struct grub_acpi_rsdp_v10 *) playground_ptr;
- playground_ptr += sizeof (struct grub_acpi_rsdp_v10);
- grub_memcpy (&(rsdpv1_new->signature), GRUB_RSDP_SIGNATURE,
- sizeof (rsdpv1_new->signature));
- grub_memcpy (&(rsdpv1_new->oemid), root_oemid, sizeof (rsdpv1_new->oemid));
- rsdpv1_new->revision = 0;
- rsdpv1_new->rsdt_addr = (grub_addr_t) rsdt_addr;
- rsdpv1_new->checksum = 0;
- rsdpv1_new->checksum = 1 + ~grub_byte_checksum (rsdpv1_new,
- sizeof (*rsdpv1_new));
- grub_dprintf ("acpi", "Generated ACPIv1 tables\n");
- }
- static void
- setv2table (void)
- {
- struct grub_acpi_table_header *xsdt;
- struct efiemu_acpi_table *cur;
- grub_uint64_t *xsdt_entry;
- int numoftables;
- numoftables = 0;
- for (cur = acpi_tables; cur; cur = cur->next)
- numoftables++;
- /* Create XSDT. */
- xsdt = (struct grub_acpi_table_header *) playground_ptr;
- playground_ptr += sizeof (struct grub_acpi_table_header) + sizeof (grub_uint64_t) * numoftables;
- xsdt_entry = (grub_uint64_t *)(xsdt + 1);
- for (cur = acpi_tables; cur; cur = cur->next)
- *(xsdt_entry++) = (grub_addr_t) cur->addr;
- grub_memcpy (&(xsdt->signature), "XSDT", 4);
- xsdt->length = sizeof (struct grub_acpi_table_header) + sizeof (grub_uint64_t) * numoftables;
- xsdt->revision = 1;
- grub_memcpy (&(xsdt->oemid), root_oemid, sizeof (xsdt->oemid));
- grub_memcpy (&(xsdt->oemtable), root_oemtable, sizeof (xsdt->oemtable));
- xsdt->oemrev = root_oemrev;
- grub_memcpy (&(xsdt->creator_id), root_creator_id, sizeof (xsdt->creator_id));
- xsdt->creator_rev = root_creator_rev;
- xsdt->checksum = 0;
- xsdt->checksum = 1 + ~grub_byte_checksum (xsdt, xsdt->length);
- /* Create RSDPv2. */
- rsdpv2_new = (struct grub_acpi_rsdp_v20 *) playground_ptr;
- playground_ptr += sizeof (struct grub_acpi_rsdp_v20);
- grub_memcpy (&(rsdpv2_new->rsdpv1.signature), GRUB_RSDP_SIGNATURE,
- sizeof (rsdpv2_new->rsdpv1.signature));
- grub_memcpy (&(rsdpv2_new->rsdpv1.oemid), root_oemid,
- sizeof (rsdpv2_new->rsdpv1.oemid));
- rsdpv2_new->rsdpv1.revision = rev2;
- rsdpv2_new->rsdpv1.rsdt_addr = (grub_addr_t) rsdt_addr;
- rsdpv2_new->rsdpv1.checksum = 0;
- rsdpv2_new->rsdpv1.checksum = 1 + ~grub_byte_checksum
- (&(rsdpv2_new->rsdpv1), sizeof (rsdpv2_new->rsdpv1));
- rsdpv2_new->length = sizeof (*rsdpv2_new);
- rsdpv2_new->xsdt_addr = (grub_addr_t) xsdt;
- rsdpv2_new->checksum = 0;
- rsdpv2_new->checksum = 1 + ~grub_byte_checksum (rsdpv2_new,
- rsdpv2_new->length);
- grub_dprintf ("acpi", "Generated ACPIv2 tables\n");
- }
- static void
- free_tables (void)
- {
- struct efiemu_acpi_table *cur, *t;
- if (table_dsdt)
- grub_free (table_dsdt);
- for (cur = acpi_tables; cur;)
- {
- t = cur;
- grub_free (cur->addr);
- cur = cur->next;
- grub_free (t);
- }
- acpi_tables = 0;
- table_dsdt = 0;
- }
- static grub_err_t
- grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args)
- {
- struct grub_arg_list *state = ctxt->state;
- struct grub_acpi_rsdp_v10 *rsdp;
- struct efiemu_acpi_table *cur, *t;
- int i, mmapregion;
- int numoftables;
- /* Default values if no RSDP is found. */
- rev1 = 1;
- rev2 = 3;
- facs_addr = 0;
- playground = playground_ptr = 0;
- playground_size = 0;
- rsdp = (struct grub_acpi_rsdp_v10 *) grub_machine_acpi_get_rsdpv2 ();
- if (! rsdp)
- rsdp = grub_machine_acpi_get_rsdpv1 ();
- grub_dprintf ("acpi", "RSDP @%p\n", rsdp);
- if (rsdp)
- {
- grub_uint32_t *entry_ptr;
- char *exclude = 0;
- char *load_only = 0;
- char *ptr;
- /* RSDT consists of header and an array of 32-bit pointers. */
- struct grub_acpi_table_header *rsdt;
- exclude = state[0].set ? grub_strdup (state[0].arg) : 0;
- if (exclude)
- {
- for (ptr = exclude; *ptr; ptr++)
- *ptr = grub_tolower (*ptr);
- }
- load_only = state[1].set ? grub_strdup (state[1].arg) : 0;
- if (load_only)
- {
- for (ptr = load_only; *ptr; ptr++)
- *ptr = grub_tolower (*ptr);
- }
- /* Set revision variables to replicate the same version as host. */
- rev1 = ! rsdp->revision;
- rev2 = rsdp->revision;
- rsdt = (struct grub_acpi_table_header *) (grub_addr_t) rsdp->rsdt_addr;
- /* Load host tables. */
- for (entry_ptr = (grub_uint32_t *) (rsdt + 1);
- entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt)
- + rsdt->length);
- entry_ptr++)
- {
- char signature[5];
- struct efiemu_acpi_table *table;
- struct grub_acpi_table_header *curtable
- = (struct grub_acpi_table_header *) (grub_addr_t) *entry_ptr;
- signature[4] = 0;
- for (i = 0; i < 4;i++)
- signature[i] = grub_tolower (curtable->signature[i]);
- /* If it's FADT it contains addresses of DSDT and FACS. */
- if (grub_strcmp (signature, "facp") == 0)
- {
- struct grub_acpi_table_header *dsdt;
- struct grub_acpi_fadt *fadt = (struct grub_acpi_fadt *) curtable;
- /* Set root header variables to the same values
- as FADT by default. */
- grub_memcpy (&root_oemid, &(fadt->hdr.oemid),
- sizeof (root_oemid));
- grub_memcpy (&root_oemtable, &(fadt->hdr.oemtable),
- sizeof (root_oemtable));
- root_oemrev = fadt->hdr.oemrev;
- grub_memcpy (&root_creator_id, &(fadt->hdr.creator_id),
- sizeof (root_creator_id));
- root_creator_rev = fadt->hdr.creator_rev;
- /* Load DSDT if not excluded. */
- dsdt = (struct grub_acpi_table_header *)
- (grub_addr_t) fadt->dsdt_addr;
- if (dsdt && (! exclude || ! grub_strword (exclude, "dsdt"))
- && (! load_only || grub_strword (load_only, "dsdt"))
- && dsdt->length >= sizeof (*dsdt))
- {
- dsdt_size = dsdt->length;
- table_dsdt = grub_malloc (dsdt->length);
- if (! table_dsdt)
- {
- free_tables ();
- grub_free (exclude);
- grub_free (load_only);
- return grub_errno;
- }
- grub_memcpy (table_dsdt, dsdt, dsdt->length);
- }
- /* Save FACS address. FACS shouldn't be overridden. */
- facs_addr = fadt->facs_addr;
- }
- /* Skip excluded tables. */
- if (exclude && grub_strword (exclude, signature))
- continue;
- if (load_only && ! grub_strword (load_only, signature))
- continue;
- /* Sanity check. */
- if (curtable->length < sizeof (*curtable))
- continue;
- table = (struct efiemu_acpi_table *) grub_malloc
- (sizeof (struct efiemu_acpi_table));
- if (! table)
- {
- free_tables ();
- grub_free (exclude);
- grub_free (load_only);
- return grub_errno;
- }
- table->size = curtable->length;
- table->addr = grub_malloc (table->size);
- playground_size += table->size;
- if (! table->addr)
- {
- free_tables ();
- grub_free (exclude);
- grub_free (load_only);
- grub_free (table);
- return grub_errno;
- }
- table->next = acpi_tables;
- acpi_tables = table;
- grub_memcpy (table->addr, curtable, table->size);
- }
- grub_free (exclude);
- grub_free (load_only);
- }
- /* Does user specify versions to generate? */
- if (state[2].set || state[3].set)
- {
- rev1 = state[2].set;
- if (state[3].set)
- rev2 = rev2 ? : 2;
- else
- rev2 = 0;
- }
- /* Does user override root header information? */
- if (state[4].set)
- grub_strncpy (root_oemid, state[4].arg, sizeof (root_oemid));
- if (state[5].set)
- grub_strncpy (root_oemtable, state[5].arg, sizeof (root_oemtable));
- if (state[6].set)
- root_oemrev = grub_strtoul (state[6].arg, 0, 0);
- if (state[7].set)
- grub_strncpy (root_creator_id, state[7].arg, sizeof (root_creator_id));
- if (state[8].set)
- root_creator_rev = grub_strtoul (state[8].arg, 0, 0);
- /* Load user tables */
- for (i = 0; i < argc; i++)
- {
- grub_file_t file;
- grub_size_t size;
- char *buf;
- file = grub_file_open (args[i]);
- if (! file)
- {
- free_tables ();
- return grub_errno;
- }
- size = grub_file_size (file);
- if (size < sizeof (struct grub_acpi_table_header))
- {
- grub_file_close (file);
- free_tables ();
- return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
- args[i]);
- }
- buf = (char *) grub_malloc (size);
- if (! buf)
- {
- grub_file_close (file);
- free_tables ();
- return grub_errno;
- }
- if (grub_file_read (file, buf, size) != (int) size)
- {
- grub_file_close (file);
- free_tables ();
- if (!grub_errno)
- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
- args[i]);
- return grub_errno;
- }
- grub_file_close (file);
- if (grub_memcmp (((struct grub_acpi_table_header *) buf)->signature,
- "DSDT", 4) == 0)
- {
- grub_free (table_dsdt);
- table_dsdt = buf;
- dsdt_size = size;
- }
- else
- {
- struct efiemu_acpi_table *table;
- table = (struct efiemu_acpi_table *) grub_malloc
- (sizeof (struct efiemu_acpi_table));
- if (! table)
- {
- free_tables ();
- return grub_errno;
- }
- table->size = size;
- table->addr = buf;
- playground_size += table->size;
- table->next = acpi_tables;
- acpi_tables = table;
- }
- }
- numoftables = 0;
- for (cur = acpi_tables; cur; cur = cur->next)
- numoftables++;
- /* DSDT. */
- playground_size += dsdt_size;
- /* RSDT. */
- playground_size += sizeof (struct grub_acpi_table_header) + sizeof (grub_uint32_t) * numoftables;
- /* RSDPv1. */
- playground_size += sizeof (struct grub_acpi_rsdp_v10);
- /* XSDT. */
- playground_size += sizeof (struct grub_acpi_table_header) + sizeof (grub_uint64_t) * numoftables;
- /* RSDPv2. */
- playground_size += sizeof (struct grub_acpi_rsdp_v20);
- playground = playground_ptr
- = grub_mmap_malign_and_register (1, playground_size, &mmapregion,
- GRUB_MEMORY_ACPI, 0);
- if (! playground)
- {
- free_tables ();
- return grub_error (GRUB_ERR_OUT_OF_MEMORY,
- "couldn't allocate space for ACPI tables");
- }
- setup_common_tables ();
- /* Request space for RSDPv1. */
- if (rev1)
- setv1table ();
- /* Request space for RSDPv2+ and XSDT. */
- if (rev2)
- setv2table ();
- for (cur = acpi_tables; cur;)
- {
- t = cur;
- cur = cur->next;
- grub_free (t);
- }
- acpi_tables = 0;
- #if defined (__i386__) || defined (__x86_64__)
- if (! state[9].set)
- {
- grub_err_t err;
- err = grub_acpi_create_ebda ();
- if (err)
- {
- rsdpv1_new = 0;
- rsdpv2_new = 0;
- grub_mmap_free_and_unregister (mmapregion);
- return err;
- }
- }
- #endif
- #ifdef GRUB_MACHINE_EFI
- {
- struct grub_efi_guid acpi = GRUB_EFI_ACPI_TABLE_GUID;
- struct grub_efi_guid acpi20 = GRUB_EFI_ACPI_20_TABLE_GUID;
- efi_call_2 (grub_efi_system_table->boot_services->install_configuration_table,
- &acpi20, grub_acpi_get_rsdpv2 ());
- efi_call_2 (grub_efi_system_table->boot_services->install_configuration_table,
- &acpi, grub_acpi_get_rsdpv1 ());
- }
- #endif
- return GRUB_ERR_NONE;
- }
- static grub_extcmd_t cmd;
- GRUB_MOD_INIT(acpi)
- {
- cmd = grub_register_extcmd ("acpi", grub_cmd_acpi, 0,
- N_("[-1|-2] [--exclude=TABLE1,TABLE2|"
- "--load-only=TABLE1,TABLE2] FILE1"
- " [FILE2] [...]"),
- N_("Load host ACPI tables and tables "
- "specified by arguments."),
- options);
- }
- GRUB_MOD_FINI(acpi)
- {
- grub_unregister_extcmd (cmd);
- }
|