Skip to content

Commit

Permalink
Bring up Linux kernel
Browse files Browse the repository at this point in the history
  • Loading branch information
ChinYikMing committed Oct 28, 2024
1 parent 23d50de commit fd87884
Show file tree
Hide file tree
Showing 19 changed files with 782 additions and 94 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ OBJS_EXT :=

ifeq ($(call has, SYSTEM), 1)
OBJS_EXT += system.o
OBJS_EXT += plic.o
OBJS_EXT += uart.o
endif

# Integer Multiplication and Division instructions
Expand Down
Binary file added build/Image
Binary file not shown.
Binary file added build/minimal.dtb
Binary file not shown.
Binary file added build/rootfs.cpio
Binary file not shown.
15 changes: 15 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@

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

/*
* Integer log base 2
*
* The input will be ORed with 1 to prevent x = 0 since
* the result is undefined if x = 0
*
*/
#if defined(__GNUC__) || defined(__clang__)
#define ilog2(x) 31 - __builtin_clz(x | 1)
#elif defined(_MSC_VER)
/* FIXME */
#else /* unsupported compilers */
#define ilog2(x)
#endif

/* Alignment macro */
#if defined(__GNUC__) || defined(__clang__)
#define __ALIGNED(x) __attribute__((aligned(x)))
Expand Down
2 changes: 0 additions & 2 deletions src/decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -922,9 +922,7 @@ static inline bool op_misc_mem(rv_insn_t *ir, const uint32_t insn)
* FENCE FM[3:0] pred[3:0] succ[3:0] rs1 000 rd 0001111
* FENCEI imm[11:0] rs1 001 rd 0001111
*/

const uint32_t funct3 = decode_funct3(insn);

