base-hw: initial RISC-V support

using the spike instruction emulator

issue #1880
This commit is contained in:
Sebastian Sumpf 2016-02-11 11:59:31 +01:00 committed by Christian Helmuth
parent ac70dfd9fe
commit c246a0d194
35 changed files with 2072 additions and 4 deletions

View 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_ */

View 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_ */

View 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_ */

View 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_ */

View 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_ */

View 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_ */

View File

@ -0,0 +1,3 @@
include $(REP_DIR)/lib/mk/base-common.inc
vpath kernel/interface.cc $(REP_DIR)/src/base/riscv

View 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

View File

@ -0,0 +1,3 @@
include $(call select_from_repositories,lib/mk/startup.inc)
vpath crt0.s $(REP_DIR)/src/lib/startup/spec/riscv

View 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)

View 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;
}

View File

@ -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:

View 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_ */

View 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_ */

View File

@ -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_ */

View 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_ */

View 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

View 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_ */

View 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_ */

View 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_ */

View 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_ */

View File

@ -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!"); }

View File

@ -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) {

View 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

View 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);
}

View 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;
}

View 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

View 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);
}

View 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());
}

View 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();
}

View 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]);
}

View 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:

View 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;
}

View File

@ -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

View 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: