From ee199589c4208b710ea0688650f72d321d638379 Mon Sep 17 00:00:00 2001 From: Julian Scheffers Date: Wed, 26 Jul 2023 19:15:55 +0200 Subject: [PATCH 1/3] Write-protect ROM and FLASH, protect lower and upper 256MiB --- cpu/rv32imac/CMakeLists.txt | 1 + cpu/rv32imac/include/cpu/riscv_pmp.h | 368 ++++++++++++++++++ cpu/rv32imac/src/riscv_pmp.c | 281 +++++++++++++ include/memprotect.h | 16 + include/meta.h | 3 + port/esp32c6/CMakeLists.txt | 1 + .../include/port/hardware_allocation.h | 37 ++ port/esp32c6/include/port/memprotect.h | 7 + port/esp32c6/src/memprotect.c | 148 +++++++ src/main.c | 4 + 10 files changed, 866 insertions(+) create mode 100644 cpu/rv32imac/include/cpu/riscv_pmp.h create mode 100644 cpu/rv32imac/src/riscv_pmp.c create mode 100644 include/memprotect.h create mode 100644 port/esp32c6/include/port/memprotect.h create mode 100644 port/esp32c6/src/memprotect.c diff --git a/cpu/rv32imac/CMakeLists.txt b/cpu/rv32imac/CMakeLists.txt index 4a5d1b0..1396a12 100644 --- a/cpu/rv32imac/CMakeLists.txt +++ b/cpu/rv32imac/CMakeLists.txt @@ -11,6 +11,7 @@ target_sources(${target} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/isr.c ${CMAKE_CURRENT_LIST_DIR}/src/kernel_ctx.c ${CMAKE_CURRENT_LIST_DIR}/src/panic.c + ${CMAKE_CURRENT_LIST_DIR}/src/riscv_pmp.c ${CMAKE_CURRENT_LIST_DIR}/src/scheduler.c ) target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) diff --git a/cpu/rv32imac/include/cpu/riscv_pmp.h b/cpu/rv32imac/include/cpu/riscv_pmp.h new file mode 100644 index 0000000..dc07b81 --- /dev/null +++ b/cpu/rv32imac/include/cpu/riscv_pmp.h @@ -0,0 +1,368 @@ + +// SPDX-License-Identifier: MIT + +#pragma once + +// This file expects RISCV_PMP_REGION_COUNT to be defined by . + +#include "assertions.h" +#include "meta.h" +#include "port/memprotect.h" + +#include +#include + +static_assert( + RISCV_PMP_REGION_COUNT == 16 || RISCV_PMP_REGION_COUNT == 64, "RISC-V PMP region count must be either 16 or 64." +); + +#if __riscv_xlen == 32 + +#define RISCV_PMP_CFG_BITPOS_0 0 +#define RISCV_PMP_CFG_BITPOS_1 8 +#define RISCV_PMP_CFG_BITPOS_2 16 +#define RISCV_PMP_CFG_BITPOS_3 24 +#define RISCV_PMP_CFG_BITPOS_4 0 +#define RISCV_PMP_CFG_BITPOS_5 8 +#define RISCV_PMP_CFG_BITPOS_6 16 +#define RISCV_PMP_CFG_BITPOS_7 24 +#define RISCV_PMP_CFG_BITPOS_8 0 +#define RISCV_PMP_CFG_BITPOS_9 8 +#define RISCV_PMP_CFG_BITPOS_10 16 +#define RISCV_PMP_CFG_BITPOS_11 24 +#define RISCV_PMP_CFG_BITPOS_12 0 +#define RISCV_PMP_CFG_BITPOS_13 8 +#define RISCV_PMP_CFG_BITPOS_14 16 +#define RISCV_PMP_CFG_BITPOS_15 24 +#if RISCV_PMP_REGION_COUNT == 64 +#define RISCV_PMP_CFG_BITPOS_16 0 +#define RISCV_PMP_CFG_BITPOS_17 8 +#define RISCV_PMP_CFG_BITPOS_18 16 +#define RISCV_PMP_CFG_BITPOS_19 24 +#define RISCV_PMP_CFG_BITPOS_20 0 +#define RISCV_PMP_CFG_BITPOS_21 8 +#define RISCV_PMP_CFG_BITPOS_22 16 +#define RISCV_PMP_CFG_BITPOS_23 24 +#define RISCV_PMP_CFG_BITPOS_24 0 +#define RISCV_PMP_CFG_BITPOS_25 8 +#define RISCV_PMP_CFG_BITPOS_26 16 +#define RISCV_PMP_CFG_BITPOS_27 24 +#define RISCV_PMP_CFG_BITPOS_28 0 +#define RISCV_PMP_CFG_BITPOS_29 8 +#define RISCV_PMP_CFG_BITPOS_30 16 +#define RISCV_PMP_CFG_BITPOS_31 24 +#define RISCV_PMP_CFG_BITPOS_32 0 +#define RISCV_PMP_CFG_BITPOS_33 8 +#define RISCV_PMP_CFG_BITPOS_34 16 +#define RISCV_PMP_CFG_BITPOS_35 24 +#define RISCV_PMP_CFG_BITPOS_36 0 +#define RISCV_PMP_CFG_BITPOS_37 8 +#define RISCV_PMP_CFG_BITPOS_38 16 +#define RISCV_PMP_CFG_BITPOS_39 24 +#define RISCV_PMP_CFG_BITPOS_40 0 +#define RISCV_PMP_CFG_BITPOS_41 8 +#define RISCV_PMP_CFG_BITPOS_42 16 +#define RISCV_PMP_CFG_BITPOS_43 24 +#define RISCV_PMP_CFG_BITPOS_44 0 +#define RISCV_PMP_CFG_BITPOS_45 8 +#define RISCV_PMP_CFG_BITPOS_46 16 +#define RISCV_PMP_CFG_BITPOS_47 24 +#define RISCV_PMP_CFG_BITPOS_48 0 +#define RISCV_PMP_CFG_BITPOS_49 8 +#define RISCV_PMP_CFG_BITPOS_50 16 +#define RISCV_PMP_CFG_BITPOS_51 24 +#define RISCV_PMP_CFG_BITPOS_52 0 +#define RISCV_PMP_CFG_BITPOS_53 8 +#define RISCV_PMP_CFG_BITPOS_54 16 +#define RISCV_PMP_CFG_BITPOS_55 24 +#define RISCV_PMP_CFG_BITPOS_56 0 +#define RISCV_PMP_CFG_BITPOS_57 8 +#define RISCV_PMP_CFG_BITPOS_58 16 +#define RISCV_PMP_CFG_BITPOS_59 24 +#define RISCV_PMP_CFG_BITPOS_60 0 +#define RISCV_PMP_CFG_BITPOS_61 8 +#define RISCV_PMP_CFG_BITPOS_62 16 +#define RISCV_PMP_CFG_BITPOS_63 24 +#endif + +#define RISCV_PMP_CFG_CSR_0 "pmpcfg0" +#define RISCV_PMP_CFG_CSR_1 "pmpcfg0" +#define RISCV_PMP_CFG_CSR_2 "pmpcfg0" +#define RISCV_PMP_CFG_CSR_3 "pmpcfg0" +#define RISCV_PMP_CFG_CSR_4 "pmpcfg1" +#define RISCV_PMP_CFG_CSR_5 "pmpcfg1" +#define RISCV_PMP_CFG_CSR_6 "pmpcfg1" +#define RISCV_PMP_CFG_CSR_7 "pmpcfg1" +#define RISCV_PMP_CFG_CSR_8 "pmpcfg2" +#define RISCV_PMP_CFG_CSR_9 "pmpcfg2" +#define RISCV_PMP_CFG_CSR_10 "pmpcfg2" +#define RISCV_PMP_CFG_CSR_11 "pmpcfg2" +#define RISCV_PMP_CFG_CSR_12 "pmpcfg3" +#define RISCV_PMP_CFG_CSR_13 "pmpcfg3" +#define RISCV_PMP_CFG_CSR_14 "pmpcfg3" +#define RISCV_PMP_CFG_CSR_15 "pmpcfg3" +#if RISCV_PMP_REGION_COUNT == 64 +#define RISCV_PMP_CFG_CSR_16 "pmpcfg4" +#define RISCV_PMP_CFG_CSR_17 "pmpcfg4" +#define RISCV_PMP_CFG_CSR_18 "pmpcfg4" +#define RISCV_PMP_CFG_CSR_19 "pmpcfg4" +#define RISCV_PMP_CFG_CSR_20 "pmpcfg5" +#define RISCV_PMP_CFG_CSR_21 "pmpcfg5" +#define RISCV_PMP_CFG_CSR_22 "pmpcfg5" +#define RISCV_PMP_CFG_CSR_23 "pmpcfg5" +#define RISCV_PMP_CFG_CSR_24 "pmpcfg6" +#define RISCV_PMP_CFG_CSR_25 "pmpcfg6" +#define RISCV_PMP_CFG_CSR_26 "pmpcfg6" +#define RISCV_PMP_CFG_CSR_27 "pmpcfg6" +#define RISCV_PMP_CFG_CSR_28 "pmpcfg7" +#define RISCV_PMP_CFG_CSR_29 "pmpcfg7" +#define RISCV_PMP_CFG_CSR_30 "pmpcfg7" +#define RISCV_PMP_CFG_CSR_31 "pmpcfg7" +#define RISCV_PMP_CFG_CSR_32 "pmpcfg8" +#define RISCV_PMP_CFG_CSR_33 "pmpcfg8" +#define RISCV_PMP_CFG_CSR_34 "pmpcfg8" +#define RISCV_PMP_CFG_CSR_35 "pmpcfg8" +#define RISCV_PMP_CFG_CSR_36 "pmpcfg9" +#define RISCV_PMP_CFG_CSR_37 "pmpcfg9" +#define RISCV_PMP_CFG_CSR_38 "pmpcfg9" +#define RISCV_PMP_CFG_CSR_39 "pmpcfg9" +#define RISCV_PMP_CFG_CSR_40 "pmpcfg10" +#define RISCV_PMP_CFG_CSR_41 "pmpcfg10" +#define RISCV_PMP_CFG_CSR_42 "pmpcfg10" +#define RISCV_PMP_CFG_CSR_43 "pmpcfg10" +#define RISCV_PMP_CFG_CSR_44 "pmpcfg11" +#define RISCV_PMP_CFG_CSR_45 "pmpcfg11" +#define RISCV_PMP_CFG_CSR_46 "pmpcfg11" +#define RISCV_PMP_CFG_CSR_47 "pmpcfg11" +#define RISCV_PMP_CFG_CSR_48 "pmpcfg12" +#define RISCV_PMP_CFG_CSR_49 "pmpcfg12" +#define RISCV_PMP_CFG_CSR_50 "pmpcfg12" +#define RISCV_PMP_CFG_CSR_51 "pmpcfg12" +#define RISCV_PMP_CFG_CSR_52 "pmpcfg13" +#define RISCV_PMP_CFG_CSR_53 "pmpcfg13" +#define RISCV_PMP_CFG_CSR_54 "pmpcfg13" +#define RISCV_PMP_CFG_CSR_55 "pmpcfg13" +#define RISCV_PMP_CFG_CSR_56 "pmpcfg14" +#define RISCV_PMP_CFG_CSR_57 "pmpcfg14" +#define RISCV_PMP_CFG_CSR_58 "pmpcfg14" +#define RISCV_PMP_CFG_CSR_59 "pmpcfg14" +#define RISCV_PMP_CFG_CSR_60 "pmpcfg15" +#define RISCV_PMP_CFG_CSR_61 "pmpcfg15" +#define RISCV_PMP_CFG_CSR_62 "pmpcfg15" +#define RISCV_PMP_CFG_CSR_63 "pmpcfg15" +#endif + +#elif __riscv_xlen == 64 + +#define RISCV_PMP_CFG_BITPOS_0 0 +#define RISCV_PMP_CFG_BITPOS_1 8 +#define RISCV_PMP_CFG_BITPOS_2 16 +#define RISCV_PMP_CFG_BITPOS_3 24 +#define RISCV_PMP_CFG_BITPOS_4 32 +#define RISCV_PMP_CFG_BITPOS_5 40 +#define RISCV_PMP_CFG_BITPOS_6 48 +#define RISCV_PMP_CFG_BITPOS_7 56 +#define RISCV_PMP_CFG_BITPOS_8 0 +#define RISCV_PMP_CFG_BITPOS_9 8 +#define RISCV_PMP_CFG_BITPOS_10 16 +#define RISCV_PMP_CFG_BITPOS_11 24 +#define RISCV_PMP_CFG_BITPOS_12 32 +#define RISCV_PMP_CFG_BITPOS_13 40 +#define RISCV_PMP_CFG_BITPOS_14 48 +#define RISCV_PMP_CFG_BITPOS_15 56 +#if RISCV_PMP_REGION_COUNT == 64 +#define RISCV_PMP_CFG_BITPOS_16 0 +#define RISCV_PMP_CFG_BITPOS_17 8 +#define RISCV_PMP_CFG_BITPOS_18 16 +#define RISCV_PMP_CFG_BITPOS_19 24 +#define RISCV_PMP_CFG_BITPOS_20 32 +#define RISCV_PMP_CFG_BITPOS_21 40 +#define RISCV_PMP_CFG_BITPOS_22 48 +#define RISCV_PMP_CFG_BITPOS_23 56 +#define RISCV_PMP_CFG_BITPOS_24 0 +#define RISCV_PMP_CFG_BITPOS_25 8 +#define RISCV_PMP_CFG_BITPOS_26 16 +#define RISCV_PMP_CFG_BITPOS_27 24 +#define RISCV_PMP_CFG_BITPOS_28 32 +#define RISCV_PMP_CFG_BITPOS_29 40 +#define RISCV_PMP_CFG_BITPOS_30 48 +#define RISCV_PMP_CFG_BITPOS_31 56 +#define RISCV_PMP_CFG_BITPOS_32 0 +#define RISCV_PMP_CFG_BITPOS_33 8 +#define RISCV_PMP_CFG_BITPOS_34 16 +#define RISCV_PMP_CFG_BITPOS_35 24 +#define RISCV_PMP_CFG_BITPOS_36 32 +#define RISCV_PMP_CFG_BITPOS_37 40 +#define RISCV_PMP_CFG_BITPOS_38 48 +#define RISCV_PMP_CFG_BITPOS_39 56 +#define RISCV_PMP_CFG_BITPOS_40 0 +#define RISCV_PMP_CFG_BITPOS_41 8 +#define RISCV_PMP_CFG_BITPOS_42 16 +#define RISCV_PMP_CFG_BITPOS_43 24 +#define RISCV_PMP_CFG_BITPOS_44 32 +#define RISCV_PMP_CFG_BITPOS_45 40 +#define RISCV_PMP_CFG_BITPOS_46 48 +#define RISCV_PMP_CFG_BITPOS_47 56 +#define RISCV_PMP_CFG_BITPOS_48 0 +#define RISCV_PMP_CFG_BITPOS_49 8 +#define RISCV_PMP_CFG_BITPOS_50 16 +#define RISCV_PMP_CFG_BITPOS_51 24 +#define RISCV_PMP_CFG_BITPOS_52 32 +#define RISCV_PMP_CFG_BITPOS_53 40 +#define RISCV_PMP_CFG_BITPOS_54 48 +#define RISCV_PMP_CFG_BITPOS_55 56 +#define RISCV_PMP_CFG_BITPOS_56 0 +#define RISCV_PMP_CFG_BITPOS_57 8 +#define RISCV_PMP_CFG_BITPOS_58 16 +#define RISCV_PMP_CFG_BITPOS_59 24 +#define RISCV_PMP_CFG_BITPOS_60 32 +#define RISCV_PMP_CFG_BITPOS_61 40 +#define RISCV_PMP_CFG_BITPOS_62 48 +#define RISCV_PMP_CFG_BITPOS_63 56 +#endif + +#define RISCV_PMP_CFG_CSR_0 "pmpcfg0" +#define RISCV_PMP_CFG_CSR_1 "pmpcfg0" +#define RISCV_PMP_CFG_CSR_2 "pmpcfg0" +#define RISCV_PMP_CFG_CSR_3 "pmpcfg0" +#define RISCV_PMP_CFG_CSR_4 "pmpcfg0" +#define RISCV_PMP_CFG_CSR_5 "pmpcfg0" +#define RISCV_PMP_CFG_CSR_6 "pmpcfg0" +#define RISCV_PMP_CFG_CSR_7 "pmpcfg0" +#define RISCV_PMP_CFG_CSR_8 "pmpcfg2" +#define RISCV_PMP_CFG_CSR_9 "pmpcfg2" +#define RISCV_PMP_CFG_CSR_10 "pmpcfg2" +#define RISCV_PMP_CFG_CSR_11 "pmpcfg2" +#define RISCV_PMP_CFG_CSR_12 "pmpcfg2" +#define RISCV_PMP_CFG_CSR_13 "pmpcfg2" +#define RISCV_PMP_CFG_CSR_14 "pmpcfg2" +#define RISCV_PMP_CFG_CSR_15 "pmpcfg2" +#if RISCV_PMP_REGION_COUNT == 64 +#define RISCV_PMP_CFG_CSR_16 "pmpcfg4" +#define RISCV_PMP_CFG_CSR_17 "pmpcfg4" +#define RISCV_PMP_CFG_CSR_18 "pmpcfg4" +#define RISCV_PMP_CFG_CSR_19 "pmpcfg4" +#define RISCV_PMP_CFG_CSR_20 "pmpcfg4" +#define RISCV_PMP_CFG_CSR_21 "pmpcfg4" +#define RISCV_PMP_CFG_CSR_22 "pmpcfg4" +#define RISCV_PMP_CFG_CSR_23 "pmpcfg4" +#define RISCV_PMP_CFG_CSR_24 "pmpcfg6" +#define RISCV_PMP_CFG_CSR_25 "pmpcfg6" +#define RISCV_PMP_CFG_CSR_26 "pmpcfg6" +#define RISCV_PMP_CFG_CSR_27 "pmpcfg6" +#define RISCV_PMP_CFG_CSR_28 "pmpcfg6" +#define RISCV_PMP_CFG_CSR_29 "pmpcfg6" +#define RISCV_PMP_CFG_CSR_30 "pmpcfg6" +#define RISCV_PMP_CFG_CSR_31 "pmpcfg6" +#define RISCV_PMP_CFG_CSR_32 "pmpcfg8" +#define RISCV_PMP_CFG_CSR_33 "pmpcfg8" +#define RISCV_PMP_CFG_CSR_34 "pmpcfg8" +#define RISCV_PMP_CFG_CSR_35 "pmpcfg8" +#define RISCV_PMP_CFG_CSR_36 "pmpcfg8" +#define RISCV_PMP_CFG_CSR_37 "pmpcfg8" +#define RISCV_PMP_CFG_CSR_38 "pmpcfg8" +#define RISCV_PMP_CFG_CSR_39 "pmpcfg8" +#define RISCV_PMP_CFG_CSR_40 "pmpcfg10" +#define RISCV_PMP_CFG_CSR_41 "pmpcfg10" +#define RISCV_PMP_CFG_CSR_42 "pmpcfg10" +#define RISCV_PMP_CFG_CSR_43 "pmpcfg10" +#define RISCV_PMP_CFG_CSR_44 "pmpcfg10" +#define RISCV_PMP_CFG_CSR_45 "pmpcfg10" +#define RISCV_PMP_CFG_CSR_46 "pmpcfg10" +#define RISCV_PMP_CFG_CSR_47 "pmpcfg10" +#define RISCV_PMP_CFG_CSR_48 "pmpcfg12" +#define RISCV_PMP_CFG_CSR_49 "pmpcfg12" +#define RISCV_PMP_CFG_CSR_50 "pmpcfg12" +#define RISCV_PMP_CFG_CSR_51 "pmpcfg12" +#define RISCV_PMP_CFG_CSR_52 "pmpcfg12" +#define RISCV_PMP_CFG_CSR_53 "pmpcfg12" +#define RISCV_PMP_CFG_CSR_54 "pmpcfg12" +#define RISCV_PMP_CFG_CSR_55 "pmpcfg12" +#define RISCV_PMP_CFG_CSR_56 "pmpcfg14" +#define RISCV_PMP_CFG_CSR_57 "pmpcfg14" +#define RISCV_PMP_CFG_CSR_58 "pmpcfg14" +#define RISCV_PMP_CFG_CSR_59 "pmpcfg14" +#define RISCV_PMP_CFG_CSR_60 "pmpcfg14" +#define RISCV_PMP_CFG_CSR_61 "pmpcfg14" +#define RISCV_PMP_CFG_CSR_62 "pmpcfg14" +#define RISCV_PMP_CFG_CSR_63 "pmpcfg14" +#endif + +#endif + + + +// RISC-V PMP addressing mode. +typedef enum { + // Disabled. + RISCV_PMPCFG_OFF = 0, + // Top of range. + RISCV_PMPCFG_TOR = 1, + // Naturally aligned 4-byte region. + RISCV_PMPCFG_NA4 = 2, + // Naturally aligned power-of-two region. + RISCV_PMPCFG_NAPOT = 3, +} riscv_pmpcfg_addr_t; + +// RISC-V PMP config entry. +typedef union { + struct { + // Read permission granted. + uint8_t read : 1; + // Write permission granted. + uint8_t write : 1; + // Execute permission granted. + uint8_t exec : 1; + + // Address matching mode. + uint8_t addr_match_mode : 2; + // Reserved; set to 0. + uint8_t _reserved : 2; + // Lock and apply to M-mode accesses. + uint8_t lock : 1; + }; + uint8_t value; +} riscv_pmpcfg_t; + + + +// Initialise memory protection driver. +void riscv_pmp_init(); + +// Read all raw PMP configurations. +void riscv_pmpcfg_read_all(riscv_pmpcfg_t cfg_out[RISCV_PMP_REGION_COUNT]); +// Read all raw PMP addresses. +void riscv_pmpaddr_read_all(size_t addr_out[RISCV_PMP_REGION_COUNT]); +// Write all raw PMP configurations. +void riscv_pmpcfg_write_all(riscv_pmpcfg_t const cfg_in[RISCV_PMP_REGION_COUNT]); +// Write all raw PMP addresses. +void riscv_pmpaddr_write_all(size_t const addr_in[RISCV_PMP_REGION_COUNT]); + +// Compute NAPOT address value. +// Assumes `base` is aligned to `size` bytes and that `size` is a power of two >= 8. +static inline size_t riscv_pmpaddr_calc_napot(size_t base, size_t size) PURE; +static inline size_t riscv_pmpaddr_calc_napot(size_t base, size_t size) { + return (base >> 2) | ((size >> 3) - 1); +} + +// Clear bits of a PMPCFG by index. +#define riscv_pmpcfg_clear(index) \ + asm volatile("csrc " concat_keywords(RISCV_PMP_CFG_CSR_, index) ", %0" ::"r"( \ + 255ul << concat_keywords(RISCV_PMP_CFG_BITPOS_, index) \ + )) + +// Set bits of a PMPCFG by index. +#define riscv_pmpcfg_set(index, config) \ + asm volatile("csrs " concat_keywords(RISCV_PMP_CFG_CSR_, index) ", %0" ::"r"( \ + (unsigned long)(config).value << (unsigned long)concat_keywords(RISCV_PMP_CFG_BITPOS_, index) \ + )) + +// Write a PMPCFG by index. +#define riscv_pmpcfg_write(index, config) \ + do { \ + riscv_pmpcfg_clear(index); \ + riscv_pmpcfg_set(index, config); \ + } while (0) + +// Write a PMPADDR by index. +#define riscv_pmpaddr_write(index, addr) asm volatile("csrw pmpaddr" convert_macro_to_string(index) ", %0" ::"r"(addr)) diff --git a/cpu/rv32imac/src/riscv_pmp.c b/cpu/rv32imac/src/riscv_pmp.c new file mode 100644 index 0000000..d2eaa3e --- /dev/null +++ b/cpu/rv32imac/src/riscv_pmp.c @@ -0,0 +1,281 @@ + +// SPDX-License-Identifier: MIT + +#include "cpu/riscv_pmp.h" + +#include "cpu/panic.h" +#include "log.h" + +// Initialise memory protection driver. +void riscv_pmp_init() { + // Make sure we're the first to touch PMP so all of it is in our control; + // Check that none of the protection regions are currently locked. + riscv_pmpcfg_t cfg[RISCV_PMP_REGION_COUNT]; + riscv_pmpcfg_read_all(cfg); + + bool lock = false; + for (int i = 0; i < RISCV_PMP_REGION_COUNT; i++) { + if (cfg[i].lock) { + logkf(LOG_FATAL, "RISC-V pmp%{d}cfg is locked!"); + } + } + + if (lock) { + panic_abort(); + } + + // Zero out PMP config, effectively disabling it. +#if __riscv_xlen == 32 + asm volatile("csrw pmpcfg0, x0"); + asm volatile("csrw pmpcfg1, x0"); + asm volatile("csrw pmpcfg2, x0"); + asm volatile("csrw pmpcfg3, x0"); +#endif +#if __riscv_xlen == 32 && RISCV_PMP_REGION_COUNT == 64 + asm volatile("csrw pmpcfg4, x0"); + asm volatile("csrw pmpcfg5, x0"); + asm volatile("csrw pmpcfg6, x0"); + asm volatile("csrw pmpcfg7, x0"); + asm volatile("csrw pmpcfg8, x0"); + asm volatile("csrw pmpcfg9, x0"); + asm volatile("csrw pmpcfg10, x0"); + asm volatile("csrw pmpcfg11, x0"); + asm volatile("csrw pmpcfg12, x0"); + asm volatile("csrw pmpcfg13, x0"); + asm volatile("csrw pmpcfg14, x0"); + asm volatile("csrw pmpcfg15, x0"); +#endif + +#if __riscv_xlen == 64 + asm volatile("csrw pmpcfg0, x0"); + asm volatile("csrw pmpcfg2, x0"); +#endif +#if __riscv_xlen == 64 && RISCV_PMP_REGION_COUNT == 64 + asm volatile("csrw pmpcfg4, x0"); + asm volatile("csrw pmpcfg6, x0"); + asm volatile("csrw pmpcfg8, x0"); + asm volatile("csrw pmpcfg10, x0"); + asm volatile("csrw pmpcfg12, x0"); + asm volatile("csrw pmpcfg14, x0"); +#endif +} + + + +// Read all raw PMP configurations. +void riscv_pmpcfg_read_all(riscv_pmpcfg_t cfg_out[RISCV_PMP_REGION_COUNT]) { + long *word_out = (void *)cfg_out; + +#if __riscv_xlen == 32 + asm volatile("csrr %0, pmpcfg0" : "=r"(word_out[0])); + asm volatile("csrr %0, pmpcfg1" : "=r"(word_out[1])); + asm volatile("csrr %0, pmpcfg2" : "=r"(word_out[2])); + asm volatile("csrr %0, pmpcfg3" : "=r"(word_out[3])); +#endif +#if __riscv_xlen == 32 && RISCV_PMP_REGION_COUNT == 64 + asm volatile("csrr %0, pmpcfg4" : "=r"(word_out[4])); + asm volatile("csrr %0, pmpcfg5" : "=r"(word_out[5])); + asm volatile("csrr %0, pmpcfg6" : "=r"(word_out[6])); + asm volatile("csrr %0, pmpcfg7" : "=r"(word_out[7])); + asm volatile("csrr %0, pmpcfg8" : "=r"(word_out[8])); + asm volatile("csrr %0, pmpcfg9" : "=r"(word_out[9])); + asm volatile("csrr %0, pmpcfg10" : "=r"(word_out[10])); + asm volatile("csrr %0, pmpcfg11" : "=r"(word_out[11])); + asm volatile("csrr %0, pmpcfg12" : "=r"(word_out[12])); + asm volatile("csrr %0, pmpcfg13" : "=r"(word_out[13])); + asm volatile("csrr %0, pmpcfg14" : "=r"(word_out[14])); + asm volatile("csrr %0, pmpcfg15" : "=r"(word_out[15])); +#endif + +#if __riscv_xlen == 64 + asm volatile("csrr %0, pmpcfg0" : "=r"(word_out[0])); + asm volatile("csrr %0, pmpcfg2" : "=r"(word_out[1])); +#endif +#if __riscv_xlen == 64 && RISCV_PMP_REGION_COUNT == 64 + asm volatile("csrr %0, pmpcfg4" : "=r"(word_out[2])); + asm volatile("csrr %0, pmpcfg6" : "=r"(word_out[3])); + asm volatile("csrr %0, pmpcfg8" : "=r"(word_out[4])); + asm volatile("csrr %0, pmpcfg10" : "=r"(word_out[5])); + asm volatile("csrr %0, pmpcfg12" : "=r"(word_out[6])); + asm volatile("csrr %0, pmpcfg14" : "=r"(word_out[7])); +#endif +} + +// Read all raw PMP addresses. +void riscv_pmpaddr_read_all(size_t addr_out[RISCV_PMP_REGION_COUNT]) { + asm volatile("csrr %0, pmpaddr0" : "=r"(addr_out[0])); + asm volatile("csrr %0, pmpaddr1" : "=r"(addr_out[1])); + asm volatile("csrr %0, pmpaddr2" : "=r"(addr_out[2])); + asm volatile("csrr %0, pmpaddr3" : "=r"(addr_out[3])); + asm volatile("csrr %0, pmpaddr4" : "=r"(addr_out[4])); + asm volatile("csrr %0, pmpaddr5" : "=r"(addr_out[5])); + asm volatile("csrr %0, pmpaddr6" : "=r"(addr_out[6])); + asm volatile("csrr %0, pmpaddr7" : "=r"(addr_out[7])); + asm volatile("csrr %0, pmpaddr8" : "=r"(addr_out[8])); + asm volatile("csrr %0, pmpaddr9" : "=r"(addr_out[9])); + asm volatile("csrr %0, pmpaddr10" : "=r"(addr_out[10])); + asm volatile("csrr %0, pmpaddr11" : "=r"(addr_out[11])); + asm volatile("csrr %0, pmpaddr12" : "=r"(addr_out[12])); + asm volatile("csrr %0, pmpaddr13" : "=r"(addr_out[13])); + asm volatile("csrr %0, pmpaddr14" : "=r"(addr_out[14])); + asm volatile("csrr %0, pmpaddr15" : "=r"(addr_out[15])); +#if RISCV_PMP_REGION_COUNT == 64 + asm volatile("csrr %0, pmpaddr16" : "=r"(addr_out[16])); + asm volatile("csrr %0, pmpaddr17" : "=r"(addr_out[17])); + asm volatile("csrr %0, pmpaddr18" : "=r"(addr_out[18])); + asm volatile("csrr %0, pmpaddr19" : "=r"(addr_out[19])); + asm volatile("csrr %0, pmpaddr20" : "=r"(addr_out[20])); + asm volatile("csrr %0, pmpaddr21" : "=r"(addr_out[21])); + asm volatile("csrr %0, pmpaddr22" : "=r"(addr_out[22])); + asm volatile("csrr %0, pmpaddr23" : "=r"(addr_out[23])); + asm volatile("csrr %0, pmpaddr24" : "=r"(addr_out[24])); + asm volatile("csrr %0, pmpaddr25" : "=r"(addr_out[25])); + asm volatile("csrr %0, pmpaddr26" : "=r"(addr_out[26])); + asm volatile("csrr %0, pmpaddr27" : "=r"(addr_out[27])); + asm volatile("csrr %0, pmpaddr28" : "=r"(addr_out[28])); + asm volatile("csrr %0, pmpaddr29" : "=r"(addr_out[29])); + asm volatile("csrr %0, pmpaddr30" : "=r"(addr_out[30])); + asm volatile("csrr %0, pmpaddr31" : "=r"(addr_out[31])); + asm volatile("csrr %0, pmpaddr32" : "=r"(addr_out[32])); + asm volatile("csrr %0, pmpaddr33" : "=r"(addr_out[33])); + asm volatile("csrr %0, pmpaddr34" : "=r"(addr_out[34])); + asm volatile("csrr %0, pmpaddr35" : "=r"(addr_out[35])); + asm volatile("csrr %0, pmpaddr36" : "=r"(addr_out[36])); + asm volatile("csrr %0, pmpaddr37" : "=r"(addr_out[37])); + asm volatile("csrr %0, pmpaddr38" : "=r"(addr_out[38])); + asm volatile("csrr %0, pmpaddr39" : "=r"(addr_out[39])); + asm volatile("csrr %0, pmpaddr40" : "=r"(addr_out[40])); + asm volatile("csrr %0, pmpaddr41" : "=r"(addr_out[41])); + asm volatile("csrr %0, pmpaddr42" : "=r"(addr_out[42])); + asm volatile("csrr %0, pmpaddr43" : "=r"(addr_out[43])); + asm volatile("csrr %0, pmpaddr44" : "=r"(addr_out[44])); + asm volatile("csrr %0, pmpaddr45" : "=r"(addr_out[45])); + asm volatile("csrr %0, pmpaddr46" : "=r"(addr_out[46])); + asm volatile("csrr %0, pmpaddr47" : "=r"(addr_out[47])); + asm volatile("csrr %0, pmpaddr48" : "=r"(addr_out[48])); + asm volatile("csrr %0, pmpaddr49" : "=r"(addr_out[49])); + asm volatile("csrr %0, pmpaddr50" : "=r"(addr_out[50])); + asm volatile("csrr %0, pmpaddr51" : "=r"(addr_out[51])); + asm volatile("csrr %0, pmpaddr52" : "=r"(addr_out[52])); + asm volatile("csrr %0, pmpaddr53" : "=r"(addr_out[53])); + asm volatile("csrr %0, pmpaddr54" : "=r"(addr_out[54])); + asm volatile("csrr %0, pmpaddr55" : "=r"(addr_out[55])); + asm volatile("csrr %0, pmpaddr56" : "=r"(addr_out[56])); + asm volatile("csrr %0, pmpaddr57" : "=r"(addr_out[57])); + asm volatile("csrr %0, pmpaddr58" : "=r"(addr_out[58])); + asm volatile("csrr %0, pmpaddr59" : "=r"(addr_out[59])); + asm volatile("csrr %0, pmpaddr60" : "=r"(addr_out[60])); + asm volatile("csrr %0, pmpaddr61" : "=r"(addr_out[61])); + asm volatile("csrr %0, pmpaddr62" : "=r"(addr_out[62])); + asm volatile("csrr %0, pmpaddr63" : "=r"(addr_out[63])); +#endif +} + +// Write all raw PMP configurations. +void riscv_pmpcfg_write_all(riscv_pmpcfg_t const cfg_in[RISCV_PMP_REGION_COUNT]) { + long const *word_in = (void *)cfg_in; + +#if __riscv_xlen == 32 + asm volatile("csrw pmpcfg0, %0" ::"r"(word_in[0])); + asm volatile("csrw pmpcfg1, %0" ::"r"(word_in[1])); + asm volatile("csrw pmpcfg2, %0" ::"r"(word_in[2])); + asm volatile("csrw pmpcfg3, %0" ::"r"(word_in[3])); +#endif +#if __riscv_xlen == 32 && RISCV_PMP_REGION_COUNT == 64 + asm volatile("csrw pmpcfg4, %0" ::"r"(word_in[4])); + asm volatile("csrw pmpcfg5, %0" ::"r"(word_in[5])); + asm volatile("csrw pmpcfg6, %0" ::"r"(word_in[6])); + asm volatile("csrw pmpcfg7, %0" ::"r"(word_in[7])); + asm volatile("csrw pmpcfg8, %0" ::"r"(word_in[8])); + asm volatile("csrw pmpcfg9, %0" ::"r"(word_in[9])); + asm volatile("csrw pmpcfg10, %0" ::"r"(word_in[10])); + asm volatile("csrw pmpcfg11, %0" ::"r"(word_in[11])); + asm volatile("csrw pmpcfg12, %0" ::"r"(word_in[12])); + asm volatile("csrw pmpcfg13, %0" ::"r"(word_in[13])); + asm volatile("csrw pmpcfg14, %0" ::"r"(word_in[14])); + asm volatile("csrw pmpcfg15, %0" ::"r"(word_in[15])); +#endif + +#if __riscv_xlen == 64 + asm volatile("csrw pmpcfg0, %0" ::"r"(word_in[0])); + asm volatile("csrw pmpcfg2, %0" ::"r"(word_in[1])); +#endif +#if __riscv_xlen == 64 && RISCV_PMP_REGION_COUNT == 64 + asm volatile("csrw pmpcfg4, %0" ::"r"(word_in[2])); + asm volatile("csrw pmpcfg6, %0" ::"r"(word_in[3])); + asm volatile("csrw pmpcfg8, %0" ::"r"(word_in[4])); + asm volatile("csrw pmpcfg10, %0" ::"r"(word_in[5])); + asm volatile("csrw pmpcfg12, %0" ::"r"(word_in[6])); + asm volatile("csrw pmpcfg14, %0" ::"r"(word_in[7])); +#endif +} + +// Write all raw PMP addresses. +void riscv_pmpaddr_write_all(size_t const addr_in[RISCV_PMP_REGION_COUNT]) { + asm volatile("csrw pmpaddr0, %0" ::"r"(addr_in[0])); + asm volatile("csrw pmpaddr1, %0" ::"r"(addr_in[1])); + asm volatile("csrw pmpaddr2, %0" ::"r"(addr_in[2])); + asm volatile("csrw pmpaddr3, %0" ::"r"(addr_in[3])); + asm volatile("csrw pmpaddr4, %0" ::"r"(addr_in[4])); + asm volatile("csrw pmpaddr5, %0" ::"r"(addr_in[5])); + asm volatile("csrw pmpaddr6, %0" ::"r"(addr_in[6])); + asm volatile("csrw pmpaddr7, %0" ::"r"(addr_in[7])); + asm volatile("csrw pmpaddr8, %0" ::"r"(addr_in[8])); + asm volatile("csrw pmpaddr9, %0" ::"r"(addr_in[9])); + asm volatile("csrw pmpaddr10, %0" ::"r"(addr_in[10])); + asm volatile("csrw pmpaddr11, %0" ::"r"(addr_in[11])); + asm volatile("csrw pmpaddr12, %0" ::"r"(addr_in[12])); + asm volatile("csrw pmpaddr13, %0" ::"r"(addr_in[13])); + asm volatile("csrw pmpaddr14, %0" ::"r"(addr_in[14])); + asm volatile("csrw pmpaddr15, %0" ::"r"(addr_in[15])); +#if RISCV_PMP_REGION_COUNT == 64 + asm volatile("csrw pmpaddr16, %0" ::"r"(addr_in[16])); + asm volatile("csrw pmpaddr17, %0" ::"r"(addr_in[17])); + asm volatile("csrw pmpaddr18, %0" ::"r"(addr_in[18])); + asm volatile("csrw pmpaddr19, %0" ::"r"(addr_in[19])); + asm volatile("csrw pmpaddr20, %0" ::"r"(addr_in[20])); + asm volatile("csrw pmpaddr21, %0" ::"r"(addr_in[21])); + asm volatile("csrw pmpaddr22, %0" ::"r"(addr_in[22])); + asm volatile("csrw pmpaddr23, %0" ::"r"(addr_in[23])); + asm volatile("csrw pmpaddr24, %0" ::"r"(addr_in[24])); + asm volatile("csrw pmpaddr25, %0" ::"r"(addr_in[25])); + asm volatile("csrw pmpaddr26, %0" ::"r"(addr_in[26])); + asm volatile("csrw pmpaddr27, %0" ::"r"(addr_in[27])); + asm volatile("csrw pmpaddr28, %0" ::"r"(addr_in[28])); + asm volatile("csrw pmpaddr29, %0" ::"r"(addr_in[29])); + asm volatile("csrw pmpaddr30, %0" ::"r"(addr_in[30])); + asm volatile("csrw pmpaddr31, %0" ::"r"(addr_in[31])); + asm volatile("csrw pmpaddr32, %0" ::"r"(addr_in[32])); + asm volatile("csrw pmpaddr33, %0" ::"r"(addr_in[33])); + asm volatile("csrw pmpaddr34, %0" ::"r"(addr_in[34])); + asm volatile("csrw pmpaddr35, %0" ::"r"(addr_in[35])); + asm volatile("csrw pmpaddr36, %0" ::"r"(addr_in[36])); + asm volatile("csrw pmpaddr37, %0" ::"r"(addr_in[37])); + asm volatile("csrw pmpaddr38, %0" ::"r"(addr_in[38])); + asm volatile("csrw pmpaddr39, %0" ::"r"(addr_in[39])); + asm volatile("csrw pmpaddr40, %0" ::"r"(addr_in[40])); + asm volatile("csrw pmpaddr41, %0" ::"r"(addr_in[41])); + asm volatile("csrw pmpaddr42, %0" ::"r"(addr_in[42])); + asm volatile("csrw pmpaddr43, %0" ::"r"(addr_in[43])); + asm volatile("csrw pmpaddr44, %0" ::"r"(addr_in[44])); + asm volatile("csrw pmpaddr45, %0" ::"r"(addr_in[45])); + asm volatile("csrw pmpaddr46, %0" ::"r"(addr_in[46])); + asm volatile("csrw pmpaddr47, %0" ::"r"(addr_in[47])); + asm volatile("csrw pmpaddr48, %0" ::"r"(addr_in[48])); + asm volatile("csrw pmpaddr49, %0" ::"r"(addr_in[49])); + asm volatile("csrw pmpaddr50, %0" ::"r"(addr_in[50])); + asm volatile("csrw pmpaddr51, %0" ::"r"(addr_in[51])); + asm volatile("csrw pmpaddr52, %0" ::"r"(addr_in[52])); + asm volatile("csrw pmpaddr53, %0" ::"r"(addr_in[53])); + asm volatile("csrw pmpaddr54, %0" ::"r"(addr_in[54])); + asm volatile("csrw pmpaddr55, %0" ::"r"(addr_in[55])); + asm volatile("csrw pmpaddr56, %0" ::"r"(addr_in[56])); + asm volatile("csrw pmpaddr57, %0" ::"r"(addr_in[57])); + asm volatile("csrw pmpaddr58, %0" ::"r"(addr_in[58])); + asm volatile("csrw pmpaddr59, %0" ::"r"(addr_in[59])); + asm volatile("csrw pmpaddr60, %0" ::"r"(addr_in[60])); + asm volatile("csrw pmpaddr61, %0" ::"r"(addr_in[61])); + asm volatile("csrw pmpaddr62, %0" ::"r"(addr_in[62])); + asm volatile("csrw pmpaddr63, %0" ::"r"(addr_in[63])); +#endif +} diff --git a/include/memprotect.h b/include/memprotect.h new file mode 100644 index 0000000..b932ebe --- /dev/null +++ b/include/memprotect.h @@ -0,0 +1,16 @@ + +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +// Initialise memory protection driver. +void memprotect_init(); + +// Set the range of external RAM assigned to userland. +void memprotect_set_user_extram(size_t base, size_t top); +// Set the range of SRAM assigned to userland. +void memprotect_set_user_sram(size_t base, size_t top); +// Set the range of flash assigned to userland. +void memprotect_set_user_flash(size_t base, size_t top); diff --git a/include/meta.h b/include/meta.h index 47e038b..5219d40 100644 --- a/include/meta.h +++ b/include/meta.h @@ -18,3 +18,6 @@ // Returns the inner `value` of the given macro as a string. Can be used to // convert things like numbers or `__LINE__` to string form. #define convert_macro_to_string(value) comptime_stringify(value) + +// Concatenate two keywords. +#define concat_keywords(a, b) a##b diff --git a/port/esp32c6/CMakeLists.txt b/port/esp32c6/CMakeLists.txt index 9b85895..dc47472 100644 --- a/port/esp32c6/CMakeLists.txt +++ b/port/esp32c6/CMakeLists.txt @@ -11,6 +11,7 @@ target_sources(${target} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/i2c.c ${CMAKE_CURRENT_LIST_DIR}/src/interrupt.c ${CMAKE_CURRENT_LIST_DIR}/src/intmtx.c + ${CMAKE_CURRENT_LIST_DIR}/src/memprotect.c ${CMAKE_CURRENT_LIST_DIR}/src/rawprint.c ${CMAKE_CURRENT_LIST_DIR}/src/time.c ) diff --git a/port/esp32c6/include/port/hardware_allocation.h b/port/esp32c6/include/port/hardware_allocation.h index 087bcd4..ebe66b8 100644 --- a/port/esp32c6/include/port/hardware_allocation.h +++ b/port/esp32c6/include/port/hardware_allocation.h @@ -41,3 +41,40 @@ #define TIMER_PREEMPT_NUM 0 // System tick rate in Hz. #define TIMER_SYSTICK_RATE 1000000 + + + +/* ==== Memory protection regions ==== */ + +// Region size used for nullpointer protection regions. +#define PMP_SIZE_NULLPTR 0x10000000 +// Region size used for ROM write protection. +#define PMP_SIZE_ROM_WP 0x00080000 +// Region size used for FLASH write protection. +#define PMP_SIZE_FLASH_WP 0x01000000 + +// Region base used for ROM write protection. +#define PMP_BASE_ROM_WP 0x40000000 +// Region base used for ROM write protection. +#define PMP_BASE_FLASH_WP 0x42000000 + +// NAPOT PMP entry for lower nullpointer protection. +#define PMP_ENTRY_NULLPTR_LOW_NAPOT 0 +// NAPOT PMP entry for upper nullpointer protection. +#define PMP_ENTRY_NULLPTR_HIGH_NAPOT 1 +// NAPOT PMP entry for ROM write protection +#define PMP_ENTRY_ROM_WP_NAPOT 2 +// NAPOT PMP entry for FLASH write protection +#define PMP_ENTRY_FLASH_WP_NAPOT 3 +// Base PMP entry for external RAM assigned to userland. +#define PMP_ENTRY_USER_EXTRAM_BASE 4 +// TOR PMP entry for external RAM assigned to userland. +#define PMP_ENTRY_USER_EXTRAM_TOR 5 +// Base PMP entry for SRAM assigned to userland. +#define PMP_ENTRY_USER_SRAM_BASE 6 +// TOR PMP entry for SRAM assigned to userland. +#define PMP_ENTRY_USER_SRAM_TOR 7 +// Base PMP entry for SRAM assigned to userland. +#define PMP_ENTRY_USER_FLASH_BASE 8 +// TOR PMP entry for SRAM assigned to userland. +#define PMP_ENTRY_USER_FLASH_TOR 9 diff --git a/port/esp32c6/include/port/memprotect.h b/port/esp32c6/include/port/memprotect.h new file mode 100644 index 0000000..173a7ea --- /dev/null +++ b/port/esp32c6/include/port/memprotect.h @@ -0,0 +1,7 @@ + +// SPDX-License-Identifier: MIT + +#pragma once + +// Number of available protection regions. +#define RISCV_PMP_REGION_COUNT 16 diff --git a/port/esp32c6/src/memprotect.c b/port/esp32c6/src/memprotect.c new file mode 100644 index 0000000..9d85554 --- /dev/null +++ b/port/esp32c6/src/memprotect.c @@ -0,0 +1,148 @@ + +// SPDX-License-Identifier: MIT + +#include "memprotect.h" + +#include "cpu/riscv_pmp.h" +#include "port/hardware_allocation.h" +#include "port/interrupt.h" + +// Initialise memory protection driver. +void memprotect_init() { + // Initialise PMP driver. + riscv_pmp_init(); + + // Add lower NULLPTR protection range. + riscv_pmpaddr_write(PMP_ENTRY_NULLPTR_LOW_NAPOT, riscv_pmpaddr_calc_napot(0, PMP_SIZE_NULLPTR)); + riscv_pmpcfg_set( + PMP_ENTRY_NULLPTR_LOW_NAPOT, + ((riscv_pmpcfg_t){ + .read = false, + .write = false, + .exec = false, + .addr_match_mode = RISCV_PMPCFG_NAPOT, + ._reserved = 0, + .lock = true, + }) + ); + + // Add upper NULLPTR protection range. + riscv_pmpaddr_write(PMP_ENTRY_NULLPTR_HIGH_NAPOT, riscv_pmpaddr_calc_napot(-PMP_SIZE_NULLPTR, PMP_SIZE_NULLPTR)); + riscv_pmpcfg_set( + PMP_ENTRY_NULLPTR_HIGH_NAPOT, + ((riscv_pmpcfg_t){ + .read = false, + .write = false, + .exec = false, + .addr_match_mode = RISCV_PMPCFG_NAPOT, + ._reserved = 0, + .lock = true, + }) + ); + + // Add ROM write-protect range. + riscv_pmpaddr_write(PMP_ENTRY_ROM_WP_NAPOT, riscv_pmpaddr_calc_napot(PMP_BASE_ROM_WP, PMP_SIZE_ROM_WP)); + riscv_pmpcfg_set( + PMP_ENTRY_ROM_WP_NAPOT, + ((riscv_pmpcfg_t){ + .read = true, + .write = false, + .exec = true, + .addr_match_mode = RISCV_PMPCFG_NAPOT, + ._reserved = 0, + .lock = true, + }) + ); + + // Add FLASH write-protect range. + riscv_pmpaddr_write(PMP_ENTRY_FLASH_WP_NAPOT, riscv_pmpaddr_calc_napot(PMP_BASE_FLASH_WP, PMP_SIZE_FLASH_WP)); + riscv_pmpcfg_set( + PMP_ENTRY_FLASH_WP_NAPOT, + ((riscv_pmpcfg_t){ + .read = true, + .write = false, + .exec = true, + .addr_match_mode = RISCV_PMPCFG_NAPOT, + ._reserved = 0, + .lock = true, + }) + ); +} + +// Set the range of external RAM currently assigned to userland. +void memprotect_set_user_extram(size_t base, size_t top) { + bool mie = interrupt_disable(); + + // Disable existing entry. + riscv_pmpcfg_clear(PMP_ENTRY_USER_EXTRAM_TOR); + // Write new addresses. + riscv_pmpaddr_write(PMP_ENTRY_USER_EXTRAM_BASE, base); + riscv_pmpaddr_write(PMP_ENTRY_USER_EXTRAM_TOR, top); + // Set PMP region type. + riscv_pmpcfg_set( + PMP_ENTRY_USER_EXTRAM_TOR, + ((riscv_pmpcfg_t){ + .read = true, + .write = true, + .exec = true, + .addr_match_mode = RISCV_PMPCFG_TOR, + ._reserved = 0, + .lock = false, + }) + ); + + if (mie) + interrupt_enable(); +} + +// Set the range of SRAM currently assigned to userland. +void memprotect_set_user_sram(size_t base, size_t top) { + bool mie = interrupt_disable(); + + // Disable existing entry. + riscv_pmpcfg_clear(PMP_ENTRY_USER_SRAM_TOR); + // Write new addresses. + riscv_pmpaddr_write(PMP_ENTRY_USER_SRAM_BASE, base); + riscv_pmpaddr_write(PMP_ENTRY_USER_SRAM_TOR, top); + // Set PMP region type. + riscv_pmpcfg_set( + PMP_ENTRY_USER_SRAM_TOR, + ((riscv_pmpcfg_t){ + .read = true, + .write = true, + .exec = true, + .addr_match_mode = RISCV_PMPCFG_TOR, + ._reserved = 0, + .lock = false, + }) + ); + + if (mie) + interrupt_enable(); +} + +// Set the range of flash currently assigned to userland. +void memprotect_set_user_flash(size_t base, size_t top) { + bool mie = interrupt_disable(); + + // Disable existing entry. + riscv_pmpcfg_clear(PMP_ENTRY_USER_FLASH_TOR); + // Write new addresses. + riscv_pmpaddr_write(PMP_ENTRY_USER_FLASH_BASE, base); + riscv_pmpaddr_write(PMP_ENTRY_USER_FLASH_TOR, top); + // Set PMP region type. + riscv_pmpcfg_set( + PMP_ENTRY_USER_FLASH_TOR, + ((riscv_pmpcfg_t){ + .read = true, + .write = true, + .exec = true, + .addr_match_mode = RISCV_PMPCFG_TOR, + ._reserved = 0, + .lock = false, + }) + ); + + if (mie) + interrupt_enable(); +} diff --git a/src/main.c b/src/main.c index 25e9a5b..eda9a4a 100644 --- a/src/main.c +++ b/src/main.c @@ -6,6 +6,7 @@ #include "gpio.h" #include "log.h" #include "malloc.h" +#include "memprotect.h" #include "port/interrupt.h" #include "rawprint.h" #include "scheduler.h" @@ -42,6 +43,9 @@ void main() { // Install interrupt and trap handlers. interrupt_init(&kctx); + // Set up memory protection. + memprotect_init(); + // Set up timers and watchdogs. // This function must run within the first ~1s of power-on time and should be // called as early as possible. From 71437e29def8239e83709b80c1015a20b1eaec02 Mon Sep 17 00:00:00 2001 From: Julian Scheffers Date: Wed, 26 Jul 2023 22:08:17 +0200 Subject: [PATCH 2/3] Memory protection testing --- cpu/rv32imac/include/cpu/riscv_pmp.h | 526 +++++++++--------- .../include/port/hardware_allocation.h | 10 +- port/esp32c6/src/memprotect.c | 14 + src/main.c | 37 ++ 4 files changed, 323 insertions(+), 264 deletions(-) diff --git a/cpu/rv32imac/include/cpu/riscv_pmp.h b/cpu/rv32imac/include/cpu/riscv_pmp.h index dc07b81..d2f6417 100644 --- a/cpu/rv32imac/include/cpu/riscv_pmp.h +++ b/cpu/rv32imac/include/cpu/riscv_pmp.h @@ -18,274 +18,280 @@ static_assert( #if __riscv_xlen == 32 -#define RISCV_PMP_CFG_BITPOS_0 0 -#define RISCV_PMP_CFG_BITPOS_1 8 -#define RISCV_PMP_CFG_BITPOS_2 16 -#define RISCV_PMP_CFG_BITPOS_3 24 -#define RISCV_PMP_CFG_BITPOS_4 0 -#define RISCV_PMP_CFG_BITPOS_5 8 -#define RISCV_PMP_CFG_BITPOS_6 16 -#define RISCV_PMP_CFG_BITPOS_7 24 -#define RISCV_PMP_CFG_BITPOS_8 0 -#define RISCV_PMP_CFG_BITPOS_9 8 -#define RISCV_PMP_CFG_BITPOS_10 16 -#define RISCV_PMP_CFG_BITPOS_11 24 -#define RISCV_PMP_CFG_BITPOS_12 0 -#define RISCV_PMP_CFG_BITPOS_13 8 -#define RISCV_PMP_CFG_BITPOS_14 16 -#define RISCV_PMP_CFG_BITPOS_15 24 +// 2^XLEN-byte NAPOT range starting at address 0. +#define RISCV_PMPADDR_NAPOT_GLOBAL 0x1fffffff + +#define __RISCV_PMP_CFG_BITPOS_0 0 +#define __RISCV_PMP_CFG_BITPOS_1 8 +#define __RISCV_PMP_CFG_BITPOS_2 16 +#define __RISCV_PMP_CFG_BITPOS_3 24 +#define __RISCV_PMP_CFG_BITPOS_4 0 +#define __RISCV_PMP_CFG_BITPOS_5 8 +#define __RISCV_PMP_CFG_BITPOS_6 16 +#define __RISCV_PMP_CFG_BITPOS_7 24 +#define __RISCV_PMP_CFG_BITPOS_8 0 +#define __RISCV_PMP_CFG_BITPOS_9 8 +#define __RISCV_PMP_CFG_BITPOS_10 16 +#define __RISCV_PMP_CFG_BITPOS_11 24 +#define __RISCV_PMP_CFG_BITPOS_12 0 +#define __RISCV_PMP_CFG_BITPOS_13 8 +#define __RISCV_PMP_CFG_BITPOS_14 16 +#define __RISCV_PMP_CFG_BITPOS_15 24 #if RISCV_PMP_REGION_COUNT == 64 -#define RISCV_PMP_CFG_BITPOS_16 0 -#define RISCV_PMP_CFG_BITPOS_17 8 -#define RISCV_PMP_CFG_BITPOS_18 16 -#define RISCV_PMP_CFG_BITPOS_19 24 -#define RISCV_PMP_CFG_BITPOS_20 0 -#define RISCV_PMP_CFG_BITPOS_21 8 -#define RISCV_PMP_CFG_BITPOS_22 16 -#define RISCV_PMP_CFG_BITPOS_23 24 -#define RISCV_PMP_CFG_BITPOS_24 0 -#define RISCV_PMP_CFG_BITPOS_25 8 -#define RISCV_PMP_CFG_BITPOS_26 16 -#define RISCV_PMP_CFG_BITPOS_27 24 -#define RISCV_PMP_CFG_BITPOS_28 0 -#define RISCV_PMP_CFG_BITPOS_29 8 -#define RISCV_PMP_CFG_BITPOS_30 16 -#define RISCV_PMP_CFG_BITPOS_31 24 -#define RISCV_PMP_CFG_BITPOS_32 0 -#define RISCV_PMP_CFG_BITPOS_33 8 -#define RISCV_PMP_CFG_BITPOS_34 16 -#define RISCV_PMP_CFG_BITPOS_35 24 -#define RISCV_PMP_CFG_BITPOS_36 0 -#define RISCV_PMP_CFG_BITPOS_37 8 -#define RISCV_PMP_CFG_BITPOS_38 16 -#define RISCV_PMP_CFG_BITPOS_39 24 -#define RISCV_PMP_CFG_BITPOS_40 0 -#define RISCV_PMP_CFG_BITPOS_41 8 -#define RISCV_PMP_CFG_BITPOS_42 16 -#define RISCV_PMP_CFG_BITPOS_43 24 -#define RISCV_PMP_CFG_BITPOS_44 0 -#define RISCV_PMP_CFG_BITPOS_45 8 -#define RISCV_PMP_CFG_BITPOS_46 16 -#define RISCV_PMP_CFG_BITPOS_47 24 -#define RISCV_PMP_CFG_BITPOS_48 0 -#define RISCV_PMP_CFG_BITPOS_49 8 -#define RISCV_PMP_CFG_BITPOS_50 16 -#define RISCV_PMP_CFG_BITPOS_51 24 -#define RISCV_PMP_CFG_BITPOS_52 0 -#define RISCV_PMP_CFG_BITPOS_53 8 -#define RISCV_PMP_CFG_BITPOS_54 16 -#define RISCV_PMP_CFG_BITPOS_55 24 -#define RISCV_PMP_CFG_BITPOS_56 0 -#define RISCV_PMP_CFG_BITPOS_57 8 -#define RISCV_PMP_CFG_BITPOS_58 16 -#define RISCV_PMP_CFG_BITPOS_59 24 -#define RISCV_PMP_CFG_BITPOS_60 0 -#define RISCV_PMP_CFG_BITPOS_61 8 -#define RISCV_PMP_CFG_BITPOS_62 16 -#define RISCV_PMP_CFG_BITPOS_63 24 +#define __RISCV_PMP_CFG_BITPOS_16 0 +#define __RISCV_PMP_CFG_BITPOS_17 8 +#define __RISCV_PMP_CFG_BITPOS_18 16 +#define __RISCV_PMP_CFG_BITPOS_19 24 +#define __RISCV_PMP_CFG_BITPOS_20 0 +#define __RISCV_PMP_CFG_BITPOS_21 8 +#define __RISCV_PMP_CFG_BITPOS_22 16 +#define __RISCV_PMP_CFG_BITPOS_23 24 +#define __RISCV_PMP_CFG_BITPOS_24 0 +#define __RISCV_PMP_CFG_BITPOS_25 8 +#define __RISCV_PMP_CFG_BITPOS_26 16 +#define __RISCV_PMP_CFG_BITPOS_27 24 +#define __RISCV_PMP_CFG_BITPOS_28 0 +#define __RISCV_PMP_CFG_BITPOS_29 8 +#define __RISCV_PMP_CFG_BITPOS_30 16 +#define __RISCV_PMP_CFG_BITPOS_31 24 +#define __RISCV_PMP_CFG_BITPOS_32 0 +#define __RISCV_PMP_CFG_BITPOS_33 8 +#define __RISCV_PMP_CFG_BITPOS_34 16 +#define __RISCV_PMP_CFG_BITPOS_35 24 +#define __RISCV_PMP_CFG_BITPOS_36 0 +#define __RISCV_PMP_CFG_BITPOS_37 8 +#define __RISCV_PMP_CFG_BITPOS_38 16 +#define __RISCV_PMP_CFG_BITPOS_39 24 +#define __RISCV_PMP_CFG_BITPOS_40 0 +#define __RISCV_PMP_CFG_BITPOS_41 8 +#define __RISCV_PMP_CFG_BITPOS_42 16 +#define __RISCV_PMP_CFG_BITPOS_43 24 +#define __RISCV_PMP_CFG_BITPOS_44 0 +#define __RISCV_PMP_CFG_BITPOS_45 8 +#define __RISCV_PMP_CFG_BITPOS_46 16 +#define __RISCV_PMP_CFG_BITPOS_47 24 +#define __RISCV_PMP_CFG_BITPOS_48 0 +#define __RISCV_PMP_CFG_BITPOS_49 8 +#define __RISCV_PMP_CFG_BITPOS_50 16 +#define __RISCV_PMP_CFG_BITPOS_51 24 +#define __RISCV_PMP_CFG_BITPOS_52 0 +#define __RISCV_PMP_CFG_BITPOS_53 8 +#define __RISCV_PMP_CFG_BITPOS_54 16 +#define __RISCV_PMP_CFG_BITPOS_55 24 +#define __RISCV_PMP_CFG_BITPOS_56 0 +#define __RISCV_PMP_CFG_BITPOS_57 8 +#define __RISCV_PMP_CFG_BITPOS_58 16 +#define __RISCV_PMP_CFG_BITPOS_59 24 +#define __RISCV_PMP_CFG_BITPOS_60 0 +#define __RISCV_PMP_CFG_BITPOS_61 8 +#define __RISCV_PMP_CFG_BITPOS_62 16 +#define __RISCV_PMP_CFG_BITPOS_63 24 #endif -#define RISCV_PMP_CFG_CSR_0 "pmpcfg0" -#define RISCV_PMP_CFG_CSR_1 "pmpcfg0" -#define RISCV_PMP_CFG_CSR_2 "pmpcfg0" -#define RISCV_PMP_CFG_CSR_3 "pmpcfg0" -#define RISCV_PMP_CFG_CSR_4 "pmpcfg1" -#define RISCV_PMP_CFG_CSR_5 "pmpcfg1" -#define RISCV_PMP_CFG_CSR_6 "pmpcfg1" -#define RISCV_PMP_CFG_CSR_7 "pmpcfg1" -#define RISCV_PMP_CFG_CSR_8 "pmpcfg2" -#define RISCV_PMP_CFG_CSR_9 "pmpcfg2" -#define RISCV_PMP_CFG_CSR_10 "pmpcfg2" -#define RISCV_PMP_CFG_CSR_11 "pmpcfg2" -#define RISCV_PMP_CFG_CSR_12 "pmpcfg3" -#define RISCV_PMP_CFG_CSR_13 "pmpcfg3" -#define RISCV_PMP_CFG_CSR_14 "pmpcfg3" -#define RISCV_PMP_CFG_CSR_15 "pmpcfg3" +#define __RISCV_PMP_CFG_CSR_0 "pmpcfg0" +#define __RISCV_PMP_CFG_CSR_1 "pmpcfg0" +#define __RISCV_PMP_CFG_CSR_2 "pmpcfg0" +#define __RISCV_PMP_CFG_CSR_3 "pmpcfg0" +#define __RISCV_PMP_CFG_CSR_4 "pmpcfg1" +#define __RISCV_PMP_CFG_CSR_5 "pmpcfg1" +#define __RISCV_PMP_CFG_CSR_6 "pmpcfg1" +#define __RISCV_PMP_CFG_CSR_7 "pmpcfg1" +#define __RISCV_PMP_CFG_CSR_8 "pmpcfg2" +#define __RISCV_PMP_CFG_CSR_9 "pmpcfg2" +#define __RISCV_PMP_CFG_CSR_10 "pmpcfg2" +#define __RISCV_PMP_CFG_CSR_11 "pmpcfg2" +#define __RISCV_PMP_CFG_CSR_12 "pmpcfg3" +#define __RISCV_PMP_CFG_CSR_13 "pmpcfg3" +#define __RISCV_PMP_CFG_CSR_14 "pmpcfg3" +#define __RISCV_PMP_CFG_CSR_15 "pmpcfg3" #if RISCV_PMP_REGION_COUNT == 64 -#define RISCV_PMP_CFG_CSR_16 "pmpcfg4" -#define RISCV_PMP_CFG_CSR_17 "pmpcfg4" -#define RISCV_PMP_CFG_CSR_18 "pmpcfg4" -#define RISCV_PMP_CFG_CSR_19 "pmpcfg4" -#define RISCV_PMP_CFG_CSR_20 "pmpcfg5" -#define RISCV_PMP_CFG_CSR_21 "pmpcfg5" -#define RISCV_PMP_CFG_CSR_22 "pmpcfg5" -#define RISCV_PMP_CFG_CSR_23 "pmpcfg5" -#define RISCV_PMP_CFG_CSR_24 "pmpcfg6" -#define RISCV_PMP_CFG_CSR_25 "pmpcfg6" -#define RISCV_PMP_CFG_CSR_26 "pmpcfg6" -#define RISCV_PMP_CFG_CSR_27 "pmpcfg6" -#define RISCV_PMP_CFG_CSR_28 "pmpcfg7" -#define RISCV_PMP_CFG_CSR_29 "pmpcfg7" -#define RISCV_PMP_CFG_CSR_30 "pmpcfg7" -#define RISCV_PMP_CFG_CSR_31 "pmpcfg7" -#define RISCV_PMP_CFG_CSR_32 "pmpcfg8" -#define RISCV_PMP_CFG_CSR_33 "pmpcfg8" -#define RISCV_PMP_CFG_CSR_34 "pmpcfg8" -#define RISCV_PMP_CFG_CSR_35 "pmpcfg8" -#define RISCV_PMP_CFG_CSR_36 "pmpcfg9" -#define RISCV_PMP_CFG_CSR_37 "pmpcfg9" -#define RISCV_PMP_CFG_CSR_38 "pmpcfg9" -#define RISCV_PMP_CFG_CSR_39 "pmpcfg9" -#define RISCV_PMP_CFG_CSR_40 "pmpcfg10" -#define RISCV_PMP_CFG_CSR_41 "pmpcfg10" -#define RISCV_PMP_CFG_CSR_42 "pmpcfg10" -#define RISCV_PMP_CFG_CSR_43 "pmpcfg10" -#define RISCV_PMP_CFG_CSR_44 "pmpcfg11" -#define RISCV_PMP_CFG_CSR_45 "pmpcfg11" -#define RISCV_PMP_CFG_CSR_46 "pmpcfg11" -#define RISCV_PMP_CFG_CSR_47 "pmpcfg11" -#define RISCV_PMP_CFG_CSR_48 "pmpcfg12" -#define RISCV_PMP_CFG_CSR_49 "pmpcfg12" -#define RISCV_PMP_CFG_CSR_50 "pmpcfg12" -#define RISCV_PMP_CFG_CSR_51 "pmpcfg12" -#define RISCV_PMP_CFG_CSR_52 "pmpcfg13" -#define RISCV_PMP_CFG_CSR_53 "pmpcfg13" -#define RISCV_PMP_CFG_CSR_54 "pmpcfg13" -#define RISCV_PMP_CFG_CSR_55 "pmpcfg13" -#define RISCV_PMP_CFG_CSR_56 "pmpcfg14" -#define RISCV_PMP_CFG_CSR_57 "pmpcfg14" -#define RISCV_PMP_CFG_CSR_58 "pmpcfg14" -#define RISCV_PMP_CFG_CSR_59 "pmpcfg14" -#define RISCV_PMP_CFG_CSR_60 "pmpcfg15" -#define RISCV_PMP_CFG_CSR_61 "pmpcfg15" -#define RISCV_PMP_CFG_CSR_62 "pmpcfg15" -#define RISCV_PMP_CFG_CSR_63 "pmpcfg15" +#define __RISCV_PMP_CFG_CSR_16 "pmpcfg4" +#define __RISCV_PMP_CFG_CSR_17 "pmpcfg4" +#define __RISCV_PMP_CFG_CSR_18 "pmpcfg4" +#define __RISCV_PMP_CFG_CSR_19 "pmpcfg4" +#define __RISCV_PMP_CFG_CSR_20 "pmpcfg5" +#define __RISCV_PMP_CFG_CSR_21 "pmpcfg5" +#define __RISCV_PMP_CFG_CSR_22 "pmpcfg5" +#define __RISCV_PMP_CFG_CSR_23 "pmpcfg5" +#define __RISCV_PMP_CFG_CSR_24 "pmpcfg6" +#define __RISCV_PMP_CFG_CSR_25 "pmpcfg6" +#define __RISCV_PMP_CFG_CSR_26 "pmpcfg6" +#define __RISCV_PMP_CFG_CSR_27 "pmpcfg6" +#define __RISCV_PMP_CFG_CSR_28 "pmpcfg7" +#define __RISCV_PMP_CFG_CSR_29 "pmpcfg7" +#define __RISCV_PMP_CFG_CSR_30 "pmpcfg7" +#define __RISCV_PMP_CFG_CSR_31 "pmpcfg7" +#define __RISCV_PMP_CFG_CSR_32 "pmpcfg8" +#define __RISCV_PMP_CFG_CSR_33 "pmpcfg8" +#define __RISCV_PMP_CFG_CSR_34 "pmpcfg8" +#define __RISCV_PMP_CFG_CSR_35 "pmpcfg8" +#define __RISCV_PMP_CFG_CSR_36 "pmpcfg9" +#define __RISCV_PMP_CFG_CSR_37 "pmpcfg9" +#define __RISCV_PMP_CFG_CSR_38 "pmpcfg9" +#define __RISCV_PMP_CFG_CSR_39 "pmpcfg9" +#define __RISCV_PMP_CFG_CSR_40 "pmpcfg10" +#define __RISCV_PMP_CFG_CSR_41 "pmpcfg10" +#define __RISCV_PMP_CFG_CSR_42 "pmpcfg10" +#define __RISCV_PMP_CFG_CSR_43 "pmpcfg10" +#define __RISCV_PMP_CFG_CSR_44 "pmpcfg11" +#define __RISCV_PMP_CFG_CSR_45 "pmpcfg11" +#define __RISCV_PMP_CFG_CSR_46 "pmpcfg11" +#define __RISCV_PMP_CFG_CSR_47 "pmpcfg11" +#define __RISCV_PMP_CFG_CSR_48 "pmpcfg12" +#define __RISCV_PMP_CFG_CSR_49 "pmpcfg12" +#define __RISCV_PMP_CFG_CSR_50 "pmpcfg12" +#define __RISCV_PMP_CFG_CSR_51 "pmpcfg12" +#define __RISCV_PMP_CFG_CSR_52 "pmpcfg13" +#define __RISCV_PMP_CFG_CSR_53 "pmpcfg13" +#define __RISCV_PMP_CFG_CSR_54 "pmpcfg13" +#define __RISCV_PMP_CFG_CSR_55 "pmpcfg13" +#define __RISCV_PMP_CFG_CSR_56 "pmpcfg14" +#define __RISCV_PMP_CFG_CSR_57 "pmpcfg14" +#define __RISCV_PMP_CFG_CSR_58 "pmpcfg14" +#define __RISCV_PMP_CFG_CSR_59 "pmpcfg14" +#define __RISCV_PMP_CFG_CSR_60 "pmpcfg15" +#define __RISCV_PMP_CFG_CSR_61 "pmpcfg15" +#define __RISCV_PMP_CFG_CSR_62 "pmpcfg15" +#define __RISCV_PMP_CFG_CSR_63 "pmpcfg15" #endif #elif __riscv_xlen == 64 -#define RISCV_PMP_CFG_BITPOS_0 0 -#define RISCV_PMP_CFG_BITPOS_1 8 -#define RISCV_PMP_CFG_BITPOS_2 16 -#define RISCV_PMP_CFG_BITPOS_3 24 -#define RISCV_PMP_CFG_BITPOS_4 32 -#define RISCV_PMP_CFG_BITPOS_5 40 -#define RISCV_PMP_CFG_BITPOS_6 48 -#define RISCV_PMP_CFG_BITPOS_7 56 -#define RISCV_PMP_CFG_BITPOS_8 0 -#define RISCV_PMP_CFG_BITPOS_9 8 -#define RISCV_PMP_CFG_BITPOS_10 16 -#define RISCV_PMP_CFG_BITPOS_11 24 -#define RISCV_PMP_CFG_BITPOS_12 32 -#define RISCV_PMP_CFG_BITPOS_13 40 -#define RISCV_PMP_CFG_BITPOS_14 48 -#define RISCV_PMP_CFG_BITPOS_15 56 +// 2^XLEN-byte NAPOT range starting at address 0. +#define RISCV_PMPADDR_NAPOT_GLOBAL 0x1fffffffffffffff + +#define __RISCV_PMP_CFG_BITPOS_0 0 +#define __RISCV_PMP_CFG_BITPOS_1 8 +#define __RISCV_PMP_CFG_BITPOS_2 16 +#define __RISCV_PMP_CFG_BITPOS_3 24 +#define __RISCV_PMP_CFG_BITPOS_4 32 +#define __RISCV_PMP_CFG_BITPOS_5 40 +#define __RISCV_PMP_CFG_BITPOS_6 48 +#define __RISCV_PMP_CFG_BITPOS_7 56 +#define __RISCV_PMP_CFG_BITPOS_8 0 +#define __RISCV_PMP_CFG_BITPOS_9 8 +#define __RISCV_PMP_CFG_BITPOS_10 16 +#define __RISCV_PMP_CFG_BITPOS_11 24 +#define __RISCV_PMP_CFG_BITPOS_12 32 +#define __RISCV_PMP_CFG_BITPOS_13 40 +#define __RISCV_PMP_CFG_BITPOS_14 48 +#define __RISCV_PMP_CFG_BITPOS_15 56 #if RISCV_PMP_REGION_COUNT == 64 -#define RISCV_PMP_CFG_BITPOS_16 0 -#define RISCV_PMP_CFG_BITPOS_17 8 -#define RISCV_PMP_CFG_BITPOS_18 16 -#define RISCV_PMP_CFG_BITPOS_19 24 -#define RISCV_PMP_CFG_BITPOS_20 32 -#define RISCV_PMP_CFG_BITPOS_21 40 -#define RISCV_PMP_CFG_BITPOS_22 48 -#define RISCV_PMP_CFG_BITPOS_23 56 -#define RISCV_PMP_CFG_BITPOS_24 0 -#define RISCV_PMP_CFG_BITPOS_25 8 -#define RISCV_PMP_CFG_BITPOS_26 16 -#define RISCV_PMP_CFG_BITPOS_27 24 -#define RISCV_PMP_CFG_BITPOS_28 32 -#define RISCV_PMP_CFG_BITPOS_29 40 -#define RISCV_PMP_CFG_BITPOS_30 48 -#define RISCV_PMP_CFG_BITPOS_31 56 -#define RISCV_PMP_CFG_BITPOS_32 0 -#define RISCV_PMP_CFG_BITPOS_33 8 -#define RISCV_PMP_CFG_BITPOS_34 16 -#define RISCV_PMP_CFG_BITPOS_35 24 -#define RISCV_PMP_CFG_BITPOS_36 32 -#define RISCV_PMP_CFG_BITPOS_37 40 -#define RISCV_PMP_CFG_BITPOS_38 48 -#define RISCV_PMP_CFG_BITPOS_39 56 -#define RISCV_PMP_CFG_BITPOS_40 0 -#define RISCV_PMP_CFG_BITPOS_41 8 -#define RISCV_PMP_CFG_BITPOS_42 16 -#define RISCV_PMP_CFG_BITPOS_43 24 -#define RISCV_PMP_CFG_BITPOS_44 32 -#define RISCV_PMP_CFG_BITPOS_45 40 -#define RISCV_PMP_CFG_BITPOS_46 48 -#define RISCV_PMP_CFG_BITPOS_47 56 -#define RISCV_PMP_CFG_BITPOS_48 0 -#define RISCV_PMP_CFG_BITPOS_49 8 -#define RISCV_PMP_CFG_BITPOS_50 16 -#define RISCV_PMP_CFG_BITPOS_51 24 -#define RISCV_PMP_CFG_BITPOS_52 32 -#define RISCV_PMP_CFG_BITPOS_53 40 -#define RISCV_PMP_CFG_BITPOS_54 48 -#define RISCV_PMP_CFG_BITPOS_55 56 -#define RISCV_PMP_CFG_BITPOS_56 0 -#define RISCV_PMP_CFG_BITPOS_57 8 -#define RISCV_PMP_CFG_BITPOS_58 16 -#define RISCV_PMP_CFG_BITPOS_59 24 -#define RISCV_PMP_CFG_BITPOS_60 32 -#define RISCV_PMP_CFG_BITPOS_61 40 -#define RISCV_PMP_CFG_BITPOS_62 48 -#define RISCV_PMP_CFG_BITPOS_63 56 +#define __RISCV_PMP_CFG_BITPOS_16 0 +#define __RISCV_PMP_CFG_BITPOS_17 8 +#define __RISCV_PMP_CFG_BITPOS_18 16 +#define __RISCV_PMP_CFG_BITPOS_19 24 +#define __RISCV_PMP_CFG_BITPOS_20 32 +#define __RISCV_PMP_CFG_BITPOS_21 40 +#define __RISCV_PMP_CFG_BITPOS_22 48 +#define __RISCV_PMP_CFG_BITPOS_23 56 +#define __RISCV_PMP_CFG_BITPOS_24 0 +#define __RISCV_PMP_CFG_BITPOS_25 8 +#define __RISCV_PMP_CFG_BITPOS_26 16 +#define __RISCV_PMP_CFG_BITPOS_27 24 +#define __RISCV_PMP_CFG_BITPOS_28 32 +#define __RISCV_PMP_CFG_BITPOS_29 40 +#define __RISCV_PMP_CFG_BITPOS_30 48 +#define __RISCV_PMP_CFG_BITPOS_31 56 +#define __RISCV_PMP_CFG_BITPOS_32 0 +#define __RISCV_PMP_CFG_BITPOS_33 8 +#define __RISCV_PMP_CFG_BITPOS_34 16 +#define __RISCV_PMP_CFG_BITPOS_35 24 +#define __RISCV_PMP_CFG_BITPOS_36 32 +#define __RISCV_PMP_CFG_BITPOS_37 40 +#define __RISCV_PMP_CFG_BITPOS_38 48 +#define __RISCV_PMP_CFG_BITPOS_39 56 +#define __RISCV_PMP_CFG_BITPOS_40 0 +#define __RISCV_PMP_CFG_BITPOS_41 8 +#define __RISCV_PMP_CFG_BITPOS_42 16 +#define __RISCV_PMP_CFG_BITPOS_43 24 +#define __RISCV_PMP_CFG_BITPOS_44 32 +#define __RISCV_PMP_CFG_BITPOS_45 40 +#define __RISCV_PMP_CFG_BITPOS_46 48 +#define __RISCV_PMP_CFG_BITPOS_47 56 +#define __RISCV_PMP_CFG_BITPOS_48 0 +#define __RISCV_PMP_CFG_BITPOS_49 8 +#define __RISCV_PMP_CFG_BITPOS_50 16 +#define __RISCV_PMP_CFG_BITPOS_51 24 +#define __RISCV_PMP_CFG_BITPOS_52 32 +#define __RISCV_PMP_CFG_BITPOS_53 40 +#define __RISCV_PMP_CFG_BITPOS_54 48 +#define __RISCV_PMP_CFG_BITPOS_55 56 +#define __RISCV_PMP_CFG_BITPOS_56 0 +#define __RISCV_PMP_CFG_BITPOS_57 8 +#define __RISCV_PMP_CFG_BITPOS_58 16 +#define __RISCV_PMP_CFG_BITPOS_59 24 +#define __RISCV_PMP_CFG_BITPOS_60 32 +#define __RISCV_PMP_CFG_BITPOS_61 40 +#define __RISCV_PMP_CFG_BITPOS_62 48 +#define __RISCV_PMP_CFG_BITPOS_63 56 #endif -#define RISCV_PMP_CFG_CSR_0 "pmpcfg0" -#define RISCV_PMP_CFG_CSR_1 "pmpcfg0" -#define RISCV_PMP_CFG_CSR_2 "pmpcfg0" -#define RISCV_PMP_CFG_CSR_3 "pmpcfg0" -#define RISCV_PMP_CFG_CSR_4 "pmpcfg0" -#define RISCV_PMP_CFG_CSR_5 "pmpcfg0" -#define RISCV_PMP_CFG_CSR_6 "pmpcfg0" -#define RISCV_PMP_CFG_CSR_7 "pmpcfg0" -#define RISCV_PMP_CFG_CSR_8 "pmpcfg2" -#define RISCV_PMP_CFG_CSR_9 "pmpcfg2" -#define RISCV_PMP_CFG_CSR_10 "pmpcfg2" -#define RISCV_PMP_CFG_CSR_11 "pmpcfg2" -#define RISCV_PMP_CFG_CSR_12 "pmpcfg2" -#define RISCV_PMP_CFG_CSR_13 "pmpcfg2" -#define RISCV_PMP_CFG_CSR_14 "pmpcfg2" -#define RISCV_PMP_CFG_CSR_15 "pmpcfg2" +#define __RISCV_PMP_CFG_CSR_0 "pmpcfg0" +#define __RISCV_PMP_CFG_CSR_1 "pmpcfg0" +#define __RISCV_PMP_CFG_CSR_2 "pmpcfg0" +#define __RISCV_PMP_CFG_CSR_3 "pmpcfg0" +#define __RISCV_PMP_CFG_CSR_4 "pmpcfg0" +#define __RISCV_PMP_CFG_CSR_5 "pmpcfg0" +#define __RISCV_PMP_CFG_CSR_6 "pmpcfg0" +#define __RISCV_PMP_CFG_CSR_7 "pmpcfg0" +#define __RISCV_PMP_CFG_CSR_8 "pmpcfg2" +#define __RISCV_PMP_CFG_CSR_9 "pmpcfg2" +#define __RISCV_PMP_CFG_CSR_10 "pmpcfg2" +#define __RISCV_PMP_CFG_CSR_11 "pmpcfg2" +#define __RISCV_PMP_CFG_CSR_12 "pmpcfg2" +#define __RISCV_PMP_CFG_CSR_13 "pmpcfg2" +#define __RISCV_PMP_CFG_CSR_14 "pmpcfg2" +#define __RISCV_PMP_CFG_CSR_15 "pmpcfg2" #if RISCV_PMP_REGION_COUNT == 64 -#define RISCV_PMP_CFG_CSR_16 "pmpcfg4" -#define RISCV_PMP_CFG_CSR_17 "pmpcfg4" -#define RISCV_PMP_CFG_CSR_18 "pmpcfg4" -#define RISCV_PMP_CFG_CSR_19 "pmpcfg4" -#define RISCV_PMP_CFG_CSR_20 "pmpcfg4" -#define RISCV_PMP_CFG_CSR_21 "pmpcfg4" -#define RISCV_PMP_CFG_CSR_22 "pmpcfg4" -#define RISCV_PMP_CFG_CSR_23 "pmpcfg4" -#define RISCV_PMP_CFG_CSR_24 "pmpcfg6" -#define RISCV_PMP_CFG_CSR_25 "pmpcfg6" -#define RISCV_PMP_CFG_CSR_26 "pmpcfg6" -#define RISCV_PMP_CFG_CSR_27 "pmpcfg6" -#define RISCV_PMP_CFG_CSR_28 "pmpcfg6" -#define RISCV_PMP_CFG_CSR_29 "pmpcfg6" -#define RISCV_PMP_CFG_CSR_30 "pmpcfg6" -#define RISCV_PMP_CFG_CSR_31 "pmpcfg6" -#define RISCV_PMP_CFG_CSR_32 "pmpcfg8" -#define RISCV_PMP_CFG_CSR_33 "pmpcfg8" -#define RISCV_PMP_CFG_CSR_34 "pmpcfg8" -#define RISCV_PMP_CFG_CSR_35 "pmpcfg8" -#define RISCV_PMP_CFG_CSR_36 "pmpcfg8" -#define RISCV_PMP_CFG_CSR_37 "pmpcfg8" -#define RISCV_PMP_CFG_CSR_38 "pmpcfg8" -#define RISCV_PMP_CFG_CSR_39 "pmpcfg8" -#define RISCV_PMP_CFG_CSR_40 "pmpcfg10" -#define RISCV_PMP_CFG_CSR_41 "pmpcfg10" -#define RISCV_PMP_CFG_CSR_42 "pmpcfg10" -#define RISCV_PMP_CFG_CSR_43 "pmpcfg10" -#define RISCV_PMP_CFG_CSR_44 "pmpcfg10" -#define RISCV_PMP_CFG_CSR_45 "pmpcfg10" -#define RISCV_PMP_CFG_CSR_46 "pmpcfg10" -#define RISCV_PMP_CFG_CSR_47 "pmpcfg10" -#define RISCV_PMP_CFG_CSR_48 "pmpcfg12" -#define RISCV_PMP_CFG_CSR_49 "pmpcfg12" -#define RISCV_PMP_CFG_CSR_50 "pmpcfg12" -#define RISCV_PMP_CFG_CSR_51 "pmpcfg12" -#define RISCV_PMP_CFG_CSR_52 "pmpcfg12" -#define RISCV_PMP_CFG_CSR_53 "pmpcfg12" -#define RISCV_PMP_CFG_CSR_54 "pmpcfg12" -#define RISCV_PMP_CFG_CSR_55 "pmpcfg12" -#define RISCV_PMP_CFG_CSR_56 "pmpcfg14" -#define RISCV_PMP_CFG_CSR_57 "pmpcfg14" -#define RISCV_PMP_CFG_CSR_58 "pmpcfg14" -#define RISCV_PMP_CFG_CSR_59 "pmpcfg14" -#define RISCV_PMP_CFG_CSR_60 "pmpcfg14" -#define RISCV_PMP_CFG_CSR_61 "pmpcfg14" -#define RISCV_PMP_CFG_CSR_62 "pmpcfg14" -#define RISCV_PMP_CFG_CSR_63 "pmpcfg14" +#define __RISCV_PMP_CFG_CSR_16 "pmpcfg4" +#define __RISCV_PMP_CFG_CSR_17 "pmpcfg4" +#define __RISCV_PMP_CFG_CSR_18 "pmpcfg4" +#define __RISCV_PMP_CFG_CSR_19 "pmpcfg4" +#define __RISCV_PMP_CFG_CSR_20 "pmpcfg4" +#define __RISCV_PMP_CFG_CSR_21 "pmpcfg4" +#define __RISCV_PMP_CFG_CSR_22 "pmpcfg4" +#define __RISCV_PMP_CFG_CSR_23 "pmpcfg4" +#define __RISCV_PMP_CFG_CSR_24 "pmpcfg6" +#define __RISCV_PMP_CFG_CSR_25 "pmpcfg6" +#define __RISCV_PMP_CFG_CSR_26 "pmpcfg6" +#define __RISCV_PMP_CFG_CSR_27 "pmpcfg6" +#define __RISCV_PMP_CFG_CSR_28 "pmpcfg6" +#define __RISCV_PMP_CFG_CSR_29 "pmpcfg6" +#define __RISCV_PMP_CFG_CSR_30 "pmpcfg6" +#define __RISCV_PMP_CFG_CSR_31 "pmpcfg6" +#define __RISCV_PMP_CFG_CSR_32 "pmpcfg8" +#define __RISCV_PMP_CFG_CSR_33 "pmpcfg8" +#define __RISCV_PMP_CFG_CSR_34 "pmpcfg8" +#define __RISCV_PMP_CFG_CSR_35 "pmpcfg8" +#define __RISCV_PMP_CFG_CSR_36 "pmpcfg8" +#define __RISCV_PMP_CFG_CSR_37 "pmpcfg8" +#define __RISCV_PMP_CFG_CSR_38 "pmpcfg8" +#define __RISCV_PMP_CFG_CSR_39 "pmpcfg8" +#define __RISCV_PMP_CFG_CSR_40 "pmpcfg10" +#define __RISCV_PMP_CFG_CSR_41 "pmpcfg10" +#define __RISCV_PMP_CFG_CSR_42 "pmpcfg10" +#define __RISCV_PMP_CFG_CSR_43 "pmpcfg10" +#define __RISCV_PMP_CFG_CSR_44 "pmpcfg10" +#define __RISCV_PMP_CFG_CSR_45 "pmpcfg10" +#define __RISCV_PMP_CFG_CSR_46 "pmpcfg10" +#define __RISCV_PMP_CFG_CSR_47 "pmpcfg10" +#define __RISCV_PMP_CFG_CSR_48 "pmpcfg12" +#define __RISCV_PMP_CFG_CSR_49 "pmpcfg12" +#define __RISCV_PMP_CFG_CSR_50 "pmpcfg12" +#define __RISCV_PMP_CFG_CSR_51 "pmpcfg12" +#define __RISCV_PMP_CFG_CSR_52 "pmpcfg12" +#define __RISCV_PMP_CFG_CSR_53 "pmpcfg12" +#define __RISCV_PMP_CFG_CSR_54 "pmpcfg12" +#define __RISCV_PMP_CFG_CSR_55 "pmpcfg12" +#define __RISCV_PMP_CFG_CSR_56 "pmpcfg14" +#define __RISCV_PMP_CFG_CSR_57 "pmpcfg14" +#define __RISCV_PMP_CFG_CSR_58 "pmpcfg14" +#define __RISCV_PMP_CFG_CSR_59 "pmpcfg14" +#define __RISCV_PMP_CFG_CSR_60 "pmpcfg14" +#define __RISCV_PMP_CFG_CSR_61 "pmpcfg14" +#define __RISCV_PMP_CFG_CSR_62 "pmpcfg14" +#define __RISCV_PMP_CFG_CSR_63 "pmpcfg14" #endif #endif @@ -347,14 +353,14 @@ static inline size_t riscv_pmpaddr_calc_napot(size_t base, size_t size) { // Clear bits of a PMPCFG by index. #define riscv_pmpcfg_clear(index) \ - asm volatile("csrc " concat_keywords(RISCV_PMP_CFG_CSR_, index) ", %0" ::"r"( \ - 255ul << concat_keywords(RISCV_PMP_CFG_BITPOS_, index) \ + asm volatile("csrc " concat_keywords(__RISCV_PMP_CFG_CSR_, index) ", %0" ::"r"( \ + 255ul << concat_keywords(__RISCV_PMP_CFG_BITPOS_, index) \ )) // Set bits of a PMPCFG by index. #define riscv_pmpcfg_set(index, config) \ - asm volatile("csrs " concat_keywords(RISCV_PMP_CFG_CSR_, index) ", %0" ::"r"( \ - (unsigned long)(config).value << (unsigned long)concat_keywords(RISCV_PMP_CFG_BITPOS_, index) \ + asm volatile("csrs " concat_keywords(__RISCV_PMP_CFG_CSR_, index) ", %0" ::"r"( \ + (unsigned long)(config).value << (unsigned long)concat_keywords(__RISCV_PMP_CFG_BITPOS_, index) \ )) // Write a PMPCFG by index. diff --git a/port/esp32c6/include/port/hardware_allocation.h b/port/esp32c6/include/port/hardware_allocation.h index ebe66b8..1c8300c 100644 --- a/port/esp32c6/include/port/hardware_allocation.h +++ b/port/esp32c6/include/port/hardware_allocation.h @@ -59,13 +59,15 @@ #define PMP_BASE_FLASH_WP 0x42000000 // NAPOT PMP entry for lower nullpointer protection. -#define PMP_ENTRY_NULLPTR_LOW_NAPOT 0 +#define PMP_ENTRY_NULLPTR_LOW_NAPOT 12 // NAPOT PMP entry for upper nullpointer protection. -#define PMP_ENTRY_NULLPTR_HIGH_NAPOT 1 +#define PMP_ENTRY_NULLPTR_HIGH_NAPOT 13 // NAPOT PMP entry for ROM write protection -#define PMP_ENTRY_ROM_WP_NAPOT 2 +#define PMP_ENTRY_ROM_WP_NAPOT 14 // NAPOT PMP entry for FLASH write protection -#define PMP_ENTRY_FLASH_WP_NAPOT 3 +#define PMP_ENTRY_FLASH_WP_NAPOT 15 +// NAPOT PMP entry for U-mode global permissions. +#define PMP_ENTRY_USER_GLOBAL_NAPOT 11 // Base PMP entry for external RAM assigned to userland. #define PMP_ENTRY_USER_EXTRAM_BASE 4 // TOR PMP entry for external RAM assigned to userland. diff --git a/port/esp32c6/src/memprotect.c b/port/esp32c6/src/memprotect.c index 9d85554..0150c77 100644 --- a/port/esp32c6/src/memprotect.c +++ b/port/esp32c6/src/memprotect.c @@ -67,6 +67,20 @@ void memprotect_init() { .lock = true, }) ); + + // Add user global permissions. + riscv_pmpaddr_write(PMP_ENTRY_USER_GLOBAL_NAPOT, RISCV_PMPADDR_NAPOT_GLOBAL); + riscv_pmpcfg_set( + PMP_ENTRY_FLASH_WP_NAPOT, + ((riscv_pmpcfg_t){ + .read = false, + .write = false, + .exec = false, + .addr_match_mode = RISCV_PMPCFG_NAPOT, + ._reserved = 0, + .lock = false, + }) + ); } // Set the range of external RAM currently assigned to userland. diff --git a/src/main.c b/src/main.c index eda9a4a..4be6ba9 100644 --- a/src/main.c +++ b/src/main.c @@ -3,6 +3,7 @@ #include "assertions.h" #include "attributes.h" +#include "cpu/riscv_pmp.h" #include "gpio.h" #include "log.h" #include "malloc.h" @@ -10,6 +11,7 @@ #include "port/interrupt.h" #include "rawprint.h" #include "scheduler.h" +#include "syscall.h" #include "time.h" #include @@ -34,6 +36,21 @@ static struct led_config led_pins[3] = { static uint8_t led_blink_stack[3][512] ALIGNED_TO(STACK_ALIGNMENT); static uint8_t uart_print_stack[3][256] ALIGNED_TO(STACK_ALIGNMENT); + +uint32_t userland_stack[1024]; + +static void userland_entry(void *ignored) { + asm(".option push\n" + ".option norelax\n" + ".global __global_pointer$\n" + ".global userland_stack\n" + "la gp, __global_pointer$\n" + "la sp, userland_stack+4096\n" + ".option pop"); + logk(LOG_DEBUG, "This is a USER MESSAGE!"); + while (1) syscall_thread_yield(); +} + // This is the entrypoint after the stack has been set up and the init functions // have been run. Main is not allowed to return, so declare it noreturn. void main() NORETURN; @@ -46,6 +63,17 @@ void main() { // Set up memory protection. memprotect_init(); + // give userland everything for now. + asm volatile("csrw pmpaddr4, %0" ::"r"(RISCV_PMPADDR_NAPOT_GLOBAL)); + riscv_pmpcfg_t cfg = { + .read = true, + .write = true, + .exec = true, + .addr_match_mode = RISCV_PMPCFG_NAPOT, + ._reserved = 0, + .lock = false}; + asm volatile("csrw pmpcfg1, %0" ::"r"(cfg.value)); + // Set up timers and watchdogs. // This function must run within the first ~1s of power-on time and should be // called as early as possible. @@ -69,6 +97,15 @@ void main() { sched_init(&err); assert_always(badge_err_is_ok(&err)); + sched_thread_t *const user_thread = + sched_create_userland_thread(&err, (void *)1, userland_entry, NULL, SCHED_PRIO_NORMAL); + assert_always(user_thread != NULL); + assert_always(badge_err_is_ok(&err)); + sched_set_name(&err, user_thread, "User Thread"); + assert_always(badge_err_is_ok(&err)); + sched_resume_thread(&err, user_thread); + assert_always(badge_err_is_ok(&err)); + for (size_t i = 0; i < 3; i++) { sched_thread_t *const led_thread = sched_create_kernel_thread( From bd1b7250d38915f29ff7f766dda8e23ab1abf36a Mon Sep 17 00:00:00 2001 From: RobotMan2412 Date: Sat, 29 Jul 2023 15:51:23 +0200 Subject: [PATCH 3/3] Memory protection --- port/esp32c6/src/memprotect.c | 7 ++++--- src/main.c | 20 -------------------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/port/esp32c6/src/memprotect.c b/port/esp32c6/src/memprotect.c index 0150c77..f359d42 100644 --- a/port/esp32c6/src/memprotect.c +++ b/port/esp32c6/src/memprotect.c @@ -69,13 +69,14 @@ void memprotect_init() { ); // Add user global permissions. + // TODO: These permissions will be NONE later, but are ALL for now. riscv_pmpaddr_write(PMP_ENTRY_USER_GLOBAL_NAPOT, RISCV_PMPADDR_NAPOT_GLOBAL); riscv_pmpcfg_set( PMP_ENTRY_FLASH_WP_NAPOT, ((riscv_pmpcfg_t){ - .read = false, - .write = false, - .exec = false, + .read = true, + .write = true, + .exec = true, .addr_match_mode = RISCV_PMPCFG_NAPOT, ._reserved = 0, .lock = false, diff --git a/src/main.c b/src/main.c index 4be6ba9..cc3711f 100644 --- a/src/main.c +++ b/src/main.c @@ -63,17 +63,6 @@ void main() { // Set up memory protection. memprotect_init(); - // give userland everything for now. - asm volatile("csrw pmpaddr4, %0" ::"r"(RISCV_PMPADDR_NAPOT_GLOBAL)); - riscv_pmpcfg_t cfg = { - .read = true, - .write = true, - .exec = true, - .addr_match_mode = RISCV_PMPCFG_NAPOT, - ._reserved = 0, - .lock = false}; - asm volatile("csrw pmpcfg1, %0" ::"r"(cfg.value)); - // Set up timers and watchdogs. // This function must run within the first ~1s of power-on time and should be // called as early as possible. @@ -97,15 +86,6 @@ void main() { sched_init(&err); assert_always(badge_err_is_ok(&err)); - sched_thread_t *const user_thread = - sched_create_userland_thread(&err, (void *)1, userland_entry, NULL, SCHED_PRIO_NORMAL); - assert_always(user_thread != NULL); - assert_always(badge_err_is_ok(&err)); - sched_set_name(&err, user_thread, "User Thread"); - assert_always(badge_err_is_ok(&err)); - sched_resume_thread(&err, user_thread); - assert_always(badge_err_is_ok(&err)); - for (size_t i = 0; i < 3; i++) { sched_thread_t *const led_thread = sched_create_kernel_thread(