switch (funct3) {
case 0b000:
ir->opcode = rv_insn_fence;
Expand Down
2 changes: 1 addition & 1 deletion src/decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ enum op_field {
) \
/* RV32 Zicsr Standard Extension */ \
IIF(RV32_HAS(Zicsr))( \
_(csrrw, 0, 4, 0, ENC(rs1, rd)) \
_(csrrw, 1, 4, 0, ENC(rs1, rd)) \
_(csrrs, 0, 4, 0, ENC(rs1, rd)) \
_(csrrc, 0, 4, 0, ENC(rs1, rd)) \
_(csrrwi, 0, 4, 0, ENC(rs1, rd)) \
Expand Down
106 changes: 101 additions & 5 deletions src/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
#include <stdlib.h>
#include <string.h>

#if RV32_HAS(SYSTEM)
#include "plic.h"
#endif /* RV32_HAS(SYSTEM) */

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
Expand Down Expand Up @@ -41,6 +45,12 @@ extern struct target_ops gdbstub_ops;
#define IF_rs2(i, r) (i->rs2 == rv_reg_##r)
#define IF_imm(i, v) (i->imm == v)

#if RV32_HAS(SYSTEM)
static uint32_t reloc_enable_mmu_jalr_addr;
static bool reloc_enable_mmu = false;
bool need_retranslate = false;
#endif

static void rv_trap_default_handler(riscv_t *rv)
{
rv->csr_mepc += rv->compressed ? 2 : 4;
Expand Down Expand Up @@ -81,6 +91,13 @@ static inline void update_time(riscv_t *rv)
rv->csr_time[1] = t >> 32;
}

#if RV32_HAS(SYSTEM)
static inline void get_time_now(struct timeval *tv)
{
rv_gettimeofday(tv);
}
#endif

#if RV32_HAS(Zicsr)
/* get a pointer to a CSR */
static uint32_t *csr_get_ptr(riscv_t *rv, uint32_t csr)
Expand Down Expand Up @@ -177,6 +194,13 @@ static uint32_t csr_csrrw(riscv_t *rv, uint32_t csr, uint32_t val)

*c = val;

/*
* guestOS's process might have same VA,
* so block_map cannot be reused
*/
if (c == &rv->csr_satp)
block_map_clear(rv);

return out;
}

Expand Down Expand Up @@ -349,6 +373,11 @@ static set_t pc_set;
static bool has_loops = false;
#endif

#if RV32_HAS(SYSTEM)
extern void emu_update_uart_interrupts(riscv_t *rv);
static uint32_t peripheral_update_ctr = 64;
#endif

/* Interpreter-based execution path */
#define RVOP(inst, code, asm) \
static bool do_##inst(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, \
Expand Down Expand Up @@ -539,6 +568,8 @@ FORCE_INLINE bool insn_is_unconditional_branch(uint8_t opcode)

static void block_translate(riscv_t *rv, block_t *block)
{
retranslate:
memset(block, 0, sizeof(block_t));
block->pc_start = block->pc_end = rv->PC;

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

/* fetch the next instruction */
const uint32_t insn = rv->io.mem_ifetch(rv, block->pc_end);
uint32_t insn = rv->io.mem_ifetch(rv, block->pc_end);

#if RV32_HAS(SYSTEM)
if (!insn && need_retranslate) {
need_retranslate = false;
goto retranslate;
}
#endif

assert(insn);

/* decode the instruction */
if (!rv_decode(ir, insn)) {
Expand All @@ -560,8 +600,7 @@ static void block_translate(riscv_t *rv, block_t *block)
break;
}
ir->impl = dispatch_table[ir->opcode];
ir->pc = block->pc_end;
/* compute the end of pc */
ir->pc = block->pc_end; /* compute the end of pc */
block->pc_end += is_compressed(insn) ? 2 : 4;
block->n_insn++;
prev_ir = ir;
Expand Down Expand Up @@ -878,6 +917,14 @@ static bool runtime_profiler(riscv_t *rv, block_t *block)
}
#endif

#if RV32_HAS(SYSTEM)
static bool rv_has_plic_trap(riscv_t *rv)
{
return ((rv->csr_sstatus & SSTATUS_SIE || !rv->priv_mode) &&
(rv->csr_sip & rv->csr_sie));
}
#endif

void rv_step(void *arg)
{
assert(arg);
Expand All @@ -891,6 +938,48 @@ void rv_step(void *arg)

/* loop until hitting the cycle target */
while (rv->csr_cycle < cycles_target && !rv->halt) {
#if RV32_HAS(SYSTEM)
/* check for any interrupt after every block emulation */

/* now time */
struct timeval tv;

if (peripheral_update_ctr-- == 0) {
peripheral_update_ctr = 64;

u8250_check_ready(PRIV(rv)->uart);
if (PRIV(rv)->uart->in_ready)
emu_update_uart_interrupts(rv);
}

get_time_now(&tv);
uint64_t t = (uint64_t) (tv.tv_sec * 1e6) + (uint32_t) tv.tv_usec;

if (t > attr->timer) {
rv->csr_sip |= RV_INT_STI;
} else {
rv->csr_sip &= ~RV_INT_STI;
}

if (rv_has_plic_trap(rv)) {
uint32_t intr_applicable = rv->csr_sip & rv->csr_sie;
uint8_t intr_idx = ilog2(intr_applicable);
switch (intr_idx) {
case 1:
SET_CAUSE_AND_TVAL_THEN_TRAP(rv, SUPERVISOR_SW_INTR, 0);
break;
case 5:
SET_CAUSE_AND_TVAL_THEN_TRAP(rv, SUPERVISOR_TIMER_INTR, 0);
break;
case 9:
SET_CAUSE_AND_TVAL_THEN_TRAP(rv, SUPERVISOR_EXTERNAL_INTR, 0);
break;
default:
break;
}
}
#endif /* RV32_HAS(SYSTEM) */

if (prev && prev->pc_start != last_pc) {
/* update previous block */
#if !RV32_HAS(JIT)
Expand Down Expand Up @@ -1018,6 +1107,8 @@ static void __trap_handler(riscv_t *rv)
assert(insn);

rv_decode(ir, insn);
reloc_enable_mmu_jalr_addr = rv->PC;

ir->impl = dispatch_table[ir->opcode];
rv->compressed = is_compressed(insn);
ir->impl(rv, ir, rv->csr_cycle, rv->PC);
Expand Down Expand Up @@ -1117,8 +1208,13 @@ void ecall_handler(riscv_t *rv)
{
assert(rv);
#if RV32_HAS(SYSTEM)
syscall_handler(rv);
rv->PC += 4;
if (rv->priv_mode == RV_PRIV_U_MODE) {
SET_CAUSE_AND_TVAL_THEN_TRAP(rv, ECALL_U, 0);
} else if (rv->priv_mode ==
RV_PRIV_S_MODE) { /* trap to SBI syscall handler */
rv->PC += 4;
syscall_handler(rv);
}
#else
SET_CAUSE_AND_TVAL_THEN_TRAP(rv, ECALL_M, 0);
syscall_handler(rv);
Expand Down
16 changes: 16 additions & 0 deletions src/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,22 @@

#include "io.h"

u8250_state_t *u8250_new()
{
u8250_state_t *uart = calloc(1, sizeof(u8250_state_t));
assert(uart);

return uart;
}

plic_t *plic_new()
{
plic_t *plic = calloc(1, sizeof(plic_t));
assert(plic);

return plic;
}

static uint8_t *data_memory_base;

memory_t *memory_new(uint32_t size)
Expand Down
38 changes: 38 additions & 0 deletions src/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,47 @@

#pragma once

#include <stdbool.h>
#include <stdint.h>
#include <string.h>

/* UART */

#define IRQ_UART 1
#define IRQ_UART_BIT (1 << IRQ_UART)

typedef struct {
uint8_t dll, dlh; /**< divisor (ignored) */
uint8_t lcr; /**< UART config */
uint8_t ier; /**< interrupt config */
uint8_t current_int, pending_ints; /**< interrupt status */
/* other output signals, loopback mode (ignored) */
uint8_t mcr;
/* I/O handling */
int in_fd, out_fd;
bool in_ready;
} u8250_state_t;
void u8250_update_interrupts(u8250_state_t *uart);
void u8250_check_ready(u8250_state_t *uart);

uint32_t u8250_read(u8250_state_t *uart, uint32_t addr);

void u8250_write(u8250_state_t *uart, uint32_t addr, uint32_t value);

/* create a UART controller */
u8250_state_t *u8250_new();

typedef struct {
uint32_t masked;
uint32_t ip;
uint32_t ie;
/* state of input interrupt lines (level-triggered), set by environment */
uint32_t active;
} plic_t;

/* create a PLIC core */
plic_t *plic_new();

typedef struct {
uint8_t *mem_base;
uint64_t mem_size;
Expand Down
6 changes: 4 additions & 2 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ int main(int argc, char **args)
run_flag |= opt_prof_data << 2;

vm_attr_t attr = {
.mem_size = MEM_SIZE,
.mem_size = 512 * 1024 * 1024, /* FIXME: variadic size */
.stack_size = STACK_SIZE,
.args_offset_size = ARGS_OFFSET_SIZE,
.argc = prog_argc,
Expand All @@ -227,7 +227,9 @@ int main(int argc, char **args)
};
#if RV32_HAS(SYSTEM)
assert(attr.data.system);
attr.data.system->elf_program = opt_prog_name;
attr.data.system->kernel = "build/Image"; /* FIXME: hardcoded */
attr.data.system->initrd = "build/rootfs.cpio"; /* FIXME: hardcoded */
attr.data.system->dtb = "build/minimal.dtb"; /* FIXME: hardcoded */
#else
assert(attr.data.user);
attr.data.user->elf_program = opt_prog_name;
Expand Down
Loading

0 comments on commit fd87884

Please sign in to comment.