Software APIs
ottf_utils.h
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 
5 #ifndef OPENTITAN_SW_DEVICE_LIB_TESTING_TEST_FRAMEWORK_OTTF_UTILS_H_
6 #define OPENTITAN_SW_DEVICE_LIB_TESTING_TEST_FRAMEWORK_OTTF_UTILS_H_
7 
8 #include <stdatomic.h>
9 #include <stdbool.h>
10 #include <stdnoreturn.h>
11 
12 #include "sw/device/lib/base/status.h"
13 #include "sw/device/lib/testing/json/command.h"
14 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
15 #include "sw/device/lib/testing/test_framework/ujson_ottf_commands.h"
16 
17 /**
18  * Wait until a condition is true.
19  *
20  * @param cond: an expression that can be repeated tested for.
21  * @param timeout_usec: timeout in microseconds.
22  *
23  * In DV, this function will simply spin since the DV environment can do
24  * backdoor writes to make the condition true. On real device, this will wait
25  * for host to send ujson message. The condition is checked after each command.
26  */
27 #define OTTF_WAIT_FOR(cond, timeout_usec) \
28  do { \
29  if (kDeviceType != kDeviceSimDV) { \
30  ujson_t uj = ujson_ottf_console(); \
31  const ibex_timeout_t timeout_ = ibex_timeout_init(timeout_usec); \
32  test_command_t command; \
33  LOG_INFO("SiVal: waiting for commands"); \
34  while (!(cond)) { \
35  CHECK(!ibex_timeout_check(&timeout_), \
36  "Timed out after %d usec waiting for " #cond, timeout_usec); \
37  /* FIXME: what to do on error? */ \
38  CHECK_STATUS_OK( \
39  UJSON_WITH_CRC(ujson_deserialize_test_command_t, &uj, &command)); \
40  CHECK_STATUS_OK(ujson_ottf_dispatch(&uj, command)); \
41  } \
42  } else { \
43  IBEX_SPIN_FOR(cond, timeout_usec); \
44  } \
45  } while (0)
46 
47 /**
48  * Declare a variable which can be used with `OTTF_WAIT_FOR`.
49  *
50  * Variable declared this way will have an associated symbol in the final ELF
51  * binary. This will allow host test harness or DV to find the variable and
52  * manipulate it with backdoor access mechanism, via OTTF uJSON commands for
53  * SiVal or directly modifying the underlying memory for DV.
54  *
55  * This variable can be accessed directly if you're certain there'll be no
56  * concurrent DV modification. However, if a concurrent modification may occur,
57  * you need to use `OTTF_BACKDOOR_READ` to provide correct synchronization to
58  * avoid miscompilation.
59  *
60  * NOTE: this macro guarantees that the variable works in all non-DV
61  * environments but may not work in DV.
62  *
63  * Example:
64  * ```c
65  * OTTF_BACKDOOR_VAR bool sival_is_ready = false;
66  * ```
67  */
68 #define OTTF_BACKDOOR_VAR OT_USED OT_SECTION(".data")
69 
70 /**
71  * Same as `OTTF_BACKDOOR_VAR` but for DV environments.
72  * ```
73  */
74 #define OTTF_BACKDOOR_VAR_DV OT_USED OT_SECTION(".rodata")
75 
76 #if defined(OPENTITAN_IS_EARLGREY)
77 
78 static void ottf_backdoor_flush_read_buffers(void) {
79  // On earlgrey, some backdoor variables may live on flash, which
80  // has a read buffer that needs to be flushed to get up-to-date value.
81  //
82  // Cause read buffers to flush since it reads 32 bytes, which is the
83  // size of the read buffers.
84  enum { kBufferBytes = 32 };
85  static volatile const uint8_t kFlashFlusher[kBufferBytes];
86  for (int i = 0; i < sizeof(kFlashFlusher); ++i) {
87  (void)kFlashFlusher[i];
88  }
89 }
90 
91 #elif defined(OPENTITAN_IS_DARJEELING)
92 
93 static void ottf_backdoor_flush_read_buffers(void) {}
94 
95 #else
96 #error Unsupported top
97 #endif
98 
99 /**
100  * Reads a backdoor variable.
101  *
102  * This function can work on both normal and DV-specific backdoor variables.
103  * This function has acquire semantics. All memory accesses after the read
104  * will not be reordered by compiler to happen before the read.
105  *
106  * @param var the variable to read from.
107  * @return the read value.
108  */
109 #define OTTF_BACKDOOR_READ(var) \
110  ({ \
111  ottf_backdoor_flush_read_buffers(); \
112  typeof(var) _tmp = *(const volatile typeof(var) *)&(var); \
113  atomic_signal_fence(memory_order_acquire); \
114  _tmp; \
115  })
116 
117 #endif // OPENTITAN_SW_DEVICE_LIB_TESTING_TEST_FRAMEWORK_OTTF_UTILS_H_