1 /*
2  * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3  * Copyright 2015, 2016 Hesham Almatary <heshamelmatary@gmail.com>
4  * Copyright 2021, HENSOLDT Cyber
5  *
6  * SPDX-License-Identifier: GPL-2.0-only
7  */
8 
9 #pragma once
10 
11 #ifndef __ASSEMBLER__
12 #include <arch/types.h>
13 #include <arch/object/structures.h>
14 #include <arch/machine/hardware.h>
15 #include <arch/model/statedata.h>
16 #include <arch/sbi.h>
17 #include <mode/machine.h>
18 
19 /* Bit flags in CSR MIP/SIP (interrupt pending). */
20 /* Bit 0 was SIP_USIP, but the N extension will be dropped in v1.12 */
21 #define SIP_SSIP   1 /* S-Mode software interrupt pending. */
22 /* Bit 2 was SIP_HSIP in v1.9, but the H extension was reworked afterwards. */
23 #define SIP_MSIP   3 /* M-Mode software interrupt pending (MIP only). */
24 /* Bit 4 was SIP_UTIP, but the N extension will be dropped in v1.12 */
25 #define SIP_STIP   5 /* S-Mode timer interrupt pending. */
26 /* Bit 6 was SIP_HTIP in v1.9, but the H extension was reworked afterwards. */
27 #define SIP_MTIP   7 /* M-Mode timer interrupt pending (MIP only). */
28 /* Bit 8 was SIP_UEIP, but the N extension will be dropped in v1.12 */
29 #define SIP_SEIP   9 /* S-Mode external interrupt pending. */
30 /* Bit 10 was SIP_HEIP in v1.9, but the H extension was reworked afterwards. */
31 #define SIP_MEIP  11 /* M-Mode external interrupt pending (MIP only). */
32 /* Bit 12 and above are reserved. */
33 
34 /* Bit flags in CSR MIE/SIE (interrupt enable). */
35 /* Bit 0 was SIE_USIE, but the N extension will be dropped in v1.12 */
36 #define SIE_SSIE   1 /* S-Mode software interrupt enable. */
37 /* Bit 2 was SIE_HSIE in v1.9, but the H extension was reworked afterwards. */
38 #define SIE_MSIE   3 /* M-Mode software interrupt enable (MIP only). */
39 /* Bit 4 was SIE_UTIE, but the N extension will be dropped in v1.12 */
40 #define SIE_STIE   5 /* S-Mode timer interrupt enable. */
41 /* Bit 6 was SIE_HTIE in v1.9, but the H extension was reworked afterwards. */
42 #define SIE_MTIE   7 /* M-Mode timer interrupt enable (MIP only). */
43 /* Bit 8 was SIE_UEIE, but the N extension will be dropped in v1.12 */
44 #define SIE_SEIE   9 /* S-Mode external interrupt enable. */
45 /* Bit 10 was SIE_HEIE in v1.9, but the H extension was reworked afterwards. */
46 #define SIE_MEIE  11 /* M-Mode external interrupt enable (MIP only). */
47 /* Bit 12 and above are reserved. */
48 
49 #ifdef ENABLE_SMP_SUPPORT
50 
fence_rw_rw(void)51 static inline void fence_rw_rw(void)
52 {
53     asm volatile("fence rw, rw" ::: "memory");
54 }
55 
fence_w_rw(void)56 static inline void fence_w_rw(void)
57 {
58     asm volatile("fence w, rw" ::: "memory");
59 }
60 
fence_r_rw(void)61 static inline void fence_r_rw(void)
62 {
63     asm volatile("fence r,rw" ::: "memory");
64 }
65 
fence_w_r(void)66 static inline void fence_w_r(void)
67 {
68     asm volatile("fence w,r" ::: "memory");
69 }
70 
ifence_local(void)71 static inline void ifence_local(void)
72 {
73     asm volatile("fence.i":::"memory");
74 }
75 
sfence_local(void)76 static inline void sfence_local(void)
77 {
78     asm volatile("sfence.vma" ::: "memory");
79 }
80 
ifence(void)81 static inline void ifence(void)
82 {
83     ifence_local();
84 
85     unsigned long mask = 0;
86     for (int i = 0; i < CONFIG_MAX_NUM_NODES; i++) {
87         if (i != getCurrentCPUIndex()) {
88             mask |= BIT(cpuIndexToID(i));
89         }
90     }
91     sbi_remote_fence_i(&mask);
92 }
93 
sfence(void)94 static inline void sfence(void)
95 {
96     fence_w_rw();
97     sfence_local();
98 
99     unsigned long mask = 0;
100     for (int i = 0; i < CONFIG_MAX_NUM_NODES; i++) {
101         if (i != getCurrentCPUIndex()) {
102             mask |= BIT(cpuIndexToID(i));
103         }
104     }
105     sbi_remote_sfence_vma(&mask, 0, 0);
106 }
107 
hwASIDFlushLocal(asid_t asid)108 static inline void hwASIDFlushLocal(asid_t asid)
109 {
110     asm volatile("sfence.vma x0, %0" :: "r"(asid): "memory");
111 }
112 
hwASIDFlush(asid_t asid)113 static inline void hwASIDFlush(asid_t asid)
114 {
115     hwASIDFlushLocal(asid);
116 
117     unsigned long mask = 0;
118     for (int i = 0; i < CONFIG_MAX_NUM_NODES; i++) {
119         if (i != getCurrentCPUIndex()) {
120             mask |= BIT(cpuIndexToID(i));
121         }
122     }
123     sbi_remote_sfence_vma_asid(&mask, 0, 0, asid);
124 }
125 
126 #else
127 
sfence(void)128 static inline void sfence(void)
129 {
130     asm volatile("sfence.vma" ::: "memory");
131 }
132 
hwASIDFlush(asid_t asid)133 static inline void hwASIDFlush(asid_t asid)
134 {
135     asm volatile("sfence.vma x0, %0" :: "r"(asid): "memory");
136 }
137 
138 #endif /* end of !ENABLE_SMP_SUPPORT */
139 
140 word_t PURE getRestartPC(tcb_t *thread);
141 void setNextPC(tcb_t *thread, word_t v);
142 
143 /* Cleaning memory before user-level access */
clearMemory(void * ptr,unsigned int bits)144 static inline void clearMemory(void *ptr, unsigned int bits)
145 {
146     memzero(ptr, BIT(bits));
147 }
148 
write_satp(word_t value)149 static inline void write_satp(word_t value)
150 {
151     asm volatile("csrw satp, %0" :: "rK"(value));
152 }
153 
write_stvec(word_t value)154 static inline void write_stvec(word_t value)
155 {
156     asm volatile("csrw stvec, %0" :: "rK"(value));
157 }
158 
read_stval(void)159 static inline word_t read_stval(void)
160 {
161     word_t temp;
162     asm volatile("csrr %0, stval" : "=r"(temp));
163     return temp;
164 }
165 
read_scause(void)166 static inline word_t read_scause(void)
167 {
168     word_t temp;
169     asm volatile("csrr %0, scause" : "=r"(temp));
170     return temp;
171 }
172 
read_sepc(void)173 static inline word_t read_sepc(void)
174 {
175     word_t temp;
176     asm volatile("csrr %0, sepc" : "=r"(temp));
177     return temp;
178 }
179 
read_sstatus(void)180 static inline word_t read_sstatus(void)
181 {
182     word_t temp;
183     asm volatile("csrr %0, sstatus" : "=r"(temp));
184     return temp;
185 }
186 
read_sip(void)187 static inline word_t read_sip(void)
188 {
189     word_t temp;
190     asm volatile("csrr %0, sip" : "=r"(temp));
191     return temp;
192 }
193 
write_sie(word_t value)194 static inline void write_sie(word_t value)
195 {
196     asm volatile("csrw sie,  %0" :: "r"(value));
197 }
198 
read_sie(void)199 static inline word_t read_sie(void)
200 {
201     word_t temp;
202     asm volatile("csrr %0, sie" : "=r"(temp));
203     return temp;
204 }
205 
set_sie_mask(word_t mask_high)206 static inline void set_sie_mask(word_t mask_high)
207 {
208     word_t temp;
209     asm volatile("csrrs %0, sie, %1" : "=r"(temp) : "rK"(mask_high));
210 }
211 
clear_sie_mask(word_t mask_low)212 static inline void clear_sie_mask(word_t mask_low)
213 {
214     word_t temp;
215     asm volatile("csrrc %0, sie, %1" : "=r"(temp) : "rK"(mask_low));
216 }
217 
218 #ifdef CONFIG_HAVE_FPU
read_fcsr(void)219 static inline uint32_t read_fcsr(void)
220 {
221     uint32_t fcsr;
222     asm volatile("csrr %0, fcsr" : "=r"(fcsr));
223     return fcsr;
224 }
225 
write_fcsr(uint32_t value)226 static inline void write_fcsr(uint32_t value)
227 {
228     asm volatile("csrw fcsr, %0" :: "rK"(value));
229 }
230 #endif
231 
232 #if CONFIG_PT_LEVELS == 2
233 #define SATP_MODE SATP_MODE_SV32
234 #elif CONFIG_PT_LEVELS == 3
235 #define SATP_MODE SATP_MODE_SV39
236 #elif CONFIG_PT_LEVELS == 4
237 #define SATP_MODE SATP_MODE_SV48
238 #else
239 #error "Unsupported PT levels"
240 #endif
setVSpaceRoot(paddr_t addr,asid_t asid)241 static inline void setVSpaceRoot(paddr_t addr, asid_t asid)
242 {
243     satp_t satp = satp_new(SATP_MODE,              /* mode */
244                            asid,                   /* asid */
245                            addr >> seL4_PageBits); /* PPN */
246 
247     write_satp(satp.words[0]);
248 
249     /* Order read/write operations */
250 #ifdef ENABLE_SMP_SUPPORT
251     sfence_local();
252 #else
253     sfence();
254 #endif
255 }
256 
257 void map_kernel_devices(void);
258 
259 /** MODIFIES: [*] */
260 void initTimer(void);
261 void initLocalIRQController(void);
262 void initIRQController(void);
263 void setIRQTrigger(irq_t irq, bool_t trigger);
264 
265 #ifdef ENABLE_SMP_SUPPORT
266 #define irq_remote_call_ipi     (INTERRUPT_IPI_0)
267 #define irq_reschedule_ipi      (INTERRUPT_IPI_1)
268 
arch_pause(void)269 static inline void arch_pause(void)
270 {
271     // use a memory fence to delay a bit.
272     // other alternatives?
273     fence_rw_rw();
274 }
275 
276 #endif
277 
278 /* Update the value of the actual register to hold the expected value */
Arch_setTLSRegister(word_t tls_base)279 static inline exception_t Arch_setTLSRegister(word_t tls_base)
280 {
281     /* The register is always reloaded upon return from kernel. */
282     setRegister(NODE_STATE(ksCurThread), TLS_BASE, tls_base);
283     return EXCEPTION_NONE;
284 }
285 
286 #endif // __ASSEMBLER__
287