Skip to content

Commit b21d054

Browse files
committed
Bring up Linux kernel
1 parent 4599b1d commit b21d054

File tree

19 files changed

+782
-96
lines changed

19 files changed

+782
-96
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ OBJS_EXT :=
4747

4848
ifeq ($(call has, SYSTEM), 1)
4949
OBJS_EXT += system.o
50+
OBJS_EXT += plic.o
51+
OBJS_EXT += uart.o
5052
endif
5153

5254
# Integer Multiplication and Division instructions

build/Image

4.48 MB
Binary file not shown.

build/minimal.dtb

1.36 KB
Binary file not shown.

build/rootfs.cpio

3.55 MB
Binary file not shown.

src/common.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@
2727

2828
#define MASK(n) (~((~0U << (n))))
2929

30+
/*
31+
* Integer log base 2
32+
*
33+
* The input will be ORed with 1 to prevent x = 0 since
34+
* the result is undefined if x = 0
35+
*
36+
*/
37+
#if defined(__GNUC__) || defined(__clang__)
38+
#define ilog2(x) 31 - __builtin_clz(x | 1)
39+
#elif defined(_MSC_VER)
40+
/* FIXME */
41+
#else /* unsupported compilers */
42+
#define ilog2(x)
43+
#endif
44+
3045
/* Alignment macro */
3146
#if defined(__GNUC__) || defined(__clang__)
3247
#define __ALIGNED(x) __attribute__((aligned(x)))

