base-hw: initial RISC-V support
using the spike instruction emulator issue #1880
This commit is contained in:
parent
ac70dfd9fe
commit
c246a0d194
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
include $(REP_DIR)/lib/mk/base-common.inc
|
||||||
|
|
||||||
|
vpath kernel/interface.cc $(REP_DIR)/src/base/riscv
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
||||||
|
include $(call select_from_repositories,lib/mk/startup.inc)
|
||||||
|
|
||||||
|
vpath crt0.s $(REP_DIR)/src/lib/startup/spec/riscv
|
|
@ -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)
|
|
@ -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:
|
private:
|
||||||
|
|
||||||
Timer _timer;
|
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:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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 */
|
/* core includes */
|
||||||
#include <kernel/pd.h>
|
#include <kernel/pd.h>
|
||||||
|
#include <util.h>
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -56,7 +57,7 @@ void Mode_transition_control::map(Genode::Translation_table * tt,
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
addr_t const phys_base = (addr_t)&_mt_begin;
|
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);
|
Genode::Page_flags::mode_transition(), alloc);
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
PERR("Inserting exception vector in page table failed!"); }
|
PERR("Inserting exception vector in page table failed!"); }
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* \brief Protection-domain facility
|
* \brief Protection-domain facility
|
||||||
* \author Martin Stein
|
* \author Martin Stein
|
||||||
* \author Stefan Kalkowski
|
* \author Stefan Kalkowski
|
||||||
|
* \author Sebastian Sumpf
|
||||||
* \date 2012-02-12
|
* \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 =
|
const Page_flags flags =
|
||||||
Page_flags::apply_mapping(true, io_mem ? UNCACHED : CACHED, io_mem);
|
Page_flags::apply_mapping(true, io_mem ? UNCACHED : CACHED, io_mem);
|
||||||
|
|
||||||
start = trunc_page(start);
|
start = trunc_page(start);
|
||||||
size_t size = round_page(end) - 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 {
|
try {
|
||||||
_table()->insert_translation(start, start, size, flags, _table_alloc());
|
_table()->insert_translation(start, start, size, flags, _table_alloc());
|
||||||
} catch(Allocator::Out_of_memory) {
|
} catch(Allocator::Out_of_memory) {
|
||||||
|
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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]);
|
||||||
|
}
|
|
@ -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:
|
|
@ -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
|
# \brief Build config for Genodes core process
|
||||||
# \author Martin Stein
|
# \author Martin Stein
|
||||||
|
# \author Sebastian Sumpf
|
||||||
# \date 2011-12-16
|
# \date 2011-12-16
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -12,3 +13,7 @@ LIBS += core
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += kernel/test.cc
|
SRC_CC += kernel/test.cc
|
||||||
|
|
||||||
|
ifneq ($(filter riscv, $(SPECS)),)
|
||||||
|
LD_TEXT_ADDR = $(CORE_LD_TEXT_ADDR)
|
||||||
|
endif
|
||||||
|
|
|
@ -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