acpi.c 23 KB

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