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