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