genode/repos/base-hw/src/core/include/spec/riscv/cpu.h

164 lines
3.7 KiB
C++

/*
* \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"); };
/**
* From the manual
*
* The behavior of SFENCE.VM depends on the current value of the sasid
* register. If sasid is nonzero, SFENCE.VM takes effect only for address
* translations in the current address space. If sasid is zero, SFENCE.VM
* affects address translations for all address spaces. In this case, it
* also affects global mappings, which are described in Section 4.5.1.
*
* Right no we will flush anything
*/
static void sfence()
{
asm volatile ("csrrw t0, sasid, x0\n"
"sfence.vm\n"
"csrw sasid, t0\n"
: : : "t0");
}
/**
* Post processing after a translation was added to a translation table
*
* \param addr virtual address of the translation
* \param size size of the translation
*/
static void translation_added(addr_t const addr, size_t const size);
static void invalidate_tlb_by_pid(unsigned const pid) { sfence(); }
/**
* 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 addr_t sbadaddr()
{
addr_t addr;
asm volatile ("csrr %0, sbadaddr\n" : "=r"(addr));
return addr;
}
/*************
** Dummies **
*************/
void switch_to(User_context&) { }
};
#endif /* _CPU_H_ */