[arch][riscv] port to riscv64

Very little needed to port except to conditionalize some assembly in the
context switch and exception code. Mostly needed to move build system
stuff around and add a new project.
This commit is contained in:
Travis Geiselbrecht
2019-11-02 17:21:13 -07:00
parent ae5200595c
commit fdc08a8446
14 changed files with 173 additions and 142 deletions

View File

@@ -7,43 +7,55 @@
*/
#include <lk/asm.h>
/* void riscv32_context_switch(
struct riscv32_context_switch_frame *oldcs,
struct riscv32_context_switch_frame *newcs); */
FUNCTION(riscv32_context_switch)
// based on 32 or 64bit register widths, select the 32 or 64 bit
// wide load/stores
#if __riscv_xlen == 32
#define REGOFF(x) ((x) * 4)
#define STR sw
#define LDR lw
#else
#define REGOFF(x) ((x) * 8)
#define STR sd
#define LDR ld
#endif
/* void riscv_context_switch(
struct riscv_context_switch_frame *oldcs,
struct riscv_context_switch_frame *newcs); */
FUNCTION(riscv_context_switch)
# a0 = oldcs
# a1 = newcs
sw ra, 0(a0)
sw sp, 4(a0)
sw tp, 8(a0)
sw s0, 12(a0)
sw s1, 16(a0)
sw s2, 20(a0)
sw s3, 24(a0)
sw s4, 28(a0)
sw s5, 32(a0)
sw s6, 36(a0)
sw s7, 40(a0)
sw s8, 44(a0)
sw s9, 48(a0)
sw s10, 52(a0)
sw s11, 56(a0)
STR ra, REGOFF(0)(a0)
STR sp, REGOFF(1)(a0)
STR tp, REGOFF(2)(a0)
STR s0, REGOFF(3)(a0)
STR s1, REGOFF(4)(a0)
STR s2, REGOFF(5)(a0)
STR s3, REGOFF(6)(a0)
STR s4, REGOFF(7)(a0)
STR s5, REGOFF(8)(a0)
STR s6, REGOFF(9)(a0)
STR s7, REGOFF(10)(a0)
STR s8, REGOFF(11)(a0)
STR s9, REGOFF(12)(a0)
STR s10, REGOFF(13)(a0)
STR s11, REGOFF(14)(a0)
lw s11, 56(a1)
lw s10, 52(a1)
lw s9, 48(a1)
lw s8, 44(a1)
lw s7, 40(a1)
lw s6, 36(a1)
lw s5, 32(a1)
lw s4, 28(a1)
lw s3, 24(a1)
lw s2, 20(a1)
lw s1, 16(a1)
lw s0, 12(a1)
lw tp, 8(a1)
lw sp, 4(a1)
lw ra, 0(a1)
LDR s11, REGOFF(14)(a1)
LDR s10, REGOFF(13)(a1)
LDR s9, REGOFF(12)(a1)
LDR s8, REGOFF(11)(a1)
LDR s7, REGOFF(10)(a1)
LDR s6, REGOFF(9)(a1)
LDR s5, REGOFF(8)(a1)
LDR s4, REGOFF(7)(a1)
LDR s3, REGOFF(6)(a1)
LDR s2, REGOFF(5)(a1)
LDR s1, REGOFF(4)(a1)
LDR s0, REGOFF(3)(a1)
LDR tp, REGOFF(2)(a1)
LDR sp, REGOFF(1)(a1)
LDR ra, REGOFF(0)(a1)
ret
@@ -51,54 +63,54 @@ FUNCTION(riscv32_context_switch)
.balign 4
FUNCTION(riscv_exception_entry)
/* dump all the callee trashed regs on the stack */
addi sp, sp, -80 // subtract a multiple of 16 to align the stack
sw t6, 68(sp)
sw t5, 64(sp)
sw t4, 60(sp)
sw t3, 56(sp)
sw t2, 52(sp)
sw t1, 48(sp)
sw t0, 44(sp)
sw a7, 40(sp)
sw a6, 36(sp)
sw a5, 32(sp)
sw a4, 28(sp)
sw a3, 24(sp)
sw a2, 20(sp)
sw a1, 16(sp)
sw a0, 12(sp)
sw ra, 8(sp)
addi sp, sp, -REGOFF(20) // subtract a multiple of 16 to align the stack in 32bit
STR t6, REGOFF(17)(sp)
STR t5, REGOFF(16)(sp)
STR t4, REGOFF(15)(sp)
STR t3, REGOFF(14)(sp)
STR t2, REGOFF(13)(sp)
STR t1, REGOFF(12)(sp)
STR t0, REGOFF(11)(sp)
STR a7, REGOFF(10)(sp)
STR a6, REGOFF(9)(sp)
STR a5, REGOFF(8)(sp)
STR a4, REGOFF(7)(sp)
STR a3, REGOFF(6)(sp)
STR a2, REGOFF(5)(sp)
STR a1, REGOFF(4)(sp)
STR a0, REGOFF(3)(sp)
STR ra, REGOFF(2)(sp)
csrr t0, mstatus
sw t0, 4(sp)
STR t0, REGOFF(1)(sp)
csrr a0, mcause
csrr a1, mepc
sw a1, 0(sp)
STR a1, REGOFF(0)(sp)
mv a2, sp
jal riscv_exception_handler
/* put everything back */
lw t0, 0(sp)
LDR t0, REGOFF(0)(sp)
csrw mepc, t0
lw t0, 4(sp)
LDR t0, REGOFF(1)(sp)
csrw mstatus, t0
lw ra, 8(sp)
lw a0, 12(sp)
lw a1, 16(sp)
lw a2, 20(sp)
lw a3, 24(sp)
lw a4, 28(sp)
lw a5, 32(sp)
lw a6, 36(sp)
lw a7, 40(sp)
lw t0, 44(sp)
lw t1, 48(sp)
lw t2, 52(sp)
lw t3, 56(sp)
lw t4, 60(sp)
lw t5, 64(sp)
lw t6, 68(sp)
addi sp, sp, 80
LDR ra, REGOFF(2)(sp)
LDR a0, REGOFF(3)(sp)
LDR a1, REGOFF(4)(sp)
LDR a2, REGOFF(5)(sp)
LDR a3, REGOFF(6)(sp)
LDR a4, REGOFF(7)(sp)
LDR a5, REGOFF(8)(sp)
LDR a6, REGOFF(9)(sp)
LDR a7, REGOFF(10)(sp)
LDR t0, REGOFF(11)(sp)
LDR t1, REGOFF(12)(sp)
LDR t2, REGOFF(13)(sp)
LDR t3, REGOFF(14)(sp)
LDR t4, REGOFF(15)(sp)
LDR t5, REGOFF(16)(sp)
LDR t6, REGOFF(17)(sp)
addi sp, sp, REGOFF(20)
mret

