Upgraded GRUB2 to 2.00 release.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / commands / acpi.c
blobc6be5e1f5cc9b3fb37db9c558e59a5861cd70127
1 /* acpi.c - modify acpi tables. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/dl.h>
21 #include <grub/extcmd.h>
22 #include <grub/file.h>
23 #include <grub/disk.h>
24 #include <grub/term.h>
25 #include <grub/misc.h>
26 #include <grub/acpi.h>
27 #include <grub/mm.h>
28 #include <grub/memory.h>
29 #include <grub/i18n.h>
31 #ifdef GRUB_MACHINE_EFI
32 #include <grub/efi/efi.h>
33 #include <grub/efi/api.h>
34 #endif
36 #pragma GCC diagnostic ignored "-Wcast-align"
38 GRUB_MOD_LICENSE ("GPLv3+");
40 static const struct grub_arg_option options[] = {
41 {"exclude", 'x', 0,
42 N_("Don't load host tables specified by comma-separated list."),
43 0, ARG_TYPE_STRING},
44 {"load-only", 'n', 0,
45 N_("Load only tables specified by comma-separated list."), 0, ARG_TYPE_STRING},
46 {"v1", '1', 0, N_("Export version 1 tables to the OS."), 0, ARG_TYPE_NONE},
47 {"v2", '2', 0, N_("Export version 2 and version 3 tables to the OS."), 0, ARG_TYPE_NONE},
48 {"oemid", 'o', 0, N_("Set OEMID of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING},
49 {"oemtable", 't', 0,
50 N_("Set OEMTABLE ID of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING},
51 {"oemtablerev", 'r', 0,
52 N_("Set OEMTABLE revision of RSDP, XSDT and RSDT."), 0, ARG_TYPE_INT},
53 {"oemtablecreator", 'c', 0,
54 N_("Set creator field of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING},
55 {"oemtablecreatorrev", 'd', 0,
56 N_("Set creator revision of RSDP, XSDT and RSDT."), 0, ARG_TYPE_INT},
57 /* TRANSLATORS: "hangs" here is a noun, not a verb. */
58 {"no-ebda", 'e', 0, N_("Don't update EBDA. May fix failures or hangs on some "
59 "BIOSes but makes it ineffective with OS not receiving RSDP from GRUB."),
60 0, ARG_TYPE_NONE},
61 {0, 0, 0, 0, 0, 0}
64 /* Simple checksum by summing all bytes. Used by ACPI and SMBIOS. */
65 grub_uint8_t
66 grub_byte_checksum (void *base, grub_size_t size)
68 grub_uint8_t *ptr;
69 grub_uint8_t ret = 0;
70 for (ptr = (grub_uint8_t *) base; ptr < ((grub_uint8_t *) base) + size;
71 ptr++)
72 ret += *ptr;
73 return ret;
76 /* rev1 is 1 if ACPIv1 is to be generated, 0 otherwise.
77 rev2 contains the revision of ACPIv2+ to generate or 0 if none. */
78 static int rev1, rev2;
79 /* OEMID of RSDP, RSDT and XSDT. */
80 static char root_oemid[6];
81 /* OEMTABLE of the same tables. */
82 static char root_oemtable[8];
83 /* OEMREVISION of the same tables. */
84 static grub_uint32_t root_oemrev;
85 /* CreatorID of the same tables. */
86 static char root_creator_id[4];
87 /* CreatorRevision of the same tables. */
88 static grub_uint32_t root_creator_rev;
89 static struct grub_acpi_rsdp_v10 *rsdpv1_new = 0;
90 static struct grub_acpi_rsdp_v20 *rsdpv2_new = 0;
91 static char *playground = 0, *playground_ptr = 0;
92 static int playground_size = 0;
94 /* Linked list of ACPI tables. */
95 struct efiemu_acpi_table
97 void *addr;
98 grub_size_t size;
99 struct efiemu_acpi_table *next;
101 static struct efiemu_acpi_table *acpi_tables = 0;
103 /* DSDT isn't in RSDT. So treat it specially. */
104 static void *table_dsdt = 0;
105 /* Pointer to recreated RSDT. */
106 static void *rsdt_addr = 0;
108 /* Allocation handles for different tables. */
109 static grub_size_t dsdt_size = 0;
111 /* Address of original FACS. */
112 static grub_uint32_t facs_addr = 0;
114 struct grub_acpi_rsdp_v20 *
115 grub_acpi_get_rsdpv2 (void)
117 if (rsdpv2_new)
118 return rsdpv2_new;
119 if (rsdpv1_new)
120 return 0;
121 return grub_machine_acpi_get_rsdpv2 ();
124 struct grub_acpi_rsdp_v10 *
125 grub_acpi_get_rsdpv1 (void)
127 if (rsdpv1_new)
128 return rsdpv1_new;
129 if (rsdpv2_new)
130 return 0;
131 return grub_machine_acpi_get_rsdpv1 ();
134 static inline int
135 iszero (grub_uint8_t *reg, int size)
137 int i;
138 for (i = 0; i < size; i++)
139 if (reg[i])
140 return 0;
141 return 1;
144 #if defined (__i386__) || defined (__x86_64__)
145 grub_err_t
146 grub_acpi_create_ebda (void)
148 int ebda_kb_len;
149 int ebda_len;
150 int mmapregion = 0;
151 grub_uint8_t *ebda, *v1inebda = 0, *v2inebda = 0;
152 grub_uint64_t highestlow = 0;
153 grub_uint8_t *targetebda, *target;
154 struct grub_acpi_rsdp_v10 *v1;
155 struct grub_acpi_rsdp_v20 *v2;
156 auto int NESTED_FUNC_ATTR find_hook (grub_uint64_t, grub_uint64_t,
157 grub_uint32_t);
158 int NESTED_FUNC_ATTR find_hook (grub_uint64_t start, grub_uint64_t size,
159 grub_memory_type_t type)
161 grub_uint64_t end = start + size;
162 if (type != GRUB_MEMORY_AVAILABLE)
163 return 0;
164 if (end > 0x100000)
165 end = 0x100000;
166 if (end > start + ebda_len
167 && highestlow < ((end - ebda_len) & (~0xf)) )
168 highestlow = (end - ebda_len) & (~0xf);
169 return 0;
172 ebda = (grub_uint8_t *) (grub_addr_t) ((*((grub_uint16_t *)0x40e)) << 4);
173 ebda_kb_len = *(grub_uint16_t *) ebda;
174 if (! ebda || ebda_kb_len > 16)
175 ebda_kb_len = 0;
176 ebda_len = (ebda_kb_len + 1) << 10;
178 /* FIXME: use low-memory mm allocation once it's available. */
179 grub_mmap_iterate (find_hook);
180 targetebda = (grub_uint8_t *) (grub_addr_t) highestlow;
181 grub_dprintf ("acpi", "creating ebda @%llx\n",
182 (unsigned long long) highestlow);
183 if (! highestlow)
184 return grub_error (GRUB_ERR_OUT_OF_MEMORY,
185 "couldn't find space for the new EBDA");
187 mmapregion = grub_mmap_register ((grub_addr_t) targetebda, ebda_len,
188 GRUB_MEMORY_RESERVED);
189 if (! mmapregion)
190 return grub_errno;
192 /* XXX: EBDA is unstandardized, so this implementation is heuristical. */
193 if (ebda_kb_len)
194 grub_memcpy (targetebda, ebda, 0x400);
195 else
196 grub_memset (targetebda, 0, 0x400);
197 *((grub_uint16_t *) targetebda) = ebda_kb_len + 1;
198 target = targetebda;
200 v1 = grub_acpi_get_rsdpv1 ();
201 v2 = grub_acpi_get_rsdpv2 ();
202 if (v2 && v2->length > 40)
203 v2 = 0;
205 /* First try to replace already existing rsdp. */
206 if (v2)
208 grub_dprintf ("acpi", "Scanning EBDA for old rsdpv2\n");
209 for (; target < targetebda + 0x400 - v2->length; target += 0x10)
210 if (grub_memcmp (target, "RSD PTR ", 8) == 0
211 && grub_byte_checksum (target,
212 sizeof (struct grub_acpi_rsdp_v10)) == 0
213 && ((struct grub_acpi_rsdp_v10 *) target)->revision != 0
214 && ((struct grub_acpi_rsdp_v20 *) target)->length <= v2->length)
216 grub_memcpy (target, v2, v2->length);
217 grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target);
218 v2inebda = target;
219 target += v2->length;
220 target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
221 v2 = 0;
222 break;
226 if (v1)
228 grub_dprintf ("acpi", "Scanning EBDA for old rsdpv1\n");
229 for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
230 target += 0x10)
231 if (grub_memcmp (target, "RSD PTR ", 8) == 0
232 && grub_byte_checksum (target,
233 sizeof (struct grub_acpi_rsdp_v10)) == 0)
235 grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10));
236 grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target);
237 v1inebda = target;
238 target += sizeof (struct grub_acpi_rsdp_v10);
239 target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
240 v1 = 0;
241 break;
245 target = targetebda + 0x100;
247 /* Try contiguous zeros. */
248 if (v2)
250 grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n");
251 for (; target < targetebda + 0x400 - v2->length; target += 0x10)
252 if (iszero (target, v2->length))
254 grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target);
255 grub_memcpy (target, v2, v2->length);
256 v2inebda = target;
257 target += v2->length;
258 target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
259 v2 = 0;
260 break;
264 if (v1)
266 grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n");
267 for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
268 target += 0x10)
269 if (iszero (target, sizeof (struct grub_acpi_rsdp_v10)))
271 grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target);
272 grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10));
273 v1inebda = target;
274 target += sizeof (struct grub_acpi_rsdp_v10);
275 target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
276 v1 = 0;
277 break;
281 if (v1 || v2)
283 grub_mmap_unregister (mmapregion);
284 return grub_error (GRUB_ERR_OUT_OF_MEMORY,
285 "couldn't find suitable spot in EBDA");
288 /* Remove any other RSDT. */
289 for (target = targetebda;
290 target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
291 target += 0x10)
292 if (grub_memcmp (target, "RSD PTR ", 8) == 0
293 && grub_byte_checksum (target,
294 sizeof (struct grub_acpi_rsdp_v10)) == 0
295 && target != v1inebda && target != v2inebda)
296 *target = 0;
298 grub_dprintf ("acpi", "Switching EBDA\n");
299 (*((grub_uint16_t *) 0x40e)) = ((long)targetebda) >> 4;
300 grub_dprintf ("acpi", "EBDA switched\n");
302 return GRUB_ERR_NONE;
304 #endif
306 /* Create tables common to ACPIv1 and ACPIv2+ */
307 static void
308 setup_common_tables (void)
310 struct efiemu_acpi_table *cur;
311 struct grub_acpi_table_header *rsdt;
312 grub_uint32_t *rsdt_entry;
313 int numoftables;
315 /* Treat DSDT. */
316 grub_memcpy (playground_ptr, table_dsdt, dsdt_size);
317 grub_free (table_dsdt);
318 table_dsdt = playground_ptr;
319 playground_ptr += dsdt_size;
321 /* Treat other tables. */
322 for (cur = acpi_tables; cur; cur = cur->next)
324 struct grub_acpi_fadt *fadt;
326 grub_memcpy (playground_ptr, cur->addr, cur->size);
327 grub_free (cur->addr);
328 cur->addr = playground_ptr;
329 playground_ptr += cur->size;
331 /* If it's FADT correct DSDT and FACS addresses. */
332 fadt = (struct grub_acpi_fadt *) cur->addr;
333 if (grub_memcmp (fadt->hdr.signature, GRUB_ACPI_FADT_SIGNATURE,
334 sizeof (fadt->hdr.signature)) == 0)
336 fadt->dsdt_addr = (grub_addr_t) table_dsdt;
337 fadt->facs_addr = facs_addr;
339 /* Does a revision 2 exist at all? */
340 if (fadt->hdr.revision >= 3)
342 fadt->dsdt_xaddr = (grub_addr_t) table_dsdt;
343 fadt->facs_xaddr = facs_addr;
346 /* Recompute checksum. */
347 fadt->hdr.checksum = 0;
348 fadt->hdr.checksum = 1 + ~grub_byte_checksum (fadt, fadt->hdr.length);
352 /* Fill RSDT entries. */
353 numoftables = 0;
354 for (cur = acpi_tables; cur; cur = cur->next)
355 numoftables++;
357 rsdt_addr = rsdt = (struct grub_acpi_table_header *) playground_ptr;
358 playground_ptr += sizeof (struct grub_acpi_table_header) + 4 * numoftables;
360 rsdt_entry = (grub_uint32_t *) (rsdt + 1);
362 /* Fill RSDT header. */
363 grub_memcpy (&(rsdt->signature), "RSDT", 4);
364 rsdt->length = sizeof (struct grub_acpi_table_header) + 4 * numoftables;
365 rsdt->revision = 1;
366 grub_memcpy (&(rsdt->oemid), root_oemid, sizeof (rsdt->oemid));
367 grub_memcpy (&(rsdt->oemtable), root_oemtable, sizeof (rsdt->oemtable));
368 rsdt->oemrev = root_oemrev;
369 grub_memcpy (&(rsdt->creator_id), root_creator_id, sizeof (rsdt->creator_id));
370 rsdt->creator_rev = root_creator_rev;
372 for (cur = acpi_tables; cur; cur = cur->next)
373 *(rsdt_entry++) = (grub_addr_t) cur->addr;
375 /* Recompute checksum. */
376 rsdt->checksum = 0;
377 rsdt->checksum = 1 + ~grub_byte_checksum (rsdt, rsdt->length);
380 /* Regenerate ACPIv1 RSDP */
381 static void
382 setv1table (void)
384 /* Create RSDP. */
385 rsdpv1_new = (struct grub_acpi_rsdp_v10 *) playground_ptr;
386 playground_ptr += sizeof (struct grub_acpi_rsdp_v10);
387 grub_memcpy (&(rsdpv1_new->signature), "RSD PTR ",
388 sizeof (rsdpv1_new->signature));
389 grub_memcpy (&(rsdpv1_new->oemid), root_oemid, sizeof (rsdpv1_new->oemid));
390 rsdpv1_new->revision = 0;
391 rsdpv1_new->rsdt_addr = (grub_addr_t) rsdt_addr;
392 rsdpv1_new->checksum = 0;
393 rsdpv1_new->checksum = 1 + ~grub_byte_checksum (rsdpv1_new,
394 sizeof (*rsdpv1_new));
395 grub_dprintf ("acpi", "Generated ACPIv1 tables\n");
398 static void
399 setv2table (void)
401 struct grub_acpi_table_header *xsdt;
402 struct efiemu_acpi_table *cur;
403 grub_uint64_t *xsdt_entry;
404 int numoftables;
406 numoftables = 0;
407 for (cur = acpi_tables; cur; cur = cur->next)
408 numoftables++;
410 /* Create XSDT. */
411 xsdt = (struct grub_acpi_table_header *) playground_ptr;
412 playground_ptr += sizeof (struct grub_acpi_table_header) + 8 * numoftables;
414 xsdt_entry = (grub_uint64_t *)(xsdt + 1);
415 for (cur = acpi_tables; cur; cur = cur->next)
416 *(xsdt_entry++) = (grub_addr_t) cur->addr;
417 grub_memcpy (&(xsdt->signature), "XSDT", 4);
418 xsdt->length = sizeof (struct grub_acpi_table_header) + 8 * numoftables;
419 xsdt->revision = 1;
420 grub_memcpy (&(xsdt->oemid), root_oemid, sizeof (xsdt->oemid));
421 grub_memcpy (&(xsdt->oemtable), root_oemtable, sizeof (xsdt->oemtable));
422 xsdt->oemrev = root_oemrev;
423 grub_memcpy (&(xsdt->creator_id), root_creator_id, sizeof (xsdt->creator_id));
424 xsdt->creator_rev = root_creator_rev;
425 xsdt->checksum = 0;
426 xsdt->checksum = 1 + ~grub_byte_checksum (xsdt, xsdt->length);
428 /* Create RSDPv2. */
429 rsdpv2_new = (struct grub_acpi_rsdp_v20 *) playground_ptr;
430 playground_ptr += sizeof (struct grub_acpi_rsdp_v20);
431 grub_memcpy (&(rsdpv2_new->rsdpv1.signature), "RSD PTR ",
432 sizeof (rsdpv2_new->rsdpv1.signature));
433 grub_memcpy (&(rsdpv2_new->rsdpv1.oemid), root_oemid,
434 sizeof (rsdpv2_new->rsdpv1.oemid));
435 rsdpv2_new->rsdpv1.revision = rev2;
436 rsdpv2_new->rsdpv1.rsdt_addr = (grub_addr_t) rsdt_addr;
437 rsdpv2_new->rsdpv1.checksum = 0;
438 rsdpv2_new->rsdpv1.checksum = 1 + ~grub_byte_checksum
439 (&(rsdpv2_new->rsdpv1), sizeof (rsdpv2_new->rsdpv1));
440 rsdpv2_new->length = sizeof (*rsdpv2_new);
441 rsdpv2_new->xsdt_addr = (grub_addr_t) xsdt;
442 rsdpv2_new->checksum = 0;
443 rsdpv2_new->checksum = 1 + ~grub_byte_checksum (rsdpv2_new,
444 rsdpv2_new->length);
445 grub_dprintf ("acpi", "Generated ACPIv2 tables\n");
448 static void
449 free_tables (void)
451 struct efiemu_acpi_table *cur, *t;
452 if (table_dsdt)
453 grub_free (table_dsdt);
454 for (cur = acpi_tables; cur;)
456 t = cur;
457 grub_free (cur->addr);
458 cur = cur->next;
459 grub_free (t);
461 acpi_tables = 0;
462 table_dsdt = 0;
465 static grub_err_t
466 grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args)
468 struct grub_arg_list *state = ctxt->state;
469 struct grub_acpi_rsdp_v10 *rsdp;
470 struct efiemu_acpi_table *cur, *t;
471 int i, mmapregion;
472 int numoftables;
474 /* Default values if no RSDP is found. */
475 rev1 = 1;
476 rev2 = 3;
478 facs_addr = 0;
479 playground = playground_ptr = 0;
480 playground_size = 0;
482 rsdp = (struct grub_acpi_rsdp_v10 *) grub_machine_acpi_get_rsdpv2 ();
484 if (! rsdp)
485 rsdp = grub_machine_acpi_get_rsdpv1 ();
487 if (rsdp)
489 grub_uint32_t *entry_ptr;
490 char *exclude = 0;
491 char *load_only = 0;
492 char *ptr;
493 /* RSDT consists of header and an array of 32-bit pointers. */
494 struct grub_acpi_table_header *rsdt;
496 exclude = state[0].set ? grub_strdup (state[0].arg) : 0;
497 if (exclude)
499 for (ptr = exclude; *ptr; ptr++)
500 *ptr = grub_tolower (*ptr);
503 load_only = state[1].set ? grub_strdup (state[1].arg) : 0;
504 if (load_only)
506 for (ptr = load_only; *ptr; ptr++)
507 *ptr = grub_tolower (*ptr);
510 /* Set revision variables to replicate the same version as host. */
511 rev1 = ! rsdp->revision;
512 rev2 = rsdp->revision;
513 rsdt = (struct grub_acpi_table_header *) (grub_addr_t) rsdp->rsdt_addr;
514 /* Load host tables. */
515 for (entry_ptr = (grub_uint32_t *) (rsdt + 1);
516 entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt)
517 + rsdt->length);
518 entry_ptr++)
520 char signature[5];
521 struct efiemu_acpi_table *table;
522 struct grub_acpi_table_header *curtable
523 = (struct grub_acpi_table_header *) (grub_addr_t) *entry_ptr;
524 signature[4] = 0;
525 for (i = 0; i < 4;i++)
526 signature[i] = grub_tolower (curtable->signature[i]);
528 /* If it's FADT it contains addresses of DSDT and FACS. */
529 if (grub_strcmp (signature, "facp") == 0)
531 struct grub_acpi_table_header *dsdt;
532 struct grub_acpi_fadt *fadt = (struct grub_acpi_fadt *) curtable;
534 /* Set root header variables to the same values
535 as FADT by default. */
536 grub_memcpy (&root_oemid, &(fadt->hdr.oemid),
537 sizeof (root_oemid));
538 grub_memcpy (&root_oemtable, &(fadt->hdr.oemtable),
539 sizeof (root_oemtable));
540 root_oemrev = fadt->hdr.oemrev;
541 grub_memcpy (&root_creator_id, &(fadt->hdr.creator_id),
542 sizeof (root_creator_id));
543 root_creator_rev = fadt->hdr.creator_rev;
545 /* Load DSDT if not excluded. */
546 dsdt = (struct grub_acpi_table_header *)
547 (grub_addr_t) fadt->dsdt_addr;
548 if (dsdt && (! exclude || ! grub_strword (exclude, "dsdt"))
549 && (! load_only || grub_strword (load_only, "dsdt"))
550 && dsdt->length >= sizeof (*dsdt))
552 dsdt_size = dsdt->length;
553 table_dsdt = grub_malloc (dsdt->length);
554 if (! table_dsdt)
556 free_tables ();
557 grub_free (exclude);
558 grub_free (load_only);
559 return grub_errno;
561 grub_memcpy (table_dsdt, dsdt, dsdt->length);
564 /* Save FACS address. FACS shouldn't be overridden. */
565 facs_addr = fadt->facs_addr;
568 /* Skip excluded tables. */
569 if (exclude && grub_strword (exclude, signature))
570 continue;
571 if (load_only && ! grub_strword (load_only, signature))
572 continue;
574 /* Sanity check. */
575 if (curtable->length < sizeof (*curtable))
576 continue;
578 table = (struct efiemu_acpi_table *) grub_malloc
579 (sizeof (struct efiemu_acpi_table));
580 if (! table)
582 free_tables ();
583 grub_free (exclude);
584 grub_free (load_only);
585 return grub_errno;
587 table->size = curtable->length;
588 table->addr = grub_malloc (table->size);
589 playground_size += table->size;
590 if (! table->addr)
592 free_tables ();
593 return grub_errno;
595 table->next = acpi_tables;
596 acpi_tables = table;
597 grub_memcpy (table->addr, curtable, table->size);
599 grub_free (exclude);
600 grub_free (load_only);
603 /* Does user specify versions to generate? */
604 if (state[2].set || state[3].set)
606 rev1 = state[2].set;
607 if (state[3].set)
608 rev2 = rev2 ? : 2;
609 else
610 rev2 = 0;
613 /* Does user override root header information? */
614 if (state[4].set)
615 grub_strncpy (root_oemid, state[4].arg, sizeof (root_oemid));
616 if (state[5].set)
617 grub_strncpy (root_oemtable, state[5].arg, sizeof (root_oemtable));
618 if (state[6].set)
619 root_oemrev = grub_strtoul (state[6].arg, 0, 0);
620 if (state[7].set)
621 grub_strncpy (root_creator_id, state[7].arg, sizeof (root_creator_id));
622 if (state[8].set)
623 root_creator_rev = grub_strtoul (state[8].arg, 0, 0);
625 /* Load user tables */
626 for (i = 0; i < argc; i++)
628 grub_file_t file;
629 grub_size_t size;
630 char *buf;
632 file = grub_file_open (args[i]);
633 if (! file)
635 free_tables ();
636 return grub_errno;
639 size = grub_file_size (file);
640 if (size < sizeof (struct grub_acpi_table_header))
642 grub_file_close (file);
643 free_tables ();
644 return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
645 args[i]);
648 buf = (char *) grub_malloc (size);
649 if (! buf)
651 grub_file_close (file);
652 free_tables ();
653 return grub_errno;
656 if (grub_file_read (file, buf, size) != (int) size)
658 grub_file_close (file);
659 free_tables ();
660 if (!grub_errno)
661 grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
662 args[i]);
663 return grub_errno;
665 grub_file_close (file);
667 if (grub_memcmp (((struct grub_acpi_table_header *) buf)->signature,
668 "DSDT", 4) == 0)
670 grub_free (table_dsdt);
671 table_dsdt = buf;
672 dsdt_size = size;
674 else
676 struct efiemu_acpi_table *table;
677 table = (struct efiemu_acpi_table *) grub_malloc
678 (sizeof (struct efiemu_acpi_table));
679 if (! table)
681 free_tables ();
682 return grub_errno;
685 table->size = size;
686 table->addr = buf;
687 playground_size += table->size;
689 table->next = acpi_tables;
690 acpi_tables = table;
694 numoftables = 0;
695 for (cur = acpi_tables; cur; cur = cur->next)
696 numoftables++;
698 /* DSDT. */
699 playground_size += dsdt_size;
700 /* RSDT. */
701 playground_size += sizeof (struct grub_acpi_table_header) + 4 * numoftables;
702 /* RSDPv1. */
703 playground_size += sizeof (struct grub_acpi_rsdp_v10);
704 /* XSDT. */
705 playground_size += sizeof (struct grub_acpi_table_header) + 8 * numoftables;
706 /* RSDPv2. */
707 playground_size += sizeof (struct grub_acpi_rsdp_v20);
709 playground = playground_ptr
710 = grub_mmap_malign_and_register (1, playground_size, &mmapregion,
711 GRUB_MEMORY_ACPI, 0);
713 if (! playground)
715 free_tables ();
716 return grub_error (GRUB_ERR_OUT_OF_MEMORY,
717 "couldn't allocate space for ACPI tables");
720 setup_common_tables ();
722 /* Request space for RSDPv1. */
723 if (rev1)
724 setv1table ();
726 /* Request space for RSDPv2+ and XSDT. */
727 if (rev2)
728 setv2table ();
730 for (cur = acpi_tables; cur;)
732 t = cur;
733 cur = cur->next;
734 grub_free (t);
736 acpi_tables = 0;
738 #if defined (__i386__) || defined (__x86_64__)
739 if (! state[9].set)
741 grub_err_t err;
742 err = grub_acpi_create_ebda ();
743 if (err)
745 rsdpv1_new = 0;
746 rsdpv2_new = 0;
747 grub_mmap_free_and_unregister (mmapregion);
748 return err;
751 #endif
753 #ifdef GRUB_MACHINE_EFI
755 struct grub_efi_guid acpi = GRUB_EFI_ACPI_TABLE_GUID;
756 struct grub_efi_guid acpi20 = GRUB_EFI_ACPI_20_TABLE_GUID;
758 grub_efi_system_table->boot_services->install_configuration_table
759 (&acpi20, grub_acpi_get_rsdpv2 ());
760 grub_efi_system_table->boot_services->install_configuration_table
761 (&acpi, grub_acpi_get_rsdpv1 ());
763 #endif
765 return GRUB_ERR_NONE;
768 static grub_extcmd_t cmd;
770 GRUB_MOD_INIT(acpi)
772 cmd = grub_register_extcmd ("acpi", grub_cmd_acpi, 0,
773 N_("[-1|-2] [--exclude=TABLE1,TABLE2|"
774 "--load-only=TABLE1,TABLE2] FILE1"
775 " [FILE2] [...]"),
776 N_("Load host ACPI tables and tables "
777 "specified by arguments."),
778 options);
781 GRUB_MOD_FINI(acpi)
783 grub_unregister_extcmd (cmd);