Skip to content

Commit

Permalink
bring back pmp test
Browse files Browse the repository at this point in the history
  • Loading branch information
wsipak committed Jan 8, 2025
1 parent 1c0179e commit 250d08b
Showing 1 changed file with 124 additions and 189 deletions.
313 changes: 124 additions & 189 deletions testbench/tests/pmp/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
#include "veer.h"
#include "fault.h"
#include "pmp.h"
#include "random_data.h"

#ifndef RV_SMEPMP
#define RV_SMEPMP 0
Expand Down Expand Up @@ -150,47 +149,6 @@ int trap_handler (const struct fault* fault) {
#define ADDR2PMP(x) ((((uint32_t)(x)) & 3) ? ((((uint32_t)(x)) >> 2) + 1) : \
(((uint32_t)(x)) >> 2))

uint32_t legalize_address(uint32_t address, uint32_t cfg) {
uint32_t area_end = ((uint32_t)&_area) + 0x40;

// if ((cfg & PMP_NA4) == PMP_NA4) {
// if ((address < (uint32_t)&_stack_hi && address > (uint32_t)&_stack_lo)
// |(address < (uint32_t)&_text && address > (uint32_t)&_text_end)
// |(address < (uint32_t)&_data && address > (uint32_t)&_data_end)
// |(address < (uint32_t)&_area && address > area_end)
// ) {
// address >>= 16;
// }
// } else if ((cfg & PMP_NAPOT) == PMP_NAPOT) {
// }
address >>= 8;
address &= ~(1<<3);
address |= 3;
return (address);
}

uint32_t legalize_config(uint32_t config) {
/* Leave only A, X and R fields as any combination of them is legal and
* does not influence PMPADDR access. Setting L would interfere with the
* test.
*/
// temporarily enforce NA4
if ((config & PMP_NAPOT) == PMP_NAPOT) {
config &= ~(PMP_NAPOT);
config |= PMP_NA4;
}
while((config & (PMP_NAPOT | PMP_NA4 | PMP_TOR) == 0) && config != 0) {
// if not enabled, shift right until it's a valid enabled region.
// if it's 0, give up.
config >>= 1;
}
config &= ~PMP_LOCK;
#if !(RV_SMEPMP)

#endif
return config;
}

