[platform][qemu-riscv] Fixup qemu-riscv target

-Fix plic driver to handle machine vs supervisor mode
-Add switch to scripts/do-qemuriscv to run in supervisor mode (with OpenSBI)
-Use the FDT to detect the number of cpus and size of memory
This commit is contained in:
Travis Geiselbrecht
2020-01-19 14:47:25 -08:00
parent 4d080aaef9
commit 9c71a0ec57
6 changed files with 85 additions and 24 deletions

View File

@@ -14,7 +14,7 @@
#define IRQ_VIRTIO_BASE 1 #define IRQ_VIRTIO_BASE 1
#define IRQ_UART0 10 #define IRQ_UART0 10
#define IRQ_PCIE_BASE 0x20 #define IRQ_PCIE_BASE 0x20
#define NUM_IRQS 0x35 #define NUM_IRQS 127
#define CLINT_BASE 0x02000000 #define CLINT_BASE 0x02000000
#define PLIC_BASE 0x0c000000 #define PLIC_BASE 0x0c000000
@@ -22,3 +22,9 @@
#define VIRTIO_BASE 0x10001000 #define VIRTIO_BASE 0x10001000
#define DRAM_BASE 0x80000000 #define DRAM_BASE 0x80000000
#if RISCV_XMODE_OFFSET == RISCV_MACH_OFFSET
#define PLIC_HART_IDX(hart) (2 * (hart))
#elif RISCV_XMODE_OFFSET == RISCV_SUPER_OFFSET
#define PLIC_HART_IDX(hart) ((2 * (hart)) + 1)
#endif

View File

