[arch][riscv] Add support for running in supervisor mode
Add support for running LK in supervisor mode or machine mode. - Macro-ify CSR access to use correct CSR # or use SBI call as req'd - Add support to make SBI calls - Split CLINT and lk timer abstraction so that RISC-V timer can use SBI as required. - Add support for booting other harts as primary since hart0 on U540 does not support S-mode. A map is used to get LK cpu number from hartid.
This commit is contained in:
committed by
Travis Geiselbrecht
parent
e137d70ccd
commit
e50d7db612
@@ -14,6 +14,7 @@
|
||||
#include <arch/mp.h>
|
||||
#include <lk/init.h>
|
||||
#include <lk/main.h>
|
||||
#include <platform.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
@@ -24,11 +25,11 @@ static volatile int secondaries_to_init = SMP_MAX_CPUS - 1;
|
||||
|
||||
void arch_early_init(void) {
|
||||
// set the top level exception handler
|
||||
riscv_csr_write(mtvec, (uintptr_t)&riscv_exception_entry);
|
||||
riscv_csr_write(RISCV_CSR_XTVEC, (uintptr_t)&riscv_exception_entry);
|
||||
|
||||
// mask all exceptions, just in case
|
||||
riscv_csr_clear(mstatus, RISCV_STATUS_MIE);
|
||||
riscv_csr_clear(mie, RISCV_MIE_MTIE | RISCV_MIE_MSIE | RISCV_MIE_SEIE | RISCV_MIE_MEIE);
|
||||
riscv_csr_clear(RISCV_CSR_XSTATUS, RISCV_CSR_XSTATUS_IE);
|
||||
riscv_csr_clear(RISCV_CSR_XIE, RISCV_CSR_XIE_SIE | RISCV_CSR_XIE_TIE | RISCV_CSR_XIE_EIE);
|
||||
|
||||
// enable cycle counter (disabled for now, unimplemented on sifive-e)
|
||||
//riscv_csr_set(mcounteren, 1);
|
||||
@@ -36,13 +37,17 @@ void arch_early_init(void) {
|
||||
|
||||
void arch_init(void) {
|
||||
// print some arch info
|
||||
dprintf(INFO, "RISCV: mvendorid %#lx marchid %#lx mimpid %#lx mhartid %#lx\n",
|
||||
riscv_csr_read(mvendorid), riscv_csr_read(marchid),
|
||||
riscv_csr_read(mimpid), riscv_csr_read(mhartid));
|
||||
dprintf(INFO, "RISCV: misa %#lx\n", riscv_csr_read(misa));
|
||||
dprintf(INFO, "RISCV: mvendorid %#lx marchid %#lx mimpid %#lx mhartid %#x\n",
|
||||
riscv_get_mvendorid(), riscv_get_marchid(),
|
||||
riscv_get_mimpid(), riscv_current_hart());
|
||||
#if RISCV_M_MODE
|
||||
dprintf(INFO, "RISCV: misa %#lx\n", riscv_csr_read(RISCV_CSR_MISA));
|
||||
#else
|
||||
dprintf(INFO, "RISCV: sbi %#lx (%#lx)\n", sbi_call(SBI_GET_SBI_IMPL_ID).value, sbi_call(SBI_GET_SBI_IMPL_VERSION).value);
|
||||
#endif
|
||||
|
||||
// enable external interrupts
|
||||
riscv_csr_set(mie, RISCV_MIE_MEIE);
|
||||
riscv_csr_set(RISCV_CSR_XIE, RISCV_CSR_XIE_EIE);
|
||||
|
||||
#if WITH_SMP
|
||||
arch_mp_init_percpu();
|
||||
@@ -61,23 +66,25 @@ void arch_init(void) {
|
||||
void riscv_secondary_entry(void) {
|
||||
arch_early_init();
|
||||
|
||||
if (unlikely(riscv_csr_read(mhartid) >= SMP_MAX_CPUS))
|
||||
if (unlikely(arch_curr_cpu_num() >= SMP_MAX_CPUS))
|
||||
while (1) arch_idle();
|
||||
|
||||
spin_lock(&boot_cpu_lock);
|
||||
spin_unlock(&boot_cpu_lock);
|
||||
|
||||
// enable external interrupts
|
||||
riscv_csr_set(mie, RISCV_MIE_MEIE);
|
||||
riscv_csr_set(RISCV_CSR_XIE, RISCV_CSR_XIE_EIE);
|
||||
|
||||
/* run early secondary cpu init routines up to the threading level */
|
||||
lk_init_level(LK_INIT_FLAG_SECONDARY_CPUS, LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_THREADING - 1);
|
||||
|
||||
arch_mp_init_percpu();
|
||||
|
||||
dprintf(INFO, "RISCV: secondary hart coming up: mvendorid %#lx marchid %#lx mimpid %#lx mhartid %#lx\n",
|
||||
# if RISCV_M_MODE
|
||||
dprintf(INFO, "RISCV: secondary hart coming up: mvendorid %#lx marchid %#lx mimpid %#lx mhartid %#x\n",
|
||||
riscv_csr_read(mvendorid), riscv_csr_read(marchid),
|
||||
riscv_csr_read(mimpid), riscv_csr_read(mhartid));
|
||||
riscv_csr_read(mimpid), riscv_current_hart());
|
||||
# endif /* RISCV_M_MODE */
|
||||
|
||||
// atomic_add(&secondaries_to_init, -1);
|
||||
// arch_mp_send_ipi(1 << 0, MP_IPI_GENERIC); // wake up hart0 to let it know this CPU has come up
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/asm.h>
|
||||
#include <arch/riscv.h>
|
||||
|
||||
// based on 32 or 64bit register widths, select the 32 or 64 bit
|
||||
// wide load/stores
|
||||
@@ -78,10 +79,10 @@ FUNCTION(riscv_exception_entry)
|
||||
STR a1, REGOFF(4)(sp)
|
||||
STR a0, REGOFF(3)(sp)
|
||||
STR ra, REGOFF(2)(sp)
|
||||
csrr t0, mstatus
|
||||
csrr t0, RISCV_CSR_XSTATUS
|
||||
STR t0, REGOFF(1)(sp)
|
||||
csrr a0, mcause
|
||||
csrr a1, mepc
|
||||
csrr a0, RISCV_CSR_XCAUSE
|
||||
csrr a1, RISCV_CSR_XEPC
|
||||
STR a1, REGOFF(0)(sp)
|
||||
mv a2, sp
|
||||
|
||||
@@ -89,9 +90,9 @@ FUNCTION(riscv_exception_entry)
|
||||
|
||||
/* put everything back */
|
||||
LDR t0, REGOFF(0)(sp)
|
||||
csrw mepc, t0
|
||||
csrw RISCV_CSR_XEPC, t0
|
||||
LDR t0, REGOFF(1)(sp)
|
||||
csrw mstatus, t0
|
||||
csrw RISCV_CSR_XSTATUS, t0
|
||||
|
||||
LDR ra, REGOFF(2)(sp)
|
||||
LDR a0, REGOFF(3)(sp)
|
||||
@@ -111,4 +112,4 @@ FUNCTION(riscv_exception_entry)
|
||||
LDR t6, REGOFF(17)(sp)
|
||||
addi sp, sp, REGOFF(20)
|
||||
|
||||
mret
|
||||
RISCV_XRET
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/reg.h>
|
||||
#include <lk/debug.h>
|
||||
#include <lk/trace.h>
|
||||
#include <lk/err.h>
|
||||
#include <platform.h>
|
||||
#include <platform/timer.h>
|
||||
#include <arch/riscv.h>
|
||||
#include <lk/trace.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
// platform must define these
|
||||
#ifndef ARCH_RISCV_CLINT_BASE
|
||||
#error Platform must define ARCH_RISCV_CLINT_BASE
|
||||
#endif
|
||||
#ifndef ARCH_RISCV_MTIME_RATE
|
||||
#error Platform must define ARCH_RISCV_MTIME_RATE
|
||||
#endif
|
||||
|
||||
#define CLINT_MSIP(x) (ARCH_RISCV_CLINT_BASE + 4 * (x))
|
||||
#define CLINT_MTIMECMP(x) (ARCH_RISCV_CLINT_BASE + 0x4000 + 8 * (x))
|
||||
#define CLINT_MTIME (ARCH_RISCV_CLINT_BASE + 0xbff8)
|
||||
|
||||
void clint_ipi_send(unsigned long target_hart) {
|
||||
if (target_hart >= SMP_MAX_CPUS)
|
||||
return;
|
||||
|
||||
*REG64(CLINT_MSIP(target_hart)) = 1;
|
||||
}
|
||||
|
||||
|
||||
void clint_ipi_clear(unsigned long target_hart) {
|
||||
if (target_hart >= SMP_MAX_CPUS)
|
||||
return;
|
||||
|
||||
*REG64(CLINT_MSIP(target_hart)) = 0;
|
||||
}
|
||||
|
||||
lk_bigtime_t current_time_hires(void) {
|
||||
#if ARCH_RISCV_MTIME_RATE < 10000000
|
||||
return current_time() * 1000llu; // hack to deal with slow clocks
|
||||
#else
|
||||
return *REG64(CLINT_MTIME) / (ARCH_RISCV_MTIME_RATE / 1000000u);
|
||||
#endif
|
||||
}
|
||||
|
||||
lk_time_t current_time(void) {
|
||||
return *REG64(CLINT_MTIME) / (ARCH_RISCV_MTIME_RATE / 1000u);
|
||||
}
|
||||
|
||||
static platform_timer_callback timer_cb;
|
||||
static void *timer_arg;
|
||||
|
||||
status_t platform_set_oneshot_timer (platform_timer_callback callback, void *arg, lk_time_t interval) {
|
||||
LTRACEF("cb %p, arg %p, interval %u\n", callback, arg, interval);
|
||||
|
||||
// disable timer
|
||||
riscv_csr_clear(mie, RISCV_MIE_MTIE);
|
||||
|
||||
timer_cb = callback;
|
||||
timer_arg = arg;
|
||||
|
||||
// convert interval to ticks
|
||||
uint64_t ticks = (interval * ARCH_RISCV_MTIME_RATE) / 1000u;
|
||||
*REG64(CLINT_MTIMECMP(riscv_current_hart())) = *REG64(CLINT_MTIME) + ticks;
|
||||
|
||||
// enable the timer
|
||||
riscv_csr_set(mie, RISCV_MIE_MTIE);
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void platform_stop_timer(void) {
|
||||
riscv_csr_clear(mie, RISCV_MIE_MTIE);
|
||||
}
|
||||
|
||||
enum handler_return riscv_timer_exception(void) {
|
||||
LTRACEF("tick\n");
|
||||
|
||||
riscv_csr_clear(mie, RISCV_MIE_MTIE);
|
||||
|
||||
enum handler_return ret = INT_NO_RESCHEDULE;
|
||||
if (timer_cb) {
|
||||
ret = timer_cb(timer_arg, current_time());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
|
||||
// keep in sync with asm.S
|
||||
struct riscv_short_iframe {
|
||||
ulong mepc;
|
||||
ulong mstatus;
|
||||
ulong epc;
|
||||
ulong status;
|
||||
ulong ra;
|
||||
ulong a0;
|
||||
ulong a1;
|
||||
@@ -39,37 +39,28 @@ extern enum handler_return riscv_platform_irq(void);
|
||||
extern enum handler_return riscv_software_exception(void);
|
||||
|
||||
void riscv_exception_handler(ulong cause, ulong epc, struct riscv_short_iframe *frame) {
|
||||
LTRACEF("cause %#lx epc %#lx mstatus %#lx\n", cause, epc, frame->mstatus);
|
||||
|
||||
DEBUG_ASSERT(arch_ints_disabled());
|
||||
// DEBUG_ASSERT(frame->mstatus & RISCV_STATUS_MPIE);
|
||||
LTRACEF("cause %#lx epc %#lx status %#lx\n", cause, epc, frame->status);
|
||||
|
||||
// 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 int_bit | 0x3: // machine software interrupt
|
||||
case int_bit | RISCV_EXCEPTION_XSWI: // machine software interrupt
|
||||
ret = riscv_software_exception();
|
||||
break;
|
||||
case int_bit | 0x7: // machine timer interrupt
|
||||
case int_bit | RISCV_EXCEPTION_XTIM: // machine timer interrupt
|
||||
ret = riscv_timer_exception();
|
||||
break;
|
||||
case int_bit | 0xb: // machine external interrupt
|
||||
case int_bit | RISCV_EXCEPTION_XEXT: // machine external interrupt
|
||||
ret = riscv_platform_irq();
|
||||
break;
|
||||
default:
|
||||
TRACEF("unhandled cause %#lx, epc %#lx, mtval %#lx\n", cause, epc, riscv_csr_read(mtval));
|
||||
TRACEF("unhandled cause %#lx, epc %#lx, tval %#lx\n", cause, epc, riscv_csr_read(RISCV_CSR_XTVAL));
|
||||
panic("stopping");
|
||||
}
|
||||
|
||||
DEBUG_ASSERT(arch_ints_disabled());
|
||||
DEBUG_ASSERT(frame->mstatus & RISCV_STATUS_MPIE);
|
||||
|
||||
if (ret == INT_RESCHEDULE) {
|
||||
thread_preempt();
|
||||
}
|
||||
|
||||
DEBUG_ASSERT(arch_ints_disabled());
|
||||
DEBUG_ASSERT(frame->mstatus & RISCV_STATUS_MPIE);
|
||||
}
|
||||
|
||||
@@ -9,19 +9,20 @@
|
||||
|
||||
#include <lk/compiler.h>
|
||||
#include <lk/debug.h>
|
||||
#include <arch/csr.h>
|
||||
#include <arch/riscv.h>
|
||||
#include <arch/clint.h>
|
||||
|
||||
static inline void arch_enable_ints(void) {
|
||||
riscv_csr_set(mstatus, RISCV_STATUS_MIE);
|
||||
riscv_csr_set(RISCV_CSR_XSTATUS, RISCV_CSR_XSTATUS_IE);
|
||||
}
|
||||
|
||||
static inline void arch_disable_ints(void) {
|
||||
riscv_csr_clear(mstatus, RISCV_STATUS_MIE);
|
||||
riscv_csr_clear(RISCV_CSR_XSTATUS, RISCV_CSR_XSTATUS_IE);
|
||||
}
|
||||
|
||||
static inline bool arch_ints_disabled(void) {
|
||||
ulong val = riscv_csr_read(mstatus);
|
||||
return !(val & RISCV_STATUS_MIE);
|
||||
return !(riscv_csr_read(RISCV_CSR_XSTATUS) & RISCV_CSR_XSTATUS_IE);
|
||||
}
|
||||
|
||||
static inline int atomic_add(volatile int *ptr, int val) {
|
||||
@@ -51,14 +52,21 @@ static inline void set_current_thread(struct thread *t) {
|
||||
}
|
||||
|
||||
static inline uint32_t arch_cycle_count(void) {
|
||||
uint32_t count;
|
||||
|
||||
//__asm__("rdcycle %0" : "=r"(count));
|
||||
count = riscv_csr_read(mcycle);
|
||||
return count;
|
||||
return riscv_csr_read(RISCV_CSR_CYCLE);
|
||||
}
|
||||
|
||||
static inline uint arch_curr_cpu_num(void) {
|
||||
return riscv_csr_read(mhartid);
|
||||
const uint hart = riscv_current_hart();
|
||||
for (size_t i = 0; i < SMP_MAX_CPUS; i++) {
|
||||
if (hart_cpu_map[i] == (int)hart)
|
||||
return i;
|
||||
else if (unlikely(hart_cpu_map[i] == -1)) {
|
||||
if(i != 0 || hart == BOOT_HART) {
|
||||
hart_cpu_map[i] = hart;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
66
arch/riscv/include/arch/clint.h
Normal file
66
arch/riscv/include/arch/clint.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Elliot Berman
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <lk/reg.h>
|
||||
#include <arch/arch_ops.h>
|
||||
|
||||
#if RISCV_M_MODE
|
||||
|
||||
// platform must define these
|
||||
#ifndef ARCH_RISCV_CLINT_BASE
|
||||
#error Platform must define ARCH_RISCV_CLINT_BASE
|
||||
#endif
|
||||
#ifndef ARCH_RISCV_MTIME_RATE
|
||||
#error Platform must define ARCH_RISCV_MTIME_RATE
|
||||
#endif
|
||||
|
||||
#define CLINT_MSIP(h) (ARCH_RISCV_CLINT_BASE + (4 * (h)))
|
||||
#define CLINT_MTIMECMP(h) (ARCH_RISCV_CLINT_BASE + 0x4000 + (8 * (h)))
|
||||
#define CLINT_MTIME (ARCH_RISCV_CLINT_BASE + 0xbff8)
|
||||
|
||||
static inline void clint_ipi_send(unsigned long target_hart) {
|
||||
if (target_hart >= SMP_MAX_CPUS)
|
||||
return;
|
||||
|
||||
*REG32(CLINT_MSIP(target_hart)) = 1;
|
||||
}
|
||||
|
||||
static inline void clint_ipi_clear(unsigned long target_hart) {
|
||||
if (target_hart >= SMP_MAX_CPUS)
|
||||
return;
|
||||
|
||||
*REG32(CLINT_MSIP(target_hart)) = 0;
|
||||
}
|
||||
|
||||
static inline void clint_set_timer(uint64_t ticks) {
|
||||
*REG64(CLINT_MTIMECMP(riscv_current_hart())) = ticks;
|
||||
}
|
||||
|
||||
|
||||
static inline uint64_t riscv_get_time(void) {
|
||||
return *REG64(CLINT_MTIME);
|
||||
}
|
||||
|
||||
static inline void clint_send_ipis(const unsigned long *hart_mask) {
|
||||
unsigned long cur_hart = riscv_current_hart(), h, m = *hart_mask;
|
||||
for (h = 0; h < SMP_MAX_CPUS && m; h++, m >>= 1) {
|
||||
if ((m & 1) && (h != cur_hart)) {
|
||||
clint_ipi_send(h);
|
||||
}
|
||||
}
|
||||
|
||||
if(*hart_mask & (1 << riscv_current_hart())) {
|
||||
clint_ipi_send(cur_hart);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
52
arch/riscv/include/arch/csr.h
Normal file
52
arch/riscv/include/arch/csr.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Elliot Berman
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <arch/riscv.h>
|
||||
|
||||
#if RISCV_M_MODE
|
||||
static inline uint riscv_current_hart(void) {
|
||||
return riscv_csr_read(RISCV_CSR_MHARTID);
|
||||
}
|
||||
|
||||
static inline long riscv_get_mvendorid(void) {
|
||||
return riscv_csr_read(RISCV_CSR_MVENDORID);
|
||||
}
|
||||
|
||||
static inline long riscv_get_marchid(void) {
|
||||
return riscv_csr_read(RISCV_CSR_MARCHID);
|
||||
}
|
||||
|
||||
static inline long riscv_get_mimpid(void) {
|
||||
return riscv_csr_read(RISCV_CSR_MIMPID);
|
||||
}
|
||||
|
||||
#elif RISCV_S_MODE
|
||||
#include <arch/sbi.h>
|
||||
|
||||
static inline uint riscv_current_hart(void) {
|
||||
return riscv_csr_read(RISCV_CSR_XSCRATCH);
|
||||
}
|
||||
|
||||
static inline long riscv_get_mvendorid(void) {
|
||||
struct sbiret ret = sbi_call(SBI_GET_MVENDORID);
|
||||
return ret.value;
|
||||
}
|
||||
|
||||
static inline long riscv_get_marchid(void) {
|
||||
struct sbiret ret = sbi_call(SBI_GET_MARCHID);
|
||||
return ret.value;
|
||||
}
|
||||
|
||||
static inline long riscv_get_mimpid(void) {
|
||||
struct sbiret ret = sbi_call(SBI_GET_MIMPID);
|
||||
return ret.value;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -7,27 +7,74 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#define RISCV_STATUS_SIE (1u << 2)
|
||||
#define RISCV_STATUS_MIE (1u << 3)
|
||||
#define RISCV_STATUS_MPIE (1u << 7)
|
||||
#define RISCV_STATUS_MPP_MASK (3u << 11)
|
||||
#include <config.h>
|
||||
|
||||
#define RISCV_MIE_MSIE (1u << 3)
|
||||
#define RISCV_MIE_MTIE (1u << 7)
|
||||
#define RISCV_MIE_SEIE (1u << 9)
|
||||
#define RISCV_MIE_MEIE (1u << 11)
|
||||
#define RISCV_USER_OFFSET (0u)
|
||||
#define RISCV_SUPER_OFFSET (1u)
|
||||
#define RISCV_HYPER_OFFSET (2u)
|
||||
#define RISCV_MACH_OFFSET (3u)
|
||||
|
||||
#define RISCV_MIP_MSIP (1u << 3)
|
||||
#define RISCV_MIP_MTIP (1u << 7)
|
||||
#define RISCV_MIP_MEIP (1u << 11)
|
||||
#if RISCV_M_MODE
|
||||
# define RISCV_XMODE_OFFSET (RISCV_MACH_OFFSET)
|
||||
# define RISCV_XRET mret
|
||||
#elif RISCV_S_MODE
|
||||
# define RISCV_XMODE_OFFSET (RISCV_SUPER_OFFSET)
|
||||
# define RISCV_XRET sret
|
||||
#else
|
||||
# error Unrecognized RISC-V privilege level selected
|
||||
#endif
|
||||
|
||||
#define RISCV_MCAUSE_INT (1u << 31)
|
||||
#define RISCV_CSR_XMODE_BITS (RISCV_XMODE_OFFSET << 8)
|
||||
|
||||
// These CSRs are only in user CSR space (still readable by all modes though)
|
||||
#define RISCV_CSR_CYCLE (0xc00)
|
||||
#define RISCV_CSR_TIME (0xc01)
|
||||
#define RISCV_CSR_INSRET (0xc02)
|
||||
#define RISCV_CSR_CYCLEH (0xc80)
|
||||
#define RISCV_CSR_TIMEH (0xc81)
|
||||
#define RISCV_CSR_INSRETH (0xc82)
|
||||
|
||||
#define RISCV_CSR_XSTATUS (0x000 | RISCV_CSR_XMODE_BITS)
|
||||
#define RISCV_CSR_XIE (0x004 | RISCV_CSR_XMODE_BITS)
|
||||
#define RISCV_CSR_XTVEC (0x005 | RISCV_CSR_XMODE_BITS)
|
||||
#define RISCV_CSR_XSCRATCH (0x040 | RISCV_CSR_XMODE_BITS)
|
||||
#define RISCV_CSR_XEPC (0x041 | RISCV_CSR_XMODE_BITS)
|
||||
#define RISCV_CSR_XCAUSE (0x042 | RISCV_CSR_XMODE_BITS)
|
||||
#define RISCV_CSR_XTVAL (0x043 | RISCV_CSR_XMODE_BITS)
|
||||
#define RISCV_CSR_XIP (0x044 | RISCV_CSR_XMODE_BITS)
|
||||
|
||||
#if RISCV_M_MODE // Machine-mode only CSRs
|
||||
#define RISCV_CSR_MVENDORID (0xf11)
|
||||
#define RISCV_CSR_MARCHID (0xf12)
|
||||
#define RISCV_CSR_MIMPID (0xf13)
|
||||
#define RISCV_CSR_MHARTID (0xf14)
|
||||
#define RISCV_CSR_MISA (0x301)
|
||||
#endif /* RISCV_M_MODE */
|
||||
|
||||
#define RISCV_CSR_XSTATUS_IE (1u << (RISCV_XMODE_OFFSET + 0))
|
||||
#define RISCV_CSR_XSTATUS_PIE (1u << (RISCV_XMODE_OFFSET + 4))
|
||||
|
||||
#define RISCV_CSR_XIE_SIE (1u << (RISCV_XMODE_OFFSET + 0))
|
||||
#define RISCV_CSR_XIE_TIE (1u << (RISCV_XMODE_OFFSET + 4))
|
||||
#define RISCV_CSR_XIE_EIE (1u << (RISCV_XMODE_OFFSET + 8))
|
||||
|
||||
#define RISCV_CSR_XIP_SIP (1u << (RISCV_XMODE_OFFSET + 0))
|
||||
#define RISCV_CSR_XIP_TIP (1u << (RISCV_XMODE_OFFSET + 4))
|
||||
#define RISCV_CSR_XIP_EIP (1u << (RISCV_XMODE_OFFSET + 8))
|
||||
|
||||
#define RISCV_EXCEPTION_XSWI (RISCV_XMODE_OFFSET)
|
||||
|
||||
#define RISCV_EXCEPTION_XTIM (4 + RISCV_XMODE_OFFSET)
|
||||
#define RISCV_EXCEPTION_XEXT (8 + RISCV_XMODE_OFFSET)
|
||||
|
||||
#ifndef ASSEMBLY
|
||||
#define __ASM_STR(x) #x
|
||||
|
||||
#define riscv_csr_clear(csr, bits) \
|
||||
({ \
|
||||
ulong __val = bits; \
|
||||
__asm__ volatile( \
|
||||
"csrc " #csr ", %0" \
|
||||
"csrc " __ASM_STR(csr) ", %0" \
|
||||
:: "rK" (__val) \
|
||||
: "memory"); \
|
||||
})
|
||||
@@ -37,7 +84,7 @@
|
||||
ulong __val = bits; \
|
||||
ulong __val_out; \
|
||||
__asm__ volatile( \
|
||||
"csrrc %0, " #csr ", %1" \
|
||||
"csrrc %0, " __ASM_STR(csr) ", %1" \
|
||||
: "=r"(__val_out) \
|
||||
: "rK" (__val) \
|
||||
: "memory"); \
|
||||
@@ -48,7 +95,7 @@
|
||||
({ \
|
||||
ulong __val = bits; \
|
||||
__asm__ volatile( \
|
||||
"csrs " #csr ", %0" \
|
||||
"csrs " __ASM_STR(csr) ", %0" \
|
||||
:: "rK" (__val) \
|
||||
: "memory"); \
|
||||
})
|
||||
@@ -57,7 +104,7 @@
|
||||
({ \
|
||||
ulong __val; \
|
||||
__asm__ volatile( \
|
||||
"csrr %0, " #csr \
|
||||
"csrr %0, " __ASM_STR(csr) \
|
||||
: "=r" (__val) \
|
||||
:: "memory"); \
|
||||
__val; \
|
||||
@@ -67,13 +114,13 @@
|
||||
({ \
|
||||
ulong __val = (ulong)val; \
|
||||
__asm__ volatile( \
|
||||
"csrw " #csr ", %0" \
|
||||
"csrw " __ASM_STR(csr) ", %0" \
|
||||
:: "rK" (__val) \
|
||||
: "memory"); \
|
||||
__val; \
|
||||
})
|
||||
|
||||
#define riscv_current_hart() riscv_csr_read(mhartid)
|
||||
|
||||
extern int hart_cpu_map[SMP_MAX_CPUS];
|
||||
void riscv_exception_entry(void);
|
||||
enum handler_return riscv_timer_exception(void);
|
||||
#endif /* ASSEMBLY */
|
||||
|
||||
96
arch/riscv/include/arch/sbi.h
Normal file
96
arch/riscv/include/arch/sbi.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Elliot Berman
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if !defined(RISCV_M_MODE) || !(RISCV_M_MODE)
|
||||
|
||||
struct sbiret {
|
||||
long error;
|
||||
long value;
|
||||
};
|
||||
|
||||
enum sbi_return_code {
|
||||
SBI_SUCCESS = 0,
|
||||
SBI_ERR_FAILURE = -1,
|
||||
SBI_ERR_NOT_SUPPORTED = -2,
|
||||
SBI_ERR_INVALID_PARAM = -3,
|
||||
SBI_ERR_DENIED = -4,
|
||||
SBI_ERR_INVALID_ADDRESS = -5,
|
||||
};
|
||||
|
||||
#define _sbi_call(extension, function, arg0, arg1, arg2, arg3, arg4, arg5, ...) ({ \
|
||||
register unsigned long a0 asm("a0") = (unsigned long)arg0; \
|
||||
register unsigned long a1 asm("a1") = (unsigned long)arg1; \
|
||||
register unsigned long a2 asm("a2") = (unsigned long)arg2; \
|
||||
register unsigned long a3 asm("a3") = (unsigned long)arg3; \
|
||||
register unsigned long a4 asm("a4") = (unsigned long)arg4; \
|
||||
register unsigned long a5 asm("a5") = (unsigned long)arg5; \
|
||||
register unsigned long a6 asm("a6") = (unsigned long)function; \
|
||||
register unsigned long a7 asm("a7") = (unsigned long)extension; \
|
||||
asm volatile ("ecall" \
|
||||
: "+r" (a0), "+r" (a1) \
|
||||
: "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r"(a6), "r"(a7) \
|
||||
: "memory"); \
|
||||
struct sbiret ret = { .error = a0, .value = a1 }; \
|
||||
ret; \
|
||||
})
|
||||
#define sbi_call(...) \
|
||||
_sbi_call(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0)
|
||||
|
||||
|
||||
#define SBI_SET_TIMER 0x00, 0
|
||||
#define SBI_CONSOLE_PUTCHAR 0x01, 0
|
||||
#define SBI_CONSOLE_GETCHAR 0x02, 0
|
||||
#define SBI_CLEAR_IPI 0x03, 0
|
||||
#define SBI_SEND_IPI 0x04, 0
|
||||
#define SBI_REMOTE_FENCEI 0x05, 0
|
||||
#define SBI_REMOTE_SFENCE_VMA 0x06, 0
|
||||
#define SBI_REMOTE_SFENCE_VMA_ASID 0x07, 0
|
||||
#define SBI_SHUTDOWN 0x08, 0
|
||||
|
||||
#define SBI_GET_SBI_SPEC_VERSION 0x10, 0
|
||||
#define SBI_GET_SBI_IMPL_ID 0x10, 1
|
||||
#define SBI_GET_SBI_IMPL_VERSION 0x10, 2
|
||||
#define SBI_PROBE_EXTENSION 0x10, 3
|
||||
#define SBI_GET_MVENDORID 0x10, 4
|
||||
#define SBI_GET_MARCHID 0x10, 5
|
||||
#define SBI_GET_MIMPID 0x10, 6
|
||||
|
||||
static inline void sbi_set_timer(uint64_t stime_value) {
|
||||
sbi_call(SBI_SET_TIMER, stime_value);
|
||||
}
|
||||
|
||||
static inline void sbi_send_ipis(const unsigned long *hart_mask) {
|
||||
sbi_call(SBI_SEND_IPI, hart_mask);
|
||||
}
|
||||
|
||||
static inline void sbi_clear_ipi(void) {
|
||||
sbi_call(SBI_CLEAR_IPI);
|
||||
}
|
||||
|
||||
# if SUBARCH == 32
|
||||
static inline uint64_t riscv_get_time(void) {
|
||||
uint32_t hi, lo;
|
||||
|
||||
do {
|
||||
hi = riscv_csr_read(RISCV_CSR_TIMEH);
|
||||
lo = riscv_csr_read(RISCV_CSR_TIME);
|
||||
} while (hi != riscv_csr_read(RISCV_CSR_TIMEH));
|
||||
|
||||
return (((uint64_t)hi << 32) | lo);
|
||||
}
|
||||
# else
|
||||
static inline uint64_t riscv_get_time(void) {
|
||||
return riscv_csr_read(RISCV_CSR_TIME);
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
@@ -56,12 +56,12 @@ static inline bool arch_spin_lock_held(spin_lock_t *lock) {
|
||||
static inline void
|
||||
arch_interrupt_save(spin_lock_saved_state_t *statep, spin_lock_save_flags_t flags) {
|
||||
/* disable interrupts by clearing the MIE bit while atomically saving the old state */
|
||||
*statep = riscv_csr_read_clear(mstatus, RISCV_STATUS_MIE) & RISCV_STATUS_MIE;
|
||||
*statep = riscv_csr_read_clear(RISCV_CSR_XSTATUS, RISCV_CSR_XSTATUS_IE) & RISCV_CSR_XSTATUS_IE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
arch_interrupt_restore(spin_lock_saved_state_t old_state, spin_lock_save_flags_t flags) {
|
||||
/* drop the old MIE flag into the status register */
|
||||
riscv_csr_set(mstatus, old_state);
|
||||
riscv_csr_set(RISCV_CSR_XSTATUS, old_state);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
#include <lk/trace.h>
|
||||
#include <lk/err.h>
|
||||
|
||||
#include <arch/ops.h>
|
||||
#include <arch/mp.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
int hart_cpu_map[SMP_MAX_CPUS] = { [0 ... SMP_MAX_CPUS-1] = -1 };
|
||||
static mp_ipi_t ipi_data[SMP_MAX_CPUS];
|
||||
|
||||
extern void clint_ipi_send(unsigned long target_hart);
|
||||
@@ -23,26 +25,32 @@ extern void clint_ipi_clear(unsigned long target_hart);
|
||||
status_t arch_mp_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi) {
|
||||
LTRACEF("target 0x%x, ipi %u\n", target, ipi);
|
||||
|
||||
unsigned long cur_hart = riscv_csr_read(mhartid);
|
||||
unsigned long h = 0;
|
||||
unsigned long hart_mask = 0;
|
||||
unsigned long c = 0, h;
|
||||
mp_cpu_mask_t m = target;
|
||||
for (; h < SMP_MAX_CPUS && m; h++, m >>= 1) {
|
||||
if ((m & 1) && (h != cur_hart)) {
|
||||
ipi_data[h] = ipi;
|
||||
asm volatile(" fence iorw,iorw");
|
||||
clint_ipi_send(h);
|
||||
for (; c < SMP_MAX_CPUS && m; c++, m >>= 1) {
|
||||
h = hart_cpu_map[c];
|
||||
if (m & 1) {
|
||||
hart_mask |= (1 << h);
|
||||
}
|
||||
}
|
||||
|
||||
if(target & (1 << cur_hart)) {
|
||||
clint_ipi_send(cur_hart);
|
||||
}
|
||||
asm volatile(" fence iorw,iorw");
|
||||
#if RISCV_M_MODE
|
||||
clint_send_ipis(&hart_mask);
|
||||
#else
|
||||
sbi_send_ipis(&hart_mask);
|
||||
#endif
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
enum handler_return riscv_software_exception(void) {
|
||||
clint_ipi_clear(riscv_csr_read(mhartid));
|
||||
#if RISCV_M_MODE
|
||||
clint_ipi_clear(riscv_current_hart());
|
||||
#else
|
||||
sbi_clear_ipi();
|
||||
#endif
|
||||
asm volatile(" fence ir,ir");
|
||||
mp_ipi_t reason = ipi_data[riscv_current_hart()];
|
||||
ipi_data[riscv_current_hart()] = 0;
|
||||
@@ -52,7 +60,7 @@ enum handler_return riscv_software_exception(void) {
|
||||
case MP_IPI_GENERIC:
|
||||
break;
|
||||
default:
|
||||
TRACEF("unhandled ipi cause %#x, hartid %#lx\n", reason, riscv_current_hart());
|
||||
TRACEF("unhandled ipi cause %#x, hartid %#x\n", reason, riscv_current_hart());
|
||||
panic("stopping");
|
||||
break;
|
||||
}
|
||||
@@ -62,5 +70,6 @@ enum handler_return riscv_software_exception(void) {
|
||||
}
|
||||
|
||||
void arch_mp_init_percpu(void) {
|
||||
riscv_csr_set(mie, RISCV_MIE_MSIE);
|
||||
dprintf(INFO, "\nRISCV: Booting hart%d (cpu%d)\n", riscv_current_hart(), arch_curr_cpu_num());
|
||||
riscv_csr_set(RISCV_CSR_XIE, RISCV_CSR_XIE_SIE);
|
||||
}
|
||||
|
||||
@@ -5,15 +5,17 @@ MODULE := $(LOCAL_DIR)
|
||||
MODULE_SRCS += $(LOCAL_DIR)/start.S
|
||||
MODULE_SRCS += $(LOCAL_DIR)/arch.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/asm.S
|
||||
MODULE_SRCS += $(LOCAL_DIR)/clint.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/exceptions.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/thread.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/mp.c
|
||||
MODULE_SRCS += $(LOCAL_DIR)/time.c
|
||||
|
||||
SMP_MAX_CPUS ?= 1
|
||||
BOOT_HART ?= 0
|
||||
|
||||
GLOBAL_DEFINES += SMP_MAX_CPUS=$(SMP_MAX_CPUS)
|
||||
GLOBAL_DEFINES += PLATFORM_HAS_DYNAMIC_TIMER=1
|
||||
GLOBAL_DEFINES += BOOT_HART=$(BOOT_HART)
|
||||
|
||||
ifeq ($(WITH_SMP),1)
|
||||
GLOBAL_DEFINES += WITH_SMP=1
|
||||
@@ -21,6 +23,20 @@ endif
|
||||
|
||||
SUBARCH ?= 32
|
||||
|
||||
RISCV_MODE ?= machine
|
||||
|
||||
ifeq ($(strip $(RISCV_MODE)),machine)
|
||||
$(info RISCV: Machine Mode)
|
||||
GLOBAL_DEFINES += RISCV_M_MODE=1
|
||||
else
|
||||
ifeq ($(strip $(RISCV_MODE)),supervisor)
|
||||
$(info RISCV: Supervisor Mode)
|
||||
GLOBAL_DEFINES += RISCV_S_MODE=1
|
||||
else
|
||||
$(error Unknown RISC-V mode: "$(strip $(RISCV_MODE))" (valid values are "machine", "supervisor"))
|
||||
endif
|
||||
endif
|
||||
|
||||
WITH_LINKER_GC ?= 0
|
||||
|
||||
KERNEL_BASE ?= $(MEMBASE)
|
||||
|
||||
@@ -17,8 +17,11 @@ FUNCTION(_start)
|
||||
la gp, __global_pointer$
|
||||
.option pop
|
||||
|
||||
// if our hart isnt 0, trap the cpu
|
||||
csrr t0, mhartid
|
||||
#if RISCV_M_MODE
|
||||
csrr a0, mhartid
|
||||
#else
|
||||
csrw sscratch, a0
|
||||
#endif
|
||||
|
||||
// set the default stack
|
||||
la sp, default_stack_top
|
||||
@@ -33,7 +36,9 @@ FUNCTION(_start)
|
||||
la t5, _boot_status
|
||||
sw zero, (t5)
|
||||
|
||||
bnez t0, .Lsecondary_trap
|
||||
// if our hart isnt BOOT_HART, trap the cpu
|
||||
li t2, BOOT_HART
|
||||
bne t2, a0, .Lsecondary_trap
|
||||
|
||||
#if ARCH_RISCV_TWOSEGMENT
|
||||
// copy preinitialized data from flash to memory
|
||||
|
||||
73
arch/riscv/time.c
Normal file
73
arch/riscv/time.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Travis Geiselbrecht
|
||||
*
|
||||
* Use of this source code is governed by a MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include <lk/reg.h>
|
||||
#include <lk/debug.h>
|
||||
#include <lk/trace.h>
|
||||
#include <lk/err.h>
|
||||
#include <lk/trace.h>
|
||||
|
||||
#include <arch/riscv.h>
|
||||
#include <arch/ops.h>
|
||||
|
||||
#include <platform.h>
|
||||
#include <platform/timer.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
static platform_timer_callback timer_cb;
|
||||
static void *timer_arg;
|
||||
|
||||
status_t platform_set_oneshot_timer (platform_timer_callback callback, void *arg, lk_time_t interval) {
|
||||
LTRACEF("cb %p, arg %p, interval %u\n", callback, arg, interval);
|
||||
|
||||
// disable timer
|
||||
riscv_csr_clear(RISCV_CSR_XIE, RISCV_CSR_XIE_TIE);
|
||||
|
||||
timer_cb = callback;
|
||||
timer_arg = arg;
|
||||
|
||||
// enable the timer
|
||||
riscv_csr_set(RISCV_CSR_XIE, RISCV_CSR_XIE_TIE);
|
||||
|
||||
// convert interval to ticks
|
||||
uint64_t ticks = riscv_get_time() + ((interval * ARCH_RISCV_MTIME_RATE) / 1000u);
|
||||
#if RISCV_M_MODE
|
||||
extern void clint_set_timer(uint64_t ticks);
|
||||
clint_set_timer(ticks);
|
||||
#elif RISCV_S_MODE
|
||||
sbi_set_timer(ticks);
|
||||
#endif
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
lk_bigtime_t current_time_hires(void) {
|
||||
return riscv_get_time() / (ARCH_RISCV_MTIME_RATE / 1000000u);
|
||||
}
|
||||
|
||||
lk_time_t current_time(void) {
|
||||
return riscv_get_time() / (ARCH_RISCV_MTIME_RATE / 1000u);
|
||||
}
|
||||
|
||||
void platform_stop_timer(void) {
|
||||
riscv_csr_clear(RISCV_CSR_XIE, RISCV_CSR_XIE_TIE);
|
||||
}
|
||||
|
||||
enum handler_return riscv_timer_exception(void) {
|
||||
LTRACEF("tick\n");
|
||||
|
||||
riscv_csr_clear(RISCV_CSR_XIE, RISCV_CSR_XIE_TIE);
|
||||
|
||||
enum handler_return ret = INT_NO_RESCHEDULE;
|
||||
if (timer_cb) {
|
||||
ret = timer_cb(timer_arg, current_time());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -18,4 +18,8 @@
|
||||
#define UART0_BASE 0x10010000
|
||||
#define UART1_BASE 0x10011000
|
||||
|
||||
#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
|
||||
@@ -7,7 +7,13 @@ VARIANT := sifive_u
|
||||
|
||||
GLOBAL_DEFINES += SIFIVE_FREQ=5000000 # 5 MHz
|
||||
|
||||
RISCV_MODE ?= machine
|
||||
|
||||
ifeq ($(RISCV_MODE),supervisor)
|
||||
MEMBASE ?= 0x080200000
|
||||
else
|
||||
MEMBASE ?= 0x080000000
|
||||
endif
|
||||
MEMSIZE ?= 0x200000000 # 8 GiB
|
||||
|
||||
WITH_SMP := 0
|
||||
|
||||
@@ -21,4 +21,8 @@
|
||||
#define PWM1_BASE 0x10021000
|
||||
#define GPIO_BASE 0x10060000
|
||||
|
||||
#if RISCV_XMODE_OFFSET == RISCV_MACH_OFFSET
|
||||
#define PLIC_HART_IDX(hart) ((hart) ? ((2 * (hart)) - 1) : 0)
|
||||
#elif RISCV_XMODE_OFFSET == RISCV_SUPER_OFFSET
|
||||
#define PLIC_HART_IDX(hart) ((hart) ? (2 * (hart)) : ~0U)
|
||||
#endif
|
||||
|
||||
@@ -5,11 +5,19 @@ PLATFORM := sifive
|
||||
VARIANT := sifive_u
|
||||
|
||||
WITH_SMP := 1
|
||||
SMP_MAX_CPUS := 5
|
||||
BOOT_HART := 1
|
||||
|
||||
GLOBAL_DEFINES += SIFIVE_FREQ=500000000 # 500 MHz
|
||||
|
||||
RISCV_MODE ?= machine
|
||||
|
||||
ifeq ($(RISCV_MODE),supervisor)
|
||||
MEMBASE ?= 0x080200000
|
||||
SMP_MAX_CPUS := 4
|
||||
else
|
||||
MEMBASE ?= 0x080000000
|
||||
SMP_MAX_CPUS := 5
|
||||
endif
|
||||
MEMSIZE ?= 0x200000000 # 8 GiB
|
||||
|
||||
MODULE_SRCS := $(LOCAL_DIR)/target.c
|
||||
|
||||
Reference in New Issue
Block a user