From fdc08a844649b69161339b34d247f12473896eb9 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Sat, 2 Nov 2019 17:21:13 -0700 Subject: [PATCH] [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. --- arch/riscv/asm.S | 156 ++++++++++++----------- arch/riscv/exceptions.c | 7 +- arch/riscv/include/arch/arch_thread.h | 38 +++--- arch/riscv/include/arch/defines.h | 4 + arch/riscv/linker-onesegment.ld | 2 +- arch/riscv/linker-twosegment.ld | 2 +- arch/riscv/rules.mk | 57 ++++++--- arch/riscv/start.S | 22 +--- arch/riscv/thread.c | 4 +- kernel/novm/novm.c | 2 +- platform/qemu-virt-riscv/rules.mk | 1 - platform/sifive/rules.mk | 4 + project/qemu-virt-riscv64-test.mk | 10 ++ scripts/{do-qemuriscv32 => do-qemuriscv} | 6 +- 14 files changed, 173 insertions(+), 142 deletions(-) create mode 100644 project/qemu-virt-riscv64-test.mk rename scripts/{do-qemuriscv32 => do-qemuriscv} (96%) diff --git a/arch/riscv/asm.S b/arch/riscv/asm.S index 37bb0d5f..33873be1 100644 --- a/arch/riscv/asm.S +++ b/arch/riscv/asm.S @@ -7,43 +7,55 @@ */ #include -/* 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 diff --git a/arch/riscv/exceptions.c b/arch/riscv/exceptions.c index 8d41c11c..7b22f7f7 100644 --- a/arch/riscv/exceptions.c +++ b/arch/riscv/exceptions.c @@ -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: diff --git a/arch/riscv/include/arch/arch_thread.h b/arch/riscv/include/arch/arch_thread.h index 3ceb1527..fa16a79c 100644 --- a/arch/riscv/include/arch/arch_thread.h +++ b/arch/riscv/include/arch/arch_thread.h @@ -9,30 +9,30 @@ #include -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); diff --git a/arch/riscv/include/arch/defines.h b/arch/riscv/include/arch/defines.h index 24ee8305..6630e6ae 100644 --- a/arch/riscv/include/arch/defines.h +++ b/arch/riscv/include/arch/defines.h @@ -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 diff --git a/arch/riscv/linker-onesegment.ld b/arch/riscv/linker-onesegment.ld index b0baef67..7759166d 100644 --- a/arch/riscv/linker-onesegment.ld +++ b/arch/riscv/linker-onesegment.ld @@ -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) diff --git a/arch/riscv/linker-twosegment.ld b/arch/riscv/linker-twosegment.ld index 70336053..6e9888f1 100644 --- a/arch/riscv/linker-twosegment.ld +++ b/arch/riscv/linker-twosegment.ld @@ -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) diff --git a/arch/riscv/rules.mk b/arch/riscv/rules.mk index 384e149b..428c1ea2 100644 --- a/arch/riscv/rules.mk +++ b/arch/riscv/rules.mk @@ -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 diff --git a/arch/riscv/start.S b/arch/riscv/start.S index 3c866b37..bbb24d92 100644 --- a/arch/riscv/start.S +++ b/arch/riscv/start.S @@ -7,26 +7,6 @@ */ #include -#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 diff --git a/arch/riscv/thread.c b/arch/riscv/thread.c index 2b0f285b..d91a7678 100644 --- a/arch/riscv/thread.c +++ b/arch/riscv/thread.c @@ -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); } } diff --git a/kernel/novm/novm.c b/kernel/novm/novm.c index 2bd67da5..0f6209d0 100644 --- a/kernel/novm/novm.c +++ b/kernel/novm/novm.c @@ -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; diff --git a/platform/qemu-virt-riscv/rules.mk b/platform/qemu-virt-riscv/rules.mk index 73b361e4..e243a41b 100644 --- a/platform/qemu-virt-riscv/rules.mk +++ b/platform/qemu-virt-riscv/rules.mk @@ -4,7 +4,6 @@ MODULE := $(LOCAL_DIR) ARCH := riscv SUBARCH ?= 32 -VARIANT ?= sifive_u MODULE_DEPS += lib/cbuf diff --git a/platform/sifive/rules.mk b/platform/sifive/rules.mk index f5bc75c6..709f0f14 100644 --- a/platform/sifive/rules.mk +++ b/platform/sifive/rules.mk @@ -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 diff --git a/project/qemu-virt-riscv64-test.mk b/project/qemu-virt-riscv64-test.mk new file mode 100644 index 00000000..5792b5de --- /dev/null +++ b/project/qemu-virt-riscv64-test.mk @@ -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 + diff --git a/scripts/do-qemuriscv32 b/scripts/do-qemuriscv similarity index 96% rename from scripts/do-qemuriscv32 rename to scripts/do-qemuriscv index b551914d..5d33c9f3 100755 --- a/scripts/do-qemuriscv32 +++ b/scripts/do-qemuriscv @@ -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"