View File

@@ -43,12 +43,15 @@ void riscv_exception_handler(ulong cause, ulong epc, struct riscv_short_iframe *
DEBUG_ASSERT(arch_ints_disabled());
DEBUG_ASSERT(frame->mstatus & RISCV_STATUS_MPIE);
// top bit of the cause register determines if it's an interrupt or not
const ulong int_bit = (__riscv_xlen == 32) ? (1ul<<31) : (1ul<<63);
enum handler_return ret = INT_NO_RESCHEDULE;
switch (cause) {
case 0x80000007: // machine timer interrupt
case int_bit | 0x7: // machine timer interrupt
ret = riscv_timer_exception();
break;
case 0x8000000b: // machine external interrupt
case int_bit | 0xb: // machine external interrupt
ret = riscv_platform_irq();
break;
default:

View File

@@ -9,30 +9,30 @@
#include <sys/types.h>
struct riscv32_context_switch_frame {
uint32_t ra; // return address (x1)
uint32_t sp; // stack pointer (x2)
uint32_t tp; // thread pointer (x4)
struct riscv_context_switch_frame {
unsigned long ra; // return address (x1)
unsigned long sp; // stack pointer (x2)
unsigned long tp; // thread pointer (x4)
uint32_t s0; // x8-x9
uint32_t s1;
unsigned long s0; // x8-x9
unsigned long s1;
uint32_t s2; // x18-x27
uint32_t s3;
uint32_t s4;
uint32_t s5;
uint32_t s6;
uint32_t s7;
uint32_t s8;
uint32_t s9;
uint32_t s10;
uint32_t s11;
unsigned long s2; // x18-x27
unsigned long s3;
unsigned long s4;
unsigned long s5;
unsigned long s6;
unsigned long s7;
unsigned long s8;
unsigned long s9;
unsigned long s10;
unsigned long s11;
};
struct arch_thread {
struct riscv32_context_switch_frame cs_frame;
struct riscv_context_switch_frame cs_frame;
};
void riscv32_context_switch(struct riscv32_context_switch_frame *oldcs,
struct riscv32_context_switch_frame *newcs);
void riscv_context_switch(struct riscv_context_switch_frame *oldcs,
struct riscv_context_switch_frame *newcs);

View File

@@ -13,4 +13,8 @@
// XXX is this right?
#define CACHE_LINE 32
#if ARCH_RISCV_EMBEDDED
#define ARCH_DEFAULT_STACK_SIZE 1024
#else
#define ARCH_DEFAULT_STACK_SIZE 4096
#endif

View File

@@ -1,4 +1,4 @@
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv")
OUTPUT_FORMAT("elf%BITS%-littleriscv", "elf%BITS%-bigriscv", "elf%BITS%-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)

View File

@@ -1,4 +1,4 @@
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv")
OUTPUT_FORMAT("elf%BITS%-littleriscv", "elf%BITS%-bigriscv", "elf%BITS%-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)

View File

@@ -12,30 +12,49 @@ MODULE_SRCS += $(LOCAL_DIR)/thread.c
GLOBAL_DEFINES += SMP_MAX_CPUS=1
GLOBAL_DEFINES += PLATFORM_HAS_DYNAMIC_TIMER=1
# set the default toolchain to riscv32 elf and set a #define
ifndef TOOLCHAIN_PREFIX
TOOLCHAIN_PREFIX := riscv32-elf-
endif
SUBARCH ?= 32
WITH_LINKER_GC ?= 0
cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc /dev/null 2>&1`"; \
then echo "$(2)"; else echo "$(3)"; fi ;)
ARCH_COMPILEFLAGS := -march=rv32imac -mabi=ilp32
ARCH_OPTFLAGS := -O2
LIBGCC := $(shell $(TOOLCHAIN_PREFIX)gcc $(GLOBAL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(GLOBAL_CFLAGS) -print-libgcc-file-name)
$(info LIBGCC = $(LIBGCC))
KERNEL_BASE ?= $(MEMBASE)
KERNEL_LOAD_OFFSET ?= 0
ROMBASE ?= 0
GLOBAL_DEFINES += \
ROMBASE=$(ROMBASE) \
MEMBASE=$(MEMBASE) \
MEMSIZE=$(MEMSIZE)
GLOBAL_DEFINES += ROMBASE=$(ROMBASE)
GLOBAL_DEFINES += MEMBASE=$(MEMBASE)
GLOBAL_DEFINES += MEMSIZE=$(MEMSIZE)
# based on 32 or 64 bitness, select the right toolchain and some
# compiler codegen flags
ifeq ($(SUBARCH),32)
ifndef TOOLCHAIN_PREFIX
TOOLCHAIN_PREFIX := riscv32-elf-
endif
ARCH_COMPILEFLAGS := -march=rv32imac -mabi=ilp32
else ifeq ($(SUBARCH),64)
ifndef TOOLCHAIN_PREFIX
TOOLCHAIN_PREFIX := riscv64-elf-
endif
ARCH_COMPILEFLAGS := -march=rv64imafdc -mabi=lp64d -mcmodel=medany
else
$(error SUBARCH not set or set to something unknown)
endif
# embedded switch sets the default compile optimization and passes
# a flag to the code to switch other things on
ifeq (true,$(call TOBOOL,$(ARCH_RISCV_EMBEDDED)))
ARCH_OPTFLAGS ?= -Os
GLOBAL_DEFINES += ARCH_RISCV_EMBEDDED=1
else
ARCH_OPTFLAGS ?= -O2
endif
LIBGCC := $(shell $(TOOLCHAIN_PREFIX)gcc $(GLOBAL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(GLOBAL_CFLAGS) -print-libgcc-file-name)
$(info LIBGCC = $(LIBGCC))
# potentially generated files that should be cleaned out with clean make rule
GENERATED += \
@@ -46,7 +65,7 @@ GENERATED += \
$(BUILDDIR)/linker-%.ld: $(LOCAL_DIR)/linker-%.ld $(wildcard arch/*.ld) linkerscript.phony
@echo generating $@
@$(MKDIR)
$(NOECHO)sed "s/%ROMBASE%/$(ROMBASE)/;s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/;s/%KERNEL_BASE%/$(KERNEL_BASE)/;s/%KERNEL_LOAD_OFFSET%/$(KERNEL_LOAD_OFFSET)/;s/%VECTOR_BASE_PHYS%/$(VECTOR_BASE_PHYS)/" < $< > $@.tmp
$(NOECHO)sed "s/%BITS%/$(SUBARCH)/g;s/%ROMBASE%/$(ROMBASE)/;s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/;s/%KERNEL_BASE%/$(KERNEL_BASE)/;s/%KERNEL_LOAD_OFFSET%/$(KERNEL_LOAD_OFFSET)/;s/%VECTOR_BASE_PHYS%/$(VECTOR_BASE_PHYS)/" < $< > $@.tmp
@$(call TESTANDREPLACEFILE,$@.tmp,$@)
linkerscript.phony:
@@ -54,8 +73,10 @@ linkerscript.phony:
# select the appropriate linker script based on if we're a one or two segment system
ifeq (true,$(call TOBOOL,$(ARCH_RISCV_TWOSEGMENT)))
GLOBAL_DEFINES += ARCH_RISCV_TWOSEGMENT=1
LINKER_SCRIPT += $(BUILDDIR)/linker-twosegment.ld
else
GLOBAL_DEFINES += ARCH_RISCV_TWOSEGMENT=0
LINKER_SCRIPT += $(BUILDDIR)/linker-onesegment.ld
endif

View File

@@ -7,26 +7,6 @@
*/
#include <lk/asm.h>
#if 0
.section ".vectors", "ax"
.globl _vectab
_vectab:
/* vector table here */
# start vector
brai start
# user exception
brai unhandled_exception
# interrupt
brai microblaze_irq
# break
brai unhandled_exception
# hardware exception
brai unhandled_exception
# reserved for future
.fill (0x50 - 0x28)
#endif
.section ".text.boot"
FUNCTION(_start)
.option push
@@ -38,7 +18,7 @@ FUNCTION(_start)
# set the default stack
la sp, default_stack_top
#if 1
#if ARCH_RISCV_TWOSEGMENT
# copy preinitialized data from flash to memory
la t0, __data_start_rom
la t1, __data_start

View File

@@ -55,13 +55,13 @@ void arch_context_switch(thread_t *oldthread, thread_t *newthread) {
LTRACEF("old %p (%s), new %p (%s)\n", oldthread, oldthread->name, newthread, newthread->name);
riscv32_context_switch(&oldthread->arch.cs_frame, &newthread->arch.cs_frame);
riscv_context_switch(&oldthread->arch.cs_frame, &newthread->arch.cs_frame);
}
void arch_dump_thread(thread_t *t) {
if (t->state != THREAD_RUNNING) {
dprintf(INFO, "\tarch: ");
dprintf(INFO, "sp 0x%x\n", t->arch.cs_frame.sp);
dprintf(INFO, "sp %#lx\n", t->arch.cs_frame.sp);
}
}

View File

@@ -281,7 +281,7 @@ static void novm_dump_arena(struct novm_arena *n) {
}
mutex_acquire(&n->lock);
printf("name '%s', %d pages, each %zdk (%zdk in all)\n", n->name, n->pages, PAGE_SIZE >> 10, (PAGE_SIZE * n->pages) >> 10);
printf("name '%s', %zu pages, each %zdk (%zdk in all)\n", n->name, n->pages, (size_t)PAGE_SIZE >> 10, (size_t)(PAGE_SIZE * n->pages) >> 10);
printf(" range: %p-%p\n", (void *)n->base, (char *)n->base + n->size);
printf(" unaligned range: %p-%p\n", n->unaligned_area, n->unaligned_area + n->unaligned_size);
unsigned i;

View File

@@ -4,7 +4,6 @@ MODULE := $(LOCAL_DIR)
ARCH := riscv
SUBARCH ?= 32
VARIANT ?= sifive_u
MODULE_DEPS += lib/cbuf

View File

@@ -16,8 +16,12 @@ ROMBASE ?= 0x20400000 # if running from rom, start here
MEMBASE ?= 0x80000000
MEMSIZE ?= 0x00100000 # default to 1MB
ifeq ($(VARIANT),sifive_e)
# uses a two segment layout, select the appropriate linker script
ARCH_RISCV_TWOSEGMENT := 1
# sets a few options in the riscv arch
ARCH_RISCV_EMBEDDED := 1
endif
# sifive_e or _u?
GLOBAL_DEFINES += PLATFORM_${VARIANT}=1

View File

@@ -0,0 +1,10 @@
# main project for qemu-riscv64
MODULES += \
app/shell
SUBARCH := 64
include project/virtual/test.mk
include project/virtual/fs.mk
include project/virtual/minip.mk
include project/target/qemu-virt-riscv.mk

View File

@@ -55,12 +55,10 @@ done
shift $((OPTIND-1))
if (( $DO_64BIT )); then
echo unsupported now
exit 1
QEMU="qemu-system-riscv64"
#CPU="cortex-a53"
CPU="any"
MACHINE="virt"
_PROJECT="qemu-virt-arm64-test"
_PROJECT="qemu-virt-riscv64-test"
elif (( $DO_EMBEDDED == 1 )); then
QEMU="qemu-system-riscv32"
MACHINE="sifive_e"