diff --git a/repos/base-hw/include/spec/riscv/cpu/cpu_state.h b/repos/base-hw/include/spec/riscv/cpu/cpu_state.h
index e6b43b109..b7f32c96d 100644
--- a/repos/base-hw/include/spec/riscv/cpu/cpu_state.h
+++ b/repos/base-hw/include/spec/riscv/cpu/cpu_state.h
@@ -1,4 +1,4 @@
-/**
+/*
* \brief CPU state
* \author Sebastian Sumpf
* \date 2015-06-01
@@ -25,11 +25,15 @@ struct Genode::Cpu_state
INSTRUCTION_UNALIGNED = 0,
INSTRUCTION_PAGE_FAULT = 1,
INSTRUCTION_ILLEGAL = 2,
+ BREAKPOINT = 3,
LOAD_UNALIGNED = 4,
LOAD_PAGE_FAULT = 5,
STORE_UNALIGNED = 6,
STORE_PAGE_FAULT = 7,
- SUPERVISOR_CALL = 8,
+ ECALL_FROM_USER = 8,
+ ECALL_FROM_SUPERVISOR = 9,
+ ECALL_FROM_HYPERVISOR = 10,
+ ECALL_FROM_MACHINE = 11,
RESET = 16,
IRQ_FLAG = 1UL << 63,
};
diff --git a/repos/base-hw/include/spec/riscv/cpu/memory_barrier.h b/repos/base-hw/include/spec/riscv/cpu/memory_barrier.h
index 66e6869e0..b6c4b2ab3 100644
--- a/repos/base-hw/include/spec/riscv/cpu/memory_barrier.h
+++ b/repos/base-hw/include/spec/riscv/cpu/memory_barrier.h
@@ -1,4 +1,4 @@
-/**
+/*
* \brief Memory barrier
* \author Sebastian Sumpf
* \date 2015-06-01
@@ -16,10 +16,8 @@
namespace Genode {
- static inline void memory_barrier()
- {
- asm volatile ("fence" ::: "memory");
- }
+ static inline void memory_barrier() {
+ asm volatile ("fence" ::: "memory"); }
}
#endif /* _INCLUDE__RISCV__CPU__MEMORY_BARRIER_H_ */
diff --git a/repos/base-hw/include/spec/riscv/kernel/interface_support.h b/repos/base-hw/include/spec/riscv/kernel/interface_support.h
index c97d80dc8..7a98374f2 100644
--- a/repos/base-hw/include/spec/riscv/kernel/interface_support.h
+++ b/repos/base-hw/include/spec/riscv/kernel/interface_support.h
@@ -25,11 +25,7 @@ namespace Kernel
/**
* Events that are provided by a kernel thread-object for user handling
*/
- struct Thread_event_id
- {
- enum { FAULT = 0 };
- };
+ struct Thread_event_id { enum { FAULT = 0 }; };
}
#endif /* _KERNEL__INTERFACE_SUPPORT_H_ */
-
diff --git a/repos/base-hw/lib/mk/spec/riscv/core.mk b/repos/base-hw/lib/mk/spec/riscv/core.mk
index 4d8066209..1437d133c 100644
--- a/repos/base-hw/lib/mk/spec/riscv/core.mk
+++ b/repos/base-hw/lib/mk/spec/riscv/core.mk
@@ -11,6 +11,7 @@ SRC_CC += spec/riscv/kernel/pd.cc
SRC_CC += spec/riscv/kernel/cpu.cc
SRC_CC += spec/riscv/kernel/exception_vector.cc
SRC_CC += spec/riscv/platform_support.cc
+SRC_CC += spec/riscv/cpu.cc
#add assembly sources
SRC_S += spec/riscv/mode_transition.s
diff --git a/repos/base-hw/mk/spec/hw_riscv.mk b/repos/base-hw/mk/spec/hw_riscv.mk
index ca8b80645..81180a2da 100644
--- a/repos/base-hw/mk/spec/hw_riscv.mk
+++ b/repos/base-hw/mk/spec/hw_riscv.mk
@@ -2,8 +2,8 @@ SPECS += hw riscv platform_riscv 64bit
LD_TEXT_ADDR ?= 0x1000
CORE_LD_TEXT_ADDR = 0x200
-NR_OF_CPUS = 1
-REP_INC_DIR += include/spec/riscv
+NR_OF_CPUS = 1
+REP_INC_DIR += include/spec/riscv
include $(call select_from_repositories,mk/spec/64bit.mk)
include $(call select_from_repositories,mk/spec/hw.mk)
diff --git a/repos/base-hw/src/core/include/spec/riscv/board.h b/repos/base-hw/src/core/include/spec/riscv/board.h
index 049b7f768..8f06bf29b 100644
--- a/repos/base-hw/src/core/include/spec/riscv/board.h
+++ b/repos/base-hw/src/core/include/spec/riscv/board.h
@@ -14,12 +14,6 @@
#ifndef _BOARD_H_
#define _BOARD_H_
-namespace Genode
-{
- struct Board
- {
- void init() { }
- };
-}
+namespace Genode { struct Board { void init() { } }; }
#endif /* _BOARD_H_ */
diff --git a/repos/base-hw/src/core/include/spec/riscv/cpu.h b/repos/base-hw/src/core/include/spec/riscv/cpu.h
index 12e1c6d02..edfdd75fe 100644
--- a/repos/base-hw/src/core/include/spec/riscv/cpu.h
+++ b/repos/base-hw/src/core/include/spec/riscv/cpu.h
@@ -107,16 +107,34 @@ class Genode::Cpu
static void wait_for_interrupt() { asm volatile ("wfi"); };
+ /**
+ * From the manual
+ *
+ * The behavior of SFENCE.VM depends on the current value of the sasid
+ * register. If sasid is nonzero, SFENCE.VM takes effect only for address
+ * translations in the current address space. If sasid is zero, SFENCE.VM
+ * affects address translations for all address spaces. In this case, it
+ * also affects global mappings, which are described in Section 4.5.1.
+ *
+ * Right no we will flush anything
+ */
+ static void sfence()
+ {
+ asm volatile ("csrrw t0, sasid, x0\n"
+ "sfence.vm\n"
+ "csrw sasid, t0\n"
+ : : : "t0");
+ }
+
/**
* Post processing after a translation was added to a translation table
*
* \param addr virtual address of the translation
* \param size size of the translation
*/
- static void translation_added(addr_t const addr, size_t const size)
- {
- PDBG("not impl");
- }
+ static void translation_added(addr_t const addr, size_t const size);
+
+ static void invalidate_tlb_by_pid(unsigned const pid) { sfence(); }
/**
* Return kernel name of the executing CPU
@@ -128,11 +146,6 @@ class Genode::Cpu
*/
static unsigned primary_id() { return 0; }
- static void flush_tlb_by_pid(unsigned const pid)
- {
- PDBG("not impl");
- }
-
static addr_t sbadaddr()
{
addr_t addr;
@@ -140,20 +153,11 @@ class Genode::Cpu
return addr;
}
- static void data_synchronization_barrier() {
- asm volatile ("fence\n" : : : "memory"); }
-
/*************
** Dummies **
*************/
void switch_to(User_context&) { }
- static void prepare_proceeding(Cpu_lazy_state *, Cpu_lazy_state *) { }
- static void invalidate_instr_caches() { }
- static void invalidate_data_caches() { }
- static void flush_data_caches() { }
- static void flush_data_caches_by_virt_region(addr_t, size_t) { }
- static void invalidate_instr_caches_by_virt_region(addr_t, size_t) { }
};
#endif /* _CPU_H_ */
diff --git a/repos/base-hw/src/core/include/spec/riscv/machine_call.h b/repos/base-hw/src/core/include/spec/riscv/machine_call.h
index 82228b008..82c46a258 100644
--- a/repos/base-hw/src/core/include/spec/riscv/machine_call.h
+++ b/repos/base-hw/src/core/include/spec/riscv/machine_call.h
@@ -1,6 +1,7 @@
/**
* \brief Calls supported by machine mode (or SBI interface in RISC-V)
* \author Sebastian Sumpf
+ * \author Martin Stein
* \date 2015-06-14
*/
@@ -14,23 +15,29 @@
#ifndef _MACHINE_CALL_H_
#define _MACHINE_CALL_H_
-#include
+/* base-hw includes */
+#include
namespace Machine {
- enum Call {
- PUT_CHAR = 0x100, /* output character */
- SET_SYS_TIMER = 0x101, /* set timer */
- IS_USER_MODE = 0x102, /* check if we are in user mode */
- };
+ using namespace Kernel;
- inline void call(Call const number, Genode::addr_t const arg0)
- {
- register Genode::addr_t a0 asm("a0") = number;;
- register Genode::addr_t a1 asm("a1") = arg0;
+ /**
+ * SBI calls to machine mode.
+ *
+ * Keep in sync with mode_transition.s.
+ */
+ constexpr Call_arg call_id_put_char() { return 0x100; }
+ constexpr Call_arg call_id_set_sys_timer() { return 0x101; }
+ constexpr Call_arg call_id_is_user_mode() { return 0x102; }
- asm volatile ("ecall\n" : : "r"(a0), "r"(a1));
- }
+ inline void put_char(Genode::uint64_t const c) {
+ call(call_id_put_char(), (Call_arg)c); }
+
+ inline void set_sys_timer(addr_t const t) {
+ call(call_id_set_sys_timer(), (Call_arg)t); }
+
+ inline bool is_user_mode() { return call(call_id_is_user_mode()); }
}
#endif /* _MACHINE_CALL_H_ */
diff --git a/repos/base-hw/src/core/include/spec/riscv/macros.s b/repos/base-hw/src/core/include/spec/riscv/macros.s
index 131b010fc..c62399fb2 100644
--- a/repos/base-hw/src/core/include/spec/riscv/macros.s
+++ b/repos/base-hw/src/core/include/spec/riscv/macros.s
@@ -11,11 +11,6 @@
* under the terms of the GNU General Public License version 2.
*/
-
-/***************************************************
- ** Constant values that are pretty commonly used **
- ***************************************************/
-
/* alignment constraints */
-.set DATA_ACCESS_ALIGNM_LOG2, 2
+.set DATA_ACCESS_ALIGNM_LOG2, 3
.set MIN_PAGE_SIZE_LOG2, 12
diff --git a/repos/base-hw/src/core/include/spec/riscv/pic.h b/repos/base-hw/src/core/include/spec/riscv/pic.h
index 5d75d6f85..a82c124d4 100644
--- a/repos/base-hw/src/core/include/spec/riscv/pic.h
+++ b/repos/base-hw/src/core/include/spec/riscv/pic.h
@@ -16,16 +16,11 @@
#ifndef _PIC_H_
#define _PIC_H_
-#include
-
-namespace Genode
-{
- /**
- * Programmable interrupt controller for core
- */
- class Pic;
-}
+namespace Genode { class Pic; }
+/**
+ * Dummy PIC driver for core
+ */
class Genode::Pic
{
public:
@@ -39,32 +34,10 @@ class Genode::Pic
NR_OF_IRQ = 15,
};
- /**
- * Constructor
- */
Pic() { }
-
- /**
- * Receive a pending request number 'i'
- */
- bool take_request(unsigned & i) {
- return true;
- }
-
- /**
- * Unmask interrupt 'i'
- */
+ bool take_request(unsigned & i) { return true; }
void unmask(unsigned const i, unsigned) { }
-
- /**
- * Mask interrupt 'i'
- */
void mask(unsigned const i) { }
-
- /*************
- ** Dummies **
- *************/
-
void finish_request() { }
};
diff --git a/repos/base-hw/src/core/include/spec/riscv/serial.h b/repos/base-hw/src/core/include/spec/riscv/serial.h
index f192dde0b..abddff0d7 100644
--- a/repos/base-hw/src/core/include/spec/riscv/serial.h
+++ b/repos/base-hw/src/core/include/spec/riscv/serial.h
@@ -44,9 +44,9 @@ class Genode::Serial
struct Stdout : Bitfield<56, 1> { };
};
- Machine::call(Machine::PUT_CHAR, Arg::Char::bits(c) |
- Arg::Stdout::bits(1) |
- Arg::Write_cmd::bits(1));
+ Machine::put_char(Arg::Char::bits(c) |
+ Arg::Stdout::bits(1) |
+ Arg::Write_cmd::bits(1));
}
};
diff --git a/repos/base-hw/src/core/include/spec/riscv/timer.h b/repos/base-hw/src/core/include/spec/riscv/timer.h
index 926f11133..56cdc680e 100644
--- a/repos/base-hw/src/core/include/spec/riscv/timer.h
+++ b/repos/base-hw/src/core/include/spec/riscv/timer.h
@@ -14,19 +14,18 @@
#ifndef _TIMER_H_
#define _TIMER_H_
+/* Genode includes */
#include
#include
+/* Core includes */
#include
-namespace Genode
-{
- /**
- * Timer driver for core
- */
- class Timer;
-}
+namespace Genode { class Timer; }
+/**
+ * Timer driver for core
+ */
struct Genode::Timer
{
private:
@@ -62,7 +61,7 @@ struct Genode::Timer
void start_one_shot(unsigned const tics, unsigned /* cpu */)
{
_timeout = _stime() + tics;
- asm volatile ("csrw stimecmp, %0" : : "r"(_timeout));
+ Machine::set_sys_timer(_timeout);
}
/**
diff --git a/repos/base-hw/src/core/include/spec/riscv/translation_table.h b/repos/base-hw/src/core/include/spec/riscv/translation_table.h
index 130fe9dc4..4d95c7ce2 100644
--- a/repos/base-hw/src/core/include/spec/riscv/translation_table.h
+++ b/repos/base-hw/src/core/include/spec/riscv/translation_table.h
@@ -14,9 +14,12 @@
#ifndef _TRANSLATION_TABLE_H_
#define _TRANSLATION_TABLE_H_
+/* Genode includes */
#include
#include
+/* Core includes */
+#include
#include
#include
@@ -186,6 +189,9 @@ class Sv39::Level_x_translation_table
func(vo, pa, sz, _entries[i]);
+ /* flush cached table entry address */
+ Cpu::translation_added((addr_t)&_entries[i], sz);
+
/* check whether we wrap */
if (end < vo) return;
@@ -215,7 +221,7 @@ class Sv39::Level_x_translation_table
typename Descriptor::access_t blk_desc =
Block_descriptor::create(flags, pa);
- if (Descriptor::valid(desc) && desc != blk_desc)
+ if (Descriptor::valid(desc) && desc == blk_desc)
throw Double_insertion();
desc = blk_desc;
@@ -372,7 +378,7 @@ namespace Sv39 {
Descriptor::access_t blk_desc =
Block_descriptor::create(flags, pa);
- if (Descriptor::valid(desc) && desc != blk_desc)
+ if (Descriptor::valid(desc) && desc == blk_desc)
throw Double_insertion();
desc = blk_desc;
@@ -382,7 +388,7 @@ namespace Sv39 {
template <> template <>
struct Level_3_translation_table::Remove_func
{
- Remove_func(Translation_table_allocator * /* alloc */) { }
+ Remove_func(Translation_table_allocator *) { }
void operator () (addr_t const vo,
addr_t const pa,
@@ -400,12 +406,12 @@ namespace Genode {
enum {
TABLE_LEVEL_X_SIZE_LOG2 = Sv39::SIZE_LOG2_4K,
- CORE_VM_AREA_SIZE = 128 * 1024 * 1024,
- CORE_TRANS_TABLE_COUNT =
- _count(CORE_VM_AREA_SIZE, Sv39::SIZE_LOG2_1G)
- + _count(CORE_VM_AREA_SIZE, Sv39::SIZE_LOG2_2M),
+ CORE_VM_AREA_SIZE = 128 * 1024 * 1024,
+ CORE_TRANS_TABLE_COUNT =
+ _count(CORE_VM_AREA_SIZE, Sv39::SIZE_LOG2_1G) +
+ _count(CORE_VM_AREA_SIZE, Sv39::SIZE_LOG2_2M),
};
};
-} /* namespace Genode */
+}
#endif /* _TRANSLATION_TABLE_H_ */
diff --git a/repos/base-hw/src/core/platform_pd.cc b/repos/base-hw/src/core/platform_pd.cc
index ee3a6eb1d..239b1e33b 100644
--- a/repos/base-hw/src/core/platform_pd.cc
+++ b/repos/base-hw/src/core/platform_pd.cc
@@ -217,9 +217,6 @@ void Core_platform_pd::_map(addr_t start, addr_t end, bool io_mem)
if (start < VIRT_ADDR_SPACE_START)
start = VIRT_ADDR_SPACE_START;
- if (end > VIRT_ADDR_SPACE_START + VIRT_ADDR_SPACE_SIZE)
- end = VIRT_ADDR_SPACE_START + VIRT_ADDR_SPACE_SIZE;
-
size_t size = round_page(end) - start;
try {
_table()->insert_translation(start, start, size, flags, _table_alloc());
diff --git a/repos/base-hw/src/core/spec/riscv/cpu.cc b/repos/base-hw/src/core/spec/riscv/cpu.cc
new file mode 100644
index 000000000..f1ab154b9
--- /dev/null
+++ b/repos/base-hw/src/core/spec/riscv/cpu.cc
@@ -0,0 +1,27 @@
+/*
+ * \brief CPU core implementation
+ * \author Sebastian Sumpf
+ * \date 2016-02-10
+ */
+
+/*
+ * Copyright (C) 2016 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* Core includes */
+#include
+#include
+
+void Genode::Cpu::translation_added(addr_t const addr, size_t const size)
+{
+ if (Machine::is_user_mode())
+ Kernel::update_data_region(addr, size);
+ else Genode::Cpu::sfence();
+}
diff --git a/repos/base-hw/src/core/spec/riscv/kernel/cpu.cc b/repos/base-hw/src/core/spec/riscv/kernel/cpu.cc
index 36aafad16..e1221b49c 100644
--- a/repos/base-hw/src/core/spec/riscv/kernel/cpu.cc
+++ b/repos/base-hw/src/core/spec/riscv/kernel/cpu.cc
@@ -38,7 +38,8 @@ struct Mstatus : Genode::Register<64>
};
-void Kernel::Cpu::init(Kernel::Pic &pic, Kernel::Pd & core_pd, Genode::Board & board)
+void Kernel::Cpu::init(Kernel::Pic &pic, Kernel::Pd & core_pd,
+ Genode::Board & board)
{
/* read status register */
Mstatus::access_t mstatus = 0;
@@ -50,6 +51,8 @@ void Kernel::Cpu::init(Kernel::Pic &pic, Kernel::Pd & core_pd, Genode::Board & b
Mstatus::Ie::set(mstatus, 0); /* disable interrupts */
Mstatus::Priv::set(mstatus, Mstatus::SUPERVISOR); /* set supervisor mode */
+ addr_t client_context_ptr_off = (addr_t)&_mt_client_context_ptr & 0xfff;
+ addr_t client_context_ptr = exception_entry | client_context_ptr_off;
asm volatile ("csrw sasid, %0\n" /* address space id */
"csrw sptbr, %1\n" /* set page table */
"csrw mstatus, %2\n" /* change mode */
@@ -60,7 +63,7 @@ void Kernel::Cpu::init(Kernel::Pic &pic, Kernel::Pd & core_pd, Genode::Board & b
"r" (core_pd.translation_table()),
"r" (mstatus),
"r" (exception_entry),
- "r" (exception_entry | ((addr_t)&_mt_client_context_ptr & 0xfff))
+ "r" (client_context_ptr)
: "memory");
}
diff --git a/repos/base-hw/src/core/spec/riscv/kernel/exception_vector.cc b/repos/base-hw/src/core/spec/riscv/kernel/exception_vector.cc
index 855ac75af..069dc29cf 100644
--- a/repos/base-hw/src/core/spec/riscv/kernel/exception_vector.cc
+++ b/repos/base-hw/src/core/spec/riscv/kernel/exception_vector.cc
@@ -11,6 +11,7 @@
* under the terms of the GNU General Public License version 2.
*/
+/* Core includes */
#include
extern int _machine_begin, _machine_end;
diff --git a/repos/base-hw/src/core/spec/riscv/kernel/pd.cc b/repos/base-hw/src/core/spec/riscv/kernel/pd.cc
index 95e0f9d9f..0d78892f2 100644
--- a/repos/base-hw/src/core/spec/riscv/kernel/pd.cc
+++ b/repos/base-hw/src/core/spec/riscv/kernel/pd.cc
@@ -1,7 +1,7 @@
/*
* \brief Kernel backend for protection domains
- * \author Stefan Kalkowski
- * \date 2015-03-20
+ * \author Seastian Sumpf
+ * \date 2015-06-02
*/
/*
@@ -38,7 +38,7 @@ Kernel::Pd::~Pd()
oir->~Object_identity_reference();
/* clean up buffers of memory management */
- Cpu::flush_tlb_by_pid(asid);
+ Cpu::invalidate_tlb_by_pid(asid);
alloc().free(asid);
}
diff --git a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc
index 4c9633856..fc96d4ce6 100644
--- a/repos/base-hw/src/core/spec/riscv/kernel/thread.cc
+++ b/repos/base-hw/src/core/spec/riscv/kernel/thread.cc
@@ -25,7 +25,7 @@ void Thread::exception(unsigned const cpu)
return;
switch(cpu_exception) {
- case SUPERVISOR_CALL:
+ case ECALL_FROM_USER:
_call();
ip += 4; /* set to next instruction */
break;
@@ -55,11 +55,14 @@ void Thread::_mmu_exception()
void Thread::_call_update_pd()
{
- asm volatile ("sfence.vm");
+ Cpu::sfence();
}
-void Thread::_call_update_data_region() { }
+void Thread::_call_update_data_region()
+{
+ Cpu::sfence();
+}
void Thread::_call_update_instr_region() { }
diff --git a/repos/base-hw/src/core/spec/riscv/kernel/thread_base.cc b/repos/base-hw/src/core/spec/riscv/kernel/thread_base.cc
index b17d7a2e3..8527632ac 100644
--- a/repos/base-hw/src/core/spec/riscv/kernel/thread_base.cc
+++ b/repos/base-hw/src/core/spec/riscv/kernel/thread_base.cc
@@ -13,16 +13,9 @@
/* core includes */
#include
-#include
-#include
using namespace Kernel;
-
-/*************************
- ** Kernel::Thread_base **
- *************************/
-
Thread_base::Thread_base(Thread * const t)
:
_fault(t),
@@ -31,35 +24,3 @@ Thread_base::Thread_base(Thread * const t)
_fault_writes(0),
_fault_signal(0)
{ }
-
-
-/*************************
- ** Kernel::Cpu_context **
- *************************/
-
-void Kernel::Cpu_context::_init(size_t const stack_size, addr_t const table)
-{
- /*
- * the stack pointer already contains the stack base address
- * of all CPU's kernel stacks, on this uni-processor platform
- * it is sufficient to increase it by the stack's size
- */
- sp = sp + stack_size;
-}
-
-
-/*************************
- ** CPU-state utilities **
- *************************/
-
-typedef Thread_reg_id Reg_id;
-
-static addr_t const _cpu_state_regs[] = { };
-
-addr_t const * cpu_state_regs() { return _cpu_state_regs; }
-
-
-size_t cpu_state_regs_length()
-{
- return sizeof(_cpu_state_regs)/sizeof(_cpu_state_regs[0]);
-}
diff --git a/repos/base-hw/src/core/spec/riscv/mode_transition.s b/repos/base-hw/src/core/spec/riscv/mode_transition.s
index fb90ec49c..b5812d16f 100644
--- a/repos/base-hw/src/core/spec/riscv/mode_transition.s
+++ b/repos/base-hw/src/core/spec/riscv/mode_transition.s
@@ -1,19 +1,24 @@
/*
* \brief Transition between kernel/userland
- * \date 2011-11-15
+ * \author Sebastian Sumpf
+ * \author Mark Vels
+ * \date 2015-06-22
*/
/*
- * Copyright (C) 2011-2015 Genode Labs GmbH
+ * Copyright (C) 2015-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
+
.set USER_MODE, 0
.set SUPERVISOR_MODE, 1
.set MACHINE_MODE, 3
-.set CALL_PUT_CHAR, 0xff
+.set CALL_PUT_CHAR, 0x100
+.set CALL_SET_SYS_TIMER, 0x101
+.set CALL_IS_USER_MODE, 0x102
.set CPU_IP, 0
.set CPU_EXCEPTION, 8
@@ -22,6 +27,42 @@
.set CPU_SASID, 33*8
.set CPU_SPTBR, 34*8
+
+# From encoding.h (riscv-opcode)
+.set MIP_MTIP, 0x00000020
+.set MIP_SSIP, 0x00000002
+.set MIP_HSIP, 0x00000004
+.set MIP_MSIP, 0x00000008
+.set MIP_STIP, 0x00000020
+.set MIP_HTIP, 0x00000040
+.set MIP_MTIP, 0x00000080
+.set MSTATUS_IE, 0x00000001
+.set MSTATUS_PRV, 0x00000006
+.set MSTATUS_IE1, 0x00000008
+.set MSTATUS_PRV1, 0x00000030
+.set MSTATUS_IE2, 0x00000040
+.set MSTATUS_PRV2, 0x00000180
+.set MSTATUS_IE3, 0x00000200
+.set MSTATUS_PRV3, 0x00000C00
+.set MSTATUS_FS, 0x00003000
+.set MSTATUS_XS, 0x0000C000
+.set MSTATUS_MPRV, 0x00010000
+.set MSTATUS_VM, 0x003E0000
+.set MSTATUS64_SD, 0x8000000000000000
+
+.set TRAP_ECALL_FROM_USER, 8
+.set TRAP_ECALL_FROM_SUPERVISOR, 9
+.set TRAP_ECALL_FROM_HYPERVISOR, 10
+.set TRAP_ECALL_FROM_MACHINE, 11
+
+.set TRAP_INTERRUPT_BITNR, 63
+.set IRQ_SOFT, 0x0
+.set IRQ_TIMER, 0x1
+.set IRQ_HOST, 0x2
+.set IRQ_COP, 0x3
+
+
+
.macro _save_scratch_registers mode
.if \mode == USER_MODE
@@ -45,48 +86,171 @@
.endif
.endm
-.macro _put_char mode
+.macro _handle_trap mode
- /* check if ecall (8 - 11) */
csrr t0, mcause
- li t1, 8
- bltu t0, t1, 9f
- li t1, 12
- bgtu t0, t1, 9f
- /* check for put char ecall number */
- li t1, CALL_PUT_CHAR
- bne t1, a0, 9f
+ # If IRQ bit not setup, goto trap handler.
+ # If an interrupt has occurred, the MSB will be set and
+ # hence mcause will be negative
+ #
+ bgez t0, 11f
- /* output character */
- csrw mtohost, a1
+ # The bit was not set so we're handling an interrupt
+ # Valid interrupts are :
+ # - Software IRQ - 0
+ # - Timer IRQ - 1
+ # - HOST HTIF - 2
+ # - COP - 3
+ #
+
+ sll t0, t0, 1 # discard MSB
+
+ # If interrupt source is IRQ TIMER ....
+ li t1, IRQ_TIMER * 2
+ bne t0, t1, 2f
+
+ # Forward handling of timer IRQ to SUPERVISOR
+ li t0, MIP_MTIP
+ csrc mip, t0
+ csrc mie, t0
+ li t1, MIP_STIP
+ csrs mip, t1
+
+ # If irq from supervisor and MSTATUS.IE1 is not set,
+ # then bail out using 'eret'
+ #
+ .if \mode == SUPERVISOR_MODE
+ csrr t1, mstatus
+ and t0, t1, MSTATUS_IE1
+ bne zero, t0, 1f
+
+ # So, IE1 is not set.
+ _restore_scratch_registers \mode
+ eret
+
+ .endif
1:
+ # should cause a interrupt trap in supervisor mode
+ _restore_scratch_registers \mode
+ mrts
+2:
+ # If interrupt source is IRQ HOST ....
+ li t1, IRQ_HOST * 2
+ bne t0, t1, 9f
+
+3:
+ # Empty mfromhost
li t0, 0
csrrw t0, mfromhost, t0
- beqz t0, 1b
+ bne zero,t0, 3b
+ j 9f
- /* advance epc */
+ # Future implementation check for more interrupt sources
+ # to handle here.....
+
+9:
+ #******** IRQ OUT *********
+ _restore_scratch_registers \mode
+ eret
+
+11:
+ # Handle trap
+
+ # check if ecall (8..11):
+ # 8 : Environment call from U-mode
+ # 9 : Environment call from S-mode
+ # 10 : Environment call from H-mode
+ # 11 : Environment call from M-mode
+ #
+ # If not, jump to end of macro.
+ #
+
+ li t1, TRAP_ECALL_FROM_USER
+ bltu t0, t1, 19f
+ li t1, TRAP_ECALL_FROM_MACHINE
+ bgt t0, t1, 19f
+
+ # Switch on ecall number
+ li t1, CALL_PUT_CHAR
+ beq t1, a0, 12f
+
+ li t1, CALL_SET_SYS_TIMER
+ beq t1, a0, 13f
+
+ li t1, CALL_IS_USER_MODE
+ beq t1, a0, 14f
+
+ # else, unknown ecall number
+ .if \mode == USER_MODE
+ # Assume that Genode (supervisor trap handler)
+ # knows what to do then.
+ _restore_scratch_registers \mode
+ mrts
+ .endif
+ j 15f
+
+12:
+ # output character but first wait until mtohost reads 0 atomically
+ # to make sure any previous character is gone..
+ csrr t1, mtohost
+ bne zero, t1, 12b
+
+ csrw mtohost, a1
+ j 15f
+
+13:
+ # Only allow timer fiddling from supervisor mode
+ .if \mode == SUPERVISOR_MODE
+ # Clear any pending STIP
+ li t0, MIP_STIP
+ csrc mip, t0
+
+ # Set system timer
+ csrw mtimecmp, a1
+
+ # enable timer interrupt in M-mode
+ li t0, MIP_MTIP
+ csrrs t0, mie, t0
+ .endif
+ j 15f
+
+14:
+ mv a0, x0
+ .if \mode == USER_MODE
+ li a0, 1
+ .endif
+ j 15f
+
+15:
+ #******* ECALL OUT *********
+ # Empty mfromhost
+ li t0, 0
+ csrrw t0, mfromhost, t0
+ bne zero,t0, 14b
+
+ # advance epc
csrr t0, mepc
addi t0, t0, 4
csrw mepc, t0
_restore_scratch_registers \mode
eret
-9:
+19:
.endm
.section .text
-/*
- * Page aligned base of mode transition code.
- *
- * This position independent code switches between a kernel context and a
- * user context and thereby between their address spaces. Due to the latter
- * it must be mapped executable to the same region in every address space.
- * To enable such switching, the kernel context must be stored within this
- * region, thus one should map it solely accessable for privileged modes.
- */
+##
+ # Page aligned base of mode transition code.
+ #
+ # This position independent code switches between a kernel context and a
+ # user context and thereby between their address spaces. Due to the latter
+ # it must be mapped executable to the same region in every address space.
+ # To enable such switching, the kernel context must be stored within this
+ # region, thus one should map it solely accessable for privileged modes.
+ #
@@ -94,42 +258,42 @@
.global _machine_begin
_machine_begin:
-/* 0x100 user mode */
+# 0x100 user mode
j user_trap
.space 0x3c
-/* 0x140 supervisor */
+# 0x140 supervisor
j supervisor_trap
.space 0x3c
-/* 0x180 hypervisor */
+# 0x180 hypervisor
1: j 1b
.space 0x3c
-/* 0x1c0 machine */
+# 0x1c0 machine
j machine_trap
.space 0x38
-/* 0x1fc non-maksable interrupt */
+# 0x1fc non-maksable interrupt
1: j 1b
user_trap:
_save_scratch_registers USER_MODE
- _put_char USER_MODE
+ _handle_trap USER_MODE
_restore_scratch_registers USER_MODE
mrts
supervisor_trap:
_save_scratch_registers SUPERVISOR_MODE
- _put_char SUPERVISOR_MODE
+ _handle_trap SUPERVISOR_MODE
j fault
machine_trap:
_save_scratch_registers MACHINE_MODE
- _put_char MACHINE_MODE
+ _handle_trap MACHINE_MODE
j fault
-fault:j fault /* TODO: handle trap from supervisor or machine mode */
+fault:j fault # TODO: handle trap from supervisor or machine mode
.global _machine_end
_machine_end:
@@ -138,23 +302,23 @@ _machine_end:
.global _mt_begin
_mt_begin:
-/* 0x100 user mode */
- j _mt_kernel_entry_pic
+# 0x100 user mode
+j _mt_kernel_entry_pic
.space 0x3c
-/* 0x140 supervisor */
+# 0x140 supervisor
1: j 1b
.space 0x3c
-/* 0x180 hypervisor */
+# 0x180 hypervisor
1: j 1b
.space 0x3c
-/* 0x1c0 machine */
+# 0x1c0 machine
1: j 1b
.space 0x38
-/* 0x1fc non-maksable interrupt */
+# 0x1fc non-maksable interrupt
1: j 1b
/* space for a client context-pointer per CPU */
-.p2align 2
+.p2align 3
.global _mt_client_context_ptr
_mt_client_context_ptr:
.space 8
@@ -172,22 +336,29 @@ _mt_master_context_end:
.global _mt_kernel_entry_pic
_mt_kernel_entry_pic:
- /* master context */
+ # master context
csrrw x31, sscratch, x31
addi x31, x31, 8
- /* save x29, x30 in master */
+ # save x29, x30 in master
sd x29, CPU_X1 + 8 * 28(x31)
sd x30, CPU_X1 + 8 * 29(x31)
- /* load kernel page table */
+ # load kernel page table
ld x29, CPU_SASID(x31)
ld x30, CPU_SPTBR(x31)
csrw sasid, x29
csrw sptbr, x30
- /* save x29 - x31 in user context */
+ #
+ # FIXME
+ # A TLB flush. Might be necessary to remove this in the near future again
+ # because on real hardware we currently get problems without.
+ #
+ sfence.vm x0
+
+ # save x29 - x31 in user context
mv x29, x31
addi x29, x29, -8
ld x29, (x29)
@@ -200,24 +371,24 @@ _mt_kernel_entry_pic:
csrr x30, sscratch /* x31 */
sd x30, CPU_X1 + 8 * 30(x29)
- /* save x1 - x28 */
+ # save x1 - x28
.irp reg,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28
sd x\reg, CPU_X1 + 8 * (\reg - 1)(x29)
.endr
- /* trap reason */
+ # trap reason
csrr x30, scause
sd x30, CPU_EXCEPTION(x29)
- /* ip */
+ # ip
csrr x30, sepc
sd x30, CPU_IP(x29)
- /* load kernel stack and ip */
+ # load kernel stack and ip
ld sp, CPU_SP(x31)
ld x30, CPU_IP(x31)
- /* restore scratch */
+ # restore scratch
addi x31, x31, -8
csrw sscratch, x31
@@ -227,42 +398,50 @@ _mt_kernel_entry_pic:
.global _mt_user_entry_pic
_mt_user_entry_pic:
- /* client context pointer */
+ # client context pointer
csrr x30, sscratch
ld x30, (x30)
- /* set return IP */
+ # set return IP
ld x31, CPU_IP(x30)
csrw sepc, x31
- /* restore x1-x28 */
+ # restore x1-x28
.irp reg,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28
ld x\reg, CPU_X1 + 8 * (\reg - 1)(x30)
.endr
- /* save x29, x30, x31 to master context */
+ # save x29, x30, x31 to master context
csrr x29, sscratch
- addi x29, x29, 8 /* master context */
+ addi x29, x29, 8 # master context
.irp reg,29,30,31
ld x31, CPU_X1 + 8 * (\reg - 1)(x30)
sd x31, CPU_X1 + 8 * (\reg - 1)(x29)
.endr
- /* switch page table */
+ # switch page table
ld x31, CPU_SASID(x30)
ld x30, CPU_SPTBR(x30)
csrw sasid, x31
csrw sptbr, x30
- /* restore x29 - x31 from master context */
+ #
+ # FIXME
+ # A TLB flush. Might be necessary to remove this in the near future again
+ # because on real hardware we currently get problems without.
+ #
+
+ sfence.vm x0
+
+ # restore x29 - x31 from master context
.irp reg,31,30,29
ld x\reg, CPU_X1 + 8 * (\reg - 1)(x29)
.endr
eret
-/* end of the mode transition code */
+# end of the mode transition code
.global _mt_end
_mt_end:
diff --git a/repos/base-hw/src/core/spec/riscv/platform_support.cc b/repos/base-hw/src/core/spec/riscv/platform_support.cc
index 09a18090a..a60d89397 100644
--- a/repos/base-hw/src/core/spec/riscv/platform_support.cc
+++ b/repos/base-hw/src/core/spec/riscv/platform_support.cc
@@ -18,40 +18,22 @@
using namespace Genode;
-Cpu::User_context::User_context() { }
-
Native_region * Platform::_ram_regions(unsigned const i)
{
- static Native_region _regions[] =
- {
- { 0, 128 * 1024 * 1024 }
- };
+ static Native_region _regions[] = { { 0, 128 * 1024 * 1024 } };
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
-Native_region * Platform::_core_only_mmio_regions(unsigned const i)
-{
- static Native_region _regions[] =
- {
- };
- return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
-}
+Cpu::User_context::User_context() { }
+Native_region * Platform::_core_only_mmio_regions(unsigned) { return 0; }
-void Platform::_init_io_port_alloc()
-{ }
+void Platform::_init_io_port_alloc() { }
+void Platform::_init_io_mem_alloc() { }
-void Platform::_init_io_mem_alloc()
-{ }
+void Platform::setup_irq_mode(unsigned, unsigned, unsigned) { }
-void Platform::setup_irq_mode(unsigned, unsigned, unsigned) { PDBG("not impl");}
-
-
-long Platform::irq(long const user_irq)
-{
- PDBG("not impl");
- return 0;
-}
+long Platform::irq(long const user_irq) { return 0; }
diff --git a/repos/base-hw/src/core/target.mk b/repos/base-hw/src/core/target.mk
index fc36051d1..75d1dd768 100644
--- a/repos/base-hw/src/core/target.mk
+++ b/repos/base-hw/src/core/target.mk
@@ -14,6 +14,10 @@ LIBS += core
# add C++ sources
SRC_CC += kernel/test.cc
+#
+# On RISCV we need a link address for core that differs from that of the other
+# components.
+#
ifneq ($(filter riscv, $(SPECS)),)
LD_TEXT_ADDR = $(CORE_LD_TEXT_ADDR)
endif