riscv64-noop: reuse cte and vme from riscv64-nemu

This commit is contained in:
Zihao Yu 2020-03-07 20:28:52 +08:00
parent 6eafb5797a
commit 70056864f7
14 changed files with 92 additions and 307 deletions

View File

@ -1,21 +1,25 @@
include $(AM_HOME)/am/arch/isa/riscv64.mk
AM_SRCS := $(ISA)/noop/trm.c \
$(ISA)/noop/uartlite.c \
$(ISA)/noop/perf.c \
$(ISA)/noop/cte.c \
$(ISA)/noop/trap.S \
$(ISA)/noop/instr.c \
$(ISA)/noop/vme.c \
nemu-common/ioe.c \
$(ISA)/noop/input.c \
nemu-common/nemu-timer.c \
nemu-common/nemu-video.c \
AM_SRCS := noop/isa/riscv/trm.c \
noop/isa/riscv/perf.c \
noop/common/uartlite.c \
nemu/isa/riscv/cte.c \
nemu/isa/riscv/trap.S \
nemu/isa/riscv/cte64.c \
nemu/isa/riscv/mtime.S \
nemu/isa/riscv/vme.c \
nemu/common/ioe.c \
noop/common/input.c \
noop/common/timer.c \
nemu/common/video.c \
noop/isa/riscv/instr.c \
dummy/mpe.c \
$(ISA)/nemu/boot/start.S
nemu/isa/riscv/boot/start.S
LDFLAGS += -L $(AM_HOME)/am/src/nemu-common
LDFLAGS += -T $(AM_HOME)/am/src/$(ISA)/nemu/boot/loader.ld
CFLAGS += -I$(AM_HOME)/am/src/nemu/include -DISA_H=\"riscv.h\"
LDFLAGS += -L $(AM_HOME)/am/src/nemu/ldscript
LDFLAGS += -T $(AM_HOME)/am/src/nemu/isa/riscv/boot/loader64.ld
image:
@echo + LD "->" $(BINARY_REL).elf

View File

@ -1,23 +1,5 @@
#ifndef __ARCH_H__
#define __ARCH_H__
#include <riscv64.h>
struct _Context {
union {
struct _AddressSpace *as;
uint64_t gpr[32];
};
uint64_t mcause;
uint64_t mstatus;
uint64_t mepc;
};
#define GPR1 gpr[17] // a7
#define GPR2 gpr[10] // a0
#define GPR3 gpr[11] // a1
#define GPR4 gpr[12] // a2
#define GPRx gpr[10] // a0
#include "riscv64-nemu.h"
#define MAP(c, f) c(f)
@ -32,7 +14,10 @@ enum {
};
typedef struct {
R64 cnts[NR_PERFCNT];
union {
struct { uint32_t lo, hi; };
int64_t val;
} cnts[NR_PERFCNT];
} PerfCntSet;
void __am_perfcnt_read(PerfCntSet *t);

View File

@ -20,10 +20,10 @@
# define FB_ADDR 0x40000000
#elif defined(__ARCH_RISCV64_NOOP)
# define KBD_ADDR 0x40900000
# define RTC_ADDR 0x4070bff8
# define RTC_ADDR 0x4800bff8
# define SCREEN_ADDR 0x40800000
# define SYNC_ADDR 0x40800004
# define FB_ADDR 0x40000000
# define FB_ADDR 0x41000000
#else
# define SERIAL_PORT 0xa10003f8
# define KBD_ADDR 0xa1000060

View File

@ -1,8 +1,14 @@
#include <riscv.h>
#ifdef __ARCH_RISCV64_NOOP
#define CLINT_MMIO 0x48000000
#define TIME_INC 0x80000
#else
#define CLINT_MMIO 0xa2000000
#define CLINT_MTIMECMP (CLINT_MMIO + 0x4000)
#define TIME_INC 0x800
#endif
#define CLINT_MTIMECMP (CLINT_MMIO + 0x4000)
extern void __am_timervec(void);

View File

