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