mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-20 03:36:33 +00:00
base-hw: initial RISC-V support
using the spike instruction emulator issue #1880
This commit is contained in:
parent
ac70dfd9fe
commit
c246a0d194
56
repos/base-hw/include/spec/riscv/cpu/atomic.h
Normal file
56
repos/base-hw/include/spec/riscv/cpu/atomic.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* \brief Atomic operations for RISCV
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-01
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__RISCV__CPU__ATOMIC_H_
|
||||
#define _INCLUDE__RISCV__CPU__ATOMIC_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <cpu/memory_barrier.h>
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/**
|
||||
* Atomic compare and exchange
|
||||
*
|
||||
* This function compares the value at dest with cmp_val.
|
||||
* If both values are equal, dest is set to new_val. If
|
||||
* both values are different, the value at dest remains
|
||||
* unchanged.
|
||||
*
|
||||
* Note, that cmpxchg() represents a memory barrier.
|
||||
*
|
||||
* \return 1 if the value was successfully changed to new_val,
|
||||
* 0 if cmp_val and the value at dest differ.
|
||||
*/
|
||||
inline int cmpxchg(volatile int *dest, int cmp_val, int new_val)
|
||||
{
|
||||
int old_val;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" 1: \n"
|
||||
" lr.w %0, (%1) \n"
|
||||
" bne %0, %2, 2f \n"
|
||||
" sc.w %0, %3, (%1) \n"
|
||||
" bnez %0, 1b \n"
|
||||
" mv %0, %2 \n"
|
||||
" 2: \n"
|
||||
: "=&r" (old_val)
|
||||
: "r" (dest), "r" (cmp_val), "r" (new_val)
|
||||
: "memory");
|
||||
|
||||
Genode::memory_barrier();
|
||||
return old_val == cmp_val ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__RISCV__CPU__ATOMIC_H_ */
|
35
repos/base-hw/include/spec/riscv/cpu/consts.h
Normal file
35
repos/base-hw/include/spec/riscv/cpu/consts.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* \brief Constants definitions for the RISCV architecture.
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-01
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__RISCV__CPU__CONSTS_H_
|
||||
#define _INCLUDE__RISCV__CPU__CONSTS_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/stdint.h>
|
||||
|
||||
namespace Abi {
|
||||
|
||||
/*
|
||||
* On RISC-V we align the stack top to 16-byte. As a call (or branch) will
|
||||
* not change the stack pointer, we need no further stack adjustment.
|
||||
*/
|
||||
static Genode::addr_t stack_align(Genode::addr_t addr) {
|
||||
return (addr & ~0xf); }
|
||||
|
||||
/**
|
||||
* Do ABI specific initialization to a freshly created stack
|
||||
*/
|
||||
inline void init_stack(Genode::addr_t) { }
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__RISCV__CPU__CONSTS_H_ */
|
45
repos/base-hw/include/spec/riscv/cpu/cpu_state.h
Normal file
45
repos/base-hw/include/spec/riscv/cpu/cpu_state.h
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* \brief CPU state
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-01
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__RISCV__CPU__CPU_STATE_H_
|
||||
#define _INCLUDE__RISCV__CPU__CPU_STATE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/stdint.h>
|
||||
|
||||
namespace Genode { struct Cpu_state; }
|
||||
|
||||
struct Genode::Cpu_state
|
||||
{
|
||||
enum Cpu_exception {
|
||||
INSTRUCTION_UNALIGNED = 0,
|
||||
INSTRUCTION_PAGE_FAULT = 1,
|
||||
INSTRUCTION_ILLEGAL = 2,
|
||||
LOAD_UNALIGNED = 4,
|
||||
LOAD_PAGE_FAULT = 5,
|
||||
STORE_UNALIGNED = 6,
|
||||
STORE_PAGE_FAULT = 7,
|
||||
SUPERVISOR_CALL = 8,
|
||||
RESET = 16,
|
||||
IRQ_FLAG = 1UL << 63,
|
||||
};
|
||||
|
||||
addr_t ip, cpu_exception, ra, sp, gp, tp, t0, t1, t2, s0, s1, a0, a1, a2,
|
||||
a3, a4, a5, a6, a7, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, t3,
|
||||
t4, t5, t6;
|
||||
|
||||
bool is_irq() { return cpu_exception & IRQ_FLAG; }
|
||||
unsigned irq() { return cpu_exception ^ IRQ_FLAG; }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__RISCV__CPU__CPU_STATE_H_ */
|
25
repos/base-hw/include/spec/riscv/cpu/memory_barrier.h
Normal file
25
repos/base-hw/include/spec/riscv/cpu/memory_barrier.h
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* \brief Memory barrier
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-01
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__RISCV__CPU__MEMORY_BARRIER_H_
|
||||
#define _INCLUDE__RISCV__CPU__MEMORY_BARRIER_H_
|
||||
|
||||
namespace Genode {
|
||||
|
||||
static inline void memory_barrier()
|
||||
{
|
||||
asm volatile ("fence" ::: "memory");
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__RISCV__CPU__MEMORY_BARRIER_H_ */
|
32
repos/base-hw/include/spec/riscv/cpu/string.h
Normal file
32
repos/base-hw/include/spec/riscv/cpu/string.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* \brief CPU-specific memcpy
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-01
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__RISCV__CPU__STRING_H_
|
||||
#define _INCLUDE__RISCV__CPU__STRING_H_
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/**
|
||||
* Copy memory block
|
||||
*
|
||||
* \param dst destination memory block
|
||||
* \param src source memory block
|
||||
* \param size number of bytes to copy
|
||||
*
|
||||
* \return number of bytes not copied
|
||||
*/
|
||||
inline size_t memcpy_cpu(void *, const void *, size_t size) {
|
||||
return size; }
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__RISCV__CPU__STRING_H_ */
|
35
repos/base-hw/include/spec/riscv/kernel/interface_support.h
Normal file
35
repos/base-hw/include/spec/riscv/kernel/interface_support.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* \brief Interface between kernel and userland
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _KERNEL__INTERFACE_SUPPORT_H_
|
||||
#define _KERNEL__INTERFACE_SUPPORT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/stdint.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
typedef Genode::uint64_t Call_arg;
|
||||
typedef Genode::uint64_t Call_ret;
|
||||
|
||||
/**
|
||||
* Events that are provided by a kernel thread-object for user handling
|
||||
*/
|
||||
struct Thread_event_id
|
||||
{
|
||||
enum { FAULT = 0 };
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _KERNEL__INTERFACE_SUPPORT_H_ */
|
||||
|
3
repos/base-hw/lib/mk/spec/riscv/base-common.mk
Normal file
3
repos/base-hw/lib/mk/spec/riscv/base-common.mk
Normal file
@ -0,0 +1,3 @@
|
||||
include $(REP_DIR)/lib/mk/base-common.inc
|
||||
|
||||
vpath kernel/interface.cc $(REP_DIR)/src/base/riscv
|
21
repos/base-hw/lib/mk/spec/riscv/core.mk
Normal file
21
repos/base-hw/lib/mk/spec/riscv/core.mk
Normal file
@ -0,0 +1,21 @@
|
||||
INC_DIR += $(REP_DIR)/src/core/include/spec/riscv
|
||||
|
||||
CC_OPT += -fno-delete-null-pointer-checks -msoft-float
|
||||
|
||||
# add C++ sources
|
||||
SRC_CC += platform_services.cc
|
||||
SRC_CC += kernel/vm_thread.cc kernel/kernel.cc
|
||||
SRC_CC += spec/riscv/kernel/cpu_context.cc
|
||||
SRC_CC += spec/riscv/kernel/thread.cc
|
||||
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
|
||||
|
||||
#add assembly sources
|
||||
SRC_S += spec/riscv/mode_transition.s
|
||||
SRC_S += spec/riscv/kernel/crt0.s
|
||||
SRC_S += spec/riscv/crt0.s
|
||||
|
||||
# include less specific configuration
|
||||
include $(REP_DIR)/lib/mk/core.inc
|
3
repos/base-hw/lib/mk/spec/riscv/startup.mk
Normal file
3
repos/base-hw/lib/mk/spec/riscv/startup.mk
Normal file
@ -0,0 +1,3 @@
|
||||
include $(call select_from_repositories,lib/mk/startup.inc)
|
||||
|
||||
vpath crt0.s $(REP_DIR)/src/lib/startup/spec/riscv
|
9
repos/base-hw/mk/spec/hw_riscv.mk
Normal file
9
repos/base-hw/mk/spec/hw_riscv.mk
Normal file
@ -0,0 +1,9 @@
|
||||
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
|
||||
|
||||
include $(call select_from_repositories,mk/spec/64bit.mk)
|
||||
include $(call select_from_repositories,mk/spec/hw.mk)
|
102
repos/base-hw/src/base/riscv/kernel/interface.cc
Normal file
102
repos/base-hw/src/base/riscv/kernel/interface.cc
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* \brief Interface between kernel and userland
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <kernel/interface.h>
|
||||
|
||||
using namespace Kernel;
|
||||
|
||||
|
||||
/************************************
|
||||
** Helper macros for kernel calls **
|
||||
************************************/
|
||||
|
||||
#define CALL_1_FILL_ARG_REGS \
|
||||
register Call_arg arg_0_reg asm("a0") = arg_0;
|
||||
|
||||
#define CALL_2_FILL_ARG_REGS \
|
||||
CALL_1_FILL_ARG_REGS \
|
||||
register Call_arg arg_1_reg asm("a1") = arg_1;
|
||||
|
||||
#define CALL_3_FILL_ARG_REGS \
|
||||
CALL_2_FILL_ARG_REGS \
|
||||
register Call_arg arg_2_reg asm("a2") = arg_2;
|
||||
|
||||
#define CALL_4_FILL_ARG_REGS \
|
||||
CALL_3_FILL_ARG_REGS \
|
||||
register Call_arg arg_3_reg asm("a3") = arg_3;
|
||||
|
||||
#define CALL_5_FILL_ARG_REGS \
|
||||
CALL_4_FILL_ARG_REGS \
|
||||
register Call_arg arg_4_reg asm("a4") = arg_4;
|
||||
|
||||
#define CALL_1_SWI "ecall\n" : "+r" (arg_0_reg)
|
||||
#define CALL_2_SWI CALL_1_SWI: "r" (arg_1_reg)
|
||||
#define CALL_3_SWI CALL_2_SWI, "r" (arg_2_reg)
|
||||
#define CALL_4_SWI CALL_3_SWI, "r" (arg_3_reg)
|
||||
#define CALL_5_SWI CALL_4_SWI, "r" (arg_4_reg)
|
||||
|
||||
|
||||
/******************
|
||||
** Kernel calls **
|
||||
******************/
|
||||
|
||||
Call_ret Kernel::call(Call_arg arg_0)
|
||||
{
|
||||
CALL_1_FILL_ARG_REGS
|
||||
asm volatile(CALL_1_SWI);
|
||||
return arg_0_reg;
|
||||
}
|
||||
|
||||
|
||||
Call_ret Kernel::call(Call_arg arg_0,
|
||||
Call_arg arg_1)
|
||||
{
|
||||
CALL_2_FILL_ARG_REGS
|
||||
asm volatile(CALL_2_SWI);
|
||||
return arg_0_reg;
|
||||
}
|
||||
|
||||
|
||||
Call_ret Kernel::call(Call_arg arg_0,
|
||||
Call_arg arg_1,
|
||||
Call_arg arg_2)
|
||||
{
|
||||
CALL_3_FILL_ARG_REGS
|
||||
asm volatile(CALL_3_SWI);
|
||||
return arg_0_reg;
|
||||
}
|
||||
|
||||
|
||||
Call_ret Kernel::call(Call_arg arg_0,
|
||||
Call_arg arg_1,
|
||||
Call_arg arg_2,
|
||||
Call_arg arg_3)
|
||||
{
|
||||
CALL_4_FILL_ARG_REGS
|
||||
asm volatile(CALL_4_SWI);
|
||||
return arg_0_reg;
|
||||
}
|
||||
|
||||
|
||||
Call_ret Kernel::call(Call_arg arg_0,
|
||||
Call_arg arg_1,
|
||||
Call_arg arg_2,
|
||||
Call_arg arg_3,
|
||||
Call_arg arg_4)
|
||||
{
|
||||
CALL_5_FILL_ARG_REGS
|
||||
asm volatile(CALL_5_SWI);
|
||||
return arg_0_reg;
|
||||
}
|
@ -332,7 +332,13 @@ class Kernel::Cpu_pool
|
||||
private:
|
||||
|
||||
Timer _timer;
|
||||
char _cpus[NR_OF_CPUS][sizeof(Cpu)];
|
||||
|
||||
/*
|
||||
* Align to machine word size, otherwise load/stores might fail on some
|
||||
* platforms.
|
||||
*/
|
||||
char _cpus[NR_OF_CPUS][sizeof(Cpu)]
|
||||
__attribute__((aligned(sizeof(addr_t))));
|
||||
|
||||
public:
|
||||
|
||||
|
25
repos/base-hw/src/core/include/spec/riscv/board.h
Normal file
25
repos/base-hw/src/core/include/spec/riscv/board.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* \brief Board spcecification
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _BOARD_H_
|
||||
#define _BOARD_H_
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
struct Board
|
||||
{
|
||||
void init() { }
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _BOARD_H_ */
|
159
repos/base-hw/src/core/include/spec/riscv/cpu.h
Normal file
159
repos/base-hw/src/core/include/spec/riscv/cpu.h
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* \brief CPU driver for core
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _CPU_H_
|
||||
#define _CPU_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/stdint.h>
|
||||
#include <cpu/cpu_state.h>
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
/**
|
||||
* CPU driver for core
|
||||
*/
|
||||
class Cpu;
|
||||
|
||||
typedef __uint128_t sizet_arithm_t;
|
||||
}
|
||||
|
||||
namespace Kernel { class Pd; }
|
||||
|
||||
class Genode::Cpu
|
||||
{
|
||||
public:
|
||||
|
||||
static constexpr addr_t mtc_size = 0x1000;
|
||||
static constexpr addr_t exception_entry = (~0ULL) & ~(0xfff);
|
||||
|
||||
/**
|
||||
* Extend basic CPU state by members relevant for 'base-hw' only
|
||||
*/
|
||||
struct Context : Cpu_state
|
||||
{
|
||||
addr_t sasid = 0;
|
||||
addr_t sptbr = 0; /* supervisor page table register */
|
||||
|
||||
/**
|
||||
* Return base of assigned translation table
|
||||
*/
|
||||
addr_t translation_table() const { return sptbr; }
|
||||
|
||||
/**
|
||||
* Assign translation-table base 'table'
|
||||
*/
|
||||
void translation_table(addr_t const table) { sptbr = table; }
|
||||
|
||||
/**
|
||||
* Assign protection domain
|
||||
*/
|
||||
void protection_domain(Genode::uint8_t const id) { sasid = id; }
|
||||
};
|
||||
|
||||
struct Pd
|
||||
{
|
||||
Genode::uint8_t asid; /* address space id */
|
||||
|
||||
Pd(Genode::uint8_t id) : asid(id) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A usermode execution state
|
||||
*/
|
||||
struct User_context : Context
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
User_context();
|
||||
|
||||
/**
|
||||
* Support for kernel calls
|
||||
*/
|
||||
void user_arg_0(unsigned const arg) { a0 = arg; }
|
||||
void user_arg_1(unsigned const arg) { a1 = arg; }
|
||||
void user_arg_2(unsigned const arg) { a2 = arg; }
|
||||
void user_arg_3(unsigned const arg) { a3 = arg; }
|
||||
void user_arg_4(unsigned const arg) { a4 = arg; }
|
||||
addr_t user_arg_0() const { return a0; }
|
||||
addr_t user_arg_1() const { return a1; }
|
||||
addr_t user_arg_2() const { return a2; }
|
||||
addr_t user_arg_3() const { return a3; }
|
||||
addr_t user_arg_4() const { return a4; }
|
||||
|
||||
/**
|
||||
* Initialize thread context
|
||||
*
|
||||
* \param table physical base of appropriate translation table
|
||||
* \param pd_id kernel name of appropriate protection domain
|
||||
*/
|
||||
void init_thread(addr_t const table, unsigned const pd_id)
|
||||
{
|
||||
protection_domain(pd_id);
|
||||
translation_table(table);
|
||||
}
|
||||
};
|
||||
|
||||
static void wait_for_interrupt() { asm volatile ("wfi"); };
|
||||
|
||||
/**
|
||||
* 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");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return kernel name of the executing CPU
|
||||
*/
|
||||
static unsigned executing_id() { return primary_id(); }
|
||||
|
||||
/**
|
||||
* Return kernel name of the primary 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;
|
||||
asm volatile ("csrr %0, sbadaddr\n" : "=r"(addr));
|
||||
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_ */
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* \brief Hardware specific base of kernel thread-objects
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _KERNEL__THREAD_BASE_H_
|
||||
#define _KERNEL__THREAD_BASE_H_
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/thread_event.h>
|
||||
|
||||
namespace Kernel { class Thread_base; }
|
||||
|
||||
/**
|
||||
* Hardware specific base of kernel thread-objects
|
||||
*/
|
||||
class Kernel::Thread_base
|
||||
{
|
||||
protected:
|
||||
|
||||
Thread_event _fault;
|
||||
addr_t _fault_pd;
|
||||
addr_t _fault_addr;
|
||||
addr_t _fault_writes;
|
||||
addr_t _fault_signal;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param t generic part of kernel thread-object
|
||||
*/
|
||||
Thread_base(Thread * const t);
|
||||
};
|
||||
|
||||
#endif /* _KERNEL__THREAD_BASE_H_ */
|
36
repos/base-hw/src/core/include/spec/riscv/machine_call.h
Normal file
36
repos/base-hw/src/core/include/spec/riscv/machine_call.h
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* \brief Calls supported by machine mode (or SBI interface in RISC-V)
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _MACHINE_CALL_H_
|
||||
#define _MACHINE_CALL_H_
|
||||
|
||||
#include <base/stdint.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 */
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
asm volatile ("ecall\n" : : "r"(a0), "r"(a1));
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _MACHINE_CALL_H_ */
|
21
repos/base-hw/src/core/include/spec/riscv/macros.s
Normal file
21
repos/base-hw/src/core/include/spec/riscv/macros.s
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* \brief Macros that are used by multiple assembly files
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/***************************************************
|
||||
** Constant values that are pretty commonly used **
|
||||
***************************************************/
|
||||
|
||||
/* alignment constraints */
|
||||
.set DATA_ACCESS_ALIGNM_LOG2, 2
|
||||
.set MIN_PAGE_SIZE_LOG2, 12
|
73
repos/base-hw/src/core/include/spec/riscv/pic.h
Normal file
73
repos/base-hw/src/core/include/spec/riscv/pic.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* \brief Programmable interrupt controller for core
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-02
|
||||
*
|
||||
* There currently is no interrupt controller defined for the RISC-V platform.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _PIC_H_
|
||||
#define _PIC_H_
|
||||
|
||||
#include <base/printf.h>
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
/**
|
||||
* Programmable interrupt controller for core
|
||||
*/
|
||||
class Pic;
|
||||
}
|
||||
|
||||
class Genode::Pic
|
||||
{
|
||||
public:
|
||||
|
||||
enum {
|
||||
/*
|
||||
* FIXME: dummy ipi value on non-SMP platform, should be removed
|
||||
* when SMP is an aspect of CPUs only compiled where necessary
|
||||
*/
|
||||
IPI = 0,
|
||||
NR_OF_IRQ = 15,
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Pic() { }
|
||||
|
||||
/**
|
||||
* Receive a pending request number 'i'
|
||||
*/
|
||||
bool take_request(unsigned & i) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmask interrupt 'i'
|
||||
*/
|
||||
void unmask(unsigned const i, unsigned) { }
|
||||
|
||||
/**
|
||||
* Mask interrupt 'i'
|
||||
*/
|
||||
void mask(unsigned const i) { }
|
||||
|
||||
/*************
|
||||
** Dummies **
|
||||
*************/
|
||||
|
||||
void finish_request() { }
|
||||
};
|
||||
|
||||
namespace Kernel { class Pic : public Genode::Pic { }; }
|
||||
|
||||
#endif /* _PIC_H_ */
|
53
repos/base-hw/src/core/include/spec/riscv/serial.h
Normal file
53
repos/base-hw/src/core/include/spec/riscv/serial.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* \brief Serial output driver for core
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SERIAL_H_
|
||||
#define _SERIAL_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/stdint.h>
|
||||
#include <util/register.h>
|
||||
|
||||
/* core includes */
|
||||
#include <machine_call.h>
|
||||
|
||||
namespace Genode { class Serial; }
|
||||
|
||||
/**
|
||||
* Serial output driver for core
|
||||
*/
|
||||
class Genode::Serial
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Serial(unsigned) { }
|
||||
|
||||
void put_char(char const c)
|
||||
{
|
||||
struct Arg : Register<64>
|
||||
{
|
||||
struct Char : Bitfield<0, 8> { };
|
||||
struct Write_cmd : Bitfield<48, 1> { };
|
||||
struct Stdout : Bitfield<56, 1> { };
|
||||
};
|
||||
|
||||
Machine::call(Machine::PUT_CHAR, Arg::Char::bits(c) |
|
||||
Arg::Stdout::bits(1) |
|
||||
Arg::Write_cmd::bits(1));
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SERIAL_H_ */
|
98
repos/base-hw/src/core/include/spec/riscv/timer.h
Normal file
98
repos/base-hw/src/core/include/spec/riscv/timer.h
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* \brief Timer driver for core
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-08-22
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _TIMER_H_
|
||||
#define _TIMER_H_
|
||||
|
||||
#include <base/printf.h>
|
||||
#include <base/stdint.h>
|
||||
|
||||
#include <machine_call.h>
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
/**
|
||||
* Timer driver for core
|
||||
*/
|
||||
class Timer;
|
||||
}
|
||||
|
||||
struct Genode::Timer
|
||||
{
|
||||
private:
|
||||
|
||||
addr_t _timeout = 0;
|
||||
|
||||
addr_t _stime()
|
||||
{
|
||||
addr_t t;
|
||||
asm volatile ("csrr %0, stime\n" : "=r"(t));
|
||||
return t;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Timer()
|
||||
{
|
||||
/* enable timer interrupt */
|
||||
enum { STIE = 0x20 };
|
||||
asm volatile ("csrs sie, %0" : : "r"(STIE));
|
||||
}
|
||||
|
||||
enum {
|
||||
SPIKE_TIMER_HZ = 500000,
|
||||
MS_TICS = SPIKE_TIMER_HZ / 1000,
|
||||
};
|
||||
|
||||
/**
|
||||
* Start single timeout run
|
||||
*
|
||||
* \param tics delay of timer interrupt
|
||||
*/
|
||||
void start_one_shot(unsigned const tics, unsigned /* cpu */)
|
||||
{
|
||||
_timeout = _stime() + tics;
|
||||
asm volatile ("csrw stimecmp, %0" : : "r"(_timeout));
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate milliseconds to a native timer value
|
||||
*/
|
||||
unsigned ms_to_tics(unsigned const ms)
|
||||
{
|
||||
return ms * MS_TICS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate native timer value to milliseconds
|
||||
*/
|
||||
unsigned tics_to_ms(unsigned const tics)
|
||||
{
|
||||
return tics / MS_TICS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current native timer value
|
||||
*/
|
||||
unsigned value(unsigned const)
|
||||
{
|
||||
addr_t time = _stime();
|
||||
return time < _timeout ? _timeout - time : 0;
|
||||
}
|
||||
|
||||
static unsigned interrupt_id(int) { return 1; }
|
||||
};
|
||||
|
||||
namespace Kernel { class Timer : public Genode::Timer { }; }
|
||||
|
||||
#endif /* _TIMER_H_ */
|
411
repos/base-hw/src/core/include/spec/riscv/translation_table.h
Normal file
411
repos/base-hw/src/core/include/spec/riscv/translation_table.h
Normal file
@ -0,0 +1,411 @@
|
||||
/**
|
||||
* \brief RISCV Sv39 page table format
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-08-04
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _TRANSLATION_TABLE_H_
|
||||
#define _TRANSLATION_TABLE_H_
|
||||
|
||||
#include <util/misc_math.h>
|
||||
#include <util/register.h>
|
||||
|
||||
#include <page_flags.h>
|
||||
#include <translation_table_allocator.h>
|
||||
|
||||
namespace Sv39
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
enum {
|
||||
SIZE_LOG2_4K = 12,
|
||||
SIZE_LOG2_2M = 21,
|
||||
SIZE_LOG2_1G = 30,
|
||||
SIZE_LOG2_512G = 39,
|
||||
};
|
||||
|
||||
struct None { };
|
||||
|
||||
template <typename ENTRY, unsigned BLOCK_SIZE_LOG2, unsigned SIZE_LOG2>
|
||||
class Level_x_translation_table;
|
||||
|
||||
using Level_3_translation_table =
|
||||
Level_x_translation_table<None, SIZE_LOG2_4K, SIZE_LOG2_2M>;
|
||||
|
||||
using Level_2_translation_table =
|
||||
Level_x_translation_table<Level_3_translation_table, SIZE_LOG2_2M, SIZE_LOG2_1G>;
|
||||
|
||||
using Level_1_translation_table =
|
||||
Level_x_translation_table<Level_2_translation_table, SIZE_LOG2_1G, SIZE_LOG2_512G>;
|
||||
|
||||
struct Descriptor;
|
||||
struct Table_descriptor;
|
||||
struct Block_descriptor;
|
||||
}
|
||||
|
||||
struct Sv39::Descriptor : Register<64>
|
||||
{
|
||||
enum Descriptor_type { INVALID, TABLE, BLOCK };
|
||||
struct V : Bitfield<0, 1> { }; /* present */
|
||||
struct Type : Bitfield<1, 4> /* type and access rights */
|
||||
{
|
||||
enum {
|
||||
POINTER = 0,
|
||||
POINTER_GLOBAL = 1,
|
||||
USER = 4, /* R + 0, RW + 1, RX + 2, RWX + 3 */
|
||||
KERNEL = 8,
|
||||
GLOBAL = 12,
|
||||
};
|
||||
};
|
||||
struct Ppn : Bitfield<10, 38> { }; /* physical address 10 bit aligned */
|
||||
struct Base : Bitfield<12, 38> { }; /* physical address page aligned */
|
||||
|
||||
template <access_t BASE>
|
||||
static access_t rwx(Page_flags const &f)
|
||||
{
|
||||
if (f.writeable && f.executable)
|
||||
return BASE + 3;
|
||||
else if (f.writeable)
|
||||
return BASE + 1;
|
||||
else if (f.executable)
|
||||
return BASE + 2;
|
||||
else
|
||||
return BASE;
|
||||
}
|
||||
|
||||
static access_t permission_bits(Page_flags const &f)
|
||||
{
|
||||
if (f.global)
|
||||
return rwx<Type::GLOBAL>(f);
|
||||
|
||||
if (f.privileged)
|
||||
return rwx<Type::KERNEL>(f);
|
||||
|
||||
return rwx<Type::USER>(f);
|
||||
}
|
||||
|
||||
static Descriptor_type type(access_t const v)
|
||||
{
|
||||
if (!V::get(v)) return INVALID;
|
||||
if (Type::get(v) == Type::POINTER || Type::get(v) == Type::POINTER_GLOBAL)
|
||||
return TABLE;
|
||||
|
||||
return BLOCK;
|
||||
}
|
||||
|
||||
static bool valid(access_t const v) {
|
||||
return V::get(v); }
|
||||
};
|
||||
|
||||
struct Sv39::Table_descriptor : Descriptor
|
||||
{
|
||||
static access_t create(void * const pa)
|
||||
{
|
||||
access_t base = Base::get((access_t)pa);
|
||||
access_t desc = 0;
|
||||
|
||||
Ppn::set(desc, base);
|
||||
Type::set(desc, Type::POINTER);
|
||||
V::set(desc, 1);
|
||||
|
||||
return desc;
|
||||
}
|
||||
};
|
||||
|
||||
struct Sv39::Block_descriptor : Descriptor
|
||||
{
|
||||
static access_t create(Page_flags const &f, addr_t const pa)
|
||||
{
|
||||
access_t base = Base::get(pa);
|
||||
access_t desc = 0;
|
||||
|
||||
Ppn::set(desc, base);
|
||||
Type::set(desc, permission_bits(f));
|
||||
V::set(desc, 1);
|
||||
|
||||
return desc;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ENTRY, unsigned BLOCK_SIZE_LOG2, unsigned SIZE_LOG2>
|
||||
class Sv39::Level_x_translation_table
|
||||
{
|
||||
private:
|
||||
|
||||
bool _aligned(addr_t const a, size_t const alignm_log2) {
|
||||
return a == ((a >> alignm_log2) << alignm_log2); }
|
||||
|
||||
public:
|
||||
|
||||
static constexpr size_t MIN_PAGE_SIZE_LOG2 = SIZE_LOG2_4K;
|
||||
static constexpr size_t ALIGNM_LOG2 = SIZE_LOG2_4K;
|
||||
static constexpr size_t MAX_ENTRIES = 1 << (SIZE_LOG2 - BLOCK_SIZE_LOG2);
|
||||
static constexpr size_t BLOCK_SIZE = 1 << BLOCK_SIZE_LOG2;
|
||||
static constexpr size_t BLOCK_MASK = ~(BLOCK_SIZE - 1);
|
||||
static constexpr size_t VM_MASK = (1UL<< SIZE_LOG2_512G) - 1;
|
||||
|
||||
class Misaligned { };
|
||||
class Invalid_range { };
|
||||
class Double_insertion { };
|
||||
|
||||
protected:
|
||||
|
||||
typename Descriptor::access_t _entries[MAX_ENTRIES];
|
||||
|
||||
/*
|
||||
* Return how many entries of an alignment fit into region
|
||||
*/
|
||||
static constexpr size_t _count(size_t region, size_t alignment) {
|
||||
return align_addr<size_t>(region, alignment) / (1UL << alignment); }
|
||||
|
||||
|
||||
template <typename FUNC>
|
||||
void _range_op(addr_t vo, addr_t pa, size_t size, FUNC &&func)
|
||||
{
|
||||
/* sanity check vo bits 38 to 63 must be equal */
|
||||
addr_t sanity = vo >> 38;
|
||||
if (sanity != 0 && sanity != 0x3ffffff) {
|
||||
PERR("Invalid virtual address: %lx", vo);
|
||||
throw Invalid_range();
|
||||
}
|
||||
|
||||
/* clear bits 39 - 63 */
|
||||
vo &= VM_MASK;
|
||||
|
||||
for (size_t i = vo >> BLOCK_SIZE_LOG2; size > 0;
|
||||
i = vo >> BLOCK_SIZE_LOG2) {
|
||||
addr_t end = (vo + BLOCK_SIZE) & BLOCK_MASK;
|
||||
size_t sz = min(size, end-vo);
|
||||
|
||||
func(vo, pa, sz, _entries[i]);
|
||||
|
||||
/* check whether we wrap */
|
||||
if (end < vo) return;
|
||||
|
||||
size = size - sz;
|
||||
vo += sz;
|
||||
pa += sz;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
struct Insert_func
|
||||
{
|
||||
Page_flags const & flags;
|
||||
Translation_table_allocator * alloc;
|
||||
|
||||
Insert_func(Page_flags const & flags,
|
||||
Translation_table_allocator * alloc)
|
||||
: flags(flags), alloc(alloc) { }
|
||||
|
||||
void operator () (addr_t const vo,
|
||||
addr_t const pa,
|
||||
size_t const size,
|
||||
typename Descriptor::access_t &desc)
|
||||
{
|
||||
/* can we insert a whole block? */
|
||||
if (!((vo & ~BLOCK_MASK) || (pa & ~BLOCK_MASK) || size < BLOCK_SIZE)) {
|
||||
typename Descriptor::access_t blk_desc =
|
||||
Block_descriptor::create(flags, pa);
|
||||
|
||||
if (Descriptor::valid(desc) && desc != blk_desc)
|
||||
throw Double_insertion();
|
||||
|
||||
desc = blk_desc;
|
||||
return;
|
||||
}
|
||||
|
||||
/* we need to use a next level table */
|
||||
ENTRY *table;
|
||||
switch (Descriptor::type(desc)) {
|
||||
|
||||
case Descriptor::INVALID: /* no entry */
|
||||
{
|
||||
if (!alloc)
|
||||
throw Allocator::Out_of_memory();
|
||||
|
||||
/* create and link next level table */
|
||||
table = new (alloc) ENTRY();
|
||||
ENTRY * phys_addr = (ENTRY*) alloc->phys_addr(table);
|
||||
desc = Table_descriptor::create(phys_addr ?
|
||||
phys_addr : table);
|
||||
}
|
||||
|
||||
case Descriptor::TABLE: /* table already available */
|
||||
{
|
||||
/* use allocator to retrieve virt address of table */
|
||||
ENTRY * phys_addr = (ENTRY*)
|
||||
Table_descriptor::Base::bits(Table_descriptor::Ppn::get(desc));
|
||||
table = (ENTRY*) alloc->virt_addr(phys_addr);
|
||||
table = table ? table : (ENTRY*)phys_addr;
|
||||
break;
|
||||
}
|
||||
|
||||
case Descriptor::BLOCK: /* there is already a block */
|
||||
throw Double_insertion();
|
||||
};
|
||||
|
||||
/* insert translation */
|
||||
table->insert_translation(vo - (vo & BLOCK_MASK),
|
||||
pa, size, flags, alloc);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename E>
|
||||
struct Remove_func
|
||||
{
|
||||
Translation_table_allocator * alloc;
|
||||
|
||||
Remove_func(Translation_table_allocator * alloc) : alloc(alloc) { }
|
||||
|
||||
void operator () (addr_t const vo,
|
||||
addr_t const pa,
|
||||
size_t const size,
|
||||
typename Descriptor::access_t &desc)
|
||||
{
|
||||
switch (Descriptor::type(desc)) {
|
||||
case Descriptor::TABLE:
|
||||
{
|
||||
/* use allocator to retrieve virt address of table */
|
||||
ENTRY * phys_addr = (ENTRY*)
|
||||
Table_descriptor::Base::bits(Table_descriptor::Ppn::get(desc));
|
||||
ENTRY * table = (ENTRY*) alloc->virt_addr(phys_addr);
|
||||
table = table ? table : (ENTRY*)phys_addr;
|
||||
table->remove_translation(vo - (vo & BLOCK_MASK),
|
||||
size, alloc);
|
||||
if (!table->empty())
|
||||
break;
|
||||
destroy(alloc, table);
|
||||
}
|
||||
case Descriptor::BLOCK:
|
||||
case Descriptor::INVALID:
|
||||
desc = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Level_x_translation_table()
|
||||
{
|
||||
if (!_aligned((addr_t)this, ALIGNM_LOG2)) {
|
||||
PWRN("misaligned address");
|
||||
throw Misaligned();
|
||||
}
|
||||
|
||||
memset(&_entries, 0, sizeof(_entries));
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
for (unsigned i = 0; i < MAX_ENTRIES; i++)
|
||||
if (Descriptor::valid(_entries[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert translations into this table
|
||||
*
|
||||
* \param vo offset of the virtual region represented
|
||||
* by the translation within the virtual
|
||||
* region represented by this table
|
||||
* \param pa base of the physical backing store
|
||||
* \param size size of the translated region
|
||||
* \param flags mapping flags
|
||||
* \param alloc level allocator
|
||||
*/
|
||||
void insert_translation(addr_t vo, addr_t pa, size_t size,
|
||||
Page_flags const & flags,
|
||||
Translation_table_allocator * alloc )
|
||||
{
|
||||
_range_op(vo, pa, size, Insert_func<ENTRY>(flags, alloc));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove translations that overlap with a given virtual region
|
||||
*
|
||||
* \param vo region offset within the tables virtual region
|
||||
* \param size region size
|
||||
* \param alloc level allocator
|
||||
*/
|
||||
void remove_translation(addr_t vo, size_t size,
|
||||
Translation_table_allocator * alloc)
|
||||
{
|
||||
_range_op(vo, 0, size, Remove_func<ENTRY>(alloc));
|
||||
}
|
||||
} __attribute__((aligned(1 << ALIGNM_LOG2)));
|
||||
|
||||
namespace Sv39 {
|
||||
|
||||
/**
|
||||
* Insert/Remove functor specialization for level 3
|
||||
*/
|
||||
template <> template <>
|
||||
struct Level_3_translation_table::Insert_func<None>
|
||||
{
|
||||
Page_flags const & flags;
|
||||
Translation_table_allocator * alloc;
|
||||
|
||||
Insert_func(Page_flags const & flags,
|
||||
Translation_table_allocator * alloc)
|
||||
: flags(flags), alloc(alloc) { }
|
||||
|
||||
void operator () (addr_t const vo,
|
||||
addr_t const pa,
|
||||
size_t const size,
|
||||
Descriptor::access_t &desc)
|
||||
{
|
||||
if ((vo & ~BLOCK_MASK) || (pa & ~BLOCK_MASK) ||
|
||||
size < BLOCK_SIZE) {
|
||||
PWRN("invalid range");
|
||||
throw Invalid_range();
|
||||
}
|
||||
|
||||
Descriptor::access_t blk_desc =
|
||||
Block_descriptor::create(flags, pa);
|
||||
|
||||
if (Descriptor::valid(desc) && desc != blk_desc)
|
||||
throw Double_insertion();
|
||||
|
||||
desc = blk_desc;
|
||||
}
|
||||
};
|
||||
|
||||
template <> template <>
|
||||
struct Level_3_translation_table::Remove_func<None>
|
||||
{
|
||||
Remove_func(Translation_table_allocator * /* alloc */) { }
|
||||
|
||||
void operator () (addr_t const vo,
|
||||
addr_t const pa,
|
||||
size_t const size,
|
||||
Descriptor::access_t &desc) {
|
||||
desc = 0; }
|
||||
};
|
||||
}
|
||||
|
||||
namespace Genode {
|
||||
|
||||
class Translation_table : public Sv39::Level_1_translation_table
|
||||
{
|
||||
public:
|
||||
|
||||
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),
|
||||
};
|
||||
};
|
||||
} /* namespace Genode */
|
||||
|
||||
#endif /* _TRANSLATION_TABLE_H_ */
|
@ -14,6 +14,7 @@
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/pd.h>
|
||||
#include <util.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <assert.h>
|
||||
@ -56,7 +57,7 @@ void Mode_transition_control::map(Genode::Translation_table * tt,
|
||||
{
|
||||
try {
|
||||
addr_t const phys_base = (addr_t)&_mt_begin;
|
||||
tt->insert_translation(VIRT_BASE, phys_base, SIZE,
|
||||
tt->insert_translation(Genode::trunc_page(VIRT_BASE), phys_base, SIZE,
|
||||
Genode::Page_flags::mode_transition(), alloc);
|
||||
} catch(...) {
|
||||
PERR("Inserting exception vector in page table failed!"); }
|
||||
|
@ -2,6 +2,7 @@
|
||||
* \brief Protection-domain facility
|
||||
* \author Martin Stein
|
||||
* \author Stefan Kalkowski
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-02-12
|
||||
*/
|
||||
|
||||
@ -210,9 +211,16 @@ void Core_platform_pd::_map(addr_t start, addr_t end, bool io_mem)
|
||||
const Page_flags flags =
|
||||
Page_flags::apply_mapping(true, io_mem ? UNCACHED : CACHED, io_mem);
|
||||
|
||||
start = trunc_page(start);
|
||||
size_t size = round_page(end) - start;
|
||||
start = trunc_page(start);
|
||||
|
||||
/* omitt regions before vm_start */
|
||||
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());
|
||||
} catch(Allocator::Out_of_memory) {
|
||||
|
27
repos/base-hw/src/core/spec/riscv/crt0.s
Normal file
27
repos/base-hw/src/core/spec/riscv/crt0.s
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* \brief Startup code for the core's userland part
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-09-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.section ".text"
|
||||
|
||||
.global _core_start
|
||||
_core_start:
|
||||
|
||||
/* create environment for main thread */
|
||||
jal init_main_thread
|
||||
|
||||
/* load stack pointer from init_main_thread_result */
|
||||
la sp, init_main_thread_result
|
||||
ld sp, (sp)
|
||||
|
||||
/* jump into init C-code */
|
||||
j _main
|
86
repos/base-hw/src/core/spec/riscv/kernel/cpu.cc
Normal file
86
repos/base-hw/src/core/spec/riscv/kernel/cpu.cc
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* \brief Class for kernel data that is needed to manage a specific CPU
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* core includes */
|
||||
#include <assert.h>
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/pd.h>
|
||||
|
||||
using namespace Kernel;
|
||||
|
||||
extern Genode::addr_t _mt_client_context_ptr;
|
||||
|
||||
struct Mstatus : Genode::Register<64>
|
||||
{
|
||||
enum {
|
||||
USER = 0,
|
||||
SUPERVISOR = 1,
|
||||
MACHINE = 3,
|
||||
Sv39 = 9,
|
||||
};
|
||||
struct Ie : Bitfield<0, 1> { };
|
||||
struct Priv : Bitfield<1, 2> { };
|
||||
struct Ie1 : Bitfield<3, 1> { };
|
||||
struct Priv1 : Bitfield<4, 2> { };
|
||||
struct Fs : Bitfield<12, 2> { enum { INITIAL = 1 }; };
|
||||
struct Vm : Bitfield<17, 5> { };
|
||||
struct Mprv : Bitfield<16, 1> { };
|
||||
};
|
||||
|
||||
|
||||
void Kernel::Cpu::init(Kernel::Pic &pic, Kernel::Pd & core_pd, Genode::Board & board)
|
||||
{
|
||||
/* read status register */
|
||||
Mstatus::access_t mstatus = 0;
|
||||
|
||||
Mstatus::Vm::set(mstatus, Mstatus::Sv39); /* enable Sv39 paging */
|
||||
Mstatus::Fs::set(mstatus, Mstatus::Fs::INITIAL); /* enable FPU */
|
||||
Mstatus::Ie1::set(mstatus, 1); /* user mode interrupt */
|
||||
Mstatus::Priv1::set(mstatus, Mstatus::USER); /* set user mode */
|
||||
Mstatus::Ie::set(mstatus, 0); /* disable interrupts */
|
||||
Mstatus::Priv::set(mstatus, Mstatus::SUPERVISOR); /* set supervisor mode */
|
||||
|
||||
asm volatile ("csrw sasid, %0\n" /* address space id */
|
||||
"csrw sptbr, %1\n" /* set page table */
|
||||
"csrw mstatus, %2\n" /* change mode */
|
||||
"csrw stvec, %3\n" /* exception vector */
|
||||
"csrw sscratch,%4\n" /* master conext ptr */
|
||||
:
|
||||
: "r" (core_pd.asid),
|
||||
"r" (core_pd.translation_table()),
|
||||
"r" (mstatus),
|
||||
"r" (exception_entry),
|
||||
"r" (exception_entry | ((addr_t)&_mt_client_context_ptr & 0xfff))
|
||||
: "memory");
|
||||
}
|
||||
|
||||
|
||||
Cpu_idle::Cpu_idle(Cpu * const cpu) : Cpu_job(Cpu_priority::MIN, 0)
|
||||
{
|
||||
Cpu_job::cpu(cpu);
|
||||
cpu_exception = RESET;
|
||||
ip = (addr_t)&_main;
|
||||
sp = (addr_t)&_stack[stack_size];
|
||||
init_thread((addr_t)core_pd()->translation_table(), core_pd()->asid);
|
||||
}
|
||||
|
||||
|
||||
void Cpu_idle::exception(unsigned const cpu)
|
||||
{
|
||||
if (is_irq()) {
|
||||
_interrupt(cpu);
|
||||
return;
|
||||
} else if (cpu_exception == RESET) return;
|
||||
|
||||
assert(0);
|
||||
}
|
26
repos/base-hw/src/core/spec/riscv/kernel/cpu_context.cc
Normal file
26
repos/base-hw/src/core/spec/riscv/kernel/cpu_context.cc
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* \brief Kernel cpu context specific implementation
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Core includes */
|
||||
#include <kernel/cpu.h>
|
||||
|
||||
void Kernel::Cpu_context::_init(size_t const stack_size, addr_t const table)
|
||||
{
|
||||
/*
|
||||
* The stack pointer currently contains the base address of the
|
||||
* kernel stack area that contains the kernel stacks of all CPUs. As this
|
||||
* is a uni-processor platform, we merely have to select the first kernel
|
||||
* stack, i.e. increasing sp by the size of one stack.
|
||||
*/
|
||||
sp = sp + stack_size;
|
||||
}
|
44
repos/base-hw/src/core/spec/riscv/kernel/crt0.s
Normal file
44
repos/base-hw/src/core/spec/riscv/kernel/crt0.s
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* \brief Kernel startup code
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-010
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.section ".text.crt0"
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
j _start_next_page
|
||||
|
||||
/* leave first page empty for mode-transition page located at 0x100 */
|
||||
.space 4096
|
||||
|
||||
_start_next_page:
|
||||
|
||||
/* clear the bss segment */
|
||||
la a0, _bss_start
|
||||
la a1, _bss_end
|
||||
1:
|
||||
sd x0, (a0)
|
||||
addi a0, a0, 8
|
||||
bne a0, a1, 1b
|
||||
|
||||
la sp, kernel_stack
|
||||
la a0, kernel_stack_size
|
||||
ld a0, (a0)
|
||||
add sp, sp, a0
|
||||
|
||||
/* save kernel stack pointer in mscratch */
|
||||
csrw mscratch, sp
|
||||
|
||||
jal setup_riscv_exception_vector
|
||||
jal init_kernel
|
||||
|
||||
1: j 1b
|
29
repos/base-hw/src/core/spec/riscv/kernel/exception_vector.cc
Normal file
29
repos/base-hw/src/core/spec/riscv/kernel/exception_vector.cc
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* \brief Exception vector initialization
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-07-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <kernel/cpu.h>
|
||||
|
||||
extern int _machine_begin, _machine_end;
|
||||
|
||||
extern "C" void setup_riscv_exception_vector()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/* retrieve exception vector */
|
||||
addr_t vector;
|
||||
asm volatile ("csrr %0, mtvec\n" : "=r"(vector));
|
||||
|
||||
/* copy machine mode exception vector */
|
||||
memcpy((void *)vector,
|
||||
&_machine_begin, (addr_t)&_machine_end - (addr_t)&_machine_begin);
|
||||
}
|
50
repos/base-hw/src/core/spec/riscv/kernel/pd.cc
Normal file
50
repos/base-hw/src/core/spec/riscv/kernel/pd.cc
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* \brief Kernel backend for protection domains
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2015-03-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* core includes */
|
||||
#include <assert.h>
|
||||
#include <platform_pd.h>
|
||||
#include <kernel/pd.h>
|
||||
|
||||
using Asid_allocator = Genode::Bit_allocator<256>;
|
||||
|
||||
static Asid_allocator &alloc() {
|
||||
return *unmanaged_singleton<Asid_allocator>(); }
|
||||
|
||||
|
||||
Kernel::Pd::Pd(Kernel::Pd::Table * const table,
|
||||
Genode::Platform_pd * const platform_pd)
|
||||
: Kernel::Cpu::Pd((Genode::uint8_t)alloc().alloc()),
|
||||
_table(table), _platform_pd(platform_pd)
|
||||
{
|
||||
capid_t invalid = _capid_alloc.alloc();
|
||||
assert(invalid == cap_id_invalid());
|
||||
}
|
||||
|
||||
|
||||
Kernel::Pd::~Pd()
|
||||
{
|
||||
while (Object_identity_reference *oir = _cap_tree.first())
|
||||
oir->~Object_identity_reference();
|
||||
|
||||
/* clean up buffers of memory management */
|
||||
Cpu::flush_tlb_by_pid(asid);
|
||||
alloc().free(asid);
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Pd::admit(Kernel::Cpu::Context * const c)
|
||||
{
|
||||
c->protection_domain(asid);
|
||||
c->translation_table((addr_t)translation_table());
|
||||
}
|
71
repos/base-hw/src/core/spec/riscv/kernel/thread.cc
Normal file
71
repos/base-hw/src/core/spec/riscv/kernel/thread.cc
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* \brief Kernel backend for execution contexts in userland
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/pd.h>
|
||||
#include <kernel/thread.h>
|
||||
|
||||
using namespace Kernel;
|
||||
|
||||
void Kernel::Thread::_init() { }
|
||||
|
||||
void Thread::exception(unsigned const cpu)
|
||||
{
|
||||
if (is_irq())
|
||||
return;
|
||||
|
||||
switch(cpu_exception) {
|
||||
case SUPERVISOR_CALL:
|
||||
_call();
|
||||
ip += 4; /* set to next instruction */
|
||||
break;
|
||||
case INSTRUCTION_PAGE_FAULT:
|
||||
case STORE_PAGE_FAULT:
|
||||
case LOAD_PAGE_FAULT:
|
||||
_mmu_exception();
|
||||
break;
|
||||
default:
|
||||
PWRN("%s -> %s: unhandled exception %lu at ip=%lx",
|
||||
pd_label(), label(), cpu_exception, ip);
|
||||
_stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Thread::_mmu_exception()
|
||||
{
|
||||
_become_inactive(AWAITS_RESUME);
|
||||
_fault_pd = (addr_t)_pd->platform_pd();
|
||||
_fault_signal = (addr_t)_fault.signal_context();
|
||||
_fault_addr = Cpu::sbadaddr();
|
||||
|
||||
_fault.submit();
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call_update_pd()
|
||||
{
|
||||
asm volatile ("sfence.vm");
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call_update_data_region() { }
|
||||
|
||||
|
||||
void Thread::_call_update_instr_region() { }
|
||||
|
||||
|
||||
void Thread_event::_signal_acknowledged()
|
||||
{
|
||||
_thread->_resume();
|
||||
}
|
65
repos/base-hw/src/core/spec/riscv/kernel/thread_base.cc
Normal file
65
repos/base-hw/src/core/spec/riscv/kernel/thread_base.cc
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* \brief CPU specific implementations of core
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* 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),
|
||||
_fault_pd(0),
|
||||
_fault_addr(0),
|
||||
_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]);
|
||||
}
|
268
repos/base-hw/src/core/spec/riscv/mode_transition.s
Normal file
268
repos/base-hw/src/core/spec/riscv/mode_transition.s
Normal file
@ -0,0 +1,268 @@
|
||||
/*
|
||||
* \brief Transition between kernel/userland
|
||||
* \date 2011-11-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2015 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 CPU_IP, 0
|
||||
.set CPU_EXCEPTION, 8
|
||||
.set CPU_X1, 2*8
|
||||
.set CPU_SP, 3*8
|
||||
.set CPU_SASID, 33*8
|
||||
.set CPU_SPTBR, 34*8
|
||||
|
||||
.macro _save_scratch_registers mode
|
||||
|
||||
.if \mode == USER_MODE
|
||||
csrrw sp, mscratch, sp
|
||||
.endif
|
||||
|
||||
addi sp, sp, -24
|
||||
sd t0, 0(sp)
|
||||
sd t1, 8(sp)
|
||||
sd t2, 16(sp)
|
||||
.endm
|
||||
|
||||
.macro _restore_scratch_registers mode
|
||||
ld t0, 0(sp)
|
||||
ld t1, 8(sp)
|
||||
ld t2, 16(sp)
|
||||
addi sp, sp, 24
|
||||
|
||||
.if \mode == USER_MODE
|
||||
csrrw sp, mscratch, sp
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro _put_char 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
|
||||
|
||||
/* output character */
|
||||
csrw mtohost, a1
|
||||
|
||||
1:
|
||||
li t0, 0
|
||||
csrrw t0, mfromhost, t0
|
||||
beqz t0, 1b
|
||||
|
||||
/* advance epc */
|
||||
csrr t0, mepc
|
||||
addi t0, t0, 4
|
||||
csrw mepc, t0
|
||||
|
||||
_restore_scratch_registers \mode
|
||||
eret
|
||||
9:
|
||||
.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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
.p2align 8
|
||||
.global _machine_begin
|
||||
_machine_begin:
|
||||
|
||||
/* 0x100 user mode */
|
||||
j user_trap
|
||||
.space 0x3c
|
||||
/* 0x140 supervisor */
|
||||
j supervisor_trap
|
||||
.space 0x3c
|
||||
/* 0x180 hypervisor */
|
||||
1: j 1b
|
||||
.space 0x3c
|
||||
/* 0x1c0 machine */
|
||||
j machine_trap
|
||||
.space 0x38
|
||||
/* 0x1fc non-maksable interrupt */
|
||||
1: j 1b
|
||||
|
||||
user_trap:
|
||||
|
||||
_save_scratch_registers USER_MODE
|
||||
_put_char USER_MODE
|
||||
_restore_scratch_registers USER_MODE
|
||||
mrts
|
||||
|
||||
supervisor_trap:
|
||||
|
||||
_save_scratch_registers SUPERVISOR_MODE
|
||||
_put_char SUPERVISOR_MODE
|
||||
j fault
|
||||
|
||||
machine_trap:
|
||||
|
||||
_save_scratch_registers MACHINE_MODE
|
||||
_put_char MACHINE_MODE
|
||||
j fault
|
||||
|
||||
|
||||
fault:j fault /* TODO: handle trap from supervisor or machine mode */
|
||||
|
||||
.global _machine_end
|
||||
_machine_end:
|
||||
|
||||
.p2align 12
|
||||
.global _mt_begin
|
||||
_mt_begin:
|
||||
|
||||
/* 0x100 user mode */
|
||||
j _mt_kernel_entry_pic
|
||||
.space 0x3c
|
||||
/* 0x140 supervisor */
|
||||
1: j 1b
|
||||
.space 0x3c
|
||||
/* 0x180 hypervisor */
|
||||
1: j 1b
|
||||
.space 0x3c
|
||||
/* 0x1c0 machine */
|
||||
1: j 1b
|
||||
.space 0x38
|
||||
/* 0x1fc non-maksable interrupt */
|
||||
1: j 1b
|
||||
|
||||
/* space for a client context-pointer per CPU */
|
||||
.p2align 2
|
||||
.global _mt_client_context_ptr
|
||||
_mt_client_context_ptr:
|
||||
.space 8
|
||||
|
||||
/* space for a copy of the kernel context */
|
||||
.global _mt_master_context_begin
|
||||
_mt_master_context_begin:
|
||||
|
||||
/* space must be at least as large as 'Context' */
|
||||
.space 35*8
|
||||
|
||||
.global _mt_master_context_end
|
||||
_mt_master_context_end:
|
||||
|
||||
.global _mt_kernel_entry_pic
|
||||
_mt_kernel_entry_pic:
|
||||
|
||||
/* master context */
|
||||
csrrw x31, sscratch, x31
|
||||
addi x31, x31, 8
|
||||
|
||||
/* save x29, x30 in master */
|
||||
sd x29, CPU_X1 + 8 * 28(x31)
|
||||
sd x30, CPU_X1 + 8 * 29(x31)
|
||||
|
||||
/* 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 */
|
||||
mv x29, x31
|
||||
addi x29, x29, -8
|
||||
ld x29, (x29)
|
||||
|
||||
.irp reg,29,30
|
||||
ld x30, CPU_X1 + 8 * (\reg - 1)(x31)
|
||||
sd x30, CPU_X1 + 8 * (\reg - 1)(x29)
|
||||
.endr
|
||||
|
||||
csrr x30, sscratch /* x31 */
|
||||
sd x30, CPU_X1 + 8 * 30(x29)
|
||||
|
||||
/* 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 */
|
||||
csrr x30, scause
|
||||
sd x30, CPU_EXCEPTION(x29)
|
||||
|
||||
/* ip */
|
||||
csrr x30, sepc
|
||||
sd x30, CPU_IP(x29)
|
||||
|
||||
/* load kernel stack and ip */
|
||||
ld sp, CPU_SP(x31)
|
||||
ld x30, CPU_IP(x31)
|
||||
|
||||
/* restore scratch */
|
||||
addi x31, x31, -8
|
||||
csrw sscratch, x31
|
||||
|
||||
jalr x30
|
||||
|
||||
|
||||
.global _mt_user_entry_pic
|
||||
_mt_user_entry_pic:
|
||||
|
||||
/* client context pointer */
|
||||
csrr x30, sscratch
|
||||
ld x30, (x30)
|
||||
|
||||
/* set return IP */
|
||||
ld x31, CPU_IP(x30)
|
||||
csrw sepc, x31
|
||||
|
||||
/* 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 */
|
||||
csrr x29, sscratch
|
||||
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 */
|
||||
ld x31, CPU_SASID(x30)
|
||||
ld x30, CPU_SPTBR(x30)
|
||||
|
||||
csrw sasid, x31
|
||||
csrw sptbr, x30
|
||||
|
||||
/* 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 */
|
||||
.global _mt_end
|
||||
_mt_end:
|
57
repos/base-hw/src/core/spec/riscv/platform_support.cc
Normal file
57
repos/base-hw/src/core/spec/riscv/platform_support.cc
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* \brief Platform implementations specific for RISC-V
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* core includes */
|
||||
#include <platform.h>
|
||||
#include <board.h>
|
||||
#include <cpu.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
Cpu::User_context::User_context() { }
|
||||
|
||||
|
||||
Native_region * Platform::_ram_regions(unsigned const i)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void Platform::_init_io_port_alloc()
|
||||
{ }
|
||||
|
||||
|
||||
void Platform::_init_io_mem_alloc()
|
||||
{ }
|
||||
|
||||
void Platform::setup_irq_mode(unsigned, unsigned, unsigned) { PDBG("not impl");}
|
||||
|
||||
|
||||
long Platform::irq(long const user_irq)
|
||||
{
|
||||
PDBG("not impl");
|
||||
return 0;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#
|
||||
# \brief Build config for Genodes core process
|
||||
# \author Martin Stein
|
||||
# \author Sebastian Sumpf
|
||||
# \date 2011-12-16
|
||||
#
|
||||
|
||||
@ -12,3 +13,7 @@ LIBS += core
|
||||
|
||||
# add C++ sources
|
||||
SRC_CC += kernel/test.cc
|
||||
|
||||
ifneq ($(filter riscv, $(SPECS)),)
|
||||
LD_TEXT_ADDR = $(CORE_LD_TEXT_ADDR)
|
||||
endif
|
||||
|
40
repos/base-hw/src/lib/startup/spec/riscv/crt0.s
Normal file
40
repos/base-hw/src/lib/startup/spec/riscv/crt0.s
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* \brief Startup code for Genode applications
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2016-02-16
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.section ".text"
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
|
||||
/* load stack pointer */
|
||||
lla sp, _stack_high
|
||||
|
||||
/* relocate linker */
|
||||
jal init_rtld
|
||||
|
||||
/* create environment for main thread */
|
||||
jal init_main_thread
|
||||
|
||||
/* load stack pointer from init_main_thread_result */
|
||||
la sp, init_main_thread_result
|
||||
ld sp, (sp)
|
||||
|
||||
mv s0, x0
|
||||
|
||||
/* jump into init C-code */
|
||||
j _main
|
||||
|
||||
.bss
|
||||
.p2align 8
|
||||
.space 32*1024
|
||||
_stack_high:
|
Loading…
Reference in New Issue
Block a user