acpi.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Tests for ACPI table generation
  4. *
  5. * Copyright 2019 Google LLC
  6. * Written by Simon Glass <sjg@chromium.org>
  7. */
  8. #include <common.h>
  9. #include <console.h>
  10. #include <dm.h>
  11. #include <malloc.h>
  12. #include <mapmem.h>
  13. #include <version.h>
  14. #include <tables_csum.h>
  15. #include <version.h>
  16. #include <acpi/acpi_device.h>
  17. #include <acpi/acpi_table.h>
  18. #include <dm/acpi.h>
  19. #include <dm/test.h>
  20. #include <test/ut.h>
  21. #define ACPI_TEST_DEV_NAME "ABCD"
  22. #define ACPI_TEST_CHILD_NAME "EFGH"
  23. #define BUF_SIZE 4096
  24. /**
  25. * struct testacpi_platdata - Platform data for the test ACPI device
  26. *
  27. * @no_name: true to emit an empty ACPI name from testacpi_get_name()
  28. * @return_error: true to return an error instead of a name
  29. */
  30. struct testacpi_platdata {
  31. bool return_error;
  32. bool no_name;
  33. };
  34. static int testacpi_write_tables(const struct udevice *dev,
  35. struct acpi_ctx *ctx)
  36. {
  37. struct acpi_dmar *dmar;
  38. int ret;
  39. dmar = (struct acpi_dmar *)ctx->current;
  40. acpi_create_dmar(dmar, DMAR_INTR_REMAP);
  41. ctx->current += sizeof(struct acpi_dmar);
  42. ret = acpi_add_table(ctx, dmar);
  43. if (ret)
  44. return log_msg_ret("add", ret);
  45. return 0;
  46. }
  47. static int testacpi_get_name(const struct udevice *dev, char *out_name)
  48. {
  49. struct testacpi_platdata *plat = dev_get_platdata(dev);
  50. if (plat->return_error)
  51. return -EINVAL;
  52. if (plat->no_name) {
  53. *out_name = '\0';
  54. return 0;
  55. }
  56. if (device_get_uclass_id(dev->parent) == UCLASS_TEST_ACPI)
  57. return acpi_copy_name(out_name, ACPI_TEST_CHILD_NAME);
  58. else
  59. return acpi_copy_name(out_name, ACPI_TEST_DEV_NAME);
  60. }
  61. struct acpi_ops testacpi_ops = {
  62. .get_name = testacpi_get_name,
  63. .write_tables = testacpi_write_tables,
  64. };
  65. static const struct udevice_id testacpi_ids[] = {
  66. { .compatible = "denx,u-boot-acpi-test" },
  67. { }
  68. };
  69. U_BOOT_DRIVER(testacpi_drv) = {
  70. .name = "testacpi_drv",
  71. .of_match = testacpi_ids,
  72. .id = UCLASS_TEST_ACPI,
  73. .bind = dm_scan_fdt_dev,
  74. .platdata_auto_alloc_size = sizeof(struct testacpi_platdata),
  75. ACPI_OPS_PTR(&testacpi_ops)
  76. };
  77. UCLASS_DRIVER(testacpi) = {
  78. .name = "testacpi",
  79. .id = UCLASS_TEST_ACPI,
  80. };
  81. /* Test ACPI get_name() */
  82. static int dm_test_acpi_get_name(struct unit_test_state *uts)
  83. {
  84. char name[ACPI_NAME_MAX];
  85. struct udevice *dev;
  86. ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev));
  87. ut_assertok(acpi_get_name(dev, name));
  88. ut_asserteq_str(ACPI_TEST_DEV_NAME, name);
  89. return 0;
  90. }
  91. DM_TEST(dm_test_acpi_get_name, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  92. /* Test acpi_get_table_revision() */
  93. static int dm_test_acpi_get_table_revision(struct unit_test_state *uts)
  94. {
  95. ut_asserteq(1, acpi_get_table_revision(ACPITAB_MCFG));
  96. ut_asserteq(2, acpi_get_table_revision(ACPITAB_RSDP));
  97. ut_asserteq(4, acpi_get_table_revision(ACPITAB_TPM2));
  98. ut_asserteq(-EINVAL, acpi_get_table_revision(ACPITAB_COUNT));
  99. return 0;
  100. }
  101. DM_TEST(dm_test_acpi_get_table_revision,
  102. DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  103. /* Test acpi_create_dmar() */
  104. static int dm_test_acpi_create_dmar(struct unit_test_state *uts)
  105. {
  106. struct acpi_dmar dmar;
  107. ut_assertok(acpi_create_dmar(&dmar, DMAR_INTR_REMAP));
  108. ut_asserteq(DMAR_INTR_REMAP, dmar.flags);
  109. ut_asserteq(32 - 1, dmar.host_address_width);
  110. return 0;
  111. }
  112. DM_TEST(dm_test_acpi_create_dmar, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  113. /* Test acpi_fill_header() */
  114. static int dm_test_acpi_fill_header(struct unit_test_state *uts)
  115. {
  116. struct acpi_table_header hdr;
  117. /* Make sure these 5 fields are not changed */
  118. hdr.length = 0x11;
  119. hdr.revision = 0x22;
  120. hdr.checksum = 0x33;
  121. hdr.aslc_revision = 0x44;
  122. acpi_fill_header(&hdr, "ABCD");
  123. ut_asserteq_mem("ABCD", hdr.signature, sizeof(hdr.signature));
  124. ut_asserteq(0x11, hdr.length);
  125. ut_asserteq(0x22, hdr.revision);
  126. ut_asserteq(0x33, hdr.checksum);
  127. ut_asserteq_mem(OEM_ID, hdr.oem_id, sizeof(hdr.oem_id));
  128. ut_asserteq_mem(OEM_TABLE_ID, hdr.oem_table_id,
  129. sizeof(hdr.oem_table_id));
  130. ut_asserteq(U_BOOT_BUILD_DATE, hdr.oem_revision);
  131. ut_asserteq_mem(ASLC_ID, hdr.aslc_id, sizeof(hdr.aslc_id));
  132. ut_asserteq(0x44, hdr.aslc_revision);
  133. return 0;
  134. }
  135. DM_TEST(dm_test_acpi_fill_header, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  136. /* Test ACPI write_tables() */
  137. static int dm_test_acpi_write_tables(struct unit_test_state *uts)
  138. {
  139. struct acpi_dmar *dmar;
  140. struct acpi_ctx ctx;
  141. void *buf;
  142. int i;
  143. buf = malloc(BUF_SIZE);
  144. ut_assertnonnull(buf);
  145. acpi_setup_base_tables(&ctx, buf);
  146. dmar = ctx.current;
  147. ut_assertok(acpi_write_dev_tables(&ctx));
  148. /*
  149. * We should have three dmar tables, one for each
  150. * "denx,u-boot-acpi-test" device
  151. */
  152. ut_asserteq_ptr(dmar + 3, ctx.current);
  153. ut_asserteq(DMAR_INTR_REMAP, dmar->flags);
  154. ut_asserteq(32 - 1, dmar->host_address_width);
  155. ut_asserteq(DMAR_INTR_REMAP, dmar[1].flags);
  156. ut_asserteq(32 - 1, dmar[1].host_address_width);
  157. ut_asserteq(DMAR_INTR_REMAP, dmar[2].flags);
  158. ut_asserteq(32 - 1, dmar[2].host_address_width);
  159. /* Check that the pointers were added correctly */
  160. for (i = 0; i < 3; i++) {
  161. ut_asserteq(map_to_sysmem(dmar + i), ctx.rsdt->entry[i]);
  162. ut_asserteq(map_to_sysmem(dmar + i), ctx.xsdt->entry[i]);
  163. }
  164. ut_asserteq(0, ctx.rsdt->entry[3]);
  165. ut_asserteq(0, ctx.xsdt->entry[3]);
  166. return 0;
  167. }
  168. DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  169. /* Test basic ACPI functions */
  170. static int dm_test_acpi_basic(struct unit_test_state *uts)
  171. {
  172. struct acpi_ctx ctx;
  173. /* Check align works */
  174. ctx.current = (void *)5;
  175. acpi_align(&ctx);
  176. ut_asserteq_ptr((void *)16, ctx.current);
  177. /* Check that align does nothing if already aligned */
  178. acpi_align(&ctx);
  179. ut_asserteq_ptr((void *)16, ctx.current);
  180. acpi_align64(&ctx);
  181. ut_asserteq_ptr((void *)64, ctx.current);
  182. acpi_align64(&ctx);
  183. ut_asserteq_ptr((void *)64, ctx.current);
  184. /* Check incrementing */
  185. acpi_inc(&ctx, 3);
  186. ut_asserteq_ptr((void *)67, ctx.current);
  187. acpi_inc_align(&ctx, 3);
  188. ut_asserteq_ptr((void *)80, ctx.current);
  189. return 0;
  190. }
  191. DM_TEST(dm_test_acpi_basic, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  192. /* Test acpi_setup_base_tables */
  193. static int dm_test_acpi_setup_base_tables(struct unit_test_state *uts)
  194. {
  195. struct acpi_rsdp *rsdp;
  196. struct acpi_rsdt *rsdt;
  197. struct acpi_xsdt *xsdt;
  198. struct acpi_ctx ctx;
  199. void *buf, *end;
  200. /*
  201. * Use an unaligned address deliberately, by allocating an aligned
  202. * address and then adding 4 to it
  203. */
  204. buf = memalign(64, BUF_SIZE);
  205. ut_assertnonnull(buf);
  206. acpi_setup_base_tables(&ctx, buf + 4);
  207. ut_asserteq(map_to_sysmem(PTR_ALIGN(buf + 4, 16)), gd->arch.acpi_start);
  208. rsdp = buf + 16;
  209. ut_asserteq_ptr(rsdp, ctx.rsdp);
  210. ut_asserteq_mem(RSDP_SIG, rsdp->signature, sizeof(rsdp->signature));
  211. ut_asserteq(sizeof(*rsdp), rsdp->length);
  212. ut_assertok(table_compute_checksum(rsdp, 20));
  213. ut_assertok(table_compute_checksum(rsdp, sizeof(*rsdp)));
  214. rsdt = PTR_ALIGN((void *)rsdp + sizeof(*rsdp), 16);
  215. ut_asserteq_ptr(rsdt, ctx.rsdt);
  216. ut_asserteq_mem("RSDT", rsdt->header.signature, ACPI_NAME_LEN);
  217. ut_asserteq(sizeof(*rsdt), rsdt->header.length);
  218. ut_assertok(table_compute_checksum(rsdt, sizeof(*rsdt)));
  219. xsdt = PTR_ALIGN((void *)rsdt + sizeof(*rsdt), 16);
  220. ut_asserteq_ptr(xsdt, ctx.xsdt);
  221. ut_asserteq_mem("XSDT", xsdt->header.signature, ACPI_NAME_LEN);
  222. ut_asserteq(sizeof(*xsdt), xsdt->header.length);
  223. ut_assertok(table_compute_checksum(xsdt, sizeof(*xsdt)));
  224. end = PTR_ALIGN((void *)xsdt + sizeof(*xsdt), 64);
  225. ut_asserteq_ptr(end, ctx.current);
  226. ut_asserteq(map_to_sysmem(rsdt), rsdp->rsdt_address);
  227. ut_asserteq(map_to_sysmem(xsdt), rsdp->xsdt_address);
  228. return 0;
  229. }
  230. DM_TEST(dm_test_acpi_setup_base_tables,
  231. DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  232. /* Test 'acpi list' command */
  233. static int dm_test_acpi_cmd_list(struct unit_test_state *uts)
  234. {
  235. struct acpi_ctx ctx;
  236. ulong addr;
  237. void *buf;
  238. buf = memalign(16, BUF_SIZE);
  239. ut_assertnonnull(buf);
  240. acpi_setup_base_tables(&ctx, buf);
  241. ut_assertok(acpi_write_dev_tables(&ctx));
  242. console_record_reset();
  243. run_command("acpi list", 0);
  244. addr = (ulong)map_to_sysmem(buf);
  245. ut_assert_nextline("ACPI tables start at %lx", addr);
  246. ut_assert_nextline("RSDP %08lx %06lx (v02 U-BOOT)", addr,
  247. sizeof(struct acpi_rsdp));
  248. addr = ALIGN(addr + sizeof(struct acpi_rsdp), 16);
  249. ut_assert_nextline("RSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
  250. addr, sizeof(struct acpi_table_header) +
  251. 3 * sizeof(u32), U_BOOT_BUILD_DATE);
  252. addr = ALIGN(addr + sizeof(struct acpi_rsdt), 16);
  253. ut_assert_nextline("XSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
  254. addr, sizeof(struct acpi_table_header) +
  255. 3 * sizeof(u64), U_BOOT_BUILD_DATE);
  256. addr = ALIGN(addr + sizeof(struct acpi_xsdt), 64);
  257. ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
  258. addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
  259. addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
  260. ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
  261. addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
  262. addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
  263. ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
  264. addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
  265. ut_assert_console_end();
  266. return 0;
  267. }
  268. DM_TEST(dm_test_acpi_cmd_list, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  269. /* Test 'acpi dump' command */
  270. static int dm_test_acpi_cmd_dump(struct unit_test_state *uts)
  271. {
  272. struct acpi_ctx ctx;
  273. ulong addr;
  274. void *buf;
  275. buf = memalign(16, BUF_SIZE);
  276. ut_assertnonnull(buf);
  277. acpi_setup_base_tables(&ctx, buf);
  278. ut_assertok(acpi_write_dev_tables(&ctx));
  279. /* First search for a non-existent table */
  280. console_record_reset();
  281. run_command("acpi dump rdst", 0);
  282. ut_assert_nextline("Table 'RDST' not found");
  283. ut_assert_console_end();
  284. /* Now a real table */
  285. console_record_reset();
  286. run_command("acpi dump dmar", 0);
  287. addr = ALIGN(map_to_sysmem(ctx.xsdt) + sizeof(struct acpi_xsdt), 64);
  288. ut_assert_nextline("DMAR @ %08lx", addr);
  289. ut_assert_nextlines_are_dump(0x30);
  290. ut_assert_console_end();
  291. return 0;
  292. }
  293. DM_TEST(dm_test_acpi_cmd_dump, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  294. /* Test acpi_device_path() */
  295. static int dm_test_acpi_device_path(struct unit_test_state *uts)
  296. {
  297. struct testacpi_platdata *plat;
  298. char buf[ACPI_PATH_MAX];
  299. struct udevice *dev, *child;
  300. ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev));
  301. ut_assertok(acpi_device_path(dev, buf, sizeof(buf)));
  302. ut_asserteq_str("\\_SB." ACPI_TEST_DEV_NAME, buf);
  303. /* Test running out of space */
  304. buf[5] = '\0';
  305. ut_asserteq(-ENOSPC, acpi_device_path(dev, buf, 5));
  306. ut_asserteq('\0', buf[5]);
  307. /* Test a three-component name */
  308. ut_assertok(device_first_child_err(dev, &child));
  309. ut_assertok(acpi_device_path(child, buf, sizeof(buf)));
  310. ut_asserteq_str("\\_SB." ACPI_TEST_DEV_NAME "." ACPI_TEST_CHILD_NAME,
  311. buf);
  312. /* Test handling of a device which doesn't produce a name */
  313. plat = dev_get_platdata(dev);
  314. plat->no_name = true;
  315. ut_assertok(acpi_device_path(child, buf, sizeof(buf)));
  316. ut_asserteq_str("\\_SB." ACPI_TEST_CHILD_NAME, buf);
  317. /* Test handling of a device which returns an error */
  318. plat = dev_get_platdata(dev);
  319. plat->return_error = true;
  320. ut_asserteq(-EINVAL, acpi_device_path(child, buf, sizeof(buf)));
  321. return 0;
  322. }
  323. DM_TEST(dm_test_acpi_device_path, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  324. /* Test acpi_device_status() */
  325. static int dm_test_acpi_device_status(struct unit_test_state *uts)
  326. {
  327. struct udevice *dev;
  328. ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev));
  329. ut_asserteq(ACPI_DSTATUS_ALL_ON, acpi_device_status(dev));
  330. return 0;
  331. }
  332. DM_TEST(dm_test_acpi_device_status, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);