33 * "LICENSE" for information on usage and redistribution of this file.
44 */
55
6- #if !RV32_HAS (SYSTEM )
7- #error "Do not manage to build this file unless you enable system support."
8- #endif
9-
106#include <assert.h>
117
128#include "devices/plic.h"
139#include "devices/uart.h"
1410#include "riscv_private.h"
11+ #include "system.h"
1512
16- #if RV32_HAS ( SYSTEM ) && !RV32_HAS (ELF_LOADER )
13+ #if !RV32_HAS (ELF_LOADER )
1714void emu_update_uart_interrupts (riscv_t * rv )
1815{
1916 vm_attr_t * attr = PRIV (rv );
@@ -24,84 +21,6 @@ void emu_update_uart_interrupts(riscv_t *rv)
2421 attr -> plic -> active &= ~IRQ_UART_BIT ;
2522 plic_update_interrupts (attr -> plic );
2623}
27-
28- #define MMIO_R 1
29- #define MMIO_W 0
30-
31- enum SUPPORTED_MMIO {
32- MMIO_PLIC ,
33- MMIO_UART ,
34- };
35-
36- /* clang-format off */
37- #define MMIO_OP (io , rw ) \
38- switch(io){ \
39- case MMIO_PLIC: \
40- IIF(rw)( /* read */ \
41- mmio_read_val = plic_read (PRIV (rv )-> plic , addr & 0x3FFFFFF ); \
42- plic_update_interrupts (PRIV (rv )-> plic ); \
43- return mmio_read_val ; \
44- , /* write */ \
45- plic_write (PRIV (rv )-> plic , addr & 0x3FFFFFF , val ); \
46- plic_update_interrupts (PRIV (rv )-> plic ); \
47- return ; \
48- ) \
49- break ; \
50- case MMIO_UART : \
51- IIF (rw )( /* read */ \
52- mmio_read_val = u8250_read (PRIV (rv )-> uart , addr & 0xFFFFF ); \
53- emu_update_uart_interrupts (rv ); \
54- return mmio_read_val ; \
55- , /* write */ \
56- u8250_write (PRIV (rv )-> uart , addr & 0xFFFFF , val ); \
57- emu_update_uart_interrupts (rv ); \
58- return ; \
59- ) \
60- break ; \
61- default : \
62- fprintf (stderr , "unknown MMIO type %d\n" , io ); \
63- break ; \
64- }
65- /* clang-format on */
66-
67- #define MMIO_READ () \
68- do { \
69- uint32_t mmio_read_val; \
70- if ((addr >> 28) == 0xF) { /* MMIO at 0xF_______ */ \
71- /* 256 regions of 1MiB */ \
72- switch ((addr >> 20 ) & MASK (8 )) { \
73- case 0x0 : \
74- case 0x2 : /* PLIC (0 - 0x3F) */ \
75- MMIO_OP (MMIO_PLIC , MMIO_R ); \
76- break ; \
77- case 0x40 : /* UART */ \
78- MMIO_OP (MMIO_UART , MMIO_R ); \
79- break ; \
80- default : \
81- __UNREACHABLE ; \
82- break ; \
83- } \
84- } \
85- } while (0 )
86-
87- #define MMIO_WRITE () \
88- do { \
89- if ((addr >> 28) == 0xF) { /* MMIO at 0xF_______ */ \
90- /* 256 regions of 1MiB */ \
91- switch ((addr >> 20 ) & MASK (8 )) { \
92- case 0x0 : \
93- case 0x2 : /* PLIC (0 - 0x3F) */ \
94- MMIO_OP (MMIO_PLIC , MMIO_W ); \
95- break ; \
96- case 0x40 : /* UART */ \
97- MMIO_OP (MMIO_UART , MMIO_W ); \
98- break ; \
99- default : \
100- __UNREACHABLE ; \
101- break ; \
102- } \
103- } \
104- } while (0 )
10524#endif
10625
10726static bool ppn_is_valid (riscv_t * rv , uint32_t ppn )
@@ -116,14 +35,7 @@ static bool ppn_is_valid(riscv_t *rv, uint32_t ppn)
11635 ? (uint32_t *) (attr->mem->mem_base + (ppn << (RV_PG_SHIFT))) \
11736 : NULL
11837
119- /* Walk through page tables and get the corresponding PTE by virtual address if
120- * exists
121- * @rv: RISC-V emulator
122- * @addr: virtual address
123- * @level: the level of which the PTE is located
124- * @return: NULL if a not found or fault else the corresponding PTE
125- */
126- static uint32_t * mmu_walk (riscv_t * rv , const uint32_t addr , uint32_t * level )
38+ uint32_t * mmu_walk (riscv_t * rv , const uint32_t addr , uint32_t * level )
12739{
12840 vm_attr_t * attr = PRIV (rv );
12941 uint32_t ppn = rv -> csr_satp & MASK (22 );
@@ -178,81 +90,71 @@ static uint32_t *mmu_walk(riscv_t *rv, const uint32_t addr, uint32_t *level)
17890/* FIXME: handle access fault, addr out of range check */
17991#define MMU_FAULT_CHECK (op , rv , pte , addr , access_bits ) \
18092 mmu_##op##_fault_check(rv, pte, addr, access_bits)
181- #define MMU_FAULT_CHECK_IMPL (op , pgfault ) \
182- static bool mmu_##op##_fault_check(riscv_t *rv, pte_t *pte, uint32_t addr, \
183- uint32_t access_bits) \
184- { \
185- uint32_t scause; \
186- uint32_t stval = addr; \
187- switch (access_bits) { \
188- case PTE_R: \
189- scause = PAGEFAULT_LOAD; \
190- break; \
191- case PTE_W: \
192- scause = PAGEFAULT_STORE; \
193- break; \
194- case PTE_X: \
195- scause = PAGEFAULT_INSN; \
196- break; \
197- default: \
198- __UNREACHABLE; \
199- break; \
200- } \
201- if (pte && (!(*pte & PTE_V))) { \
202- SET_CAUSE_AND_TVAL_THEN_TRAP(rv, scause, stval); \
203- return false; \
204- } \
205- if (!(pte && (*pte & access_bits))) { \
206- SET_CAUSE_AND_TVAL_THEN_TRAP(rv, scause, stval); \
207- return false; \
208- } \
209- /* \
210- * (1) When MXR=0, only loads from pages marked readable (R=1) will \
211- * succeed. \
212- * \
213- * (2) When MXR=1, loads from pages marked either readable or \
214- * executable (R=1 or X=1) will succeed. \
215- */ \
216- if (pte && ((!(SSTATUS_MXR & rv -> csr_sstatus ) && !(* pte & PTE_R ) && \
217- (access_bits == PTE_R )) || \
218- ((SSTATUS_MXR & rv -> csr_sstatus ) && \
219- !((* pte & PTE_R ) | (* pte & PTE_X )) && \
220- (access_bits == PTE_R )))) { \
221- SET_CAUSE_AND_TVAL_THEN_TRAP (rv , scause , stval ); \
222- return false; \
223- } \
224- /* \
225- * When SUM=0, S-mode memory accesses to pages that are accessible by \
226- * U-mode will fault. \
227- */ \
228- if (pte && rv -> priv_mode == RV_PRIV_S_MODE && \
229- !(SSTATUS_SUM & rv -> csr_sstatus ) && (* pte & PTE_U )) { \
230- SET_CAUSE_AND_TVAL_THEN_TRAP (rv , scause , stval ); \
231- return false; \
232- } \
233- /* PTE not found, map it in handler */ \
234- if (!pte ) { \
235- SET_CAUSE_AND_TVAL_THEN_TRAP (rv , scause , stval ); \
236- return false; \
237- } \
238- /* valid PTE */ \
239- return true; \
93+ #define MMU_FAULT_CHECK_IMPL (op , pgfault ) \
94+ bool mmu_##op##_fault_check(riscv_t *rv, pte_t *pte, uint32_t addr, \
95+ uint32_t access_bits) \
96+ { \
97+ uint32_t scause; \
98+ uint32_t stval = addr; \
99+ switch (access_bits) { \
100+ case PTE_R: \
101+ scause = PAGEFAULT_LOAD; \
102+ break; \
103+ case PTE_W: \
104+ scause = PAGEFAULT_STORE; \
105+ break; \
106+ case PTE_X: \
107+ scause = PAGEFAULT_INSN; \
108+ break; \
109+ default: \
110+ __UNREACHABLE; \
111+ break; \
112+ } \
113+ if (pte && (!(*pte & PTE_V))) { \
114+ SET_CAUSE_AND_TVAL_THEN_TRAP(rv, scause, stval); \
115+ return false; \
116+ } \
117+ if (!(pte && (*pte & access_bits))) { \
118+ SET_CAUSE_AND_TVAL_THEN_TRAP(rv, scause, stval); \
119+ return false; \
120+ } \
121+ /* \
122+ * (1) When MXR=0, only loads from pages marked readable (R=1) will \
123+ * succeed. \
124+ * \
125+ * (2) When MXR=1, loads from pages marked either readable or \
126+ * executable (R=1 or X=1) will succeed. \
127+ */ \
128+ if (pte && ((!(SSTATUS_MXR & rv -> csr_sstatus ) && !(* pte & PTE_R ) && \
129+ (access_bits == PTE_R )) || \
130+ ((SSTATUS_MXR & rv -> csr_sstatus ) && \
131+ !((* pte & PTE_R ) | (* pte & PTE_X )) && \
132+ (access_bits == PTE_R )))) { \
133+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , scause , stval ); \
134+ return false; \
135+ } \
136+ /* \
137+ * When SUM=0, S-mode memory accesses to pages that are accessible by \
138+ * U-mode will fault. \
139+ */ \
140+ if (pte && rv -> priv_mode == RV_PRIV_S_MODE && \
141+ !(SSTATUS_SUM & rv -> csr_sstatus ) && (* pte & PTE_U )) { \
142+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , scause , stval ); \
143+ return false; \
144+ } \
145+ /* PTE not found, map it in handler */ \
146+ if (!pte ) { \
147+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , scause , stval ); \
148+ return false; \
149+ } \
150+ /* valid PTE */ \
151+ return true; \
240152 }
241153
242154MMU_FAULT_CHECK_IMPL (ifetch , pagefault_insn )
243155MMU_FAULT_CHECK_IMPL (read , pagefault_load )
244156MMU_FAULT_CHECK_IMPL (write , pagefault_store )
245157
246- #define get_ppn_and_offset () \
247- uint32_t ppn; \
248- uint32_t offset; \
249- do { \
250- assert(pte); \
251- ppn = *pte >> (RV_PG_SHIFT - 2) << RV_PG_SHIFT; \
252- offset = level == 1 ? addr & MASK((RV_PG_SHIFT + 10)) \
253- : addr & MASK(RV_PG_SHIFT); \
254- } while (0)
255-
256158/* The IO handler that operates when the Memory Management Unit (MMU)
257159 * is enabled during system emulation is responsible for managing
258160 * input/output operations. These callbacks are designed to implement
0 commit comments