Software APIs
otbn_testutils.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 
6 
11 #include "sw/device/lib/testing/test_framework/check.h"
12 
13 #define MODULE_ID MAKE_MODULE_ID('o', 'b', 't')
14 
15 enum {
16  /**
17  * Data width of big number subset, in bytes.
18  */
19  kOtbnWlenBytes = 256 / 8,
20 };
21 
22 status_t otbn_testutils_wait_for_done(const dif_otbn_t *otbn,
23  dif_otbn_err_bits_t expected_err_bits) {
24  bool busy = true;
26  while (busy) {
27  TRY(dif_otbn_get_status(otbn, &status));
28  busy = status != kDifOtbnStatusIdle && status != kDifOtbnStatusLocked;
29  }
30 
31  // Get instruction count so that we can print them to help with debugging.
32  uint32_t instruction_count;
33  TRY(dif_otbn_get_insn_cnt(otbn, &instruction_count));
34 
35  dif_otbn_err_bits_t err_bits;
36  TRY(dif_otbn_get_err_bits(otbn, &err_bits));
37 
38  // Error out if OTBN is locked.
39  TRY_CHECK(status == kDifOtbnStatusIdle, "OTBN is locked. Error bits: 0x%08x",
40  err_bits);
41 
42  // Error out if error bits do not match expectations.
43  TRY_CHECK(
44  err_bits == expected_err_bits,
45  "OTBN error bits: got: 0x%08x, expected: 0x%08x.\nInstruction count: "
46  "0x%08x",
47  err_bits, expected_err_bits, instruction_count);
48  return OK_STATUS();
49 }
50 
51 /**
52  * Checks if the OTBN application's IMEM and DMEM address parameters are valid.
53  *
54  * IMEM and DMEM ranges must not be "backwards" in memory, with the end address
55  * coming before the start address, and the IMEM range must additionally be
56  * non-empty. Finally, separate sections in DMEM must not overlap each other
57  * when converted to DMEM address space.
58  *
59  * @param app the OTBN application to check
60  */
61 static void check_app_address_ranges(const otbn_app_t *app) {
62  // IMEM must have a strictly positive range (cannot be backwards or empty)
63  CHECK(app->imem_end > app->imem_start);
64  // Initialised DMEM section must not be backwards
65  CHECK(app->dmem_data_end >= app->dmem_data_start);
66 }
67 
68 status_t otbn_testutils_load_app(const dif_otbn_t *otbn, const otbn_app_t app) {
69  check_app_address_ranges(&app);
70 
71  const size_t imem_size = (size_t)(app.imem_end - app.imem_start);
72  const size_t data_size = (size_t)(app.dmem_data_end - app.dmem_data_start);
73 
74  // Memory images and offsets must be multiples of 32b words.
75  TRY_CHECK(imem_size % sizeof(uint32_t) == 0);
76  TRY_CHECK(data_size % sizeof(uint32_t) == 0);
77 
78  TRY(dif_otbn_imem_write(otbn, 0, app.imem_start, imem_size));
79 
80  // Write initialized data
81  if (data_size > 0) {
82  TRY(dif_otbn_dmem_write(otbn, 0, app.dmem_data_start, data_size));
83  }
84  return OK_STATUS();
85 }
86 
87 status_t otbn_testutils_execute(const dif_otbn_t *otbn) {
88  TRY(dif_otbn_write_cmd(otbn, kDifOtbnCmdExecute));
89  return OK_STATUS();
90 }
91 
92 status_t otbn_testutils_write_data(const dif_otbn_t *otbn, size_t len_bytes,
93  const void *src, otbn_addr_t dest) {
94  TRY(dif_otbn_dmem_write(otbn, dest, src, len_bytes));
95  return OK_STATUS();
96 }
97 
98 status_t otbn_testutils_read_data(const dif_otbn_t *otbn, size_t len_bytes,
99  otbn_addr_t src, void *dest) {
100  TRY(dif_otbn_dmem_read(otbn, src, dest, len_bytes));
101  return OK_STATUS();
102 }
103 
104 status_t otbn_dump_dmem(const dif_otbn_t *otbn, uint32_t max_addr) {
105  TRY_CHECK(max_addr % kOtbnWlenBytes == 0);
106 
107  if (max_addr == 0) {
108  max_addr = dif_otbn_get_dmem_size_bytes(otbn);
109  }
110 
111  TRY_CHECK(max_addr <= UINT32_MAX, "max_addr must fit in uint32_t");
112  for (uint32_t i = 0; i < max_addr; i += kOtbnWlenBytes) {
113  uint32_t data[kOtbnWlenBytes / sizeof(uint32_t)];
114  TRY(dif_otbn_dmem_read(otbn, i, data, kOtbnWlenBytes));
115  LOG_INFO("DMEM @%04d: 0x%08x%08x%08x%08x%08x%08x%08x%08x",
116  i / kOtbnWlenBytes, data[7], data[6], data[5], data[4], data[3],
117  data[2], data[1], data[0]);
118  }
119  return OK_STATUS();
120 }