Software APIs
pmp_smoketest_tor.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 
7 #include "sw/device/lib/runtime/irq.h"
8 #include "sw/device/lib/runtime/pmp.h"
9 #include "sw/device/lib/testing/test_framework/check.h"
11 #include "sw/device/silicon_creator/lib/epmp_state.h"
12 
13 /**
14  * PMP regions that are used for load/store and execution permission violation
15  * tests.
16  *
17  * "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
18  * "3.6 Physical Memory Protection", "Address Matching":
19  *
20  * "If PMP entry i’s A field is set to TOR, the entry matches any address y
21  * such that pmpaddri−1 <= y < pmpaddri. If PMP entry 0’s A field is set to TOR,
22  * zero is used for the lower bound, and so it matches any address
23  * y < pmpaddr0."
24  *
25  * To protect an address range that starts above 0 address, the first region
26  * we can use is 1.
27  */
28 
29 // Usable PMP regions vary depending on different exectuion environments.
30 // PMP regions with small or large indices are usually reserved by ROM/ROM_EXT
31 // So use PMP region 6 & 7 for this test.
32 #define PMP_LOAD_REGION_ID 7
33 
34 #define PMP_LOAD_RANGE_BUFFER_SIZE 1024
35 #define PMP_LOAD_RANGE_SIZE 512
36 #define PMP_LOAD_RANGE_BOTTOM_OFFSET 0
37 #define PMP_LOAD_RANGE_TOP_OFFSET \
38  (PMP_LOAD_RANGE_BOTTOM_OFFSET + PMP_LOAD_RANGE_SIZE - 1)
39 
40 // These flags are used in the test routine to verify that a corresponding
41 // interrupt has elapsed, and has been serviced. These are declared as volatile
42 // since they are referenced in the ISR routine as well as in the main program
43 // flow.
44 static volatile bool pmp_load_exception;
45 
46 /**
47  * The buffer that is used for load/store access violation test.
48  */
49 __attribute__((aligned(PMP_LOAD_RANGE_SIZE))) //
50 static volatile char pmp_load_test_data[PMP_LOAD_RANGE_BUFFER_SIZE];
51 
52 void ottf_load_store_fault_handler(uint32_t *exc_info) {
53  pmp_load_exception = true;
54 }
55 
56 static void pmp_configure_load_tor(void) {
57  uintptr_t load_range_start =
58  (uintptr_t)&pmp_load_test_data[PMP_LOAD_RANGE_BOTTOM_OFFSET];
59 
60  // Non-inclusive
61  uintptr_t load_range_end =
62  (uintptr_t)&pmp_load_test_data[PMP_LOAD_RANGE_SIZE];
63 
64  pmp_region_config_t config = {
65  .lock = kPmpRegionLockLocked,
66  .permissions = kPmpRegionPermissionsNone,
67  };
68 
69  pmp_region_configure_result_t result = pmp_region_configure_tor(
70  PMP_LOAD_REGION_ID, config, load_range_start, load_range_end);
71  CHECK(result == kPmpRegionConfigureOk,
72  "Load configuration failed, error code = %d", result);
73 }
74 
75 OTTF_DEFINE_TEST_CONFIG();
76 
77 bool test_main(void) {
78  // Check that `PMP_LOAD_REGION_ID-1` and `PMP_LOAD_REGION_ID` regions are not
79  // already used.
80  for (pmp_region_index_t region = PMP_LOAD_REGION_ID - 1;
81  region <= PMP_LOAD_REGION_ID; region++) {
82  bool configured;
83  pmp_region_configure_result_t result =
84  pmp_region_is_configured(region, &configured);
85  CHECK(result == kPmpRegionConfigureOk,
86  "PMP region %d cfg read failed, error code = %d", region, result);
87  CHECK(!configured, "PMP region %d is already configured", region);
88  }
89 
90  pmp_load_exception = false;
91  char load = pmp_load_test_data[PMP_LOAD_RANGE_BOTTOM_OFFSET];
92  CHECK(!pmp_load_exception, "Load access violation before PMP configuration");
93 
94  pmp_configure_load_tor();
95 
96  pmp_load_exception = false;
97  load = pmp_load_test_data[PMP_LOAD_RANGE_BOTTOM_OFFSET];
98  CHECK(pmp_load_exception,
99  "No load access violation on the bottom of the range load");
100 
101  pmp_load_exception = false;
102  load = pmp_load_test_data[PMP_LOAD_RANGE_TOP_OFFSET];
103  CHECK(pmp_load_exception,
104  "No load access violation on the top of the range load");
105 
106  pmp_load_exception = false;
107  load = pmp_load_test_data[PMP_LOAD_RANGE_TOP_OFFSET + 1];
108  CHECK(!pmp_load_exception, "Load access violation on top of the range + 1");
109 
110  (void)load;
111 
112  return true;
113 }