src/decode.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -922,9 +922,7 @@ static inline bool op_misc_mem(rv_insn_t *ir, const uint32_t insn)
922922
* FENCE FM[3:0] pred[3:0] succ[3:0] rs1 000 rd 0001111
923923
* FENCEI imm[11:0] rs1 001 rd 0001111
924924
*/
925-
926925
const uint32_t funct3 = decode_funct3(insn);
927-
928926
switch (funct3) {
929927
case 0b000:
930928
ir->opcode = rv_insn_fence;

src/decode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ enum op_field {
9090
) \
9191
/* RV32 Zicsr Standard Extension */ \
9292
IIF(RV32_HAS(Zicsr))( \
93-
_(csrrw, 0, 4, 0, ENC(rs1, rd)) \
93+
_(csrrw, 1, 4, 0, ENC(rs1, rd)) \
9494
_(csrrs, 0, 4, 0, ENC(rs1, rd)) \
9595
_(csrrc, 0, 4, 0, ENC(rs1, rd)) \
9696
_(csrrwi, 0, 4, 0, ENC(rs1, rd)) \

src/emulate.c

Lines changed: 101 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
#include <stdlib.h>
1111
#include <string.h>
1212

13+
#if RV32_HAS(SYSTEM)
14+
#include "plic.h"
15+
#endif /* RV32_HAS(SYSTEM) */
16+
1317
#ifdef __EMSCRIPTEN__
1418
#include <emscripten.h>
1519
#endif
@@ -41,6 +45,12 @@ extern struct target_ops gdbstub_ops;
4145
#define IF_rs2(i, r) (i->rs2 == rv_reg_##r)
4246
#define IF_imm(i, v) (i->imm == v)
4347

48+
#if RV32_HAS(SYSTEM)
49+
static uint32_t reloc_enable_mmu_jalr_addr;
50+
static bool reloc_enable_mmu = false;
51+
bool need_retranslate = false;
52+
#endif
53+
4454
static void rv_trap_default_handler(riscv_t *rv)
4555
{
4656
rv->csr_mepc += rv->compressed ? 2 : 4;
@@ -81,6 +91,13 @@ static inline void update_time(riscv_t *rv)
8191
rv->csr_time[1] = t >> 32;
8292
}
8393

94+
#if RV32_HAS(SYSTEM)
95+
static inline void get_time_now(struct timeval *tv)
96+
{
97+
rv_gettimeofday(tv);
98+
}
99+
#endif
100+
84101
#if RV32_HAS(Zicsr)
85102
/* get a pointer to a CSR */
86103
static uint32_t *csr_get_ptr(riscv_t *rv, uint32_t csr)
@@ -177,6 +194,13 @@ static uint32_t csr_csrrw(riscv_t *rv, uint32_t csr, uint32_t val)
177194

178195
*c = val;
179196

197+
/*
198+
* guestOS's process might have same VA,
199+
* so block_map cannot be reused
200+
*/
201+
if (c == &rv->csr_satp)
202+
block_map_clear(rv);
203+
180204
return out;
181205
}
182206

@@ -349,6 +373,11 @@ static set_t pc_set;
349373
static bool has_loops = false;
350374
#endif
351375

376+
#if RV32_HAS(SYSTEM)
377+
extern void emu_update_uart_interrupts(riscv_t *rv);
378+
static uint32_t peripheral_update_ctr = 64;
379+
#endif
380+
352381
/* Interpreter-based execution path */
353382
#define RVOP(inst, code, asm) \
354383
static bool do_##inst(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, \
@@ -539,6 +568,8 @@ FORCE_INLINE bool insn_is_unconditional_branch(uint8_t opcode)
539568

540569
static void block_translate(riscv_t *rv, block_t *block)
541570
{
571+
retranslate:
572+
memset(block, 0, sizeof(block_t));
542573
block->pc_start = block->pc_end = rv->PC;
543574

544575
rv_insn_t *prev_ir = NULL;
@@ -551,7 +582,16 @@ static void block_translate(riscv_t *rv, block_t *block)
551582
prev_ir->next = ir;
552583

553584
/* fetch the next instruction */
554-
const uint32_t insn = rv->io.mem_ifetch(rv, block->pc_end);
585+
uint32_t insn = rv->io.mem_ifetch(rv, block->pc_end);
586+
587+
#if RV32_HAS(SYSTEM)
588+
if (!insn && need_retranslate) {
589+
need_retranslate = false;
590+
goto retranslate;
591+
}
592+
#endif
593+
594+
assert(insn);
555595

556596
/* decode the instruction */
557597
if (!rv_decode(ir, insn)) {
@@ -560,8 +600,7 @@ static void block_translate(riscv_t *rv, block_t *block)
560600
break;
561601
}
562602
ir->impl = dispatch_table[ir->opcode];
563-
ir->pc = block->pc_end;
564-
/* compute the end of pc */
603+
ir->pc = block->pc_end; /* compute the end of pc */
565604
block->pc_end += is_compressed(insn) ? 2 : 4;
566605
block->n_insn++;
567606
prev_ir = ir;
@@ -878,6 +917,14 @@ static bool runtime_profiler(riscv_t *rv, block_t *block)
878917
}
879918
#endif
880919

920+
#if RV32_HAS(SYSTEM)
921+
static bool rv_has_plic_trap(riscv_t *rv)
922+
{
923+
return ((rv->csr_sstatus & SSTATUS_SIE || !rv->priv_mode) &&
924+
(rv->csr_sip & rv->csr_sie));
925+
}
926+
#endif
927+
881928
void rv_step(void *arg)
882929
{
883930
assert(arg);
@@ -891,6 +938,48 @@ void rv_step(void *arg)
891938

892939
/* loop until hitting the cycle target */
893940
while (rv->csr_cycle < cycles_target && !rv->halt) {
941+
#if RV32_HAS(SYSTEM)
942+
/* check for any interrupt after every block emulation */
943+
944+
/* now time */
945+
struct timeval tv;
946+
947+
if (peripheral_update_ctr-- == 0) {
948+
peripheral_update_ctr = 64;
949+
950+
u8250_check_ready(PRIV(rv)->uart);
951+
if (PRIV(rv)->uart->in_ready)
952+
emu_update_uart_interrupts(rv);
953+
}
954+
955+
get_time_now(&tv);
956+
uint64_t t = (uint64_t) (tv.tv_sec * 1e6) + (uint32_t) tv.tv_usec;
957+
958+
if (t > attr->timer) {
959+
rv->csr_sip |= RV_INT_STI;
960+
} else {
961+
rv->csr_sip &= ~RV_INT_STI;
962+
}
963+
964+
if (rv_has_plic_trap(rv)) {
965+
uint32_t intr_applicable = rv->csr_sip & rv->csr_sie;
966+
uint8_t intr_idx = ilog2(intr_applicable);
967+
switch (intr_idx) {
968+
case 1:
969+
SET_CAUSE_AND_TVAL_THEN_TRAP(rv, SUPERVISOR_SW_INTR, 0);
970+
break;
971+
case 5:
972+
SET_CAUSE_AND_TVAL_THEN_TRAP(rv, SUPERVISOR_TIMER_INTR, 0);
973+
break;
974+
case 9:
975+
SET_CAUSE_AND_TVAL_THEN_TRAP(rv, SUPERVISOR_EXTERNAL_INTR, 0);
976+
break;
977+
default:
978+
break;
979+
}
980+
}
981+
#endif /* RV32_HAS(SYSTEM) */
982+
894983
if (prev && prev->pc_start != last_pc) {
895984
/* update previous block */
896985
#if !RV32_HAS(JIT)
@@ -1018,6 +1107,8 @@ static void __trap_handler(riscv_t *rv)
10181107
assert(insn);
10191108

10201109
rv_decode(ir, insn);
1110+
reloc_enable_mmu_jalr_addr = rv->PC;
1111+
10211112
ir->impl = dispatch_table[ir->opcode];
10221113
rv->compressed = is_compressed(insn);
10231114
ir->impl(rv, ir, rv->csr_cycle, rv->PC);
@@ -1117,8 +1208,13 @@ void ecall_handler(riscv_t *rv)
11171208
{
11181209
assert(rv);
11191210
#if RV32_HAS(SYSTEM)
1120-
syscall_handler(rv);
1121-
rv->PC += 4;
1211+
if (rv->priv_mode == RV_PRIV_U_MODE) {
1212+
SET_CAUSE_AND_TVAL_THEN_TRAP(rv, ECALL_U, 0);
1213+
} else if (rv->priv_mode ==
1214+
RV_PRIV_S_MODE) { /* trap to SBI syscall handler */
1215+
rv->PC += 4;
1216+
syscall_handler(rv);
1217+
}
11221218
#else
11231219
SET_CAUSE_AND_TVAL_THEN_TRAP(rv, ECALL_M, 0);
11241220
syscall_handler(rv);

src/io.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@
1515

1616
#include "io.h"
1717

18+
u8250_state_t *u8250_new()
19+
{
20+
u8250_state_t *uart = calloc(1, sizeof(u8250_state_t));
21+
assert(uart);
22+
23+
return uart;
24+
}
25+
26+
plic_t *plic_new()
27+
{
28+
plic_t *plic = calloc(1, sizeof(plic_t));
29+
assert(plic);
30+
31+
return plic;
32+
}
33+
1834
static uint8_t *data_memory_base;
1935

2036
memory_t *memory_new(uint32_t size)

src/io.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,47 @@
55

66
#pragma once
77

8+
#include <stdbool.h>
89
#include <stdint.h>
910
#include <string.h>
1011

12+
/* UART */
13+
14+
#define IRQ_UART 1
15+
#define IRQ_UART_BIT (1 << IRQ_UART)
16+
17+
typedef struct {
18+
uint8_t dll, dlh; /**< divisor (ignored) */
19+
uint8_t lcr; /**< UART config */
20+
uint8_t ier; /**< interrupt config */
21+
uint8_t current_int, pending_ints; /**< interrupt status */
22+
/* other output signals, loopback mode (ignored) */
23+
uint8_t mcr;
24+
/* I/O handling */
25+
int in_fd, out_fd;
26+
bool in_ready;
27+
} u8250_state_t;
28+
void u8250_update_interrupts(u8250_state_t *uart);
29+
void u8250_check_ready(u8250_state_t *uart);
30+
31+
uint32_t u8250_read(u8250_state_t *uart, uint32_t addr);
32+
33+
void u8250_write(u8250_state_t *uart, uint32_t addr, uint32_t value);
34+
35+
/* create a UART controller */
36+
u8250_state_t *u8250_new();
37+
38+
typedef struct {
39+
uint32_t masked;
40+
uint32_t ip;
41+
uint32_t ie;
42+
/* state of input interrupt lines (level-triggered), set by environment */
43+
uint32_t active;
44+
} plic_t;
45+
46+
/* create a PLIC core */
47+
plic_t *plic_new();
48+
1149
typedef struct {
1250
uint8_t *mem_base;
1351
uint64_t mem_size;

src/main.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ int main(int argc, char **args)
209209
run_flag |= opt_prof_data << 2;
210210

211211
vm_attr_t attr = {
212-
.mem_size = MEM_SIZE,
212+
.mem_size = 512 * 1024 * 1024, /* FIXME: variadic size */
213213
.stack_size = STACK_SIZE,
214214
.args_offset_size = ARGS_OFFSET_SIZE,
215215
.argc = prog_argc,
@@ -227,7 +227,9 @@ int main(int argc, char **args)
227227
};
228228
#if RV32_HAS(SYSTEM)
229229
assert(attr.data.system);
230-
attr.data.system->elf_program = opt_prog_name;
230+
attr.data.system->kernel = "build/Image"; /* FIXME: hardcoded */
231+
attr.data.system->initrd = "build/rootfs.cpio"; /* FIXME: hardcoded */
232+
attr.data.system->dtb = "build/minimal.dtb"; /* FIXME: hardcoded */
231233
#else
232234
assert(attr.data.user);
233235
attr.data.user->elf_program = opt_prog_name;

0 commit comments

Comments
 (0)