Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bring up Linux kernel #508

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
43 changes: 43 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

#pragma once

#include <stdint.h>

#include "feature.h"

#if defined(__GNUC__) || defined(__clang__)
Expand All @@ -27,6 +29,47 @@

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

#if defined(_MSC_VER)
#include <intrin.h>
static inline int clz(uint32_t v)
ChinYikMing marked this conversation as resolved.
Show resolved Hide resolved
{
uint32_t leading_zero = 0;
if (_BitScanReverse(&leading_zero, v))
return 31 - leading_zero;
return 32; /* undefined behavior */
}
#elif defined(__GNUC__) || defined(__clang__)
static inline int clz(uint32_t v)
{
return __builtin_clz(v);
ChinYikMing marked this conversation as resolved.
Show resolved Hide resolved
}
#else /* generic implementation */
static inline int clz(uint32_t v)
{
/* http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn */
static const uint8_t mul_debruijn[] = {
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31,
};

v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;

return mul_debruijn[(uint32_t) (v * 0x07C4ACDDU) >> 27];
}
#endif

/*
jserv marked this conversation as resolved.
Show resolved Hide resolved
* Integer log base 2
*/
static inline uint8_t ilog2(uint32_t x)
{
return 31 - clz(x);
}

/* 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
*/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't do this. Minimize the necessary changes.

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)) \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If SYSTEM configuration is set, the Zicsr should be set accordingly.

_(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
Loading