Skip to content

Commit a4d3eb1

Browse files
committed
Refactor "src/system.c" to enhence reusability
1 parent a965b24 commit a4d3eb1

File tree

3 files changed

+201
-162
lines changed

3 files changed

+201
-162
lines changed

Makefile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ CFLAGS = -std=gnu99 -O2 -Wall -Wextra
1111
CFLAGS += -Wno-unused-label
1212
CFLAGS += -include src/common.h -Isrc/
1313

14+
OBJS_EXT :=
15+
1416
# In the system test suite, the executable is an ELF file (e.g., MMU).
1517
# However, the Linux kernel emulation includes the Image, DT, and
1618
# root filesystem (rootfs). Therefore, the test suite needs this
@@ -29,6 +31,9 @@ $(call set-feature, BLOCK_CHAINING)
2931
# Enable system emulation
3032
ENABLE_SYSTEM ?= 0
3133
$(call set-feature, SYSTEM)
34+
ifeq ($(call has, SYSTEM), 1)
35+
OBJS_EXT += system.o
36+
endif
3237

3338
# Enable link-time optimization (LTO)
3439
ENABLE_LTO ?= 1
@@ -59,8 +64,6 @@ endif
5964
# Disable Intel's Control-flow Enforcement Technology (CET)
6065
CFLAGS += $(CFLAGS_NO_CET)
6166

62-
OBJS_EXT :=
63-
6467
# Integer Multiplication and Division instructions
6568
ENABLE_EXT_M ?= 1
6669
$(call set-feature, EXT_M)

src/system.c

Lines changed: 62 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,14 @@
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)
1714
void 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

10726
static 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

242154
MMU_FAULT_CHECK_IMPL(ifetch, pagefault_insn)
243155
MMU_FAULT_CHECK_IMPL(read, pagefault_load)
244156
MMU_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

Comments
 (0)