2015-02-19 14:50:27 +01:00
|
|
|
/*
|
|
|
|
* \brief Kernel backend for virtual machines
|
|
|
|
* \author Stefan Kalkowski
|
|
|
|
* \date 2015-02-10
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 13:23:52 +01:00
|
|
|
* Copyright (C) 2015-2017 Genode Labs GmbH
|
2015-02-19 14:50:27 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2015-02-19 14:50:27 +01:00
|
|
|
*/
|
|
|
|
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
#include <base/log.h>
|
2017-02-21 13:46:59 +01:00
|
|
|
#include <hw/assert.h>
|
2019-03-21 13:59:30 +01:00
|
|
|
#include <cpu/vm_state_virtualization.h>
|
2017-02-21 13:46:59 +01:00
|
|
|
|
2015-02-19 14:50:27 +01:00
|
|
|
#include <platform_pd.h>
|
2017-10-05 16:11:24 +02:00
|
|
|
#include <kernel/cpu.h>
|
2015-02-19 14:50:27 +01:00
|
|
|
#include <kernel/vm.h>
|
|
|
|
|
|
|
|
namespace Kernel
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* ARM's virtual interrupt controller cpu interface
|
|
|
|
*/
|
|
|
|
struct Virtual_pic;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ARM's virtual timer counter
|
|
|
|
*/
|
|
|
|
struct Virtual_timer;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Kernel private virtualization interrupts, delivered to VM/VMMs
|
|
|
|
*/
|
|
|
|
struct Vm_irq;
|
|
|
|
}
|
|
|
|
|
|
|
|
using namespace Kernel;
|
|
|
|
|
2017-06-30 12:00:27 +02:00
|
|
|
extern "C" void kernel();
|
|
|
|
extern void * kernel_stack;
|
2019-09-04 15:38:19 +02:00
|
|
|
extern "C" void hypervisor_enter_vm(Genode::Vm_state&);
|
2017-06-30 12:00:27 +02:00
|
|
|
|
|
|
|
struct Host_context {
|
|
|
|
addr_t sp;
|
|
|
|
addr_t ip;
|
|
|
|
Cpu::Ttbr_64bit::access_t ttbr0;
|
|
|
|
Cpu::Ttbr_64bit::access_t ttbr1;
|
|
|
|
Cpu::Sctlr::access_t sctlr;
|
|
|
|
Cpu::Ttbcr::access_t ttbcr;
|
|
|
|
Cpu::Mair0::access_t mair0;
|
|
|
|
Cpu::Dacr::access_t dacr;
|
|
|
|
} vt_host_context;
|
2015-02-19 14:50:27 +01:00
|
|
|
|
|
|
|
|
2019-11-14 10:52:20 +01:00
|
|
|
Board::Vcpu_context::Vm_irq::Vm_irq(unsigned const irq, Cpu & cpu)
|
|
|
|
: Kernel::Irq(irq, cpu.irq_pool())
|
|
|
|
{ }
|
2015-02-19 14:50:27 +01:00
|
|
|
|
|
|
|
|
2019-11-14 10:52:20 +01:00
|
|
|
void Board::Vcpu_context::Vm_irq::handle(Cpu &, Vm & vm, unsigned irq) {
|
|
|
|
vm.inject_irq(irq); }
|
2015-02-19 14:50:27 +01:00
|
|
|
|
|
|
|
|
2019-11-14 10:52:20 +01:00
|
|
|
void Board::Vcpu_context::Vm_irq::occurred()
|
|
|
|
{
|
|
|
|
Cpu & cpu = Kernel::cpu_pool().executing_cpu();
|
|
|
|
Vm *vm = dynamic_cast<Vm*>(&cpu.scheduled_job());
|
|
|
|
if (!vm) Genode::raw("VM interrupt while VM is not runnning!");
|
|
|
|
else handle(cpu, *vm, _irq_nr);
|
|
|
|
}
|
2015-02-19 14:50:27 +01:00
|
|
|
|
|
|
|
|
2019-11-14 10:52:20 +01:00
|
|
|
Board::Vcpu_context::Pic_maintainance_irq::Pic_maintainance_irq(Cpu & cpu)
|
|
|
|
: Board::Vcpu_context::Vm_irq(Board::VT_MAINTAINANCE_IRQ, cpu) {
|
|
|
|
//FIXME Irq::enable only enables caller cpu
|
|
|
|
cpu.pic().unmask(_irq_nr, cpu.id()); }
|
2015-02-19 14:50:27 +01:00
|
|
|
|
2019-11-14 10:52:20 +01:00
|
|
|
Board::Vcpu_context::Virtual_timer_irq::Virtual_timer_irq(Cpu & cpu)
|
|
|
|
: irq(Board::VT_TIMER_IRQ, cpu) {}
|
2015-02-19 14:50:27 +01:00
|
|
|
|
|
|
|
|
2019-11-14 10:52:20 +01:00
|
|
|
void Board::Vcpu_context::Virtual_timer_irq::enable() { irq.enable(); }
|
2015-02-19 14:50:27 +01:00
|
|
|
|
|
|
|
|
2019-11-14 10:52:20 +01:00
|
|
|
void Board::Vcpu_context::Virtual_timer_irq::disable()
|
2015-02-19 14:50:27 +01:00
|
|
|
{
|
2019-11-14 10:52:20 +01:00
|
|
|
irq.disable();
|
|
|
|
asm volatile("mcr p15, 0, %0, c14, c3, 1" :: "r" (0));
|
|
|
|
asm volatile("mcr p15, 0, %0, c14, c1, 0" :: "r" (0b11));
|
|
|
|
}
|
2015-02-19 14:50:27 +01:00
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
using Vmid_allocator = Genode::Bit_allocator<256>;
|
|
|
|
|
|
|
|
static Vmid_allocator &alloc()
|
|
|
|
{
|
|
|
|
static Vmid_allocator * allocator = nullptr;
|
|
|
|
if (!allocator) {
|
|
|
|
allocator = unmanaged_singleton<Vmid_allocator>();
|
|
|
|
|
|
|
|
/* reserve VM ID 0 for the hypervisor */
|
|
|
|
unsigned id = allocator->alloc();
|
|
|
|
assert (id == 0);
|
|
|
|
}
|
|
|
|
return *allocator;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-04 15:38:19 +02:00
|
|
|
Kernel::Vm::Vm(unsigned, /* FIXME: smp support */
|
|
|
|
Genode::Vm_state & state,
|
|
|
|
Kernel::Signal_context & context,
|
2015-02-19 14:50:27 +01:00
|
|
|
void * const table)
|
2015-06-29 13:30:35 +02:00
|
|
|
: Cpu_job(Cpu_priority::MIN, 0),
|
2015-05-19 14:18:40 +02:00
|
|
|
_id(alloc().alloc()),
|
2019-09-04 15:38:19 +02:00
|
|
|
_state(state),
|
2015-02-19 14:50:27 +01:00
|
|
|
_context(context),
|
2019-09-04 15:38:19 +02:00
|
|
|
_table(table),
|
|
|
|
_vcpu_context(cpu_pool().primary_cpu())
|
2015-05-19 14:18:40 +02:00
|
|
|
{
|
base/core: use references instead of pointers
This patch replaces the former prominent use of pointers by references
wherever feasible. This has the following benefits:
* The contract between caller and callee becomes more obvious. When
passing a reference, the contract says that the argument cannot be
a null pointer. The caller is responsible to ensure that. Therefore,
the use of reference eliminates the need to add defensive null-pointer
checks at the callee site, which sometimes merely exist to be on the
safe side. The bottom line is that the code becomes easier to follow.
* Reference members must be initialized via an object initializer,
which promotes a programming style that avoids intermediate object-
construction states. Within core, there are still a few pointers
as member variables left though. E.g., caused by the late association
of 'Platform_thread' objects with their 'Platform_pd' objects.
* If no pointers are present as member variables, we don't need to
manually provide declarations of a private copy constructor and
an assignment operator to avoid -Weffc++ errors "class ... has
pointer data members [-Werror=effc++]".
This patch also changes a few system bindings on NOVA and Fiasco.OC,
e.g., the return value of the global 'cap_map' accessor has become a
reference. Hence, the patch touches a few places outside of core.
Fixes #3135
2019-01-24 22:00:01 +01:00
|
|
|
affinity(cpu_pool().primary_cpu());
|
2017-06-30 12:00:27 +02:00
|
|
|
|
2017-10-06 12:02:36 +02:00
|
|
|
vt_host_context.sp = _cpu->stack_start();
|
2017-06-30 12:00:27 +02:00
|
|
|
vt_host_context.ttbr0 = Cpu::Ttbr0_64bit::read();
|
|
|
|
vt_host_context.ttbr1 = Cpu::Ttbr1_64bit::read();
|
|
|
|
vt_host_context.sctlr = Cpu::Sctlr::read();
|
|
|
|
vt_host_context.ttbcr = Cpu::Ttbcr::read();
|
|
|
|
vt_host_context.mair0 = Cpu::Mair0::read();
|
|
|
|
vt_host_context.dacr = Cpu::Dacr::read();
|
|
|
|
vt_host_context.ip = (addr_t) &kernel;
|
2015-02-19 14:50:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-19 14:18:40 +02:00
|
|
|
Kernel::Vm::~Vm() { alloc().free(_id); }
|
|
|
|
|
|
|
|
|
2017-10-06 12:02:36 +02:00
|
|
|
void Kernel::Vm::exception(Cpu & cpu)
|
2015-02-19 14:50:27 +01:00
|
|
|
{
|
2019-09-04 15:38:19 +02:00
|
|
|
switch(_state.cpu_exception) {
|
2015-02-19 14:50:27 +01:00
|
|
|
case Genode::Cpu_state::INTERRUPT_REQUEST:
|
|
|
|
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
2017-10-06 12:02:36 +02:00
|
|
|
_interrupt(cpu.id());
|
2015-02-19 14:50:27 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pause();
|
2019-09-04 15:38:19 +02:00
|
|
|
_context.submit(1);
|
2015-02-19 14:50:27 +01:00
|
|
|
}
|
|
|
|
|
2019-11-14 10:52:20 +01:00
|
|
|
if (cpu.pic().ack_virtual_irq(_vcpu_context.pic))
|
|
|
|
inject_irq(Board::VT_MAINTAINANCE_IRQ);
|
|
|
|
_vcpu_context.vtimer_irq.disable();
|
2015-02-19 14:50:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-14 10:52:20 +01:00
|
|
|
void Kernel::Vm::proceed(Cpu & cpu)
|
2015-02-19 14:50:27 +01:00
|
|
|
{
|
2019-11-14 10:52:20 +01:00
|
|
|
if (_state.timer.irq) _vcpu_context.vtimer_irq.enable();
|
|
|
|
|
|
|
|
cpu.pic().insert_virtual_irq(_vcpu_context.pic, _state.irqs.virtual_irq);
|
|
|
|
|
2015-02-19 14:50:27 +01:00
|
|
|
/*
|
|
|
|
* the following values have to be enforced by the hypervisor
|
|
|
|
*/
|
2019-09-04 15:38:19 +02:00
|
|
|
_state.vttbr = Cpu::Ttbr_64bit::Ba::masked((Cpu::Ttbr_64bit::access_t)_table);
|
|
|
|
Cpu::Ttbr_64bit::Asid::set(_state.vttbr, _id);
|
2015-02-19 14:50:27 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* use the following report fields not needed for loading the context
|
|
|
|
* to transport the HSTR and HCR register descriptions into the assembler
|
|
|
|
* path in a dense way
|
|
|
|
*/
|
2019-11-14 10:52:20 +01:00
|
|
|
_state.esr_el2 = Cpu::Hstr::init();
|
|
|
|
_state.hpfar_el2 = Cpu::Hcr::init();
|
2015-02-19 14:50:27 +01:00
|
|
|
|
2019-09-04 15:38:19 +02:00
|
|
|
hypervisor_enter_vm(_state);
|
2015-02-19 14:50:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Vm::inject_irq(unsigned irq)
|
|
|
|
{
|
2019-11-14 10:52:20 +01:00
|
|
|
_state.irqs.last_irq = irq;
|
2015-02-19 14:50:27 +01:00
|
|
|
pause();
|
2019-09-04 15:38:19 +02:00
|
|
|
_context.submit(1);
|
2015-02-19 14:50:27 +01:00
|
|
|
}
|