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
15extern "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
50enum {
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 */
63typedef 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 */
101OT_ASSERT_MEMBER_OFFSET(sec_mmio_ctx_t, expected_write_count, 8);
105OT_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 */
134void 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 */
146void 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 */
161uint32_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 */
180void 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 */
199void 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 */
218void 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 */
239void 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 */
252void 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_