Software APIs
alert_handler_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
5#include "sw/device/lib/testing/alert_handler_testutils.h"
6
7#include "dt/dt_alert_handler.h" // Generated
8#include "dt/dt_api.h" // Generated
14#include "sw/device/lib/testing/test_framework/check.h"
15
16#include "alert_handler_regs.h" // Generated
17
18#define MODULE_ID MAKE_MODULE_ID('a', 'h', 't')
19
20const char kAlertClassName[] = {'A', 'B', 'C', 'D'};
21static_assert(ARRAYSIZE(kAlertClassName) == ALERT_HANDLER_PARAM_N_CLASSES,
22 "Expected four alert classes!");
23
24/**
25 * This is used to traverse the dump treating it as an array of bits, and
26 * extract a number of bits placing them in a uint32_t. The word and bit index
27 * are updated by num_bits before returning.
28 */
29static uint32_t get_next_n_bits(
30 int num_bits, const dif_rstmgr_alert_info_dump_segment_t *dump,
31 int *word_index, int *bit_index) {
32 CHECK(num_bits <= 32);
33 CHECK(*bit_index < 32);
34 uint32_t word = dump[*word_index] >> *bit_index;
35 if (*bit_index + num_bits >= 32) {
36 (*word_index) += 1;
37 *bit_index = *bit_index + num_bits - 32;
38 } else {
39 *bit_index += num_bits;
40 }
41 word &= (1 << num_bits) - 1;
42 return word;
43}
44
45status_t alert_handler_testutils_info_parse(
46 const dif_rstmgr_alert_info_dump_segment_t *dump, int dump_size,
47 alert_handler_testutils_info_t *info) {
48 int word_index = 0;
49 int bit_index = 0;
50 for (int i = 0; i < ALERT_HANDLER_PARAM_N_CLASSES; ++i) {
51 info->class_esc_state[i] =
52 get_next_n_bits(3, dump, &word_index, &bit_index);
53 }
54 for (int i = 0; i < ALERT_HANDLER_PARAM_N_CLASSES; ++i) {
55 info->class_esc_cnt[i] = get_next_n_bits(32, dump, &word_index, &bit_index);
56 }
57 for (int i = 0; i < ALERT_HANDLER_PARAM_N_CLASSES; ++i) {
58 info->class_accum_cnt[i] =
59 (uint16_t)get_next_n_bits(16, dump, &word_index, &bit_index);
60 }
61 info->loc_alert_cause =
62 (uint8_t)get_next_n_bits(7, dump, &word_index, &bit_index);
63 TRY_CHECK(word_index < dump_size);
64 for (int i = 0; i < ALERT_HANDLER_PARAM_N_ALERTS; ++i) {
65 info->alert_cause[i] = get_next_n_bits(1, dump, &word_index, &bit_index);
66 }
67 TRY_CHECK(word_index < dump_size);
68 return OK_STATUS();
69}
70
71void alert_handler_testutils_info_dump(
72 const alert_handler_testutils_info_t *info) {
73 LOG_INFO("alert_info:");
74 LOG_INFO("esc_state [0]=%x, [1]=%x, [2]=%x, [3]=%x", info->class_esc_state[0],
75 info->class_esc_state[1], info->class_esc_state[2],
76 info->class_esc_state[3]);
77 LOG_INFO("esc_cnt [0]=0x%x, [1]=0x%x, [2]=0x%x, [3]=0x%x",
78 info->class_esc_cnt[0], info->class_esc_cnt[1],
79 info->class_esc_cnt[2], info->class_esc_cnt[3]);
80 LOG_INFO("accum_cnt [0]=0x%x, [1]=0x%x, [2]=0x%x, [3]=0x%x",
81 info->class_accum_cnt[0], info->class_accum_cnt[1],
82 info->class_accum_cnt[2], info->class_accum_cnt[3]);
83 LOG_INFO("loc_alert_cause=0x%x", info->loc_alert_cause);
84 int set_count = 0;
85 LOG_INFO("alert_cause bits set:");
86 // Typically very few bits are set, so it is more clear to only show the
87 // on bits.
88 for (int i = 0; i < ALERT_HANDLER_PARAM_N_ALERTS; ++i) {
89 if (info->alert_cause[i]) {
90 LOG_INFO("alert_cause[%d] = 1", i);
91 ++set_count;
92 }
93 }
94 if (set_count == 0) {
95 LOG_INFO("No bits set");
96 }
97}
98
99status_t alert_handler_testutils_configure_all(
100 const dif_alert_handler_t *alert_handler, dif_alert_handler_config_t config,
101 dif_toggle_t locked) {
102 TRY_CHECK(alert_handler != NULL);
103 TRY_CHECK(dif_is_valid_toggle(locked));
104
105 // Check lengths of alert, local alert, and class arrays.
106 TRY_CHECK((config.alerts_len > 0 && config.alerts != NULL &&
107 config.alert_classes != NULL) ||
108 (config.alerts_len == 0 && config.alerts == NULL &&
109 config.alert_classes == NULL));
110 TRY_CHECK((config.local_alerts_len > 0 && config.local_alerts != NULL &&
111 config.local_alert_classes != NULL) ||
112 (config.local_alerts_len == 0 && config.local_alerts == NULL &&
113 config.local_alert_classes == NULL));
114 TRY_CHECK((config.classes_len > 0 && config.classes != NULL &&
115 config.class_configs != NULL) ||
116 (config.classes_len == 0 && config.classes == NULL &&
117 config.class_configs == NULL));
118
119 // Check that the provided ping timeout actually fits in the timeout
120 // register, which is smaller than a native word length.
121 TRY_CHECK(
122 config.ping_timeout <=
123 ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_PING_TIMEOUT_CYC_SHADOWED_MASK);
124
125 // Configure and enable the requested alerts.
126 for (int i = 0; i < config.alerts_len; ++i) {
127 TRY(dif_alert_handler_configure_alert(alert_handler, config.alerts[i],
128 config.alert_classes[i],
129 kDifToggleEnabled, locked));
130 }
131
132 // Configure and enable the requested local alerts.
133 for (int i = 0; i < config.local_alerts_len; ++i) {
134 TRY(dif_alert_handler_configure_local_alert(
135 alert_handler, config.local_alerts[i], config.local_alert_classes[i],
136 kDifToggleEnabled, locked));
137 }
138
139 // Configure and enable the requested classes.
140 for (int i = 0; i < config.classes_len; ++i) {
141 TRY(dif_alert_handler_configure_class(alert_handler, config.classes[i],
142 config.class_configs[i],
143 kDifToggleEnabled, locked));
144 }
145
146 // Configure the ping timer.
147 TRY(dif_alert_handler_configure_ping_timer(alert_handler, config.ping_timeout,
148 kDifToggleEnabled, locked));
149
150 return OK_STATUS();
151}
152
153status_t alert_handler_testutils_get_cycles_from_us(uint64_t microseconds,
154 uint32_t *cycles) {
155 uint64_t cycles_ = udiv64_slow(
158 1000000,
159 /*rem_out=*/NULL);
160 TRY_CHECK(cycles_ < UINT32_MAX,
161 "The value 0x%08x%08x can't fit into the 32 bits timer counter.",
162 (uint32_t)(cycles_ >> 32), (uint32_t)cycles_);
163 *cycles = (uint32_t)cycles_;
164 return OK_STATUS();
165}
166
167uint32_t alert_handler_testutils_cycle_rescaling_factor(void) {
168 return kDeviceType == kDeviceSimDV ? 1 : 10;
169}
170
171static status_t alert_handler_class_info_log(
172 const dif_alert_handler_t *alert_handler,
173 dif_alert_handler_class_t alert_class) {
175 TRY(dif_alert_handler_get_class_state(alert_handler, alert_class, &state));
176
177 uint16_t num_alerts;
178 TRY(dif_alert_handler_get_accumulator(alert_handler, alert_class,
179 &num_alerts));
180
181 if (num_alerts > 0) {
182 LOG_INFO("Alert class %c state: %d, acc_cnt: %d",
183 kAlertClassName[alert_class], state, num_alerts);
184
185 for (dif_alert_handler_alert_t alert = 0;
186 alert < ALERT_HANDLER_PARAM_N_ALERTS; ++alert) {
187 bool is_cause;
188 TRY(dif_alert_handler_alert_is_cause(alert_handler, alert, &is_cause));
189 if (is_cause) {
190 LOG_INFO("Alert %d is set", alert);
191 }
192 }
193
194 bool can_clear;
195 TRY(dif_alert_handler_escalation_can_clear(alert_handler, alert_class,
196 &can_clear));
197 if (can_clear) {
198 TRY(dif_alert_handler_escalation_clear(alert_handler, alert_class));
199 } else {
200 LOG_INFO("Alert class %c can't be cleared", kAlertClassName[alert_class]);
201 }
202 }
203
204 return OK_STATUS();
205}
206
207static status_t alert_handler_class_log(
208 const dif_alert_handler_t *alert_handler,
209 dif_alert_handler_class_t alert_class) {
211 TRY(dif_alert_handler_get_class_state(alert_handler, alert_class, &state));
212
213 uint16_t num_alerts;
214 TRY(dif_alert_handler_get_accumulator(alert_handler, alert_class,
215 &num_alerts));
216
217 if (num_alerts > 0) {
218 LOG_INFO("Alert class %c state: %d, acc_cnt: %d",
219 kAlertClassName[alert_class], state, num_alerts);
220 for (dif_alert_handler_alert_t alert = 0;
221 alert < ALERT_HANDLER_PARAM_N_ALERTS; ++alert) {
222 bool is_cause;
223 TRY(dif_alert_handler_alert_is_cause(alert_handler, alert, &is_cause));
224 if (is_cause) {
225 LOG_INFO("Alert %d is set", alert);
226 }
227 }
228 }
229
230 return OK_STATUS();
231}
232
233status_t alert_handler_testutils_status_log(
234 const dif_alert_handler_t *alert_handler) {
235 TRY_CHECK(alert_handler != NULL);
236
237 for (dif_alert_handler_class_t alert_class = 0;
238 alert_class < ALERT_HANDLER_PARAM_N_CLASSES; ++alert_class) {
239 TRY(alert_handler_class_log(alert_handler, alert_class));
240 }
241
242 return OK_STATUS();
243}
244
245status_t alert_handler_testutils_dump_log(const dif_rstmgr_t *rstmgr) {
246 TRY_CHECK(rstmgr != NULL);
247
249 size_t seg_size;
250 alert_handler_testutils_info_t actual_info;
251
252 uint32_t log_count = 0;
253
254 CHECK_DIF_OK(dif_rstmgr_alert_info_dump_read(
255 rstmgr, dump, DIF_RSTMGR_ALERT_INFO_MAX_SIZE, &seg_size));
256 CHECK(seg_size <= INT_MAX, "seg_size must fit in int");
257 CHECK_STATUS_OK(
258 alert_handler_testutils_info_parse(dump, (int)seg_size, &actual_info));
259
260 for (dif_alert_handler_class_t alert_class = 0;
261 alert_class < ALERT_HANDLER_PARAM_N_CLASSES; ++alert_class) {
262 if (actual_info.class_esc_state[alert_class] != kCstateIdle) {
263 LOG_INFO("crashdump - Alert class %c state: %d, acc_cnt: %d, esc_cnt: %d",
264 kAlertClassName[alert_class],
265 actual_info.class_esc_state[alert_class],
266 actual_info.class_accum_cnt[alert_class],
267 actual_info.class_esc_cnt[alert_class]);
268 log_count++;
269 }
270 }
271 for (dif_alert_handler_alert_t alert = 0;
272 alert < ALERT_HANDLER_PARAM_N_ALERTS; ++alert) {
273 if (actual_info.alert_cause[alert]) {
274 LOG_INFO("crashdump - Alert %d is set", alert);
275 log_count++;
276 }
277 }
278
279 if (log_count == 0) {
280 LOG_INFO("crashdump - No alerts reported");
281 }
282
283 return OK_STATUS();
284}
285
286status_t alert_handler_testutils_dump_enable(
287 const dif_alert_handler_t *alert_handler, const dif_rstmgr_t *rstmgr) {
288 TRY_CHECK(alert_handler != NULL);
289 TRY_CHECK(rstmgr != NULL);
290
291 uint32_t enable_count = 0;
292 for (dif_alert_handler_class_t alert_class = 0;
293 alert_class < ALERT_HANDLER_PARAM_N_CLASSES; ++alert_class) {
294 bool is_enabled;
295 TRY(dif_alert_handler_is_class_enabled(alert_handler, alert_class,
296 &is_enabled));
297 if (is_enabled) {
298 TRY(dif_alert_handler_crash_dump_trigger_set(
299 alert_handler, alert_class, kDifAlertHandlerClassStatePhase3));
300 enable_count++;
301 }
302 }
303
304 if (enable_count) {
305 CHECK_DIF_OK(dif_rstmgr_alert_info_set_enabled(rstmgr, kDifToggleEnabled));
306 }
307
308 return OK_STATUS();
309}