Software APIs
boot_data_functest.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
7 #include "sw/device/lib/testing/test_framework/check.h"
10 #include "sw/device/silicon_creator/lib/boot_data.h"
11 #include "sw/device/silicon_creator/lib/drivers/flash_ctrl.h"
12 #include "sw/device/silicon_creator/lib/drivers/otp.h"
13 
14 #include "flash_ctrl_regs.h" // Generated.
16 #include "otp_ctrl_regs.h"
17 
18 OTTF_DEFINE_TEST_CONFIG();
19 
20 /**
21  * Boot data flash info pages.
22  */
23 static const flash_ctrl_info_page_t *kPages[2] = {
24  &kFlashCtrlInfoPageBootData0,
25  &kFlashCtrlInfoPageBootData1,
26 };
27 
28 /**
29  * Boot data entry used in tests.
30  */
31 boot_data_t kTestBootData = (boot_data_t){
32  .digest = {{
33  0x44e757cb,
34  0x19899a04,
35  0xf872d77f,
36  0x58361229,
37  0x48d748f1,
38  0xfcafabf1,
39  0x4fbc4153,
40  0x0f05e1c9,
41  }},
42  .identifier = kBootDataIdentifier,
43  .version = kBootDataVersion2,
44  .is_valid = kBootDataValidEntry,
45  // `kBootDataDefaultCounterVal` + 1 for consistency.
46  .counter = kBootDataDefaultCounterVal + 1,
47  .min_security_version_rom_ext = 0,
48  .primary_bl0_slot = kBootSlotA,
49 };
50 
51 /**
52  * Sets read, write, and erase permissions for boot data pages.
53  *
54  * This function is intended for backdoor access during tests, e.g. to set the
55  * contents of a page before a read test or check the contents after a write
56  * test.
57  *
58  * @param enable New read, write, and erase permissions.
59  */
60 static void boot_data_pages_mp_set(hardened_bool_t perm) {
61  multi_bit_bool_t mubi_perm =
62  perm == kHardenedBoolTrue ? kMultiBitBool4True : kMultiBitBool4False;
63  for (size_t i = 0; i < ARRAYSIZE(kPages); ++i) {
64  flash_ctrl_info_perms_set(kPages[i], (flash_ctrl_perms_t){
65  .read = mubi_perm,
66  .write = mubi_perm,
67  .erase = mubi_perm,
68  });
69  }
70 }
71 
72 /**
73  * Erases boot data info pages.
74  */
75 static void erase_boot_data_pages(void) {
76  boot_data_pages_mp_set(kHardenedBoolTrue);
77  for (size_t i = 0; i < ARRAYSIZE(kPages); ++i) {
78  CHECK(flash_ctrl_info_erase(kPages[i], kFlashCtrlEraseTypePage) == kErrorOk,
79  "Flash page erase failed.");
80  }
81  boot_data_pages_mp_set(kHardenedBoolFalse);
82 }
83 
84 /**
85  * Writes a boot data entry at the given page and index.
86  *
87  * This function also checks that the entry was written correctly by reading it
88  * back from the flash.
89  *
90  * @param page Flash info page.
91  * @param index Index of the entry to write in the given page.
92  * @param boot_data A boot data entry.
93  */
94 static void write_boot_data(const flash_ctrl_info_page_t *page, size_t index,
95  const boot_data_t *boot_data) {
96  const uint32_t offset = index * sizeof(boot_data_t);
97  uint32_t buf[kBootDataNumWords];
98  memcpy(buf, boot_data, sizeof(boot_data_t));
99  boot_data_pages_mp_set(kHardenedBoolTrue);
100  CHECK(flash_ctrl_info_write(page, offset, kBootDataNumWords, buf) == kErrorOk,
101  "Flash write failed.");
102  CHECK(flash_ctrl_info_read(page, offset, kBootDataNumWords, buf) == kErrorOk,
103  "Flash read failed.");
104  boot_data_pages_mp_set(kHardenedBoolFalse);
105  CHECK(memcmp(buf, boot_data, sizeof(boot_data_t)) == 0,
106  "Flash write failed.");
107 }
108 
109 /**
110  * Reads the boot data entry at the given page and index.
111  *
112  * @param page Flash info page.
113  * @param index Index of the entry to read in the given page.
114  * @param boot_data A boot data entry.
115  */
116 static void read_boot_data(const flash_ctrl_info_page_t *page, size_t index,
118  const uint32_t offset = index * sizeof(boot_data_t);
119  uint32_t buf[kBootDataNumWords];
120  boot_data_pages_mp_set(kHardenedBoolTrue);
121  CHECK(flash_ctrl_info_read(page, offset, kBootDataNumWords, buf) == kErrorOk,
122  "Flash read failed.");
123  boot_data_pages_mp_set(kHardenedBoolFalse);
124  memcpy(boot_data, buf, sizeof(boot_data_t));
125 }
126 
127 /**
128  * Writes the given number of invalidated boot data entries to a page.
129  *
130  * This function invalidates the given boot data entry by setting its
131  * `is_valid` field to `kBootDataInvalidEntry` before writing it to the
132  * flash.
133  *
134  * @param page Flash info page.
135  * @param num_entries Number of entries to write.
136  * @param boot_data A boot data entry.
137  */
138 static void fill_with_invalidated_boot_data(const flash_ctrl_info_page_t *page,
139  size_t num_entries,
140  const boot_data_t *boot_data) {
141  boot_data_t invalidated = *boot_data;
142  invalidated.identifier = kBootDataIdentifier;
143  invalidated.is_valid = kBootDataInvalidEntry;
144  for (size_t i = 0; i < num_entries; ++i) {
145  write_boot_data(page, i, &invalidated);
146  }
147 }
148 
149 /**
150  * Compares two `boot_data_t` structs.
151  *
152  * @param lhs LHS of the comparison.
153  * @param rhs RHS of the comparison.
154  * @return The result of the operation.
155  */
156 static rom_error_t compare_boot_data(const boot_data_t *lhs,
157  const boot_data_t *rhs) {
158  if (memcmp(lhs, rhs, sizeof(boot_data_t)) != 0) {
159  return kErrorUnknown;
160  }
161  return kErrorOk;
162 }
163 
164 /**
165  * Checks whether a boot data entry is valid.
166  *
167  * This function checks the `identifier`, `digest`, and counter fields of a boot
168  * data entry.
169  *
170  * @param boot_data A boot data entry.
171  * @return The result of the operation.
172  */
173 static rom_error_t check_boot_data(const boot_data_t *boot_data,
174  uint32_t counter) {
175  enum {
176  kDigestRegionOffset = sizeof(boot_data->digest),
177  kDigestRegionSize = sizeof(boot_data_t) - sizeof(boot_data->digest),
178  };
179 
180  if (boot_data->identifier != kBootDataIdentifier) {
181  return kErrorUnknown;
182  }
183 
184  if (boot_data->counter != counter) {
185  return kErrorUnknown;
186  }
187 
188  hmac_digest_t exp_digest;
189  hmac_sha256((const char *)boot_data + kDigestRegionOffset, kDigestRegionSize,
190  &exp_digest);
191  if (memcmp(&exp_digest, &boot_data->digest, sizeof(exp_digest)) != 0) {
192  return kErrorUnknown;
193  }
194  return kErrorOk;
195 }
196 
197 rom_error_t check_test_data_test(void) {
198  RETURN_IF_ERROR(check_boot_data(&kTestBootData, kTestBootData.counter));
199  return kErrorOk;
200 }
201 
202 rom_error_t read_empty_default_in_non_prod(void) {
203  erase_boot_data_pages();
204 
206  RETURN_IF_ERROR(boot_data_read(kLcStateTest, &boot_data));
207  RETURN_IF_ERROR(check_boot_data(&boot_data, 5));
208  return kErrorOk;
209 }
210 
211 rom_error_t read_empty_default_in_prod(void) {
212  erase_boot_data_pages();
213 
214  rom_error_t exp_error = kErrorBootDataNotFound;
215  hardened_bool_t allowed_in_prod = otp_read32(
216  OTP_CTRL_PARAM_CREATOR_SW_CFG_DEFAULT_BOOT_DATA_IN_PROD_EN_OFFSET);
217  if (allowed_in_prod == kHardenedBoolTrue) {
218  exp_error = kErrorOk;
219  }
220 
222  if (boot_data_read(kLcStateProd, &boot_data) == exp_error) {
223  return kErrorOk;
224  }
225  return kErrorUnknown;
226 }
227 
228 rom_error_t read_single_page_0_test(void) {
229  erase_boot_data_pages();
230  write_boot_data(kPages[0], 0, &kTestBootData);
231 
233  RETURN_IF_ERROR(boot_data_read(kLcStateProd, &boot_data));
234  RETURN_IF_ERROR(compare_boot_data(&boot_data, &kTestBootData));
235  return kErrorOk;
236 }
237 
238 rom_error_t read_single_page_1_test(void) {
239  erase_boot_data_pages();
240  write_boot_data(kPages[1], 0, &kTestBootData);
241 
243  uint64_t start = ibex_mcycle_read();
244  RETURN_IF_ERROR(boot_data_read(kLcStateProd, &boot_data));
245  uint64_t end = ibex_mcycle_read();
246  RETURN_IF_ERROR(compare_boot_data(&boot_data, &kTestBootData));
247  if (end - start > UINT32_MAX) {
248  LOG_FATAL("boot_data_read() took more than UINT32_MAX cycles");
249  return kErrorUnknown;
250  }
251  uint32_t cycles = (uint32_t)(end - start);
252  LOG_INFO("boot_data_read() took %u cycles", cycles);
253  return kErrorOk;
254 }
255 
256 rom_error_t read_full_page_0_test(void) {
257  erase_boot_data_pages();
258  fill_with_invalidated_boot_data(kPages[0], kBootDataEntriesPerPage - 1,
259  &kTestBootData);
260  write_boot_data(kPages[0], kBootDataEntriesPerPage - 1, &kTestBootData);
261  fill_with_invalidated_boot_data(kPages[1], kBootDataEntriesPerPage,
262  &kTestBootData);
263 
265  RETURN_IF_ERROR(boot_data_read(kLcStateProd, &boot_data));
266  RETURN_IF_ERROR(compare_boot_data(&boot_data, &kTestBootData));
267  return kErrorOk;
268 }
269 
270 rom_error_t read_full_page_1_test(void) {
271  erase_boot_data_pages();
272  fill_with_invalidated_boot_data(kPages[0], kBootDataEntriesPerPage,
273  &kTestBootData);
274  fill_with_invalidated_boot_data(kPages[1], kBootDataEntriesPerPage - 1,
275  &kTestBootData);
276  write_boot_data(kPages[1], kBootDataEntriesPerPage - 1, &kTestBootData);
277 
279  uint64_t start = ibex_mcycle_read();
280  RETURN_IF_ERROR(boot_data_read(kLcStateProd, &boot_data));
281  uint64_t end = ibex_mcycle_read();
282  RETURN_IF_ERROR(compare_boot_data(&boot_data, &kTestBootData));
283 
284  CHECK(end - start <= UINT32_MAX, "Cycle count must fit in uint32_t");
285  uint32_t cycles = (uint32_t)(end - start);
286  LOG_INFO("boot_data_read() took %u cycles", cycles);
287  return kErrorOk;
288 }
289 
290 rom_error_t write_empty_test(void) {
291  erase_boot_data_pages();
292  RETURN_IF_ERROR(boot_data_write(&kTestBootData));
294  RETURN_IF_ERROR(boot_data_read(kLcStateProd, &boot_data));
295  RETURN_IF_ERROR(compare_boot_data(&kTestBootData, &boot_data));
296  return kErrorOk;
297 }
298 
299 rom_error_t write_page_switch_test(void) {
300  erase_boot_data_pages();
301  boot_data_t boot_data_act;
302  boot_data_t boot_data_exp;
303  uint32_t counter_exp = kBootDataDefaultCounterVal;
304 
305  // Write `kBootDataEntriesPerPage` + 1 entries to test the switch from page 0
306  // to page 1.
307  for (size_t i = 0; i < kBootDataEntriesPerPage + 1; ++i) {
308  RETURN_IF_ERROR(boot_data_write(&kTestBootData));
309  // Check `identifier`, `digest`, and `counter` fields.
310  RETURN_IF_ERROR(boot_data_read(kLcStateProd, &boot_data_act));
311  RETURN_IF_ERROR(check_boot_data(&boot_data_act, ++counter_exp));
312  if (i > 0) {
313  // Previous entry must be invalidated.
314  boot_data_t prev_entry;
315  read_boot_data(kPages[0], i - 1, &prev_entry);
316  if (prev_entry.is_valid != kBootDataInvalidEntry) {
317  LOG_ERROR("Previous entry was not invalidated");
318  return kErrorUnknown;
319  }
320  }
321  }
322  // Last written entry must be at entry 0 in page 1.
323  read_boot_data(kPages[1], 0, &boot_data_exp);
324  if (memcmp(&boot_data_act, &boot_data_exp, sizeof(boot_data_t)) != 0) {
325  LOG_ERROR("Page 0 -> 1 switch failed.");
326  return kErrorUnknown;
327  }
328 
329  // Write `kBootDataEntriesPerPage` entries to test the switch from page 1 to
330  // page 0.
331  for (size_t i = 1; i < kBootDataEntriesPerPage + 1; ++i) {
332  RETURN_IF_ERROR(boot_data_write(&kTestBootData));
333  // Check `identifier`, `digest`, and `counter` fields.
334  RETURN_IF_ERROR(boot_data_read(kLcStateProd, &boot_data_act));
335  RETURN_IF_ERROR(check_boot_data(&boot_data_act, ++counter_exp));
336  // Previous entry must be invalidated.
337  boot_data_t prev_entry;
338  read_boot_data(kPages[1], i - 1, &prev_entry);
339  if (prev_entry.is_valid != kBootDataInvalidEntry) {
340  LOG_ERROR("Previous entry was not invalidated");
341  return kErrorUnknown;
342  }
343  }
344  // Last written entry must be at entry 0 in page 0.
345  read_boot_data(kPages[0], 0, &boot_data_exp);
346  if (memcmp(&boot_data_act, &boot_data_exp, sizeof(boot_data_t)) != 0) {
347  LOG_ERROR("Page 1 -> 0 switch failed.");
348  return kErrorUnknown;
349  }
350 
351  return kErrorOk;
352 }
353 
354 bool test_main(void) {
355  status_t result = OK_STATUS();
356 
357  // Initialize the sec_mmio table so that we can run this test with both rom
358  // and test_rom.
359  sec_mmio_init();
360  flash_ctrl_init();
361  SEC_MMIO_WRITE_INCREMENT(kFlashCtrlSecMmioInit);
362  sec_mmio_check_counters(/*expected_check_count=*/0);
363 
364  EXECUTE_TEST(result, check_test_data_test);
365  EXECUTE_TEST(result, read_empty_default_in_non_prod);
366  EXECUTE_TEST(result, read_empty_default_in_prod);
367  EXECUTE_TEST(result, read_single_page_0_test);
368  EXECUTE_TEST(result, read_single_page_1_test);
369  EXECUTE_TEST(result, read_full_page_0_test);
370  EXECUTE_TEST(result, read_full_page_1_test);
371  EXECUTE_TEST(result, write_empty_test);
372  EXECUTE_TEST(result, write_page_switch_test);
373 
374  return status_ok(result);
375 }