bloblist.c 9.8 KB

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