From 1668983efaa4e41e36e98f2ca751e3c5a21d5752 Mon Sep 17 00:00:00 2001 From: Mark Vels Date: Tue, 10 Nov 2015 12:49:05 +0100 Subject: [PATCH] base-hw: RISC-V Rocket Core on Zynq This commit adds rocket core on the Zynq FPGA support to base HW. It also takes advantage of the new timer infrastructure introduced with the privileged 1.8 and adds improved TLB flush support. fixes #1880 --- .../include/spec/riscv/cpu/cpu_state.h | 8 +- .../include/spec/riscv/cpu/memory_barrier.h | 8 +- .../spec/riscv/kernel/interface_support.h | 6 +- repos/base-hw/lib/mk/spec/riscv/core.mk | 1 + repos/base-hw/mk/spec/hw_riscv.mk | 4 +- .../src/core/include/spec/riscv/board.h | 8 +- .../base-hw/src/core/include/spec/riscv/cpu.h | 40 +-- .../core/include/spec/riscv/machine_call.h | 31 +- .../src/core/include/spec/riscv/macros.s | 7 +- .../base-hw/src/core/include/spec/riscv/pic.h | 37 +-- .../src/core/include/spec/riscv/serial.h | 6 +- .../src/core/include/spec/riscv/timer.h | 15 +- .../include/spec/riscv/translation_table.h | 22 +- repos/base-hw/src/core/platform_pd.cc | 3 - repos/base-hw/src/core/spec/riscv/cpu.cc | 27 ++ .../base-hw/src/core/spec/riscv/kernel/cpu.cc | 7 +- .../spec/riscv/kernel/exception_vector.cc | 1 + .../base-hw/src/core/spec/riscv/kernel/pd.cc | 6 +- .../src/core/spec/riscv/kernel/thread.cc | 9 +- .../src/core/spec/riscv/kernel/thread_base.cc | 39 --- .../src/core/spec/riscv/mode_transition.s | 297 ++++++++++++++---- .../src/core/spec/riscv/platform_support.cc | 32 +- repos/base-hw/src/core/target.mk | 4 + 23 files changed, 376 insertions(+), 242 deletions(-) create mode 100644 repos/base-hw/src/core/spec/riscv/cpu.cc 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