mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 08:25:38 +00:00
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
This commit is contained in:
parent
c246a0d194
commit
1668983efa
@ -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,
|
||||
};
|
||||
|
@ -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_ */
|
||||
|
@ -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_ */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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_ */
|
||||
|
@ -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_ */
|
||||
|
@ -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/stdint.h>
|
||||
/* base-hw includes */
|
||||
#include <kernel/interface.h>
|
||||
|
||||
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_ */
|
||||
|
@ -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
|
||||
|
@ -16,16 +16,11 @@
|
||||
#ifndef _PIC_H_
|
||||
#define _PIC_H_
|
||||
|
||||
#include <base/printf.h>
|
||||
|
||||
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() { }
|
||||
};
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -14,19 +14,18 @@
|
||||
#ifndef _TIMER_H_
|
||||
#define _TIMER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <base/stdint.h>
|
||||
|
||||
/* Core includes */
|
||||
#include <machine_call.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,9 +14,12 @@
|
||||
#ifndef _TRANSLATION_TABLE_H_
|
||||
#define _TRANSLATION_TABLE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/misc_math.h>
|
||||
#include <util/register.h>
|
||||
|
||||
/* Core includes */
|
||||
#include <cpu.h>
|
||||
#include <page_flags.h>
|
||||
#include <translation_table_allocator.h>
|
||||
|
||||
@ -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<None>
|
||||
{
|
||||
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_ */
|
||||
|
@ -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());
|
||||
|
27
repos/base-hw/src/core/spec/riscv/cpu.cc
Normal file
27
repos/base-hw/src/core/spec/riscv/cpu.cc
Normal file
@ -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 <base/printf.h>
|
||||
#include <kernel/interface.h>
|
||||
|
||||
/* Core includes */
|
||||
#include <cpu.h>
|
||||
#include <machine_call.h>
|
||||
|
||||
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();
|
||||
}
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Core includes */
|
||||
#include <kernel/cpu.h>
|
||||
|
||||
extern int _machine_begin, _machine_end;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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() { }
|
||||
|
@ -13,16 +13,9 @@
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/thread.h>
|
||||
#include <kernel/pd.h>
|
||||
#include <kernel/kernel.h>
|
||||
|
||||
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]);
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user