@@ -6,6 +6,7 @@
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include <lk/reg.h> #include <lk/reg.h>
#include <lk/trace.h>
#include <kernel/thread.h> #include <kernel/thread.h>
#include <kernel/novm.h> #include <kernel/novm.h>
#include <platform.h> #include <platform.h>
@@ -18,16 +19,23 @@
#include "platform_p.h" #include "platform_p.h"
#define LOCAL_TRACE 1
extern ulong lk_boot_args[4]; extern ulong lk_boot_args[4];
static int cpu_count = 0;
void platform_early_init(void) { void platform_early_init(void) {
plic_early_init(); plic_early_init();
LTRACEF("starting FDT scan\n");
/* look for a flattened device tree in the second arg passed to us */ /* look for a flattened device tree in the second arg passed to us */
bool found_mem = false;
const void *fdt = (void *)lk_boot_args[1]; const void *fdt = (void *)lk_boot_args[1];
int err = fdt_check_header(fdt); int err = fdt_check_header(fdt);
if (err >= 0) { if (err >= 0) {
/* walk the nodes, looking for 'memory@*' */ /* walk the nodes */
int depth = 0; int depth = 0;
int offset = 0; int offset = 0;
for (;;) { for (;;) {
@@ -40,23 +48,42 @@ void platform_early_init(void) {
if (!name) if (!name)
continue; continue;
LTRACEF_LEVEL(2, "name '%s', depth %d\n", name, depth);
/* look for the 'memory@*' property */ /* look for the 'memory@*' property */
if (strncmp(name, "memory@", 7) == 0) { if (!found_mem && strncmp(name, "memory@", 7) == 0 && depth == 1) {
int lenp; int lenp;
const void *prop_ptr = fdt_getprop(fdt, offset, "reg", &lenp); const void *prop_ptr = fdt_getprop(fdt, offset, "reg", &lenp);
if (prop_ptr && lenp == 0x10) { if (prop_ptr && lenp == 0x10) {
/* we're looking at a memory descriptor */ /* we're looking at a memory descriptor */
uint64_t base = fdt64_to_cpu(*(uint64_t *)prop_ptr); uint64_t base = fdt64_to_cpu(*(const uint64_t *)prop_ptr);
uint64_t len = fdt64_to_cpu(*((const uint64_t *)prop_ptr + 1)); uint64_t len = fdt64_to_cpu(*((const uint64_t *)prop_ptr + 1));
/* add another novm arena */ /* add another novm arena */
printf("FDT: found memory arena, base %#llx size %#llx\n", base, len); printf("FDT: found memory arena, base %#llx size %#llx\n", base, len);
novm_add_arena("fdt", base, len); novm_add_arena("fdt", base, len);
break; // stop searching after the first one found_mem = true; // stop searching after the first one
}
}
/* look for a cpu leaf and count the number of cpus */
if (strncmp(name, "cpu@", 4) == 0 && depth == 2) {
int lenp;
const void *prop_ptr = fdt_getprop(fdt, offset, "reg", &lenp);
if (prop_ptr && lenp == 0x4) {
uint32_t id = fdt32_to_cpu(*(const uint32_t *)prop_ptr);
printf("FDT: found cpu id %u\n", id);
cpu_count++;
} }
} }
} }
} }
if (cpu_count > 0) {
riscv_set_secondary_count(cpu_count - 1);
}
LTRACEF("done scanning FDT\n");
} }
void platform_init(void) { void platform_init(void) {

View File

@@ -20,13 +20,12 @@
#define LOCAL_TRACE 0 #define LOCAL_TRACE 0
// Driver for PLIC implementation for qemu riscv virt machine // Driver for PLIC implementation for qemu riscv virt machine
#define PLIC_PRIORITY(irq) (PLIC_BASE + 4 + 4 * (irq))
#define PLIC_PRIORITY(x) (PLIC_BASE + 4 * (x)) #define PLIC_PENDING(irq) (PLIC_BASE + 0x1000 + (4 * ((irq) / 32)))
#define PLIC_PENDING(x) (PLIC_BASE + 0x1000 + 4 * ((x) / 32)) #define PLIC_ENABLE(irq, hart) (PLIC_BASE + 0x2000 + (0x80 * PLIC_HART_IDX(hart)) + (4 * ((irq) / 32)))
#define PLIC_ENABLE(x) (PLIC_BASE + 0x2000 + 4 * ((x) / 32)) #define PLIC_THRESHOLD(hart) (PLIC_BASE + 0x200000 + (0x1000 * PLIC_HART_IDX(hart)))
#define PLIC_THRESHOLD (PLIC_BASE + 0x200000) #define PLIC_COMPLETE(hart) (PLIC_BASE + 0x200004 + (0x1000 * PLIC_HART_IDX(hart)))
#define PLIC_COMPLETE (PLIC_BASE + 0x200004) #define PLIC_CLAIM(hart) PLIC_COMPLETE(hart)
#define PLIC_CLAIM PLIC_COMPLETE
static struct int_handlers { static struct int_handlers {
int_handler handler; int_handler handler;
@@ -35,25 +34,26 @@ static struct int_handlers {
void plic_early_init(void) { void plic_early_init(void) {
// mask all irqs and set their priority to 1 // mask all irqs and set their priority to 1
// TODO: mask on all the other cpus too
for (int i = 1; i < NUM_IRQS; i++) { for (int i = 1; i < NUM_IRQS; i++) {
*REG32(PLIC_ENABLE(i)) &= ~(1 << (i % 32)); *REG32(PLIC_ENABLE(i, riscv_current_hart())) &= ~(1 << (i % 32));
*REG32(PLIC_PRIORITY(i)) = 1; *REG32(PLIC_PRIORITY(i)) = 1;
} }
// set global priority threshold to 0 // set global priority threshold to 0
*REG32(PLIC_THRESHOLD) = 0; *REG32(PLIC_THRESHOLD(riscv_current_hart())) = 0;
} }
void plic_init(void) { void plic_init(void) {
} }
status_t mask_interrupt(unsigned int vector) { status_t mask_interrupt(unsigned int vector) {
*REG32(PLIC_ENABLE(vector)) &= ~(1 << (vector % 32)); *REG32(PLIC_ENABLE(vector, riscv_current_hart())) &= ~(1 << (vector % 32));
return NO_ERROR; return NO_ERROR;
} }
status_t unmask_interrupt(unsigned int vector) { status_t unmask_interrupt(unsigned int vector) {
*REG32(PLIC_ENABLE(vector)) |= (1 << (vector % 32)); *REG32(PLIC_ENABLE(vector, riscv_current_hart())) |= (1 << (vector % 32));
return NO_ERROR; return NO_ERROR;
} }
@@ -68,7 +68,7 @@ void register_int_handler(unsigned int vector, int_handler handler, void *arg) {
enum handler_return riscv_platform_irq(void) { enum handler_return riscv_platform_irq(void) {
// see what irq triggered it // see what irq triggered it
uint32_t vector = *REG32(PLIC_CLAIM); uint32_t vector = *REG32(PLIC_CLAIM(riscv_current_hart()));
LTRACEF("vector %u\n", vector); LTRACEF("vector %u\n", vector);
if (unlikely(vector == 0)) { if (unlikely(vector == 0)) {
@@ -85,7 +85,7 @@ enum handler_return riscv_platform_irq(void) {
} }
// ack the interrupt // ack the interrupt
*REG32(PLIC_COMPLETE) = vector; *REG32(PLIC_COMPLETE(riscv_current_hart())) = vector;
KEVLOG_IRQ_EXIT(vector); KEVLOG_IRQ_EXIT(vector);

View File

@@ -4,6 +4,9 @@ MODULE := $(LOCAL_DIR)
ARCH := riscv ARCH := riscv
SUBARCH ?= 32 SUBARCH ?= 32
RISCV_MODE ?= machine
WITH_SMP ?= 1
SMP_MAX_CPUS ?= 8
MODULE_DEPS += lib/cbuf MODULE_DEPS += lib/cbuf
MODULE_DEPS += lib/fdt MODULE_DEPS += lib/fdt
@@ -14,7 +17,11 @@ MODULE_SRCS += $(LOCAL_DIR)/uart.c
#ROMBASE ?= 0x20400000 # if running from rom, start here #ROMBASE ?= 0x20400000 # if running from rom, start here
MEMBASE ?= 0x80000000 MEMBASE ?= 0x80000000
MEMSIZE ?= 0x00100000 # default to 1MB MEMSIZE ?= 0x01000000 # default to 16MB
ifeq ($(RISCV_MODE),supervisor)
# offset the kernel to account for OpenSBI using the bottom
KERNEL_LOAD_OFFSET ?= 0x00200000 # kernel load offset
endif
# sifive_e or _u? # sifive_e or _u?
GLOBAL_DEFINES += PLATFORM_${VARIANT}=1 GLOBAL_DEFINES += PLATFORM_${VARIANT}=1

View File

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

View File

@@ -12,6 +12,8 @@ function HELP {
echo "-d a virtio display" echo "-d a virtio display"
echo "-e embeded platform" echo "-e embeded platform"
echo "-6 64bit" echo "-6 64bit"
echo "-u supervisor mode (using OpenSBI)"
echo " currently only works in 64bit mode"
echo "-m <memory in MB>" echo "-m <memory in MB>"
echo "-s <number of cpus>" echo "-s <number of cpus>"
echo "-h for help" echo "-h for help"
@@ -27,12 +29,14 @@ DO_EMBEDDED=0
DO_DISPLAY=0 DO_DISPLAY=0
DO_CMPCTMALLOC=0 DO_CMPCTMALLOC=0
DO_MINIHEAP=0 DO_MINIHEAP=0
DO_SUPERVISOR=0
SMP=1 SMP=1
MEMSIZE=512 MEMSIZE=512
SUDO="" SUDO=""
PROJECT="" PROJECT=""
BIOS="none"
while getopts bdhm:cMnte6p:s: FLAG; do while getopts bdhm:cMmnte6p:s:u FLAG; do
case $FLAG in case $FLAG in
b) DO_BLOCK=1;; b) DO_BLOCK=1;;
c) DO_CMPCTMALLOC=1;; c) DO_CMPCTMALLOC=1;;
@@ -45,6 +49,7 @@ while getopts bdhm:cMnte6p:s: FLAG; do
m) MEMSIZE=$OPTARG;; m) MEMSIZE=$OPTARG;;
s) SMP=$OPTARG;; s) SMP=$OPTARG;;
p) PROJECT=$OPTARG;; p) PROJECT=$OPTARG;;
u) DO_SUPERVISOR=1;;
h) HELP;; h) HELP;;
\?) \?)
echo unrecognized option echo unrecognized option
@@ -56,16 +61,21 @@ shift $((OPTIND-1))
if (( $DO_64BIT )); then if (( $DO_64BIT )); then
QEMU="qemu-system-riscv64" QEMU="qemu-system-riscv64"
CPU="any" CPU="rv64"
MACHINE="virt" MACHINE="virt"
_PROJECT="qemu-virt-riscv64-test" if (( $DO_SUPERVISOR )); then
_PROJECT="qemu-virt-riscv64-supervisor-test"
BIOS="default"
else
_PROJECT="qemu-virt-riscv64-test"
fi
elif (( $DO_EMBEDDED == 1 )); then elif (( $DO_EMBEDDED == 1 )); then
QEMU="qemu-system-riscv32" QEMU="qemu-system-riscv32"
MACHINE="sifive_e" MACHINE="sifive_e"
_PROJECT="sifive-e-test" _PROJECT="sifive-e-test"
else else
QEMU="qemu-system-riscv32" QEMU="qemu-system-riscv32"
CPU="any" CPU="rv32"
MACHINE="virt" MACHINE="virt"
_PROJECT="qemu-virt-riscv32-test" _PROJECT="qemu-virt-riscv32-test"
fi fi
@@ -82,7 +92,7 @@ DISPLAY_ARGS=" -device virtio-gpu-device -serial stdio"
# the following args only really make sense on non embedded versions # the following args only really make sense on non embedded versions
if (( ! $DO_EMBEDDED )); then if (( ! $DO_EMBEDDED )); then
ARGS=" -cpu $CPU -m $MEMSIZE -smp $SMP -machine $MACHINE -kernel build-${PROJECT}/lk.elf" ARGS=" -cpu $CPU -m $MEMSIZE -smp $SMP -machine $MACHINE -kernel build-${PROJECT}/lk.elf"
ARGS+=" -bios none" ARGS+=" -bios $BIOS"
if (( $DO_BLOCK )); then if (( $DO_BLOCK )); then
ARGS+=$BLOCK_ARGS ARGS+=$BLOCK_ARGS
fi fi