Skip to content

Commit 7567ba0

Browse files
committed
tests: riscv: Add uint test for PMP memattr configuration
Introduce a new test suite to validate the RISC-V Physical Memory Protection (PMP) settings configured via the Zephyr Device Tree 'zephyr,memory-attr' property. The test case `test_pmp_devicetree_memattr_config` reads the actual PMP configuration (pmpcfg) and address (pmpaddr) Control and Status Registers (CSRs) using the helper functions `z_riscv_pmp_read_config` and `z_riscv_pmp_read_addr`. It then compares the first three PMP entries against a set of hardcoded expected values. These expected values are derived from the memory regions defined with `zephyr,memory-attr` in the Device Tree for the specific board or test setup. This ensures that the PMP hardware is programmed correctly based on the Device Tree definitions. Signed-off-by: Firas Sammoura <[email protected]>
1 parent 6c1b227 commit 7567ba0

File tree

6 files changed

+144
-2
lines changed

6 files changed

+144
-2
lines changed

arch/riscv/core/pmp.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ static void print_pmp_entries(unsigned int pmp_start, unsigned int pmp_end,
113113
* @param pmp_cfg Pointer to the array where the CSR contents will be stored.
114114
* @param pmp_cfg_size The size of the pmp_cfg array, measured in unsigned long entries.
115115
*/
116-
static inline void z_riscv_pmp_read_config(unsigned long *pmp_cfg, size_t pmp_cfg_size)
116+
IF_DISABLED(CONFIG_ZTEST, (static inline)) void z_riscv_pmp_read_config(unsigned long *pmp_cfg,
117+
size_t pmp_cfg_size)
117118
{
118119
__ASSERT(pmp_cfg_size == (size_t)(CONFIG_PMP_SLOTS / PMPCFG_STRIDE),
119120
"Invalid PMP config array size");
@@ -179,7 +180,8 @@ static inline void z_riscv_pmp_write_config(unsigned long *pmp_cfg, size_t pmp_c
179180
* @param pmp_addr Pointer to the array where the CSR contents will be stored.
180181
* @param pmp_addr_size The size of the pmp_addr array, measured in unsigned long entries.
181182
*/
182-
static inline void z_riscv_pmp_read_addr(unsigned long *pmp_addr, size_t pmp_addr_size)
183+
IF_DISABLED(CONFIG_ZTEST, (static inline)) void z_riscv_pmp_read_addr(unsigned long *pmp_addr,
184+
size_t pmp_addr_size)
183185
{
184186
__ASSERT(pmp_addr_size == (size_t)(CONFIG_PMP_SLOTS), "PMP address array size mismatch");
185187

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
5+
project(riscv_pmp)
6+
7+
FILE(GLOB app_sources src/*.c)
8+
target_sources(app PRIVATE ${app_sources})
9+
10+
target_include_directories(app PRIVATE
11+
${ZEPHYR_BASE}/kernel/include
12+
${ZEPHYR_BASE}/arch/${ARCH}/include
13+
)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) 2025 Google LLC
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/dt-bindings/memory-attr/memory-attr-riscv.h>
8+
9+
/ {
10+
memattr_region1: memattr_region1@80000000 {
11+
compatible = "zephyr,memory-region";
12+
reg = <0x80000000 0x20000>;
13+
zephyr,memory-region = "MEMATTR_REGION1";
14+
zephyr,memory-attr = <(DT_MEM_RISCV_TYPE_IO_R | \
15+
DT_MEM_RISCV_TYPE_IO_W | DT_MEM_RISCV_TYPE_IO_X)>;
16+
};
17+
18+
memattr_region2: memattr_region2@80000000 {
19+
compatible = "zephyr,memory-region";
20+
reg = <0x80000000 0x30000>;
21+
zephyr,memory-region = "MEMATTR_REGION2";
22+
zephyr,memory-attr = <(DT_MEM_RISCV_TYPE_IO_R | \
23+
DT_MEM_RISCV_TYPE_IO_W | DT_MEM_RISCV_TYPE_IO_X)>;
24+
};
25+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CONFIG_ZTEST=y
2+
CONFIG_MULTITHREADING=y
3+
CONFIG_MEM_ATTR=y
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright (c) 2025 Google LLC
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <kernel_internal.h>
8+
#include <zephyr/mem_mgmt/mem_attr.h>
9+
#include <zephyr/tc_util.h>
10+
#include <zephyr/ztest.h>
11+
12+
void z_riscv_pmp_read_config(unsigned long *pmp_cfg, size_t pmp_cfg_size);
13+
void z_riscv_pmp_read_addr(unsigned long *pmp_addr, size_t pmp_addr_size);
14+
15+
/**
16+
* @brief Verifies the RISC-V PMP entries configured via Device Tree (zephyr,memattr).
17+
*
18+
* @details Reads the PMP configuration (pmpcfg) and address (pmpaddr) registers
19+
* and asserts that the entries programmed by the CONFIG_MEM_ATTR process match
20+
* the expected values for the Device Tree-defined memory regions.
21+
*/
22+
ZTEST(riscv_pmp_memattr_entries, test_pmp_devicetree_memattr_config)
23+
{
24+
const size_t num_pmpcfg_regs = CONFIG_PMP_SLOTS / sizeof(unsigned long);
25+
const size_t num_pmpaddr_regs = CONFIG_PMP_SLOTS;
26+
27+
unsigned long current_pmpcfg_regs[num_pmpcfg_regs];
28+
unsigned long current_pmpaddr_regs[num_pmpaddr_regs];
29+
30+
/* Read the current PMP configuration from the control registers */
31+
z_riscv_pmp_read_config(current_pmpcfg_regs, num_pmpcfg_regs);
32+
z_riscv_pmp_read_addr(current_pmpaddr_regs, num_pmpaddr_regs);
33+
34+
const uint8_t *const current_pmp_cfg_entries = (const uint8_t *)current_pmpcfg_regs;
35+
36+
const unsigned long expected_pmp_addr[3] = {0x20003fff, 0x20000000, 0x2000c000};
37+
const uint8_t expected_pmp_cfg_entries[3] = {0x1f, 0x00, 0x0f};
38+
39+
size_t found_idx = -1;
40+
bool found_sequence = false;
41+
const size_t expected_len = ARRAY_SIZE(expected_pmp_addr);
42+
43+
for (size_t i = 0; i <= CONFIG_PMP_SLOTS - expected_len; ++i) {
44+
if (memcmp(&current_pmpaddr_regs[i], expected_pmp_addr,
45+
expected_len * sizeof(unsigned long)) == 0) {
46+
47+
if (memcmp(&current_pmp_cfg_entries[i], expected_pmp_cfg_entries,
48+
expected_len * sizeof(uint8_t)) == 0) {
49+
found_sequence = true;
50+
found_idx = i;
51+
break;
52+
}
53+
}
54+
}
55+
56+
zassert_true(found_sequence,
57+
"Expected PMP sequence (Addrs: 0x%lx, Cfg: 0x%x, ...) was not found in any "
58+
"slot. Last checked slot: %zu",
59+
expected_pmp_addr[0], expected_pmp_cfg_entries[0], found_idx);
60+
}
61+
62+
ZTEST(riscv_pmp_memattr_entries, test_dt_pmp_perm_conversion)
63+
{
64+
uint8_t result;
65+
66+
result = DT_MEM_RISCV_TO_PMP_PERM(0);
67+
zassert_equal(result, 0, "Expected 0, got 0x%x", result);
68+
69+
result = DT_MEM_RISCV_TO_PMP_PERM(DT_MEM_RISCV_TYPE_IO_R);
70+
zassert_equal(result, PMP_R, "Expected PMP_R (0x%x), got 0x%x", PMP_R, result);
71+
72+
result = DT_MEM_RISCV_TO_PMP_PERM(DT_MEM_RISCV_TYPE_IO_W);
73+
zassert_equal(result, PMP_W, "Expected PMP_W (0x%x), got 0x%x", PMP_W, result);
74+
75+
result = DT_MEM_RISCV_TO_PMP_PERM(DT_MEM_RISCV_TYPE_IO_X);
76+
zassert_equal(result, PMP_X, "Expected PMP_X (0x%x), got 0x%x", PMP_X, result);
77+
78+
result = DT_MEM_RISCV_TO_PMP_PERM(DT_MEM_RISCV_TYPE_IO_R | DT_MEM_RISCV_TYPE_IO_W);
79+
zassert_equal(result, PMP_R | PMP_W, "Expected R|W (0x%x), got 0x%x", PMP_R | PMP_W,
80+
result);
81+
82+
result = DT_MEM_RISCV_TO_PMP_PERM(DT_MEM_RISCV_TYPE_IO_R | DT_MEM_RISCV_TYPE_IO_W |
83+
DT_MEM_RISCV_TYPE_IO_X);
84+
zassert_equal(result, PMP_R | PMP_W | PMP_X, "Expected R|W|X (0x%x), got 0x%x",
85+
PMP_R | PMP_W | PMP_X, result);
86+
}
87+
88+
ZTEST_SUITE(riscv_pmp_memattr_entries, NULL, NULL, NULL, NULL, NULL);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
common:
2+
platform_allow:
3+
- qemu_riscv32
4+
- qemu_riscv32e
5+
- qemu_riscv64
6+
filter: CONFIG_RISCV_PMP
7+
8+
tests:
9+
arch.riscv.pmp.memattr.entries:
10+
extra_args:
11+
DTC_OVERLAY_FILE="memattr_mapping.overlay"

0 commit comments

Comments
 (0)