acpi.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. /* acpi.c - modify acpi tables. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2009 Free Software Foundation, Inc.
  5. *
  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.
  10. *
  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.
  15. *
  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/>.
  18. */
  19. #include <grub/dl.h>
  20. #include <grub/extcmd.h>
  21. #include <grub/file.h>
  22. #include <grub/disk.h>
  23. #include <grub/term.h>
  24. #include <grub/misc.h>
  25. #include <grub/gzio.h>
  26. #include <grub/acpi.h>
  27. #include <grub/mm.h>
  28. #include <grub/machine/memory.h>
  29. #include <grub/memory.h>
  30. #include <grub/i18n.h>
  31. #ifdef GRUB_MACHINE_EFI
  32. #include <grub/efi/efi.h>
  33. #include <grub/efi/api.h>
  34. #endif
  35. GRUB_EXPORT(grub_byte_checksum);
  36. GRUB_EXPORT(grub_acpi_get_rsdpv1);
  37. GRUB_EXPORT(grub_acpi_get_rsdpv2);
  38. static const struct grub_arg_option options[] = {
  39. {"exclude", 'x', 0,
  40. N_("Don't load host tables specified by comma-separated list."),
  41. 0, ARG_TYPE_STRING},
  42. {"load-only", 'n', 0,
  43. N_("Load only tables specified by comma-separated list."), 0, ARG_TYPE_STRING},
  44. {"v1", '1', 0, N_("Expose v1 tables."), 0, ARG_TYPE_NONE},
  45. {"v2", '2', 0, N_("Expose v2 and v3 tables."), 0, ARG_TYPE_NONE},
  46. {"oemid", 'o', 0, N_("Set OEMID of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING},
  47. {"oemtable", 't', 0,
  48. N_("Set OEMTABLE ID of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING},
  49. {"oemtablerev", 'r', 0,
  50. N_("Set OEMTABLE revision of RSDP, XSDT and RSDT."), 0, ARG_TYPE_INT},
  51. {"oemtablecreator", 'c', 0,
  52. N_("Set creator field of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING},
  53. {"oemtablecreatorrev", 'd', 0,
  54. N_("Set creator revision of RSDP, XSDT and RSDT."), 0, ARG_TYPE_INT},
  55. {"no-ebda", 'e', 0, N_("Don't update EBDA. May fix failures or hangs on some."
  56. " BIOSes but makes it ineffective with OS not receiving RSDP from GRUB."),
  57. 0, ARG_TYPE_NONE},
  58. {0, 0, 0, 0, 0, 0}
  59. };
  60. /* Simple checksum by summing all bytes. Used by ACPI and SMBIOS. */
  61. grub_uint8_t
  62. grub_byte_checksum (void *base, grub_size_t size)
  63. {
  64. grub_uint8_t *ptr;
  65. grub_uint8_t ret = 0;
  66. for (ptr = (grub_uint8_t *) base; ptr < ((grub_uint8_t *) base) + size;
  67. ptr++)
  68. ret += *ptr;
  69. return ret;
  70. }
  71. /* rev1 is 1 if ACPIv1 is to be generated, 0 otherwise.
  72. rev2 contains the revision of ACPIv2+ to generate or 0 if none. */
  73. static int rev1, rev2;
  74. /* OEMID of RSDP, RSDT and XSDT. */
  75. static char root_oemid[6];
  76. /* OEMTABLE of the same tables. */
  77. static char root_oemtable[8];
  78. /* OEMREVISION of the same tables. */
  79. static grub_uint32_t root_oemrev;
  80. /* CreatorID of the same tables. */
  81. static char root_creator_id[4];
  82. /* CreatorRevision of the same tables. */
  83. static grub_uint32_t root_creator_rev;
  84. static struct grub_acpi_rsdp_v10 *rsdpv1_new = 0;
  85. static struct grub_acpi_rsdp_v20 *rsdpv2_new = 0;
  86. static char *playground = 0, *playground_ptr = 0;
  87. static int playground_size = 0;
  88. /* Linked list of ACPI tables. */
  89. struct efiemu_acpi_table
  90. {
  91. void *addr;
  92. grub_size_t size;
  93. struct efiemu_acpi_table *next;
  94. };
  95. static struct efiemu_acpi_table *acpi_tables = 0;
  96. /* DSDT isn't in RSDT. So treat it specially. */
  97. static void *table_dsdt = 0;
  98. /* Pointer to recreated RSDT. */
  99. static void *rsdt_addr = 0;
  100. /* Allocation handles for different tables. */
  101. static grub_size_t dsdt_size = 0;
  102. /* Address of original FACS. */
  103. static grub_uint32_t facs_addr = 0;
  104. struct grub_acpi_rsdp_v20 *
  105. grub_acpi_get_rsdpv2 (void)
  106. {
  107. if (rsdpv2_new)
  108. return rsdpv2_new;
  109. if (rsdpv1_new)
  110. return 0;
  111. return grub_machine_acpi_get_rsdpv2 ();
  112. }
  113. struct grub_acpi_rsdp_v10 *
  114. grub_acpi_get_rsdpv1 (void)
  115. {
  116. if (rsdpv1_new)
  117. return rsdpv1_new;
  118. if (rsdpv2_new)
  119. return 0;
  120. return grub_machine_acpi_get_rsdpv1 ();
  121. }
  122. static inline int
  123. iszero (grub_uint8_t *reg, int size)
  124. {
  125. int i;
  126. for (i = 0; i < size; i++)
  127. if (reg[i])
  128. return 0;
  129. return 1;
  130. }
  131. struct grub_acpi_create_ebda_closure
  132. {
  133. int ebda_len;
  134. grub_uint64_t highestlow;
  135. };
  136. static int
  137. find_hook (grub_uint64_t start, grub_uint64_t size,
  138. grub_uint32_t type, void *closure)
  139. {
  140. struct grub_acpi_create_ebda_closure *c = closure;
  141. grub_uint64_t end = start + size;
  142. if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
  143. return 0;
  144. if (end > 0x100000)
  145. end = 0x100000;
  146. if (end > start + c->ebda_len
  147. && c->highestlow < ((end - c->ebda_len) & (~0xf)) )
  148. c->highestlow = (end - c->ebda_len) & (~0xf);
  149. return 0;
  150. }
  151. grub_err_t
  152. grub_acpi_create_ebda (void)
  153. {
  154. int ebda_kb_len;
  155. int mmapregion = 0;
  156. grub_uint8_t *ebda, *v1inebda = 0, *v2inebda = 0;
  157. grub_uint8_t *targetebda, *target;
  158. struct grub_acpi_rsdp_v10 *v1;
  159. struct grub_acpi_rsdp_v20 *v2;
  160. struct grub_acpi_create_ebda_closure c;
  161. c.highestlow = 0;
  162. ebda = (grub_uint8_t *) UINT_TO_PTR ((*((grub_uint16_t *)0x40e)) << 4);
  163. ebda_kb_len = *(grub_uint16_t *) ebda;
  164. if (! ebda || ebda_kb_len > 16)
  165. ebda_kb_len = 0;
  166. c.ebda_len = (ebda_kb_len + 1) << 10;
  167. /* FIXME: use low-memory mm allocation once it's available. */
  168. grub_mmap_iterate (find_hook, &c);
  169. targetebda = (grub_uint8_t *) UINT_TO_PTR (c.highestlow);
  170. grub_dprintf ("acpi", "creating ebda @%llx\n",
  171. (unsigned long long) c.highestlow);
  172. if (! c.highestlow)
  173. return grub_error (GRUB_ERR_OUT_OF_MEMORY,
  174. "couldn't find space for the new EBDA");
  175. mmapregion = grub_mmap_register (PTR_TO_UINT64 (targetebda), c.ebda_len,
  176. GRUB_MACHINE_MEMORY_RESERVED);
  177. if (! mmapregion)
  178. return grub_errno;
  179. /* XXX: EBDA is unstandardized, so this implementation is heuristical. */
  180. if (ebda_kb_len)
  181. grub_memcpy (targetebda, ebda, 0x400);
  182. else
  183. grub_memset (targetebda, 0, 0x400);
  184. *((grub_uint16_t *) targetebda) = ebda_kb_len + 1;
  185. target = targetebda;
  186. v1 = grub_acpi_get_rsdpv1 ();
  187. v2 = grub_acpi_get_rsdpv2 ();
  188. if (v2 && v2->length > 40)
  189. v2 = 0;
  190. /* First try to replace already existing rsdp. */
  191. if (v2)
  192. {
  193. grub_dprintf ("acpi", "Scanning EBDA for old rsdpv2\n");
  194. for (; target < targetebda + 0x400 - v2->length; target += 0x10)
  195. if (grub_memcmp (target, "RSD PTR ", 8) == 0
  196. && grub_byte_checksum (target,
  197. sizeof (struct grub_acpi_rsdp_v10)) == 0
  198. && ((struct grub_acpi_rsdp_v10 *) target)->revision != 0
  199. && ((struct grub_acpi_rsdp_v20 *) target)->length <= v2->length)
  200. {
  201. grub_memcpy (target, v2, v2->length);
  202. grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target);
  203. v2inebda = target;
  204. target += v2->length;
  205. target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
  206. v2 = 0;
  207. break;
  208. }
  209. }
  210. if (v1)
  211. {
  212. grub_dprintf ("acpi", "Scanning EBDA for old rsdpv1\n");
  213. for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
  214. target += 0x10)
  215. if (grub_memcmp (target, "RSD PTR ", 8) == 0
  216. && grub_byte_checksum (target,
  217. sizeof (struct grub_acpi_rsdp_v10)) == 0)
  218. {
  219. grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10));
  220. grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target);
  221. v1inebda = target;
  222. target += sizeof (struct grub_acpi_rsdp_v10);
  223. target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
  224. v1 = 0;
  225. break;
  226. }
  227. }
  228. target = targetebda + 0x100;
  229. /* Try contiguous zeros. */
  230. if (v2)
  231. {
  232. grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n");
  233. for (; target < targetebda + 0x400 - v2->length; target += 0x10)
  234. if (iszero (target, v2->length))
  235. {
  236. grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target);
  237. grub_memcpy (target, v2, v2->length);
  238. v2inebda = target;
  239. target += v2->length;
  240. target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
  241. v2 = 0;
  242. break;
  243. }
  244. }
  245. if (v1)
  246. {
  247. grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n");
  248. for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
  249. target += 0x10)
  250. if (iszero (target, sizeof (struct grub_acpi_rsdp_v10)))
  251. {
  252. grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target);
  253. grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10));
  254. v1inebda = target;
  255. target += sizeof (struct grub_acpi_rsdp_v10);
  256. target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
  257. v1 = 0;
  258. break;
  259. }
  260. }
  261. if (v1 || v2)
  262. {
  263. grub_mmap_unregister (mmapregion);
  264. return grub_error (GRUB_ERR_OUT_OF_MEMORY,
  265. "couldn't find suitable spot in EBDA");
  266. }
  267. /* Remove any other RSDT. */
  268. for (target = targetebda;
  269. target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
  270. target += 0x10)
  271. if (grub_memcmp (target, "RSD PTR ", 8) == 0
  272. && grub_byte_checksum (target,
  273. sizeof (struct grub_acpi_rsdp_v10)) == 0
  274. && target != v1inebda && target != v2inebda)
  275. *target = 0;
  276. grub_dprintf ("acpi", "Switching EBDA\n");
  277. (*((grub_uint16_t *) 0x40e)) = ((long)targetebda) >> 4;
  278. grub_dprintf ("acpi", "EBDA switched\n");
  279. return GRUB_ERR_NONE;
  280. }
  281. /* Create tables common to ACPIv1 and ACPIv2+ */
  282. static void
  283. setup_common_tables (void)
  284. {
  285. struct efiemu_acpi_table *cur;
  286. struct grub_acpi_table_header *rsdt;
  287. grub_uint32_t *rsdt_entry;
  288. int numoftables;
  289. /* Treat DSDT. */
  290. grub_memcpy (playground_ptr, table_dsdt, dsdt_size);
  291. grub_free (table_dsdt);
  292. table_dsdt = playground_ptr;
  293. playground_ptr += dsdt_size;
  294. /* Treat other tables. */
  295. for (cur = acpi_tables; cur; cur = cur->next)
  296. {
  297. struct grub_acpi_fadt *fadt;
  298. grub_memcpy (playground_ptr, cur->addr, cur->size);
  299. grub_free (cur->addr);
  300. cur->addr = playground_ptr;
  301. playground_ptr += cur->size;
  302. /* If it's FADT correct DSDT and FACS addresses. */
  303. fadt = (struct grub_acpi_fadt *) cur->addr;
  304. if (grub_memcmp (fadt->hdr.signature, "FACP", 4) == 0)
  305. {
  306. fadt->dsdt_addr = PTR_TO_UINT32 (table_dsdt);
  307. fadt->facs_addr = facs_addr;
  308. /* Does a revision 2 exist at all? */
  309. if (fadt->hdr.revision >= 3)
  310. {
  311. fadt->dsdt_xaddr = PTR_TO_UINT64 (table_dsdt);
  312. fadt->facs_xaddr = facs_addr;
  313. }
  314. /* Recompute checksum. */
  315. fadt->hdr.checksum = 0;
  316. fadt->hdr.checksum = 1 + ~grub_byte_checksum (fadt, fadt->hdr.length);
  317. }
  318. }
  319. /* Fill RSDT entries. */
  320. numoftables = 0;
  321. for (cur = acpi_tables; cur; cur = cur->next)
  322. numoftables++;
  323. rsdt_addr = rsdt = (struct grub_acpi_table_header *) playground_ptr;
  324. playground_ptr += sizeof (struct grub_acpi_table_header) + 4 * numoftables;
  325. rsdt_entry = (grub_uint32_t *)(rsdt + 1);
  326. /* Fill RSDT header. */
  327. grub_memcpy (&(rsdt->signature), "RSDT", 4);
  328. rsdt->length = sizeof (struct grub_acpi_table_header) + 4 * numoftables;
  329. rsdt->revision = 1;
  330. grub_memcpy (&(rsdt->oemid), root_oemid, 6);
  331. grub_memcpy (&(rsdt->oemtable), root_oemtable, 4);
  332. rsdt->oemrev = root_oemrev;
  333. grub_memcpy (&(rsdt->creator_id), root_creator_id, 6);
  334. rsdt->creator_rev = root_creator_rev;
  335. for (cur = acpi_tables; cur; cur = cur->next)
  336. *(rsdt_entry++) = PTR_TO_UINT32 (cur->addr);
  337. /* Recompute checksum. */
  338. rsdt->checksum = 0;
  339. rsdt->checksum = 1 + ~grub_byte_checksum (rsdt, rsdt->length);
  340. }
  341. /* Regenerate ACPIv1 RSDP */
  342. static void
  343. setv1table (void)
  344. {
  345. /* Create RSDP. */
  346. rsdpv1_new = (struct grub_acpi_rsdp_v10 *) playground_ptr;
  347. playground_ptr += sizeof (struct grub_acpi_rsdp_v10);
  348. grub_memcpy (&(rsdpv1_new->signature), "RSD PTR ", 8);
  349. grub_memcpy (&(rsdpv1_new->oemid), root_oemid, sizeof (rsdpv1_new->oemid));
  350. rsdpv1_new->revision = 0;
  351. rsdpv1_new->rsdt_addr = PTR_TO_UINT32 (rsdt_addr);
  352. rsdpv1_new->checksum = 0;
  353. rsdpv1_new->checksum = 1 + ~grub_byte_checksum (rsdpv1_new,
  354. sizeof (*rsdpv1_new));
  355. grub_dprintf ("acpi", "Generated ACPIv1 tables\n");
  356. }
  357. static void
  358. setv2table (void)
  359. {
  360. struct grub_acpi_table_header *xsdt;
  361. struct efiemu_acpi_table *cur;
  362. grub_uint64_t *xsdt_entry;
  363. int numoftables;
  364. numoftables = 0;
  365. for (cur = acpi_tables; cur; cur = cur->next)
  366. numoftables++;
  367. /* Create XSDT. */
  368. xsdt = (struct grub_acpi_table_header *) playground_ptr;
  369. playground_ptr += sizeof (struct grub_acpi_table_header) + 8 * numoftables;
  370. xsdt_entry = (grub_uint64_t *)(xsdt + 1);
  371. for (cur = acpi_tables; cur; cur = cur->next)
  372. *(xsdt_entry++) = PTR_TO_UINT64 (cur->addr);
  373. grub_memcpy (&(xsdt->signature), "XSDT", 4);
  374. xsdt->length = sizeof (struct grub_acpi_table_header) + 8 * numoftables;
  375. xsdt->revision = 1;
  376. grub_memcpy (&(xsdt->oemid), root_oemid, sizeof (xsdt->oemid));
  377. grub_memcpy (&(xsdt->oemtable), root_oemtable, sizeof (xsdt->oemtable));
  378. xsdt->oemrev = root_oemrev;
  379. grub_memcpy (&(xsdt->creator_id), root_creator_id, sizeof (xsdt->creator_id));
  380. xsdt->creator_rev = root_creator_rev;
  381. xsdt->checksum = 0;
  382. xsdt->checksum = 1 + ~grub_byte_checksum (xsdt, xsdt->length);
  383. /* Create RSDPv2. */
  384. rsdpv2_new = (struct grub_acpi_rsdp_v20 *) playground_ptr;
  385. playground_ptr += sizeof (struct grub_acpi_rsdp_v20);
  386. grub_memcpy (&(rsdpv2_new->rsdpv1.signature), "RSD PTR ",
  387. sizeof (rsdpv2_new->rsdpv1.signature));
  388. grub_memcpy (&(rsdpv2_new->rsdpv1.oemid), root_oemid,
  389. sizeof (rsdpv2_new->rsdpv1.oemid));
  390. rsdpv2_new->rsdpv1.revision = rev2;
  391. rsdpv2_new->rsdpv1.rsdt_addr = PTR_TO_UINT32 (rsdt_addr);
  392. rsdpv2_new->rsdpv1.checksum = 0;
  393. rsdpv2_new->rsdpv1.checksum = 1 + ~grub_byte_checksum
  394. (&(rsdpv2_new->rsdpv1), sizeof (rsdpv2_new->rsdpv1));
  395. rsdpv2_new->length = sizeof (*rsdpv2_new);
  396. rsdpv2_new->xsdt_addr = PTR_TO_UINT64 (xsdt);
  397. rsdpv2_new->checksum = 0;
  398. rsdpv2_new->checksum = 1 + ~grub_byte_checksum (rsdpv2_new,
  399. rsdpv2_new->length);
  400. grub_dprintf ("acpi", "Generated ACPIv2 tables\n");
  401. }
  402. static void
  403. free_tables (void)
  404. {
  405. struct efiemu_acpi_table *cur, *t;
  406. if (table_dsdt)
  407. grub_free (table_dsdt);
  408. for (cur = acpi_tables; cur;)
  409. {
  410. t = cur;
  411. grub_free (cur->addr);
  412. cur = cur->next;
  413. grub_free (t);
  414. }
  415. acpi_tables = 0;
  416. table_dsdt = 0;
  417. }
  418. static grub_err_t
  419. grub_cmd_acpi (struct grub_extcmd *cmd,
  420. int argc, char **args)
  421. {
  422. struct grub_arg_list *state = cmd->state;
  423. struct grub_acpi_rsdp_v10 *rsdp;
  424. struct efiemu_acpi_table *cur, *t;
  425. grub_err_t err;
  426. int i, mmapregion;
  427. int numoftables;
  428. /* Default values if no RSDP is found. */
  429. rev1 = 1;
  430. rev2 = 3;
  431. facs_addr = 0;
  432. playground = playground_ptr = 0;
  433. playground_size = 0;
  434. rsdp = (struct grub_acpi_rsdp_v10 *) grub_machine_acpi_get_rsdpv2 ();
  435. if (! rsdp)
  436. rsdp = grub_machine_acpi_get_rsdpv1 ();
  437. if (rsdp)
  438. {
  439. grub_uint32_t *entry_ptr;
  440. char *exclude = 0;
  441. char *load_only = 0;
  442. char *ptr;
  443. /* RSDT consists of header and an array of 32-bit pointers. */
  444. struct grub_acpi_table_header *rsdt;
  445. exclude = state[0].set ? grub_strdup (state[0].arg) : 0;
  446. if (exclude)
  447. {
  448. for (ptr = exclude; *ptr; ptr++)
  449. *ptr = grub_tolower (*ptr);
  450. }
  451. load_only = state[1].set ? grub_strdup (state[1].arg) : 0;
  452. if (load_only)
  453. {
  454. for (ptr = load_only; *ptr; ptr++)
  455. *ptr = grub_tolower (*ptr);
  456. }
  457. /* Set revision variables to replicate the same version as host. */
  458. rev1 = ! rsdp->revision;
  459. rev2 = rsdp->revision;
  460. rsdt = (struct grub_acpi_table_header *) UINT_TO_PTR (rsdp->rsdt_addr);
  461. /* Load host tables. */
  462. for (entry_ptr = (grub_uint32_t *) (rsdt + 1);
  463. entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt)
  464. + rsdt->length);
  465. entry_ptr++)
  466. {
  467. char signature[5];
  468. struct efiemu_acpi_table *table;
  469. struct grub_acpi_table_header *curtable
  470. = (struct grub_acpi_table_header *) UINT_TO_PTR (*entry_ptr);
  471. signature[4] = 0;
  472. for (i = 0; i < 4;i++)
  473. signature[i] = grub_tolower (curtable->signature[i]);
  474. /* If it's FADT it contains addresses of DSDT and FACS. */
  475. if (grub_strcmp (signature, "facp") == 0)
  476. {
  477. struct grub_acpi_table_header *dsdt;
  478. struct grub_acpi_fadt *fadt = (struct grub_acpi_fadt *) curtable;
  479. /* Set root header variables to the same values
  480. as FACP by default. */
  481. grub_memcpy (&root_oemid, &(fadt->hdr.oemid),
  482. sizeof (root_oemid));
  483. grub_memcpy (&root_oemtable, &(fadt->hdr.oemtable),
  484. sizeof (root_oemtable));
  485. root_oemrev = fadt->hdr.oemrev;
  486. grub_memcpy (&root_creator_id, &(fadt->hdr.creator_id),
  487. sizeof (root_creator_id));
  488. root_creator_rev = fadt->hdr.creator_rev;
  489. /* Load DSDT if not excluded. */
  490. dsdt = (struct grub_acpi_table_header *)
  491. UINT_TO_PTR (fadt->dsdt_addr);
  492. if (dsdt && (! exclude || ! grub_strword (exclude, "dsdt"))
  493. && (! load_only || grub_strword (load_only, "dsdt"))
  494. && dsdt->length >= sizeof (*dsdt))
  495. {
  496. dsdt_size = dsdt->length;
  497. table_dsdt = grub_malloc (dsdt->length);
  498. if (! table_dsdt)
  499. {
  500. free_tables ();
  501. grub_free (exclude);
  502. grub_free (load_only);
  503. return grub_error (GRUB_ERR_OUT_OF_MEMORY,
  504. "couldn't allocate table");
  505. }
  506. grub_memcpy (table_dsdt, dsdt, dsdt->length);
  507. }
  508. /* Save FACS address. FACS shouldn't be overridden. */
  509. facs_addr = fadt->facs_addr;
  510. }
  511. /* Skip excluded tables. */
  512. if (exclude && grub_strword (exclude, signature))
  513. continue;
  514. if (load_only && ! grub_strword (load_only, signature))
  515. continue;
  516. /* Sanity check. */
  517. if (curtable->length < sizeof (*curtable))
  518. continue;
  519. table = (struct efiemu_acpi_table *) grub_malloc
  520. (sizeof (struct efiemu_acpi_table));
  521. if (! table)
  522. {
  523. free_tables ();
  524. grub_free (exclude);
  525. grub_free (load_only);
  526. return grub_error (GRUB_ERR_OUT_OF_MEMORY,
  527. "couldn't allocate table structure");
  528. }
  529. table->size = curtable->length;
  530. table->addr = grub_malloc (table->size);
  531. playground_size += table->size;
  532. if (! table->addr)
  533. {
  534. free_tables ();
  535. return grub_error (GRUB_ERR_OUT_OF_MEMORY,
  536. "couldn't allocate table");
  537. }
  538. table->next = acpi_tables;
  539. acpi_tables = table;
  540. grub_memcpy (table->addr, curtable, table->size);
  541. }
  542. grub_free (exclude);
  543. grub_free (load_only);
  544. }
  545. /* Does user specify versions to generate? */
  546. if (state[2].set || state[3].set)
  547. {
  548. rev1 = state[2].set;
  549. if (state[3].set)
  550. rev2 = rev2 ? : 2;
  551. else
  552. rev2 = 0;
  553. }
  554. /* Does user override root header information? */
  555. if (state[4].set)
  556. grub_strncpy (root_oemid, state[4].arg, sizeof (root_oemid));
  557. if (state[5].set)
  558. grub_strncpy (root_oemtable, state[5].arg, sizeof (root_oemtable));
  559. if (state[6].set)
  560. root_oemrev = grub_strtoul (state[6].arg, 0, 0);
  561. if (state[7].set)
  562. grub_strncpy (root_creator_id, state[7].arg, sizeof (root_creator_id));
  563. if (state[8].set)
  564. root_creator_rev = grub_strtoul (state[8].arg, 0, 0);
  565. /* Load user tables */
  566. for (i = 0; i < argc; i++)
  567. {
  568. grub_file_t file;
  569. grub_size_t size;
  570. char *buf;
  571. file = grub_gzfile_open (args[i], 1);
  572. if (! file)
  573. {
  574. free_tables ();
  575. return grub_error (GRUB_ERR_BAD_OS, "couldn't open file %s", args[i]);
  576. }
  577. size = grub_file_size (file);
  578. if (size < sizeof (struct grub_acpi_table_header))
  579. {
  580. grub_file_close (file);
  581. free_tables ();
  582. return grub_error (GRUB_ERR_BAD_OS, "file %s is too small", args[i]);
  583. }
  584. buf = (char *) grub_malloc (size);
  585. if (! buf)
  586. {
  587. grub_file_close (file);
  588. free_tables ();
  589. return grub_error (GRUB_ERR_OUT_OF_MEMORY,
  590. "couldn't read file %s", args[i]);
  591. }
  592. if (grub_file_read (file, buf, size) != (int) size)
  593. {
  594. grub_file_close (file);
  595. free_tables ();
  596. return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[i]);
  597. }
  598. grub_file_close (file);
  599. if (grub_memcmp (((struct grub_acpi_table_header *) buf)->signature,
  600. "DSDT", 4) == 0)
  601. {
  602. grub_free (table_dsdt);
  603. table_dsdt = buf;
  604. dsdt_size = size;
  605. }
  606. else
  607. {
  608. struct efiemu_acpi_table *table;
  609. table = (struct efiemu_acpi_table *) grub_malloc
  610. (sizeof (struct efiemu_acpi_table));
  611. if (! table)
  612. {
  613. free_tables ();
  614. return grub_error (GRUB_ERR_OUT_OF_MEMORY,
  615. "couldn't allocate table structure");
  616. }
  617. table->size = size;
  618. table->addr = buf;
  619. playground_size += table->size;
  620. table->next = acpi_tables;
  621. acpi_tables = table;
  622. }
  623. }
  624. numoftables = 0;
  625. for (cur = acpi_tables; cur; cur = cur->next)
  626. numoftables++;
  627. /* DSDT. */
  628. playground_size += dsdt_size;
  629. /* RSDT. */
  630. playground_size += sizeof (struct grub_acpi_table_header) + 4 * numoftables;
  631. /* RSDPv1. */
  632. playground_size += sizeof (struct grub_acpi_rsdp_v10);
  633. /* XSDT. */
  634. playground_size += sizeof (struct grub_acpi_table_header) + 8 * numoftables;
  635. /* RSDPv2. */
  636. playground_size += sizeof (struct grub_acpi_rsdp_v20);
  637. playground = playground_ptr
  638. = grub_mmap_malign_and_register (1, playground_size, &mmapregion,
  639. GRUB_MACHINE_MEMORY_ACPI, 0);
  640. if (! playground)
  641. {
  642. free_tables ();
  643. return grub_error (GRUB_ERR_OUT_OF_MEMORY,
  644. "couldn't allocate space for ACPI tables");
  645. }
  646. setup_common_tables ();
  647. /* Request space for RSDPv1. */
  648. if (rev1)
  649. setv1table ();
  650. /* Request space for RSDPv2+ and XSDT. */
  651. if (rev2)
  652. setv2table ();
  653. for (cur = acpi_tables; cur;)
  654. {
  655. t = cur;
  656. cur = cur->next;
  657. grub_free (t);
  658. }
  659. acpi_tables = 0;
  660. if (! state[9].set && (err = grub_acpi_create_ebda ()))
  661. {
  662. rsdpv1_new = 0;
  663. rsdpv2_new = 0;
  664. grub_mmap_free_and_unregister (mmapregion);
  665. return err;
  666. }
  667. #ifdef GRUB_MACHINE_EFI
  668. {
  669. struct grub_efi_guid acpi = GRUB_EFI_ACPI_TABLE_GUID;
  670. struct grub_efi_guid acpi20 = GRUB_EFI_ACPI_20_TABLE_GUID;
  671. grub_efi_system_table->boot_services->install_configuration_table
  672. (&acpi20, grub_acpi_get_rsdpv2 ());
  673. grub_efi_system_table->boot_services->install_configuration_table
  674. (&acpi, grub_acpi_get_rsdpv1 ());
  675. }
  676. #endif
  677. return GRUB_ERR_NONE;
  678. }
  679. static grub_extcmd_t cmd;
  680. GRUB_MOD_INIT(acpi)
  681. {
  682. cmd = grub_register_extcmd ("acpi", grub_cmd_acpi,
  683. GRUB_COMMAND_FLAG_BOTH,
  684. N_("[-1|-2] [--exclude=TABLE1,TABLE2|"
  685. "--load-only=table1,table2] FILE1"
  686. " [FILE2] [...]"),
  687. N_("Load host ACPI tables and tables "
  688. "specified by arguments."),
  689. options);
  690. }
  691. GRUB_MOD_FINI(acpi)
  692. {
  693. grub_unregister_extcmd (cmd);
  694. }