[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:
Elliot Berman
2019-12-04 09:35:56 -08:00
committed by Travis Geiselbrecht
parent e137d70ccd
commit e50d7db612
18 changed files with 477 additions and 180 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;
}

View 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

View 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

View File

@@ -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 */

View 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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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
View 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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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