// Set mstatus MPRV
#define set_mprv(x) { \
uint32_t mstatus; \
Expand Down Expand Up @@ -256,7 +214,6 @@ int main () {

// .......................................................................
struct pmp_entry_s entry;
struct pmp_entry_s random_entry;
int tid = 0;
int failed = 0;

Expand Down Expand Up @@ -423,167 +380,145 @@ int main () {
// ................................
// Do the tests

// use regions 6..15 for random data
int region_for_rand_data = 6;

for (size_t i=0; i<test_count; ++i) {
// In the first iteration, iterate also over random test data.
// In other iterations use only one random item.
for (int rand_test_i = (i==0 ? 0 : RANDOM_ITERATIONS-1);rand_test_i<RANDOM_ITERATIONS;++rand_test_i) {
uint32_t bits = test_cases[i];

uint32_t r = (bits & TST_R) ? PMP_R : 0;
uint32_t w = (bits & TST_W) ? PMP_W : 0;
uint32_t x = (bits & TST_X) ? PMP_X : 0;
uint32_t m = (bits & TST_M) != 0;
uint32_t mprv = (bits & TST_MPRV) != 0;
uint32_t mpp = (bits & TST_MPP ) != 0;

// Effective mode
uint32_t r_eff = (m && !(mprv && !mpp)) ? 1 : r;
uint32_t w_eff = (m && !(mprv && !mpp)) ? 1 : w;
uint32_t x_eff = (m) ? 1 : x; // MPRV affects load/store only

char pstr[4] = {
r ? 'R' : '-',
w ? 'W' : '-',
x ? 'X' : '-',
0x00
};

const char* mstr = m ? "Machine" : "User";
printf("%02d - %s mode (MPRV=%d, MPP=%d) %s from designated areas\n", tid++, mstr, mprv, mpp, pstr);

// Prepare data
const uint32_t* pattern = (i & 1) ? test_pattern_b : test_pattern_a;
const uint32_t* other = (i & 1) ? test_pattern_a : test_pattern_b;

memcpy((void*)test_area, other, sizeof(test_area));

// Configure .area1 access
printf(" configuring PMP...\n");
entry.addr = ADDR2PMP(&_area);
entry.addr = (entry.addr & 0xFFFFFC00) | 0x000001FF; // NAPOT, 2^12
entry.cfg = PMP_NAPOT | r | w | x;
pmp_entry_write(5, &entry);

// Disable the region previously used for random data.
random_entry.cfg = PMP_OFF;
random_entry.addr = 0;
pmp_entry_write(region_for_rand_data, &random_entry);

// Use the next region for random data (from the range 6..15)
region_for_rand_data = (region_for_rand_data < 15) ? region_for_rand_data+1 : 6;

printf(" using random data (%d)...\n", rand_test_i);
random_entry.cfg = legalize_config(rand_config[rand_test_i]);
random_entry.addr = legalize_address(rand_address[rand_test_i], random_entry.cfg);
pmp_entry_write(region_for_rand_data, &random_entry);

// Check
struct pmp_entry_s readback;
pmp_entry_read(5, &readback);

// An illegal PMP region configuration has been written and readback
// this is an error
//
// -W- and -WX combinations are reserved except for when Smepmp is
// present and mseccfg.MML=1. This test does not enable the latter
// so the combinations are not legal.
if (!pmp_is_cfg_legal(readback.cfg)) {
printf(" error, an illegal PMP configuration accepted by the core\n", readback.cfg);
failed++;
continue;
}
uint32_t bits = test_cases[i];

uint32_t r = (bits & TST_R) ? PMP_R : 0;
uint32_t w = (bits & TST_W) ? PMP_W : 0;
uint32_t x = (bits & TST_X) ? PMP_X : 0;
uint32_t m = (bits & TST_M) != 0;
uint32_t mprv = (bits & TST_MPRV) != 0;
uint32_t mpp = (bits & TST_MPP ) != 0;

// Effective mode
uint32_t r_eff = (m && !(mprv && !mpp)) ? 1 : r;
uint32_t w_eff = (m && !(mprv && !mpp)) ? 1 : w;
uint32_t x_eff = (m) ? 1 : x; // MPRV affects load/store only

char pstr[4] = {
r ? 'R' : '-',
w ? 'W' : '-',
x ? 'X' : '-',
0x00
};

const char* mstr = m ? "Machine" : "User";
printf("%02d - %s mode (MPRV=%d, MPP=%d) %s from designated areas\n", tid++, mstr, mprv, mpp, pstr);

// Prepare data
const uint32_t* pattern = (i & 1) ? test_pattern_b : test_pattern_a;
const uint32_t* other = (i & 1) ? test_pattern_a : test_pattern_b;

memcpy((void*)test_area, other, sizeof(test_area));

// Configure .area1 access
printf(" configuring PMP...\n");
entry.addr = ADDR2PMP(&_area);
entry.addr = (entry.addr & 0xFFFFFC00) | 0x000001FF; // NAPOT, 2^12
entry.cfg = PMP_NAPOT | r | w | x;
pmp_entry_write(5, &entry);

// R,W and X fields are WARL which means that the readback does not
// need to match what was written. In such a case skip the test but
// not mark it as an error.
if (readback.cfg != entry.cfg) {
continue;
}
// Check
struct pmp_entry_s readback;
pmp_entry_read(5, &readback);

// An illegal PMP region configuration has been written and readback
// this is an error
//
// -W- and -WX combinations are reserved except for when Smepmp is
// present and mseccfg.MML=1. This test does not enable the latter
// so the combinations are not legal.
if (!pmp_is_cfg_legal(readback.cfg)) {
printf(" error, an illegal PMP configuration accepted by the core\n", readback.cfg);
failed++;
continue;
}

int exc;
int cmp;
int any_fail = 0;

// Test writing. Write pattern from user mode and check if it was
// successfully written.
printf(" testing W...\n");
did_execute = 0;
exc = 0;
set_mpp(mpp);
set_mprv(mprv);
TRY { if (m) test_write(pattern); else ucall(test_write, pattern); }
CATCH { exc = 1; }
END_TRY;
set_mprv(0);

cmp = memcmp((void*)test_area, pattern, sizeof(test_area));
if (cmp) {
printf(" data mismatch\n");
} else {
printf(" data match\n");
}
// R,W and X fields are WARL which means that the readback does not
// need to match what was written. In such a case skip the test but
// not mark it as an error.
if (readback.cfg != entry.cfg) {
continue;
}

if (did_execute && ((!w_eff && exc && cmp) || (w_eff && !exc && !cmp))) {
printf(" pass\n");
} else {
printf(" fail\n");
any_fail = 1;
printf(" random data used:\n addr: 0x%x,\n cfg: 0x%x\n", rand_address[rand_test_i], rand_config[rand_test_i]);
return 0;
}
int exc;
int cmp;
int any_fail = 0;

// Test writing. Write pattern from user mode and check if it was
// successfully written.
printf(" testing W...\n");
did_execute = 0;
exc = 0;
set_mpp(mpp);
set_mprv(mprv);
TRY { if (m) test_write(pattern); else ucall(test_write, pattern); }
CATCH { exc = 1; }
END_TRY;
set_mprv(0);

// Test reading. Read area from user mode and compare against the
// pattern
printf(" testing R...\n");
cmp = memcmp((void*)test_area, pattern, sizeof(test_area));
if (cmp) {
printf(" data mismatch\n");
} else {
printf(" data match\n");
}

// Write pattern
if (!w_eff) {
memcpy((void*)test_area, pattern, sizeof(test_area));
}
if (did_execute && ((!w_eff && exc && cmp) || (w_eff && !exc && !cmp))) {
printf(" pass\n");
} else {
printf(" fail\n");
any_fail = 1;
}

// Test reading. Read area from user mode and compare against the
// pattern
printf(" testing R...\n");

// Write pattern
if (!w_eff) {
memcpy((void*)test_area, pattern, sizeof(test_area));
}

did_execute = 0;
exc = 0;
set_mpp(mpp);
set_mprv(mprv);
TRY { if (m) cmp = test_read(pattern); else cmp = ucall(test_read, pattern); }
CATCH { exc = 1; }
END_TRY;
set_mprv(0);

did_execute = 0;
exc = 0;
set_mpp(mpp);
set_mprv(mprv);
TRY { if (m) cmp = test_read(pattern); else cmp = ucall(test_read, pattern); }
CATCH { exc = 1; }
END_TRY;
set_mprv(0);
if (did_execute && ((!r_eff && exc) || (r_eff && !exc && !cmp))) {
printf(" pass\n");
} else {
printf(" fail\n");
any_fail = 1;
}

if (did_execute && ((!r_eff && exc) || (r_eff && !exc && !cmp))) {
// Call a function placed in the designated area
printf(" testing X...\n");
TRY {
if (m) test_exec(); else ucall(test_exec);
if (x_eff) {
printf(" pass\n");
} else {
printf(" fail\n");
any_fail = 1;
}

// Call a function placed in the designated area
printf(" testing X...\n");
TRY {
if (m) test_exec(); else ucall(test_exec);
if (x_eff) {
printf(" pass\n");
} else {
printf(" fail\n");
any_fail = 1;
}
}
CATCH {
if (x_eff) {
printf(" fail\n");
any_fail = 1;
} else {
printf(" pass\n");
}
}
CATCH {
if (x_eff) {
printf(" fail\n");
any_fail = 1;
} else {
printf(" pass\n");
}
END_TRY;

// Count fails
failed += any_fail;
}
END_TRY;

// Count fails
failed += any_fail;
}

// .......................................................................
Expand Down

0 comments on commit 250d08b

Please sign in to comment.