|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | #include "sw/device/lib/base/csr.h" | 
|  | #include "sw/device/lib/handler.h" | 
|  | #include "sw/device/lib/irq.h" | 
|  | #include "sw/device/lib/runtime/hart.h" | 
|  | #include "sw/device/lib/runtime/pmp.h" | 
|  | #include "sw/device/lib/testing/check.h" | 
|  | #include "sw/device/lib/testing/test_main.h" | 
|  | #include "sw/device/lib/testing/test_status.h" | 
|  |  | 
|  | #define PMP_LOAD_REGION_ID 0 | 
|  |  | 
|  | #define PMP_LOAD_RANGE_BUFFER_SIZE 2048 | 
|  | #define PMP_LOAD_RANGE_SIZE 1024 | 
|  | #define PMP_LOAD_RANGE_BOTTOM_OFFSET 0 | 
|  | #define PMP_LOAD_RANGE_TOP_OFFSET 1023 | 
|  |  | 
|  | // These flags are used in the test routine to verify that a corresponding | 
|  | // interrupt has elapsed, and has been serviced. These are declared as volatile | 
|  | // since they are referenced in the ISR routine as well as in the main program | 
|  | // flow. | 
|  | static volatile bool pmp_load_exception; | 
|  |  | 
|  | /** | 
|  | * The buffer that is used for load/store access violation test. | 
|  | */ | 
|  | __attribute__((aligned(PMP_LOAD_RANGE_SIZE)))  // | 
|  | static volatile char pmp_load_store_test_data[PMP_LOAD_RANGE_BUFFER_SIZE]; | 
|  |  | 
|  | static uint32_t get_mepc(void) { | 
|  | uint32_t mepc; | 
|  | CSR_READ(CSR_REG_MEPC, &mepc); | 
|  | return mepc; | 
|  | } | 
|  |  | 
|  | static void set_mepc(uint32_t mepc) { CSR_WRITE(CSR_REG_MEPC, mepc); } | 
|  |  | 
|  | void handler_lsu_fault(void) { | 
|  | pmp_load_exception = true; | 
|  |  | 
|  | uint32_t mepc = get_mepc(); | 
|  | LOG_INFO("Load fault exception handler: mepc = 0x%x", mepc); | 
|  |  | 
|  | // Check if the two least significant bits of the instruction are b11 (0x3), | 
|  | // which means that the trapped instruction is not compressed | 
|  | // (32bits = 4bytes), otherwise (16bits = 2bytes). | 
|  | // | 
|  | // NOTE: | 
|  | // with RISC-V "c" (compressed instructions extension), 32bit | 
|  | // instructions can start on 16bit boundary. | 
|  | // | 
|  | // Please see: | 
|  | // "āCā Standard Extension for Compressed Instructions, Version 2.0", | 
|  | // section 16.1. | 
|  | uint32_t fault_instruction = *((uint32_t *)mepc); | 
|  | bool not_compressed = (fault_instruction & 0x3) == 0x3; | 
|  | mepc = not_compressed ? (mepc + 4) : (mepc + 2); | 
|  | set_mepc(mepc); | 
|  | } | 
|  |  | 
|  | static void pmp_configure_load_napot(void) { | 
|  | uintptr_t load_range_start = | 
|  | (uintptr_t)&pmp_load_store_test_data[PMP_LOAD_RANGE_BOTTOM_OFFSET]; | 
|  |  | 
|  | pmp_region_config_t config = { | 
|  | .lock = kPmpRegionLockLocked, | 
|  | .permissions = kPmpRegionPermissionsNone, | 
|  | }; | 
|  |  | 
|  | pmp_region_configure_napot_result_t result = pmp_region_configure_napot( | 
|  | PMP_LOAD_REGION_ID, config, load_range_start, PMP_LOAD_RANGE_SIZE); | 
|  | CHECK(result == kPmpRegionConfigureNapotOk, | 
|  | "Load configuration failed, error code = %d", result); | 
|  | } | 
|  |  | 
|  | const test_config_t kTestConfig = { | 
|  | .can_clobber_uart = false, | 
|  | }; | 
|  |  | 
|  | bool test_main(void) { | 
|  | pmp_load_exception = false; | 
|  | char load = pmp_load_store_test_data[PMP_LOAD_RANGE_BOTTOM_OFFSET]; | 
|  | CHECK(!pmp_load_exception, "Load access violation before PMP configuration"); | 
|  |  | 
|  | pmp_configure_load_napot(); | 
|  |  | 
|  | pmp_load_exception = false; | 
|  | load = pmp_load_store_test_data[PMP_LOAD_RANGE_BOTTOM_OFFSET]; | 
|  | CHECK(pmp_load_exception, | 
|  | "No load access violation on the bottom of the range load"); | 
|  |  | 
|  | pmp_load_exception = false; | 
|  | load = pmp_load_store_test_data[PMP_LOAD_RANGE_TOP_OFFSET]; | 
|  | CHECK(pmp_load_exception, | 
|  | "No load access violation on the top of the range load"); | 
|  |  | 
|  | pmp_load_exception = false; | 
|  | load = pmp_load_store_test_data[PMP_LOAD_RANGE_TOP_OFFSET + 1]; | 
|  | CHECK(!pmp_load_exception, "Load access violation on top of the range + 1"); | 
|  |  | 
|  | (void)load; | 
|  |  | 
|  | return true; | 
|  | } |