Software APIs
sec_mmio.h
Go to the documentation of this file.
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_SILICON_CREATOR_LIB_BASE_SEC_MMIO_H_
6 #define OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_BASE_SEC_MMIO_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
12 #include "sw/device/silicon_creator/lib/error.h"
13 
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17 
18 /**
19  * @file
20  * @brief Secure Memory-mapped IO functions, for volatile access.
21  *
22  * This module is responsible for tracking critical register values for an
23  * initialized context `sec_mmio_ctx_t`, and provides a mechanism to evaluate
24  * expectations and trigger an exception on fault detection.
25  *
26  * Initialization
27  *
28  * - `sec_mmio_init()`.
29  *
30  * Register writes
31  *
32  * - Perform a number (N) of calls to `sec_mmio_write32()`.
33  * - Increment the expected number of writes by N with
34  * `SEC_MMIO_WRITE_INCREMENT()`. This is done using a separate function call
35  * to be able to detect skip instruction faults on `sec_mmio_write32()`
36  * calls.
37  *
38  * Register reads
39  *
40  * Use the `sec_mmio_read32()`.
41  *
42  * Expectation checks
43  *
44  * See the following:
45  *
46  * - `sec_mmio_check_values()`
47  * - `sec_mmio_check_counters()`
48  */
49 
50 enum {
51  /**
52  * Number of registers stored in the sec_mmio context.
53  */
55 };
56 
57 /**
58  * Working context.
59  *
60  * Contains list of expected register addresses and associated values, as well
61  * as expected counters.
62  */
63 typedef struct sec_mmio_ctx {
64  /**
65  * Represents the expected number of register values.
66  */
67  uint32_t last_index;
68  /**
69  * Represents the number of register write operations. Incremented by the
70  * `sec_mmio_write32()` function.
71  */
72  uint32_t write_count;
73  /**
74  * Represents the expected number of register write operations. Incremented by
75  * `SEC_MMIO_WRITE_INCREMENT()`.
76  */
78  /**
79  * Represents the number of times the check functions have been called.
80  * Incremented by the `sec_mmio_check_values()` and the
81  * `sec_mmio_check_counters()` functions.
82  */
83  uint32_t check_count;
84  /**
85  * List of expected register values.
86  */
88  /**
89  * List of expected register addresses.
90  */
93 
94 /**
95  * The `sec_mmio_ctx_t` structure is accessible by both the ROM and ROM
96  * extension. It's layout is therefore fixed and any changes must be applied
97  * to both boot stages.
98  */
100 OT_ASSERT_MEMBER_OFFSET(sec_mmio_ctx_t, write_count, 4);
101 OT_ASSERT_MEMBER_OFFSET(sec_mmio_ctx_t, expected_write_count, 8);
102 OT_ASSERT_MEMBER_OFFSET(sec_mmio_ctx_t, check_count, 12);
105 OT_ASSERT_SIZE(sec_mmio_ctx_t, 8016); // Checked by linker script.
106 
107 // The sec_mmio_ctx is referenced here to be able to use it inside the
108 // `SEC_MMIO_WRITE_INCREMENT()` macro.
110 
111 /**
112  * Increment the expected count of register writes by `value`.
113  *
114  * This macro must be used to increment the number of expected register writes
115  * before calling `sec_mmio_check_counters()`.
116  *
117  * @param value The expected write count increment.
118  */
119 #define SEC_MMIO_WRITE_INCREMENT(value) \
120  (sec_mmio_ctx.expected_write_count += (value))
121 
122 /**
123  * Assert macro used to cross-reference exported sec_mmio expected write counts
124  * to their respective functions.
125  */
126 #define SEC_MMIO_ASSERT_WRITE_INCREMENT(enum_val, expected) \
127  static_assert(enum_val == expected, "Unexpected value for " #enum_val)
128 
129 /**
130  * Initializes the module.
131  *
132  * Initializes the internal `sec_mmio_ctx_t` context.
133  */
134 void sec_mmio_init(void);
135 
136 /**
137  * Executes sec_mmio next boot stage initialization.
138  *
139  * Performs the following operations to the internal `sec_mmio_ctx_t` context:
140  *
141  * - Clear the check count. This allows the caller to reset the
142  * `sec_mmio_check_counters()` expected count argument.
143  * - Reset all expected address and values in the expectations table starting at
144  * the last_index.
145  */
146 void sec_mmio_next_stage_init(void);
147 
148 /**
149  * Reads an aligned uint32_t from the MMIO region `addr`.
150  *
151  * This function implements a read-read-comparison operation. The first read
152  * is stored in the list of expected register values for later comparison
153  * via `sec_mmio_check_values()`.
154  *
155  * An exception is thrown if the comparison operation fails.
156  *
157  * @param addr The address to read from.
158  * @return the read value.
159  */
161 uint32_t sec_mmio_read32(uint32_t addr);
162 
163 /**
164  * Writes an aligned uint32_t to the MMIO region `base` at the give byte
165  * `offset`.
166  *
167  * This function implements a write-read-comparison operation. The first write
168  * value is stored in the list of expected register values for later comparison
169  * via `sec_mmio_check_values()`.
170  *
171  * On successful calls, this function will increment the internal count of
172  * writes. The caller is responsible to setting the expected write count with
173  * `SEC_MMIO_WRITE_INCREMENT()`.
174  *
175  * An exception is thrown if the comparison operation fails.
176  *
177  * @param addr The address to write to.
178  * @param value The value to write.
179  */
180 void sec_mmio_write32(uint32_t addr, uint32_t value);
181 
182 /**
183  * Writes an aligned uint32_t to the MMIO region `base` at the give byte
184  * `offset`.
185  *
186  * This function implements a write-write-read-comparison operation for shadowed
187  * registers. The first write value is stored in the list of expected register
188  * values for later comparison via `sec_mmio_check_values()`.
189  *
190  * On successful calls, this function will increment the internal count of
191  * writes. The caller is responsible to setting the expected write count with
192  * `SEC_MMIO_WRITE_INCREMENT()`.
193  *
194  * An exception is thrown if the comparison operation fails.
195  *
196  * @param addr The address to write to.
197  * @param value The value to write.
198  */
199 void sec_mmio_write32_shadowed(uint32_t addr, uint32_t value);
200 
201 /**
202  * Checks the expected list of register values.
203  *
204  * All expected register values are verified against expectations. An exception
205  * is thrown if any of the comparison fails.
206  *
207  * The `rnd_offset` parameter can be set to a random value to randomize the
208  * order of reads.
209  *
210  * Calling this function will increment the check function counter on a
211  * successful call.
212  *
213  * The `rnd_offset` parameter can be generated by calling the entropy source or
214  * the CSRNG driver.
215  *
216  * @param rnd_offset A random value used to generate a random read sequence.
217  */
218 void sec_mmio_check_values(uint32_t rnd_offset);
219 
220 /**
221  * Checks the expected list of register values except for OTP values.
222  *
223  * All expected register values (except OTP) are verified against expectations.
224  * An exception is thrown if any of the comparison fails.
225  *
226  * The `rnd_offset` parameter can be set to a random value to randomize the
227  * order of reads.
228  *
229  * Calling this function will increment the check function counter on a
230  * successful call.
231  *
232  * The `rnd_offset` parameter can be generated by calling the entropy source or
233  * the CSRNG driver.
234  *
235  * @param rnd_offset A random value used to generate a random read sequence.
236  * @param otp_base The base address of the OTP peripheral. The avoided region
237  * is 64K in size.
238  */
239 void sec_mmio_check_values_except_otp(uint32_t rnd_offset, uint32_t otp_base);
240 
241 /**
242  * Checks the expected counter state.
243  *
244  * Checks the expected number of register writes and check counts. An exception
245  * is thrown if the counters fail to match expectations.
246  *
247  * Calling this function will increment the check function counter on a
248  * successful
249  *
250  * @param expected_check_count The expected check counter.
251  */
252 void sec_mmio_check_counters(uint32_t expected_check_count);
253 
254 #ifdef __cplusplus
255 }
256 #endif
257 
258 #endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_BASE_SEC_MMIO_H_