1 // Copyright (c) 2013, The Regents of the University of California (Regents). 2 // Copyright (c) 2018-2019, The libfemto authors 3 // Copyright (c) 2020 Espressif Systems (Shanghai) PTE LTD 4 // All Rights Reserved. 5 6 // Redistribution and use in source and binary forms, with or without 7 // modification, are permitted provided that the following conditions are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. Neither the name of the Regents nor the 14 // names of its contributors may be used to endorse or promote products 15 // derived from this software without specific prior written permission. 16 17 // IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, 18 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING 19 // OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS 20 // BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 21 22 // REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 // PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED 25 // HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE 26 // MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 27 28 #pragma once 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 #include <stdint.h> 35 #include <stddef.h> 36 #include <stdbool.h> 37 #include <sys/param.h> 38 #include "encoding.h" 39 #include "esp_assert.h" 40 41 /******************************************************** 42 Physical Memory Attributes (PMA) register fields 43 (privileged spec) 44 ********************************************************/ 45 46 /******************************************************** 47 PMA CSR and TOR & NAPOT macros 48 ********************************************************/ 49 #define CSR_PMACFG0 0xBC0 50 #define CSR_PMAADDR0 0xBD0 51 52 #define CSR_PMACFG(i) (CSR_PMACFG0 + (i)) 53 #define CSR_PMAADDR(i) (CSR_PMAADDR0 + (i)) 54 55 #define PMA_EN BIT(0) 56 #define PMA_R BIT(4) 57 #define PMA_W BIT(3) 58 #define PMA_X BIT(2) 59 #define PMA_L BIT(29) 60 #define PMA_SHIFT 2 61 62 #define PMA_TOR 0x40000000 63 #define PMA_NA4 0x80000000 64 #define PMA_NAPOT 0xC0000000 65 66 #define PMA_NONCACHEABLE BIT(27) 67 #define PMA_WRITETHROUGH BIT(26) 68 #define PMA_WRITEMISSNOALLOC BIT(25) 69 #define PMA_READMISSNOALLOC BIT(24) 70 71 #define PMA_ENTRY_SET_TOR(ENTRY, ADDR, CFG) \ 72 do { \ 73 RV_WRITE_CSR((CSR_PMAADDR0) + (ENTRY), (ADDR) >> (PMA_SHIFT)); \ 74 RV_WRITE_CSR((CSR_PMACFG0) + (ENTRY), CFG); \ 75 } while (0) 76 77 #define PMA_ENTRY_SET_NAPOT(ENTRY, ADDR, SIZE, CFG) \ 78 do { \ 79 ESP_STATIC_ASSERT(__builtin_popcount((SIZE)) == 1, "Size must be a power of 2"); \ 80 ESP_STATIC_ASSERT((ADDR) % ((SIZE)) == 0, "Addr must be aligned to size"); \ 81 RV_WRITE_CSR((CSR_PMAADDR0) + (ENTRY), ((ADDR) | ((SIZE >> 1) - 1)) >> 2); \ 82 RV_WRITE_CSR((CSR_PMACFG0) + (ENTRY), CFG); \ 83 } while (0) 84 85 /******************************************************** 86 Physical Memory Protection (PMP) register fields 87 (privileged spec) 88 ********************************************************/ 89 90 /* Value of pmpcfg0 CSR. Note this macro is only needed for calculations like (CSR_PMPCFG0 + 1), which must 91 still be constant at compile time. Use the assembler name pmpcfg0, pmpcfg1, pmpcfg2, etc. in other cases */ 92 #define CSR_PMPCFG0 0x3A0 93 94 /* Value of pmpaddr0 CSR. Note, as above, this macro is only needed for calculations and the assembler names 95 pmpaddr0, pmpaddr1, pmpaddr2, etc should be used otherwise. */ 96 #define CSR_PMPADDR0 0x3B0 97 98 /* Generate the PMP address field value when PMPCFG.A == NAPOT 99 100 START & END should be calculated at compile time. The size of the region 101 (END-START) must be a power of 2 size, and START must be aligned to this 102 size. 103 104 Note: this value must be right-shifted PMP_SHIFT when written to the PMPADDR 105 register. The PMP_ENTRY_SET macro will do this. 106 */ 107 #define PMPADDR_NAPOT(START, END) ({ \ 108 ESP_STATIC_ASSERT(__builtin_popcount((END)-(START)) == 1, "Size must be a power of 2"); \ 109 ESP_STATIC_ASSERT((START) % ((END)-(START)) == 0, "Start must be aligned to size"); \ 110 (((START)) | (((END)-(START)-1)>>1)); \ 111 }) 112 113 #define PMPADDR_ALL 0xFFFFFFFF 114 115 116 /* Set a PMP entry. 117 118 - ENTRY is number of the PMP entry to set. This must be a compile-time constant because it's used to 119 generate specific assembly instructions. 120 - ADDR is the address to write to the PMPADDRx register. Note this is the unshifted address. 121 - CFG is the configuration value to write to the correct CFG entry register. Note that 122 the macro only sets bits in the CFG register, so it sould be zeroed already. 123 */ 124 #define PMP_ENTRY_SET(ENTRY, ADDR, CFG) do { \ 125 RV_WRITE_CSR((CSR_PMPADDR0) + (ENTRY), (ADDR) >> (PMP_SHIFT)); \ 126 RV_SET_CSR((CSR_PMPCFG0) + (ENTRY)/4, ((CFG)&0xFF) << (ENTRY%4)*8); \ 127 } while(0) 128 129 /*Only set PMPCFG entries*/ 130 #define PMP_ENTRY_CFG_SET(ENTRY, CFG) do {\ 131 RV_SET_CSR((CSR_PMPCFG0) + (ENTRY)/4, ((CFG)&0xFF) << (ENTRY%4)*8); \ 132 } while(0) 133 134 /*Reset all permissions of a particular PMPCFG entry*/ 135 #define PMP_ENTRY_CFG_RESET(ENTRY) do {\ 136 RV_CLEAR_CSR((CSR_PMPCFG0) + (ENTRY)/4, (0xFF) << (ENTRY%4)*8); \ 137 } while(0) 138 139 /******************************************************** 140 Trigger Module register fields (Debug specification) 141 ********************************************************/ 142 143 /* tcontrol CSRs not recognized by toolchain currently */ 144 #define CSR_TCONTROL 0x7a5 145 #define CSR_TDATA1 0x7a1 146 147 #define TCONTROL_MTE (1<<3) /*R/W, Current M mode trigger enable bit*/ 148 #define TCONTROL_MPTE (1<<7) /*R/W, Previous M mode trigger enable bit*/ 149 150 #define TDATA1_LOAD (1<<0) /*R/W,Fire trigger on load address match*/ 151 #define TDATA1_STORE (1<<1) /*R/W,Fire trigger on store address mat*/ 152 #define TDATA1_EXECUTE (1<<2) /*R/W,Fire trigger on instruction fetch address match*/ 153 #define TDATA1_USER (1<<3) /*R/W,allow trigger to be fired in user mode*/ 154 #define TDATA1_MACHINE (1<<6) /*R/W,Allow trigger to be fired while hart is executing in machine mode*/ 155 #define TDATA1_MATCH (1<<7) 156 #define TDATA1_MATCH_V (0xF) /*R/W,Address match type :0 : Exact byte match 1 : NAPOT range match */ 157 #define TDATA1_MATCH_S (7) 158 159 160 /* RISC-V CSR macros 161 * Adapted from https://github.com/michaeljclark/riscv-probe/blob/master/libfemto/include/arch/riscv/machine.h 162 */ 163 164 #define RV_READ_CONST_CSR(reg) ({ unsigned long __tmp; \ 165 asm ("csrr %0, " _CSR_STRINGIFY(reg) : "=r"(__tmp)); __tmp; }) 166 167 #define RV_READ_CSR(reg) ({ unsigned long __tmp; \ 168 asm volatile ("csrr %0, " _CSR_STRINGIFY(reg) : "=r"(__tmp)); __tmp; }) 169 170 #define RV_WRITE_CSR(reg, val) ({ \ 171 asm volatile ("csrw " _CSR_STRINGIFY(reg) ", %0" :: "rK"(val)); }) 172 173 #define RV_SWAP_CSR(reg, val) ({ unsigned long __tmp; \ 174 asm volatile ("csrrw %0, " _CSR_STRINGIFY(reg) ", %1" : "=r"(__tmp) : "rK"(val)); __tmp; }) 175 176 /* Note: this uses the atomic read-and-set instruction so possible to read the old CSR value as a result */ 177 #define RV_SET_CSR(reg, bit) ({ unsigned long __tmp; \ 178 asm volatile ("csrrs %0, " _CSR_STRINGIFY(reg) ", %1" : "=r"(__tmp) : "rK"(bit)); __tmp; }) 179 180 /* Note: this uses the atomic read-and-clear instruction so possible to read the old CSR value as a result */ 181 #define RV_CLEAR_CSR(reg, bit) ({ unsigned long __tmp; \ 182 asm volatile ("csrrc %0, " _CSR_STRINGIFY(reg) ", %1" : "=r"(__tmp) : "rK"(bit)); __tmp; }) 183 184 #define RV_SET_CSR_FIELD(_r, _f, _v) ({ (RV_WRITE_CSR((_r),((RV_READ_CSR(_r) & ~((_f##_V) << (_f##_S)))|(((_v) & (_f##_V))<<(_f##_S)))));}) 185 #define RV_CLEAR_CSR_FIELD(_r, _f) ({ (RV_WRITE_CSR((_r),(RV_READ_CSR(_r) & ~((_f##_V) << (_f##_S)))));}) 186 187 #define _CSR_STRINGIFY(REG) #REG /* needed so the 'reg' argument can be a macro or a register name */ 188 189 #ifdef __cplusplus 190 } 191 #endif 192