Software APIs
hardened_functest.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 <stdbool.h>
6 #include <stdint.h>
7 
9 #include "sw/device/lib/base/status.h"
12 #include "sw/device/lib/testing/test_framework/ottf_isrs.h"
14 
15 OTTF_DEFINE_TEST_CONFIG();
16 
17 status_t good_eq_test(void) {
18  uint32_t a = 100, b = 100;
19  HARDENED_CHECK_EQ(a, b);
20  return OK_STATUS();
21 }
22 status_t good_ne_test(void) {
23  uint32_t a = 100, b = 150;
24  HARDENED_CHECK_NE(a, b);
25  return OK_STATUS();
26 }
27 status_t good_lt_test(void) {
28  uint32_t a = 100, b = 150;
29  HARDENED_CHECK_LT(a, b);
30  return OK_STATUS();
31 }
32 status_t good_gt_test(void) {
33  uint32_t a = 150, b = 100;
34  HARDENED_CHECK_GT(a, b);
35  return OK_STATUS();
36 }
37 status_t good_le_test(void) {
38  uint32_t a = 100, b = 100;
39  HARDENED_CHECK_LE(a, b);
40  HARDENED_CHECK_LE(a, b + 1);
41  return OK_STATUS();
42 }
43 status_t good_ge_test(void) {
44  uint32_t a = 100, b = 100;
45  HARDENED_CHECK_GE(a, b);
46  HARDENED_CHECK_GE(a + 1, b);
47  return OK_STATUS();
48 }
49 
50 uint32_t exc_seen;
51 void ottf_illegal_instr_fault_handler(uint32_t *exc_info) {
52  switch (exc_seen) {
53  case 0:
54  // The first exception is when we hit `unimp` after failing the first
55  // comparison in the hardenend check. The exception handler has
56  // already computed the correct return PC for us, so we can simply
57  // increment the state and return. This will cause execution to
58  // continue at the inverted compare/branch instruction in the hardened
59  // sequence. The comparison will succeed and branch back to the
60  // `unimp` instruction. This will re-invoke this fault handler in the
61  // next state.
62  exc_seen += 1;
63  return;
64  case 1:
65  // The second exception is when we hit `unimp` after failing the second
66  // comparison in the hardenend check.
67  exc_seen += 1;
68  // Jump the PC over the comparison so we can exit the test function. In
69  // this case, the PC is again pointing at the inverse compare/branch after
70  // the `unimp` instruction. Since that instruction is 4 bytes, increment
71  // the PC by 4. In the exception frame, the return PC is the zeroth word.
72  exc_info[0] += 4;
73  return;
74  default:
75  // In all other cases, we are in an invalid test state. Invoke the
76  // generic fault handler.
77  ottf_generic_fault_print(exc_info, "Illegal Instruction",
79  abort();
80  }
81 }
82 
83 status_t bad_eq_test(void) {
84  uint32_t a = 100, b = 199;
85  exc_seen = 0;
86  HARDENED_CHECK_EQ(a, b);
87  return exc_seen == 2 ? OK_STATUS() : UNKNOWN();
88 }
89 status_t bad_ne_test(void) {
90  uint32_t a = 100, b = 100;
91  exc_seen = 0;
92  HARDENED_CHECK_NE(a, b);
93  return exc_seen == 2 ? OK_STATUS() : UNKNOWN();
94 }
95 status_t bad_lt_test(void) {
96  uint32_t a = 199, b = 100;
97  exc_seen = 0;
98  HARDENED_CHECK_LT(a, b);
99  return exc_seen == 2 ? OK_STATUS() : UNKNOWN();
100 }
101 status_t bad_gt_test(void) {
102  uint32_t a = 100, b = 199;
103  exc_seen = 0;
104  HARDENED_CHECK_GT(a, b);
105  return exc_seen == 2 ? OK_STATUS() : UNKNOWN();
106 }
107 status_t bad_le_test(void) {
108  uint32_t a = 199, b = 100;
109  exc_seen = 0;
110  HARDENED_CHECK_LE(a, b);
111  return exc_seen == 2 ? OK_STATUS() : UNKNOWN();
112 }
113 status_t bad_ge_test(void) {
114  uint32_t a = 100, b = 199;
115  exc_seen = 0;
116  HARDENED_CHECK_GE(a, b);
117  return exc_seen == 2 ? OK_STATUS() : UNKNOWN();
118 }
119 
120 bool test_main(void) {
121  status_t result = OK_STATUS();
122  // Test each hardened check when the check is valid.
123  EXECUTE_TEST(result, good_eq_test);
124  EXECUTE_TEST(result, good_ne_test);
125  EXECUTE_TEST(result, good_lt_test);
126  EXECUTE_TEST(result, good_gt_test);
127  EXECUTE_TEST(result, good_le_test);
128  EXECUTE_TEST(result, good_ge_test);
129 
130  // Test each hardened check when the check is invalid.
131  // Each of these tests is expected to hit the `unimp` instruction in the
132  // hardended sequence twice. The exception handler will guide the test
133  // through the hardened check so that we know we've examined both
134  // compare/branch instructions in the hardened sequence.
135  EXECUTE_TEST(result, bad_eq_test);
136  EXECUTE_TEST(result, bad_ne_test);
137  EXECUTE_TEST(result, bad_lt_test);
138  EXECUTE_TEST(result, bad_gt_test);
139  EXECUTE_TEST(result, bad_le_test);
140  EXECUTE_TEST(result, bad_ge_test);
141  return status_ok(result);
142 }