@ -6,10 +6,20 @@ static void* (*pgalloc_usr)(size_t) = NULL;
static void (*pgfree_usr)(void*) = NULL;
static int vme_enable = 0;
#define RANGE_LEN(start, len) RANGE((start), (start + len))
static const _Area segments[] = { // Kernel memory mappings
#ifdef __ARCH_RISCV64_NOOP
RANGE_LEN(0x80000000, 0x8000000), // PMEM
RANGE_LEN(0x40600000, 0x1000), // uart
RANGE_LEN(0x48000000, 0x10000), // clint/timer
RANGE_LEN(0x41000000, 0x400000), // vmem
RANGE_LEN(0x40800000, 0x1000), // vmem
#else
NEMU_PADDR_SPACE,
#if __riscv_xlen == 64
RANGE(0xa2000000, 0xa2000000 + 0x10000), // clint
RANGE_LEN(0xa2000000, 0x10000), // clint
#endif
#endif
};

View File

@ -40,8 +40,9 @@ size_t __am_input_read(uintptr_t reg, void *buf, size_t size) {
timestamp = uptime();
} else {
int _k = __am_uartlite_getchar();
if (_k == 255) _k = 0;
assert(_k < 128 && _k >= 0);
int key = am_keycode[_k];
int key = (_k == -1 ? _KEY_NONE : am_keycode[_k]);
if (key == _KEY_NONE) {
if (last_key != _KEY_NONE) {
unsigned long now = uptime();

View File

@ -0,0 +1,36 @@
#include <am.h>
#include <amdev.h>
#include <nemu.h>
#include <klib.h>
static unsigned long boot_time = 0;
static inline uint32_t read_time(void) {
return ind(RTC_ADDR) / 1000; // unit: ms
}
size_t __am_timer_read(uintptr_t reg, void *buf, size_t size) {
switch (reg) {
case _DEVREG_TIMER_UPTIME: {
_DEV_TIMER_UPTIME_t *uptime = (_DEV_TIMER_UPTIME_t *)buf;
uptime->hi = 0;
uptime->lo = read_time() - boot_time;
// printf("lo = %d\n", uptime->lo);
return sizeof(_DEV_TIMER_UPTIME_t);
}
case _DEVREG_TIMER_DATE: {
_DEV_TIMER_DATE_t *rtc = (_DEV_TIMER_DATE_t *)buf;
rtc->second = 0;
rtc->minute = 0;
rtc->hour = 0;
rtc->day = 0;
rtc->month = 0;
rtc->year = 2018;
return sizeof(_DEV_TIMER_DATE_t);
}
}
return 0;
}
void __am_timer_init() {
boot_time = read_time();
}

View File

@ -1,4 +1,4 @@
#include <riscv64.h>
#include <riscv.h>
#define UARTLITE_MMIO 0x40600000
#define UARTLITE_RX_FIFO 0x0

View File

@ -1,6 +1,8 @@
#include <am.h>
#include <riscv64.h>
#include <riscv.h>
#include <klib.h>
#include <klib-macros.h>
//TODO: have not done riscv64 software mul/div
static uint32_t mul(uint32_t a, uint32_t b, int sign, int hi) {
if (a == 0x80000000 && b == 0x80000000) {
@ -83,7 +85,7 @@ int __am_illegal_instr(_Context *c) {
};
uint32_t val;
} instr;
instr.val = *(uint32_t *)(c->mepc);
instr.val = *(uint32_t *)(c->sepc);
if (instr.opcode == 0x33 && instr.func2 == 1) {
// M extension
@ -99,7 +101,7 @@ int __am_illegal_instr(_Context *c) {
}
}
printf("invalid instruction at pc = %x\n", c->mepc);
printf("invalid instruction at pc = %x\n", c->sepc);
_halt(1);
return false;
}

View File

@ -1,16 +1,16 @@
#include <am.h>
#include <riscv64.h>
#include <riscv.h>
#include <klib.h>
extern char _heap_start;
extern char _heap_end;
extern char _pmem_end;
int main(const char *args);
void __am_init_uartlite(void);
void __am_uartlite_putchar(char ch);
_Area _heap = {
.start = &_heap_start,
.end = &_heap_end,
.end = &_pmem_end,
};
void _putc(char ch) {
@ -29,7 +29,7 @@ void _halt(int code) {
void _trm_init() {
__am_init_uartlite();
extern const char _mainargs;
int ret = main(&_mainargs);
const char *mainargs = "";
int ret = main(mainargs);
_halt(ret);
}

View File

@ -1,99 +0,0 @@
#include <am.h>
#include <riscv64.h>
#include <klib.h>
#define CLINT_MMIO 0x40700000
#define CLINT_MTIME (CLINT_MMIO + 0xbff8)
#define CLINT_MTIMECMP (CLINT_MMIO + 0x4000)
#define TIME_INC 10
static inline void inc_mtimecmp(uint64_t this) {
outd(CLINT_MTIMECMP, this + TIME_INC);
}
static _Context* (*user_handler)(_Event, _Context*) = NULL;
void __am_get_cur_as(_Context *c);
void __am_switch(_Context *c);
int __am_illegal_instr(_Context *c);
#define INTR_BIT (1ULL << 63)
_Context* __am_irq_handle(_Context *c) {
__am_get_cur_as(c);
_Context *next = c;
if (user_handler) {
_Event ev = {0};
switch (c->mcause) {
case 2:
if (__am_illegal_instr(c)) c->mepc += 4;
break;
case (0x7 | INTR_BIT):
inc_mtimecmp(ind(CLINT_MTIME));
ev.event = _EVENT_IRQ_TIMER;
break;
case (0xb | INTR_BIT):
ev.event = _EVENT_IRQ_IODEV;
break;
case 11:
ev.event = (c->GPR1 == -1) ? _EVENT_YIELD : _EVENT_SYSCALL;
c->mepc += 4;
break;
default: ev.event = _EVENT_ERROR; break;
}
next = user_handler(ev, c);
if (next == NULL) {
next = c;
}
}
__am_switch(next);
return next;
}
extern void __am_asm_trap(void);
int _cte_init(_Context*(*handler)(_Event, _Context*)) {
// initialize exception entry
asm volatile("csrw mtvec, %0" : : "r"(__am_asm_trap));
// register event handler
user_handler = handler;
inc_mtimecmp(0);
asm volatile("csrw mie, %0" : : "r"((1 << 7) | (1 << 11)));
return 0;
}
_Context *_kcontext(_Area stack, void (*entry)(void *), void *arg) {
_Context *c = (_Context*)stack.end - 1;
c->mepc = (uintptr_t)entry;
c->mstatus = 0x000c1880;
return c;
}
void _yield() {
asm volatile("li a7, -1; ecall");
}
int _intr_read() {
uintptr_t mstatus;
asm volatile("csrr %0, mstatus" : "=r"(mstatus));
return (mstatus & 0x8) != 0;
}
void _intr_write(int enable) {
uintptr_t mstatus;
asm volatile("csrr %0, mstatus" : "=r"(mstatus));
if (enable) {
mstatus |= 0x8;
} else {
mstatus &= ~0x8;
}
asm volatile("csrw mstatus, %0" : : "r"(mstatus));
}

View File

@ -1,54 +0,0 @@
// unmodified for cputest
#define concat_temp(x, y) x ## y
#define concat(x, y) concat_temp(x, y)
#define MAP(c, f) c(f)
#define REGS(f) \
f( 1) f( 3) f( 4) f( 5) f( 6) f( 7) f( 8) f( 9) \
f(10) f(11) f(12) f(13) f(14) f(15) f(16) f(17) f(18) f(19) \
f(20) f(21) f(22) f(23) f(24) f(25) f(26) f(27) f(28) f(29) \
f(30) f(31)
#define PUSH(n) sd concat(x, n), (n * 8)(sp);
#define POP(n) ld concat(x, n), (n * 8)(sp);
#define CONTEXT_SIZE ((31 + 4) * 8)
#define OFFSET_SP ( 2 * 8)
#define OFFSET_CAUSE (32 * 8)
#define OFFSET_STATUS (33 * 8)
#define OFFSET_EPC (34 * 8)
.globl __am_asm_trap
__am_asm_trap:
addi sp, sp, -CONTEXT_SIZE
MAP(REGS, PUSH)
mv t0, sp
addi t0, t0, CONTEXT_SIZE
sd t0, OFFSET_SP(sp)
csrr t0, mcause
csrr t1, mstatus
csrr t2, mepc
sd t0, OFFSET_CAUSE(sp)
sd t1, OFFSET_STATUS(sp)
sd t2, OFFSET_EPC(sp)
mv a0, sp
jal __am_irq_handle
mv sp, a0
ld t1, OFFSET_STATUS(sp)
ld t2, OFFSET_EPC(sp)
csrw mstatus, t1
csrw mepc, t2
MAP(REGS, POP)
addi sp, sp, CONTEXT_SIZE
mret

View File

@ -1,106 +0,0 @@
#include <riscv64.h>
#include <nemu.h>
#include <klib.h>
#define PG_ALIGN __attribute((aligned(PGSIZE)))
static _AddressSpace kas; // Kernel address space
static void* (*pgalloc_usr)(size_t) = NULL;
static void (*pgfree_usr)(void*) = NULL;
static int vme_enable = 0;
static _Area segments[] = { // Kernel memory mappings
{.start = (void*)0x80000000u, .end = (void*)(0x80000000u + 0x3000000)}, //PMEM_SIZE)},
{.start = (void*)0x40600000u, .end = (void*)(0x40600000u + 0x1000)}, // uart
{.start = (void*)0x40700000u, .end = (void*)(0x40700000u + 0x1000)}, // clint/timer
{.start = (void*)0x40000000u, .end = (void*)(0x40000000u + 0x400000)}, // vmem
{.start = (void*)0x40800000u, .end = (void*)(0x40800000u + 0x1000)} // vga ctrl
};
#define NR_KSEG_MAP (sizeof(segments) / sizeof(segments[0]))
static inline void set_satp(void *pdir) {
uintptr_t mode = 8ull << 60;
asm volatile("csrw satp, %0" : : "r"(mode | PN(pdir)));
}
int _vme_init(void* (*pgalloc_f)(size_t), void (*pgfree_f)(void*)) {
pgalloc_usr = pgalloc_f;
pgfree_usr = pgfree_f;
kas.ptr = pgalloc_f(1);
// make all PTEs invalid
memset(kas.ptr, 0, PGSIZE);
int i;
for (i = 0; i < NR_KSEG_MAP; i ++) {
void *va = segments[i].start;
for (; va < segments[i].end; va += PGSIZE) {
_map(&kas, va, va, 0);
}
}
set_satp(kas.ptr);
vme_enable = 1;
return 0;
}
int _protect(_AddressSpace *as) {
PTE *updir = (PTE *)(pgalloc_usr(1));
as->ptr = updir;
// map kernel space
memcpy(updir, kas.ptr, PGSIZE);
return 0;
}
void _unprotect(_AddressSpace *as) {
}
static _AddressSpace *cur_as = NULL;
void __am_get_cur_as(_Context *c) {
c->as = cur_as;
}
void __am_switch(_Context *c) {
if (vme_enable) {
set_satp(c->as->ptr);
cur_as = c->as;
}
}
int _map(_AddressSpace *as, void *va, void *pa, int prot) {
PTE *pg_base = as->ptr;
PTE *pte;
int level;
for (level = PTW_LEVEL - 1; level >= 0; level --) {
pte = &pg_base[VPNi((uintptr_t)va, level)];
pg_base = (PTE *)PTE_ADDR(*pte);
if (level != 0 && !(*pte & PTE_V)) {
pg_base = pgalloc_usr(1);
*pte = PTE_V | (PN(pg_base) << 10);
}
}
if (!(*pte & PTE_V)) {
*pte = PTE_V | PTE_R | PTE_W | PTE_X | (PN(pa) << 10);
} else {
#define ptr_to_u32(p) ((uint32_t)(uintptr_t)p)
printf("remap: ptr = 0x%08x, vpn = 0x%08x, old ppn = 0x%08x, new ppn = 0x%08x\nSomething may be wrong.",
ptr_to_u32(as->ptr), PN(va), PN(PTE_ADDR(*pte)), PN(pa));
assert(0);
}
return 0;
}
_Context *_ucontext(_AddressSpace *as, _Area ustack, _Area kstack, void *entry, void *args) {
_Context *c = (_Context*)ustack.end - 1;
c->gpr[10] = c->gpr[11] = 0;
c->as = as;
c->mepc = (uintptr_t)entry;
c->mstatus = 0x000c1880;
return c;
}