bloblist.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2018, Google Inc. All rights reserved.
  4. */
  5. #include <common.h>
  6. #include <bloblist.h>
  7. #include <log.h>
  8. #include <mapmem.h>
  9. #include <asm/state.h>
  10. #include <test/suites.h>
  11. #include <test/test.h>
  12. #include <test/ut.h>
  13. DECLARE_GLOBAL_DATA_PTR;
  14. /* Declare a new compression test */
  15. #define BLOBLIST_TEST(_name, _flags) \
  16. UNIT_TEST(_name, _flags, bloblist_test)
  17. enum {
  18. TEST_TAG = 1,
  19. TEST_TAG2 = 2,
  20. TEST_TAG_MISSING = 3,
  21. TEST_SIZE = 10,
  22. TEST_SIZE2 = 20,
  23. TEST_SIZE_LARGE = 0x3e0,
  24. TEST_ADDR = CONFIG_BLOBLIST_ADDR,
  25. TEST_BLOBLIST_SIZE = 0x400,
  26. ERASE_BYTE = '\xff',
  27. };
  28. static struct bloblist_hdr *clear_bloblist(void)
  29. {
  30. struct bloblist_hdr *hdr;
  31. /*
  32. * Clear out any existing bloblist so we have a clean slate. Zero the
  33. * header so that existing records are removed, but set everything else
  34. * to 0xff for testing purposes.
  35. */
  36. hdr = map_sysmem(CONFIG_BLOBLIST_ADDR, TEST_BLOBLIST_SIZE);
  37. memset(hdr, ERASE_BYTE, TEST_BLOBLIST_SIZE);
  38. memset(hdr, '\0', sizeof(*hdr));
  39. return hdr;
  40. }
  41. static int check_zero(void *data, int size)
  42. {
  43. u8 *ptr;
  44. int i;
  45. for (ptr = data, i = 0; i < size; i++, ptr++) {
  46. if (*ptr)
  47. return -EINVAL;
  48. }
  49. return 0;
  50. }
  51. static int bloblist_test_init(struct unit_test_state *uts)
  52. {
  53. struct bloblist_hdr *hdr;
  54. hdr = clear_bloblist();
  55. ut_asserteq(-ENOENT, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  56. ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
  57. hdr->version++;
  58. ut_asserteq(-EPROTONOSUPPORT, bloblist_check(TEST_ADDR,
  59. TEST_BLOBLIST_SIZE));
  60. ut_asserteq(-ENOSPC, bloblist_new(TEST_ADDR, 0x10, 0));
  61. ut_asserteq(-EFAULT, bloblist_new(1, TEST_BLOBLIST_SIZE, 0));
  62. ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
  63. ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  64. ut_assertok(bloblist_finish());
  65. ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  66. hdr->flags++;
  67. ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  68. return 1;
  69. }
  70. BLOBLIST_TEST(bloblist_test_init, 0);
  71. static int bloblist_test_blob(struct unit_test_state *uts)
  72. {
  73. struct bloblist_hdr *hdr;
  74. struct bloblist_rec *rec, *rec2;
  75. char *data;
  76. /* At the start there should be no records */
  77. hdr = clear_bloblist();
  78. ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE));
  79. ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
  80. ut_asserteq(map_to_sysmem(hdr), TEST_ADDR);
  81. /* Add a record and check that we can find it */
  82. data = bloblist_add(TEST_TAG, TEST_SIZE, 0);
  83. rec = (void *)(hdr + 1);
  84. ut_asserteq_addr(rec + 1, data);
  85. data = bloblist_find(TEST_TAG, TEST_SIZE);
  86. ut_asserteq_addr(rec + 1, data);
  87. /* Check the data is zeroed */
  88. ut_assertok(check_zero(data, TEST_SIZE));
  89. /* Check the 'ensure' method */
  90. ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
  91. ut_assertnull(bloblist_ensure(TEST_TAG, TEST_SIZE2));
  92. rec2 = (struct bloblist_rec *)(data + ALIGN(TEST_SIZE, BLOBLIST_ALIGN));
  93. ut_assertok(check_zero(data, TEST_SIZE));
  94. /* Check for a non-existent record */
  95. ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
  96. ut_asserteq_addr(rec2 + 1, bloblist_ensure(TEST_TAG2, TEST_SIZE2));
  97. ut_assertnull(bloblist_find(TEST_TAG_MISSING, 0));
  98. return 0;
  99. }
  100. BLOBLIST_TEST(bloblist_test_blob, 0);
  101. /* Check bloblist_ensure_size_ret() */
  102. static int bloblist_test_blob_ensure(struct unit_test_state *uts)
  103. {
  104. void *data, *data2;
  105. int size;
  106. /* At the start there should be no records */
  107. clear_bloblist();
  108. ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
  109. /* Test with an empty bloblist */
  110. size = TEST_SIZE;
  111. ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data));
  112. ut_asserteq(TEST_SIZE, size);
  113. ut_assertok(check_zero(data, TEST_SIZE));
  114. /* Check that we get the same thing again */
  115. ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data2));
  116. ut_asserteq(TEST_SIZE, size);
  117. ut_asserteq_addr(data, data2);
  118. /* Check that the size remains the same */
  119. size = TEST_SIZE2;
  120. ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data));
  121. ut_asserteq(TEST_SIZE, size);
  122. /* Check running out of space */
  123. size = TEST_SIZE_LARGE;
  124. ut_asserteq(-ENOSPC, bloblist_ensure_size_ret(TEST_TAG2, &size, &data));
  125. return 0;
  126. }
  127. BLOBLIST_TEST(bloblist_test_blob_ensure, 0);
  128. static int bloblist_test_bad_blob(struct unit_test_state *uts)
  129. {
  130. struct bloblist_hdr *hdr;
  131. void *data;
  132. hdr = clear_bloblist();
  133. ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
  134. data = hdr + 1;
  135. data += sizeof(struct bloblist_rec);
  136. ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
  137. ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
  138. return 0;
  139. }
  140. BLOBLIST_TEST(bloblist_test_bad_blob, 0);
  141. static int bloblist_test_checksum(struct unit_test_state *uts)
  142. {
  143. struct bloblist_hdr *hdr;
  144. char *data, *data2;
  145. hdr = clear_bloblist();
  146. ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
  147. ut_assertok(bloblist_finish());
  148. ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  149. /*
  150. * Now change things amd make sure that the checksum notices. We cannot
  151. * change the size or alloced fields, since that will crash the code.
  152. * It has to rely on these being correct.
  153. */
  154. hdr->flags--;
  155. ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  156. hdr->flags++;
  157. hdr->size--;
  158. ut_asserteq(-EFBIG, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  159. hdr->size++;
  160. hdr->spare++;
  161. ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  162. hdr->spare--;
  163. hdr->chksum++;
  164. ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  165. hdr->chksum--;
  166. /* Make sure the checksum changes when we add blobs */
  167. data = bloblist_add(TEST_TAG, TEST_SIZE, 0);
  168. ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  169. data2 = bloblist_add(TEST_TAG2, TEST_SIZE2, 0);
  170. ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  171. ut_assertok(bloblist_finish());
  172. /* It should also change if we change the data */
  173. ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  174. *data += 1;
  175. ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  176. *data -= 1;
  177. ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  178. *data2 += 1;
  179. ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  180. *data2 -= 1;
  181. /*
  182. * Changing data outside the range of valid data should not affect
  183. * the checksum.
  184. */
  185. ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  186. data[TEST_SIZE]++;
  187. data2[TEST_SIZE2]++;
  188. ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
  189. return 0;
  190. }
  191. BLOBLIST_TEST(bloblist_test_checksum, 0);
  192. /* Test the 'bloblist info' command */
  193. static int bloblist_test_cmd_info(struct unit_test_state *uts)
  194. {
  195. struct sandbox_state *state = state_get_current();
  196. struct bloblist_hdr *hdr;
  197. char *data, *data2;
  198. hdr = clear_bloblist();
  199. ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
  200. data = bloblist_ensure(TEST_TAG, TEST_SIZE);
  201. data2 = bloblist_ensure(TEST_TAG2, TEST_SIZE2);
  202. console_record_reset_enable();
  203. if (!state->show_test_output)
  204. gd->flags |= GD_FLG_SILENT;
  205. console_record_reset();
  206. run_command("bloblist info", 0);
  207. ut_assert_nextline("base: %lx", (ulong)map_to_sysmem(hdr));
  208. ut_assert_nextline("size: 400 1 KiB");
  209. ut_assert_nextline("alloced: 70 112 Bytes");
  210. ut_assert_nextline("free: 390 912 Bytes");
  211. ut_assert_console_end();
  212. gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
  213. return 0;
  214. }
  215. BLOBLIST_TEST(bloblist_test_cmd_info, 0);
  216. /* Test the 'bloblist list' command */
  217. static int bloblist_test_cmd_list(struct unit_test_state *uts)
  218. {
  219. struct sandbox_state *state = state_get_current();
  220. struct bloblist_hdr *hdr;
  221. char *data, *data2;
  222. hdr = clear_bloblist();
  223. ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
  224. data = bloblist_ensure(TEST_TAG, TEST_SIZE);
  225. data2 = bloblist_ensure(TEST_TAG2, TEST_SIZE2);
  226. console_record_reset_enable();
  227. if (!state->show_test_output)
  228. gd->flags |= GD_FLG_SILENT;
  229. console_record_reset();
  230. run_command("bloblist list", 0);
  231. ut_assert_nextline("Address Size Tag Name");
  232. ut_assert_nextline("%08lx %8x 1 EC host event",
  233. (ulong)map_to_sysmem(data), TEST_SIZE);
  234. ut_assert_nextline("%08lx %8x 2 SPL hand-off",
  235. (ulong)map_to_sysmem(data2), TEST_SIZE2);
  236. ut_assert_console_end();
  237. gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
  238. return 0;
  239. }
  240. BLOBLIST_TEST(bloblist_test_cmd_list, 0);
  241. /* Test alignment of bloblist blobs */
  242. static int bloblist_test_align(struct unit_test_state *uts)
  243. {
  244. struct bloblist_hdr *hdr;
  245. ulong addr;
  246. char *data;
  247. int i;
  248. /* At the start there should be no records */
  249. hdr = clear_bloblist();
  250. ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
  251. ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE));
  252. /* Check the default alignment */
  253. for (i = 0; i < 3; i++) {
  254. int size = i * 3;
  255. ulong addr;
  256. char *data;
  257. int j;
  258. data = bloblist_add(i, size, 0);
  259. ut_assertnonnull(data);
  260. addr = map_to_sysmem(data);
  261. ut_asserteq(0, addr & (BLOBLIST_ALIGN - 1));
  262. /* Only the bytes in the blob data should be zeroed */
  263. for (j = 0; j < size; j++)
  264. ut_asserteq(0, data[j]);
  265. for (; j < BLOBLIST_ALIGN; j++)
  266. ut_asserteq(ERASE_BYTE, data[j]);
  267. }
  268. /* Check larger alignment */
  269. for (i = 0; i < 3; i++) {
  270. int align = 32 << i;
  271. data = bloblist_add(3 + i, i * 4, align);
  272. ut_assertnonnull(data);
  273. addr = map_to_sysmem(data);
  274. ut_asserteq(0, addr & (align - 1));
  275. }
  276. /* Check alignment with an bloblist starting on a smaller alignment */
  277. hdr = map_sysmem(TEST_ADDR + BLOBLIST_ALIGN, TEST_BLOBLIST_SIZE);
  278. memset(hdr, ERASE_BYTE, TEST_BLOBLIST_SIZE);
  279. memset(hdr, '\0', sizeof(*hdr));
  280. ut_assertok(bloblist_new(TEST_ADDR + BLOBLIST_ALIGN, TEST_BLOBLIST_SIZE,
  281. 0));
  282. data = bloblist_add(1, 5, BLOBLIST_ALIGN * 2);
  283. ut_assertnonnull(data);
  284. addr = map_to_sysmem(data);
  285. ut_asserteq(0, addr & (BLOBLIST_ALIGN * 2 - 1));
  286. return 0;
  287. }
  288. BLOBLIST_TEST(bloblist_test_align, 0);
  289. int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc,
  290. char *const argv[])
  291. {
  292. struct unit_test *tests = ll_entry_start(struct unit_test,
  293. bloblist_test);
  294. const int n_ents = ll_entry_count(struct unit_test, bloblist_test);
  295. return cmd_ut_category("bloblist", "bloblist_test_",
  296. tests, n_ents, argc, argv);
  297. }