Merge branch 'riscv64' into 'master'
Riscv64 See merge request projectn/nexus-am!31
This commit is contained in:
commit
fc1833a390
|
@ -1,5 +1,5 @@
|
|||
CROSS_COMPILE := riscv-none-embed-
|
||||
COMMON_FLAGS := -fno-pic -march=rv64im -mabi=lp64 -mcmodel=medany
|
||||
CROSS_COMPILE := riscv64-linux-gnu-
|
||||
COMMON_FLAGS := -fno-pic -march=rv64g -mcmodel=medany
|
||||
CFLAGS += $(COMMON_FLAGS) -static
|
||||
ASFLAGS += $(COMMON_FLAGS) -O0
|
||||
LDFLAGS += -melf64lriscv
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
include $(AM_HOME)/am/arch/isa/riscv32.mk
|
||||
|
||||
AM_SRCS := $(ISA)/noop/trm.c \
|
||||
$(ISA)/noop/uartlite.c \
|
||||
$(ISA)/noop/perf.c \
|
||||
$(ISA)/noop/cte.c \
|
||||
$(ISA)/nemu/trap.S \
|
||||
$(ISA)/noop/instr.c \
|
||||
$(ISA)/nemu/vme.c \
|
||||
nemu-common/ioe.c \
|
||||
$(ISA)/noop/input.c \
|
||||
nemu-common/nemu-timer.c \
|
||||
nemu-common/nemu-video.c \
|
||||
dummy/mpe.c \
|
||||
$(ISA)/nemu/boot/start.S
|
||||
|
||||
LDFLAGS += -L $(AM_HOME)/am/src/nemu-common
|
||||
LDFLAGS += -T $(AM_HOME)/am/src/$(ISA)/nemu/boot/loader.ld
|
||||
|
||||
image:
|
||||
@echo + LD "->" $(BINARY_REL).elf
|
||||
@$(LD) $(LDFLAGS) --gc-sections -o $(BINARY).elf --start-group $(LINK_FILES) --end-group
|
||||
@$(OBJDUMP) -d $(BINARY).elf > $(BINARY).txt
|
||||
@echo + OBJCOPY "->" $(BINARY_REL).bin
|
||||
@$(OBJCOPY) -S --set-section-flags .bss=alloc,contents -O binary $(BINARY).elf $(BINARY).bin
|
||||
|
||||
run:
|
||||
$(MAKE) -C $(NOOP_HOME) emu IMAGE="$(BINARY).bin"
|
|
@ -2,8 +2,10 @@ include $(AM_HOME)/am/arch/isa/riscv64.mk
|
|||
include $(AM_HOME)/am/arch/platform/nemu.mk
|
||||
|
||||
AM_SRCS += nemu/isa/riscv/trm.c \
|
||||
nemu/isa/riscv/cte64.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/isa/riscv/boot/start.S
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
#ifndef __ARCH_H__
|
||||
#define __ARCH_H__
|
||||
|
||||
#include <riscv32.h>
|
||||
|
||||
struct _Context {
|
||||
union {
|
||||
struct _AddressSpace *as;
|
||||
uint32_t gpr[32];
|
||||
};
|
||||
uint32_t cause;
|
||||
uint32_t status;
|
||||
uint32_t epc;
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
#define MAP(c, f) c(f)
|
||||
|
||||
#define COUNTERS(f) \
|
||||
f(cycle) f(time) f(instr)
|
||||
|
||||
#define CNT_IDX(cnt) PERFCNT_##cnt
|
||||
#define CNT_ENUM_ITEM(cnt) CNT_IDX(cnt),
|
||||
enum {
|
||||
MAP(COUNTERS, CNT_ENUM_ITEM)
|
||||
NR_PERFCNT,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
R64 cnts[NR_PERFCNT];
|
||||
} PerfCntSet;
|
||||
|
||||
void __am_perfcnt_read(PerfCntSet *t);
|
||||
void __am_perfcnt_sub(PerfCntSet *res, PerfCntSet *t1, PerfCntSet *t0);
|
||||
void __am_perfcnt_add(PerfCntSet *res, PerfCntSet *t1, PerfCntSet *t0);
|
||||
void __am_perfcnt_show(PerfCntSet *t);
|
||||
void __am_perfcnt_excel(PerfCntSet *t);
|
||||
|
||||
#endif
|
|
@ -1,20 +1 @@
|
|||
#ifndef __ARCH_H__
|
||||
#define __ARCH_H__
|
||||
|
||||
struct _Context {
|
||||
union {
|
||||
void *pdir;
|
||||
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
|
||||
|
||||
#endif
|
||||
#include "riscv32-nemu.h"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -8,6 +8,12 @@ static void* (*pgalloc_usr)(size_t) = NULL;
|
|||
static void (*pgfree_usr)(void*) = NULL;
|
||||
static int vme_enable = 0;
|
||||
|
||||
static inline void *new_page() {
|
||||
void *p = pgalloc_usr(PGSIZE);
|
||||
memset(p, 0, PGSIZE);
|
||||
return p;
|
||||
}
|
||||
|
||||
int _vme_init(void* (*pgalloc_f)(size_t), void (*pgfree_f)(void*)) {
|
||||
pgalloc_usr = pgalloc_f;
|
||||
pgfree_usr = pgfree_f;
|
||||
|
@ -17,7 +23,7 @@ int _vme_init(void* (*pgalloc_f)(size_t), void (*pgfree_f)(void*)) {
|
|||
}
|
||||
|
||||
void _protect(_AddressSpace *as) {
|
||||
as->ptr = (PTE*)(pgalloc_usr(PGSIZE));
|
||||
as->ptr = new_page();
|
||||
as->pgsize = PGSIZE;
|
||||
as->area = USER_SPACE;
|
||||
}
|
||||
|
@ -46,7 +52,7 @@ void _map(_AddressSpace *as, void *va, void *pa, int prot) {
|
|||
PTE *pdir = (PTE*)as->ptr;
|
||||
PTE *pde = &pdir[PDX(va)];
|
||||
if (!(*pde & PTE_V)) {
|
||||
*pde = PTE_V | (uint32_t)pgalloc_usr(PGSIZE);
|
||||
*pde = PTE_V | (uintptr_t)new_page();
|
||||
}
|
||||
PTE *pte = &((PTE*)PTE_ADDR(*pde))[PTX(va)];
|
||||
if (!(*pte & PTE_V)) {
|
||||
|
|
|
@ -7,13 +7,21 @@ static _Context* (*user_handler)(_Event, _Context*) = NULL;
|
|||
void __am_get_cur_as(_Context *c);
|
||||
void __am_switch(_Context *c);
|
||||
|
||||
#define INTR_BIT (1ul << (sizeof(uintptr_t) * 8 - 1))
|
||||
|
||||
_Context* __am_irq_handle(_Context *c) {
|
||||
__am_get_cur_as(c);
|
||||
|
||||
if (user_handler) {
|
||||
_Event ev = {0};
|
||||
switch (c->scause) {
|
||||
case 0x80000005: ev.event = _EVENT_IRQ_TIMER; break;
|
||||
#if __riscv_xlen == 64
|
||||
// SSIP, which is set at mtime.S
|
||||
case 0x1 | INTR_BIT: asm volatile ("csrwi sip, 0");
|
||||
#else
|
||||
case 0x5 | INTR_BIT:
|
||||
#endif
|
||||
ev.event = _EVENT_IRQ_TIMER; break;
|
||||
case 9:
|
||||
ev.event = (c->GPR1 == -1) ? _EVENT_YIELD : _EVENT_SYSCALL;
|
||||
c->sepc += 4;
|
||||
|
@ -27,6 +35,10 @@ _Context* __am_irq_handle(_Context *c) {
|
|||
|
||||
__am_switch(c);
|
||||
|
||||
#if __riscv_xlen == 64
|
||||
asm volatile("fence.i");
|
||||
#endif
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -41,6 +53,11 @@ int _cte_init(_Context*(*handler)(_Event, _Context*)) {
|
|||
// register event handler
|
||||
user_handler = handler;
|
||||
|
||||
#if __riscv_xlen == 64
|
||||
extern void __am_init_cte64();
|
||||
__am_init_cte64();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,70 +1,46 @@
|
|||
#include <am.h>
|
||||
#include <nemu.h>
|
||||
#include <klib.h>
|
||||
#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 CLINT_MTIME (CLINT_MMIO + 0xbff8)
|
||||
#define TIME_INC 0x800
|
||||
static inline void inc_mtimecmp(uint64_t this) {
|
||||
outd(CLINT_MTIMECMP, this + TIME_INC);
|
||||
}
|
||||
#endif
|
||||
|
||||
static _Context* (*user_handler)(_Event, _Context*) = NULL;
|
||||
#define CLINT_MTIMECMP (CLINT_MMIO + 0x4000)
|
||||
|
||||
void __am_get_cur_as(_Context *c);
|
||||
void __am_switch(_Context *c);
|
||||
extern void __am_timervec(void);
|
||||
|
||||
#define INTR_BIT (1ULL << 63)
|
||||
static void init_timer() {
|
||||
static struct {
|
||||
uintptr_t mtimecmp;
|
||||
uintptr_t time_inc;
|
||||
uintptr_t temp[3];
|
||||
} handle;
|
||||
|
||||
_Context* __am_irq_handle(_Context *c) {
|
||||
__am_get_cur_as(c);
|
||||
handle.mtimecmp = CLINT_MTIMECMP;
|
||||
handle.time_inc = TIME_INC;
|
||||
|
||||
_Context *next = c;
|
||||
if (user_handler) {
|
||||
_Event ev = {0};
|
||||
switch (c->cause) {
|
||||
case (0x7 | INTR_BIT):
|
||||
inc_mtimecmp(ind(CLINT_MTIME));
|
||||
ev.event = _EVENT_IRQ_TIMER;
|
||||
break;
|
||||
case 9:
|
||||
ev.event = (c->GPR1 == -1) ? _EVENT_YIELD : _EVENT_SYSCALL;
|
||||
c->epc += 4;
|
||||
break;
|
||||
default: ev.event = _EVENT_ERROR; break;
|
||||
}
|
||||
asm volatile("csrw mscratch, %0" : : "r"(&handle));
|
||||
|
||||
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 stvec, %0" : : "r"(__am_asm_trap));
|
||||
|
||||
// register event handler
|
||||
user_handler = handler;
|
||||
// set M-mode exception entry to handle machine timer interrupt
|
||||
asm volatile("csrw mtvec, %0" : : "r"(__am_timervec));
|
||||
|
||||
// set machine timer interrupt
|
||||
inc_mtimecmp(0);
|
||||
asm volatile("csrs mie, %0" : : "r"(1 << 7));
|
||||
asm volatile("csrs mie, %0" : : "r"((1 << 7) | (1 << 1)));
|
||||
outd(CLINT_MTIMECMP, 0);
|
||||
}
|
||||
|
||||
void __am_init_cte64() {
|
||||
// set delegation
|
||||
asm volatile("csrw mideleg, %0" : : "r"(0xffff));
|
||||
asm volatile("csrw medeleg, %0" : : "r"(0xffff));
|
||||
|
||||
init_timer();
|
||||
|
||||
// enter S-mode
|
||||
uintptr_t status = MSTATUS_MXR | MSTATUS_SUM | MSTATUS_SPP(MODE_S);
|
||||
uintptr_t status = MSTATUS_SPP(MODE_S);
|
||||
extern char _here;
|
||||
asm volatile(
|
||||
"csrw sstatus, %0;"
|
||||
|
@ -72,26 +48,4 @@ int _cte_init(_Context*(*handler)(_Event, _Context*)) {
|
|||
"sret;"
|
||||
"_here:"
|
||||
: : "r"(status), "r"(&_here));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_Context *_kcontext(_Area stack, void (*entry)(void *), void *arg) {
|
||||
_Context *c = (_Context*)stack.end - 1;
|
||||
|
||||
c->epc = (uintptr_t)entry;
|
||||
uintptr_t mprotect = MSTATUS_MXR | MSTATUS_SUM;
|
||||
c->status = mprotect | MSTATUS_SPP(MODE_S) | MSTATUS_PIE(MODE_S);
|
||||
return c;
|
||||
}
|
||||
|
||||
void _yield() {
|
||||
asm volatile("li a7, -1; ecall");
|
||||
}
|
||||
|
||||
int _intr_read() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _intr_write(int enable) {
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
# machine-mode timer interrupt handler from xv6 code
|
||||
|
||||
.globl __am_timervec
|
||||
.align 4
|
||||
__am_timervec:
|
||||
csrrw a0, mscratch, a0
|
||||
sd a1, 16(a0)
|
||||
sd a2, 24(a0)
|
||||
sd a3, 32(a0)
|
||||
|
||||
# schedule the next timer interrupt
|
||||
# by adding interval to mtimecmp.
|
||||
ld a1, 0(a0) # CLINT_MTIMECMP(hart)
|
||||
ld a2, 8(a0) # interval
|
||||
ld a3, 0(a1)
|
||||
add a3, a3, a2
|
||||
sd a3, 0(a1)
|
||||
|
||||
# raise a supervisor software interrupt.
|
||||
csrwi sip, 2
|
||||
|
||||
ld a3, 32(a0)
|
||||
ld a2, 24(a0)
|
||||
ld a1, 16(a0)
|
||||
csrrw a0, mscratch, a0
|
||||
|
||||
mret
|
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -25,6 +35,9 @@ static const _Area segments[] = { // Kernel memory mappings
|
|||
|
||||
static inline void set_satp(void *pdir) {
|
||||
asm volatile("csrw satp, %0" : : "r"(SATP_MODE | PN(pdir)));
|
||||
#if __riscv_xlen == 64
|
||||
asm volatile("sfence.vma");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uintptr_t get_satp() {
|
||||
|
@ -33,14 +46,17 @@ static inline uintptr_t get_satp() {
|
|||
return satp << 12; // the mode bits will be shifted out
|
||||
}
|
||||
|
||||
static inline void *new_page() {
|
||||
void *p = pgalloc_usr(PGSIZE);
|
||||
memset(p, 0, PGSIZE);
|
||||
return p;
|
||||
}
|
||||
|
||||
int _vme_init(void* (*pgalloc_f)(size_t), void (*pgfree_f)(void*)) {
|
||||
pgalloc_usr = pgalloc_f;
|
||||
pgfree_usr = pgfree_f;
|
||||
|
||||
kas.ptr = pgalloc_f(PGSIZE);
|
||||
// make all PTEs invalid
|
||||
memset(kas.ptr, 0, PGSIZE);
|
||||
|
||||
kas.ptr = new_page();
|
||||
int i;
|
||||
for (i = 0; i < LENGTH(segments); i ++) {
|
||||
void *va = segments[i].start;
|
||||
|
@ -56,7 +72,7 @@ int _vme_init(void* (*pgalloc_f)(size_t), void (*pgfree_f)(void*)) {
|
|||
}
|
||||
|
||||
void _protect(_AddressSpace *as) {
|
||||
PTE *updir = (PTE*)(pgalloc_usr(PGSIZE));
|
||||
PTE *updir = new_page();
|
||||
as->ptr = updir;
|
||||
as->area = USER_SPACE;
|
||||
as->pgsize = PGSIZE;
|
||||
|
@ -88,7 +104,7 @@ void _map(_AddressSpace *as, void *va, void *pa, int prot) {
|
|||
pg_base = (PTE *)PTE_ADDR(*pte);
|
||||
if (level == 0) break;
|
||||
if (!(*pte & PTE_V)) {
|
||||
pg_base = pgalloc_usr(PGSIZE);
|
||||
pg_base = new_page();
|
||||
*pte = PTE_V | (PN(pg_base) << 10);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,14 +15,17 @@ static _Area segments[] = { // Kernel memory mappings
|
|||
|
||||
#define USER_SPACE RANGE(0x40000000, 0xc0000000)
|
||||
|
||||
static inline void *new_page() {
|
||||
void *p = pgalloc_usr(PGSIZE);
|
||||
memset(p, 0, PGSIZE);
|
||||
return p;
|
||||
}
|
||||
|
||||
int _vme_init(void* (*pgalloc_f)(size_t), void (*pgfree_f)(void*)) {
|
||||
pgalloc_usr = pgalloc_f;
|
||||
pgfree_usr = pgfree_f;
|
||||
|
||||
kas.ptr = pgalloc_f(PGSIZE);
|
||||
// make all PTEs invalid
|
||||
memset(kas.ptr, 0, PGSIZE);
|
||||
|
||||
kas.ptr = new_page();
|
||||
int i;
|
||||
for (i = 0; i < LENGTH(segments); i ++) {
|
||||
void *va = segments[i].start;
|
||||
|
@ -39,7 +42,7 @@ int _vme_init(void* (*pgalloc_f)(size_t), void (*pgfree_f)(void*)) {
|
|||
}
|
||||
|
||||
void _protect(_AddressSpace *as) {
|
||||
PTE *updir = (PTE*)(pgalloc_usr(PGSIZE));
|
||||
PTE *updir = new_page();
|
||||
as->ptr = updir;
|
||||
as->area = USER_SPACE;
|
||||
as->pgsize = PGSIZE;
|
||||
|
@ -71,7 +74,7 @@ void _map(_AddressSpace *as, void *va, void *pa, int prot) {
|
|||
pg_base = (PTE *)PTE_ADDR(*pte);
|
||||
if (level == 0) break;
|
||||
if (!(*pte & PTE_P)) {
|
||||
pg_base = pgalloc_usr(PGSIZE);
|
||||
pg_base = new_page();
|
||||
*pte = PTE_P | PTE_W | PTE_U | (uintptr_t)pg_base;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
|
@ -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();
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
#include <riscv32.h>
|
||||
#include <riscv.h>
|
||||
|
||||
#define UARTLITE_MMIO 0x40600000
|
||||
#define UARTLITE_RX_FIFO 0x0
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
#include <am.h>
|
||||
#include <riscv32.h>
|
||||
#include <klib.h>
|
||||
|
||||
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);
|
||||
|
||||
_Context* __am_irq_handle(_Context *c) {
|
||||
__am_get_cur_as(c);
|
||||
|
||||
_Context *next = c;
|
||||
if (user_handler) {
|
||||
_Event ev = {0};
|
||||
switch (c->cause) {
|
||||
//case 0: ev.event = _EVENT_IRQ_TIMER; break;
|
||||
case 2:
|
||||
if (__am_illegal_instr(c)) c->epc += 4;
|
||||
break;
|
||||
case 9:
|
||||
ev.event = (c->GPR1 == -1) ? _EVENT_YIELD : _EVENT_SYSCALL;
|
||||
c->epc += 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 stvec, %0" : : "r"(__am_asm_trap));
|
||||
|
||||
// register event handler
|
||||
user_handler = handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_Context *_kcontext(_Area stack, void (*entry)(void *), void *arg) {
|
||||
_Context *c = (_Context*)stack.end - 1;
|
||||
|
||||
c->epc = (uintptr_t)entry;
|
||||
c->status = 0x000c0100;
|
||||
return c;
|
||||
}
|
||||
|
||||
void _yield() {
|
||||
asm volatile("li a7, -1; ecall");
|
||||
}
|
||||
|
||||
int _intr_read() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _intr_write(int enable) {
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
#include <am.h>
|
||||
#include <amdev.h>
|
||||
#include <nemu.h>
|
||||
#include <klib.h>
|
||||
|
||||
#define KEYDOWN_MASK 0x8000
|
||||
|
||||
int __am_uartlite_getchar();
|
||||
|
||||
static int am_keycode[128] = {
|
||||
[' '] = _KEY_SPACE,
|
||||
['a'] = _KEY_A, ['b'] = _KEY_B, ['c'] = _KEY_C, ['d'] = _KEY_D,
|
||||
['e'] = _KEY_E, ['f'] = _KEY_F, ['g'] = _KEY_G, ['h'] = _KEY_H,
|
||||
['i'] = _KEY_I, ['j'] = _KEY_J, ['k'] = _KEY_K, ['l'] = _KEY_L,
|
||||
['m'] = _KEY_M, ['n'] = _KEY_N, ['o'] = _KEY_O, ['p'] = _KEY_P,
|
||||
['q'] = _KEY_Q, ['r'] = _KEY_R, ['s'] = _KEY_S, ['t'] = _KEY_T,
|
||||
['u'] = _KEY_U, ['v'] = _KEY_V, ['w'] = _KEY_W, ['x'] = _KEY_X,
|
||||
['y'] = _KEY_Y, ['z'] = _KEY_Z
|
||||
};
|
||||
|
||||
size_t __am_input_read(uintptr_t reg, void *buf, size_t size) {
|
||||
switch (reg) {
|
||||
case _DEVREG_INPUT_KBD: {
|
||||
_DEV_INPUT_KBD_t *kbd = (_DEV_INPUT_KBD_t *)buf;
|
||||
static int last_key = _KEY_NONE;
|
||||
static int last_release = 0;
|
||||
static unsigned long timestamp = 0;
|
||||
|
||||
kbd->keydown = 0;
|
||||
kbd->keycode = _KEY_NONE;
|
||||
|
||||
if (last_release) {
|
||||
// and return the makecode of the last key
|
||||
kbd->keydown = 1;
|
||||
kbd->keycode = last_key;
|
||||
last_release = 0;
|
||||
timestamp = uptime();
|
||||
} else {
|
||||
int _k = __am_uartlite_getchar();
|
||||
assert(_k < 128 && _k >= 0);
|
||||
int key = am_keycode[_k];
|
||||
if (key == _KEY_NONE) {
|
||||
if (last_key != _KEY_NONE) {
|
||||
unsigned long now = uptime();
|
||||
if (now - timestamp > 500) {
|
||||
kbd->keydown = 0;
|
||||
kbd->keycode = last_key;
|
||||
last_key = _KEY_NONE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int another_key = (key != _KEY_NONE && last_key != _KEY_NONE && key != last_key);
|
||||
// if we press a different key, now return the breakcode of the old key,
|
||||
// and return the makecode of new key next time
|
||||
kbd->keydown = another_key ? 0 : 1;
|
||||
kbd->keycode = another_key ? last_key : key;
|
||||
last_key = key;
|
||||
last_release = another_key;
|
||||
if (!another_key) timestamp = uptime();
|
||||
}
|
||||
}
|
||||
|
||||
return sizeof(_DEV_INPUT_KBD_t);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
#include <am.h>
|
||||
#include <riscv32.h>
|
||||
#include <klib.h>
|
||||
#include <klib-macros.h>
|
||||
|
||||
static uint32_t mul(uint32_t a, uint32_t b, int sign, int hi) {
|
||||
if (a == 0x80000000 && b == 0x80000000) {
|
||||
// hard code the result for this special case
|
||||
const R64 res = {.val = 0x4000000000000000LL};
|
||||
return (hi ? res.hi : res.lo);
|
||||
}
|
||||
else if (b == 0x80000000) {
|
||||
// swap the operands
|
||||
uint32_t t = a;
|
||||
a = b;
|
||||
b = t;
|
||||
}
|
||||
|
||||
int sign_a = 0, sign_b = 0;
|
||||
if (sign) {
|
||||
if ((int32_t)a < 0) { sign_a = 1; a = -a; }
|
||||
if ((int32_t)b < 0) { sign_b = 1; b = -b; }
|
||||
}
|
||||
|
||||
// booth algorithm
|
||||
R64 P = {.hi = 0, .lo = b };
|
||||
uint32_t choose = (P.lo & 1) << 1;
|
||||
int i;
|
||||
for (i = 32; i > 0; i --) {
|
||||
switch (choose) {
|
||||
case 1: P.hi += a; break;
|
||||
case 2: P.hi -= a; break;
|
||||
}
|
||||
choose = P.lo & 0x3;
|
||||
P.val >>= 1;
|
||||
}
|
||||
|
||||
if (sign_a ^ sign_b) P.val = -P.val;
|
||||
return (hi ? P.hi : P.lo);
|
||||
}
|
||||
|
||||
static uint32_t div(uint32_t a, uint32_t b, int sign, int reminder) {
|
||||
int sign_a = 0, sign_b = 0;
|
||||
if (sign) {
|
||||
if ((int32_t)a < 0) { sign_a = 1; a = -a; }
|
||||
if ((int32_t)b < 0) { sign_b = 1; b = -b; }
|
||||
}
|
||||
|
||||
// non-performing restoring division
|
||||
|
||||
R64 R = {.val = a};
|
||||
R.val <<= 1;
|
||||
int i;
|
||||
for (i = 32; i > 1; i --) {
|
||||
if (R.hi >= b) {
|
||||
R.hi -= b;
|
||||
R.val = (R.val << 1) + 1;
|
||||
}
|
||||
else {
|
||||
R.val <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
R.lo <<= 1;
|
||||
if (R.hi >= b) {
|
||||
R.hi -= b;
|
||||
R.lo ++;
|
||||
}
|
||||
|
||||
if (sign_a ^ sign_b) R.lo = -R.lo;
|
||||
if (sign_a) R.hi = -R.hi;
|
||||
return (reminder ? R.hi : R.lo);
|
||||
}
|
||||
|
||||
int __am_illegal_instr(_Context *c) {
|
||||
union {
|
||||
struct {
|
||||
uint32_t opcode :7;
|
||||
uint32_t rd :5;
|
||||
uint32_t func :3;
|
||||
uint32_t rs1 :5;
|
||||
uint32_t rs2 :5;
|
||||
uint32_t func2 :7;
|
||||
};
|
||||
uint32_t val;
|
||||
} instr;
|
||||
instr.val = *(uint32_t *)(c->epc);
|
||||
|
||||
if (instr.opcode == 0x33 && instr.func2 == 1) {
|
||||
// M extension
|
||||
uint32_t rs1 = c->gpr[instr.rs1];
|
||||
uint32_t rs2 = c->gpr[instr.rs2];
|
||||
switch (instr.func) {
|
||||
/* mul */ case 0: c->gpr[instr.rd] = mul(rs1, rs2, true, false); return true;
|
||||
/* mulh */ case 1: c->gpr[instr.rd] = mul(rs1, rs2, true, true); return true;
|
||||
/* div */ case 4: c->gpr[instr.rd] = div(rs1, rs2, true, false); return true;
|
||||
/* divu */ case 5: c->gpr[instr.rd] = div(rs1, rs2, false, false); return true;
|
||||
/* rem */ case 6: c->gpr[instr.rd] = div(rs1, rs2, true, true); return true;
|
||||
/* remu */ case 7: c->gpr[instr.rd] = div(rs1, rs2, false, true); return true;
|
||||
}
|
||||
}
|
||||
|
||||
printf("invalid instruction\n");
|
||||
_halt(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t __mulsi3 (uint32_t a, uint32_t b) {
|
||||
// mul a0, a0, a1
|
||||
asm volatile(".word 0x02b50533");
|
||||
return a;
|
||||
// return mul(a, b, true, false);
|
||||
}
|
||||
uint32_t __divsi3 (uint32_t a, uint32_t b) { return div(a, b, true, false); }
|
||||
uint32_t __modsi3 (uint32_t a, uint32_t b) { return div(a, b, true, true); }
|
||||
uint32_t __umodsi3(uint32_t a, uint32_t b) { return div(a, b, false, true); }
|
||||
uint32_t __udivsi3(uint32_t a, uint32_t b) { return div(a, b, false, false); }
|
|
@ -1,32 +0,0 @@
|
|||
#include <am.h>
|
||||
#include <riscv32.h>
|
||||
#include <klib.h>
|
||||
|
||||
extern char _heap_start;
|
||||
extern char _heap_end;
|
||||
int main(const char *args);
|
||||
void __am_init_uartlite(void);
|
||||
void __am_uartlite_putchar(char ch);
|
||||
|
||||
_Area _heap = RANGE(&_heap_start, &_heap_end);
|
||||
|
||||
void _putc(char ch) {
|
||||
__am_uartlite_putchar(ch);
|
||||
}
|
||||
|
||||
void _halt(int code) {
|
||||
__asm__ volatile("mv a0, %0; .word 0x0005006b" : :"r"(code));
|
||||
|
||||
// should not reach here during simulation
|
||||
printf("Exit with code = %d\n", code);
|
||||
|
||||
// should not reach here on FPGA
|
||||
while (1);
|
||||
}
|
||||
|
||||
void _trm_init() {
|
||||
__am_init_uartlite();
|
||||
extern const char _mainargs;
|
||||
int ret = main(&_mainargs);
|
||||
_halt(ret);
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
#include <am.h>
|
||||
#include <klib.h>
|
||||
|
||||
#define PERFCNT_BASE 0xb00
|
||||
|
||||
#define CNT_NAME(cnt) #cnt,
|
||||
static const char *name [] = {
|
||||
MAP(COUNTERS, CNT_NAME)
|
||||
};
|
||||
|
||||
void __am_perfcnt_read(PerfCntSet *set) {
|
||||
#define READ_LO(cnt) \
|
||||
asm volatile("csrr %0, %1" : "=r"(set->cnts[CNT_IDX(cnt)].lo) : "i"(PERFCNT_BASE + CNT_IDX(cnt)));
|
||||
#define READ_HI(cnt) \
|
||||
asm volatile("csrr %0, %1" : "=r"(set->cnts[CNT_IDX(cnt)].hi) : "i"(PERFCNT_BASE + 0x80 + CNT_IDX(cnt)));
|
||||
|
||||
MAP(COUNTERS, READ_LO)
|
||||
MAP(COUNTERS, READ_HI)
|
||||
}
|
||||
|
||||
void __am_perfcnt_sub(PerfCntSet *res, PerfCntSet *t1, PerfCntSet *t0) {
|
||||
int i;
|
||||
for (i = 0; i < NR_PERFCNT; i ++) {
|
||||
if (i != CNT_IDX(time)) {
|
||||
res->cnts[i].val = t1->cnts[i].val - t0->cnts[i].val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __am_perfcnt_add(PerfCntSet *res, PerfCntSet *t1, PerfCntSet *t0) {
|
||||
int i;
|
||||
for (i = 0; i < NR_PERFCNT; i ++) {
|
||||
if (i != CNT_IDX(time)) {
|
||||
res->cnts[i].val = t1->cnts[i].val + t0->cnts[i].val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __am_perfcnt_show(PerfCntSet *t) {
|
||||
int i;
|
||||
for (i = 0; i < NR_PERFCNT; i ++) {
|
||||
if (i != CNT_IDX(time)) {
|
||||
printf("{%10u, %10u} <- %s\n", t->cnts[i].hi, t->cnts[i].lo, name[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __am_perfcnt_excel(PerfCntSet *t) {
|
||||
int i;
|
||||
for (i = 0; i < NR_PERFCNT; i ++) {
|
||||
if (i != CNT_IDX(time)) {
|
||||
if (i == CNT_IDX(cycle)) {
|
||||
printf("%u,", t->cnts[i].hi);
|
||||
}
|
||||
printf("%u,", t->cnts[i].lo);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
|
@ -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
|
|
@ -1,28 +0,0 @@
|
|||
#include <riscv64.h>
|
||||
|
||||
#define UARTLITE_MMIO 0x40600000
|
||||
#define UARTLITE_RX_FIFO 0x0
|
||||
#define UARTLITE_TX_FIFO 0x4
|
||||
#define UARTLITE_STAT_REG 0x8
|
||||
#define UARTLITE_CTRL_REG 0xc
|
||||
|
||||
#define UARTLITE_RST_FIFO 0x03
|
||||
#define UARTLITE_TX_FULL 0x08
|
||||
#define UARTLITE_RX_VALID 0x01
|
||||
|
||||
void __am_init_uartlite(void) {
|
||||
outb(UARTLITE_MMIO + UARTLITE_CTRL_REG, UARTLITE_RST_FIFO);
|
||||
}
|
||||
|
||||
void __am_uartlite_putchar(char ch) {
|
||||
if (ch == '\n') __am_uartlite_putchar('\r');
|
||||
|
||||
while (inb(UARTLITE_MMIO + UARTLITE_STAT_REG) & UARTLITE_TX_FULL);
|
||||
outb(UARTLITE_MMIO + UARTLITE_TX_FIFO, ch);
|
||||
}
|
||||
|
||||
int __am_uartlite_getchar() {
|
||||
if (inb(UARTLITE_MMIO + UARTLITE_STAT_REG) & UARTLITE_RX_VALID)
|
||||
return inb(UARTLITE_MMIO + UARTLITE_RX_FIFO);
|
||||
return 0;
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue