mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-09 04:15:52 +00:00
parent
7e79128c03
commit
cfab4e74a9
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM cpu object
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-07-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -37,16 +38,16 @@ Cpu_base::System_register::System_register(unsigned op0,
|
||||
}
|
||||
|
||||
|
||||
bool Cpu_base::_handle_sys_reg()
|
||||
bool Cpu_base::_handle_sys_reg(State & state)
|
||||
{
|
||||
using Iss = System_register::Iss;
|
||||
|
||||
Iss::access_t v = _state.esr_el2;
|
||||
Iss::access_t v = state.esr_el2;
|
||||
System_register * reg = _reg_tree.first();
|
||||
if (reg) reg = reg->find_by_encoding(Iss::mask_encoding(v));
|
||||
|
||||
if (!reg) {
|
||||
Genode::error("ignore unknown system register access @ ip=", (void*)_state.ip, ":");
|
||||
Genode::error("ignore unknown system register access @ ip=", (void*)state.ip, ":");
|
||||
Genode::error(Iss::Direction::get(v) ? "read" : "write",
|
||||
": "
|
||||
"op0=", Iss::Opcode0::get(v), " "
|
||||
@ -55,125 +56,138 @@ bool Cpu_base::_handle_sys_reg()
|
||||
"crn=", Iss::Crn::get(v), " "
|
||||
"crm=", Iss::Crm::get(v), " ",
|
||||
"op2=", Iss::Opcode2::get(v));
|
||||
if (Iss::Direction::get(v)) _state.reg(Iss::Register::get(v), 0);
|
||||
_state.ip += sizeof(Genode::uint32_t);
|
||||
if (Iss::Direction::get(v)) state.reg(Iss::Register::get(v), 0);
|
||||
state.ip += sizeof(Genode::uint32_t);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Iss::Direction::get(v)) { /* read access */
|
||||
_state.reg(Iss::Register::get(v), reg->read());
|
||||
state.reg(Iss::Register::get(v), reg->read());
|
||||
} else { /* write access */
|
||||
if (!reg->writeable()) {
|
||||
Genode::error("writing to system register ",
|
||||
reg->name(), " not allowed!");
|
||||
return false;
|
||||
}
|
||||
reg->write(_state.reg(Iss::Register::get(v)));
|
||||
reg->write(state.reg(Iss::Register::get(v)));
|
||||
}
|
||||
_state.ip += sizeof(Genode::uint32_t);
|
||||
state.ip += sizeof(Genode::uint32_t);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::_handle_wfi()
|
||||
void Cpu_base::_handle_wfi(State &state)
|
||||
{
|
||||
_state.ip += sizeof(Genode::uint32_t);
|
||||
state.ip += sizeof(Genode::uint32_t);
|
||||
|
||||
if (_state.esr_el2 & 1) return; /* WFE */
|
||||
if (state.esr_el2 & 1) return; /* WFE */
|
||||
|
||||
_active = false;
|
||||
_timer.schedule_timeout();
|
||||
_timer.schedule_timeout(state);
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::_handle_sync()
|
||||
void Cpu_base::_handle_startup(State &state)
|
||||
{
|
||||
Generic_timer::setup_state(state);
|
||||
Gic::Gicd_banked::setup_state(state);
|
||||
|
||||
setup_state(state);
|
||||
|
||||
if (cpu_id() == 0) {
|
||||
initialize_boot(state, _vm.kernel_addr(), _vm.dtb_addr());
|
||||
} else {
|
||||
_cpu_ready.down();
|
||||
}
|
||||
_active = true;
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::_handle_sync(State &state)
|
||||
{
|
||||
/* check device number*/
|
||||
switch (Esr::Ec::get(_state.esr_el2)) {
|
||||
switch (Esr::Ec::get(state.esr_el2)) {
|
||||
case Esr::Ec::HVC_32: [[fallthrough]];
|
||||
case Esr::Ec::HVC:
|
||||
_handle_hyper_call();
|
||||
_handle_hyper_call(state);
|
||||
break;
|
||||
case Esr::Ec::MRC_MCR: [[fallthrough]];
|
||||
case Esr::Ec::MRS_MSR:
|
||||
_handle_sys_reg();
|
||||
_handle_sys_reg(state);
|
||||
break;
|
||||
case Esr::Ec::DA:
|
||||
_handle_data_abort();
|
||||
_handle_data_abort(state);
|
||||
break;
|
||||
case Esr::Ec::WFI:
|
||||
_handle_wfi();
|
||||
_handle_wfi(state);
|
||||
return;
|
||||
case Esr::Ec::BRK:
|
||||
_handle_brk();
|
||||
_handle_brk(state);
|
||||
return;
|
||||
default:
|
||||
throw Exception("Unknown trap: ",
|
||||
Esr::Ec::get(_state.esr_el2));
|
||||
Esr::Ec::get(state.esr_el2));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::_handle_irq()
|
||||
void Cpu_base::_handle_irq(State &state)
|
||||
{
|
||||
switch (_state.irqs.last_irq) {
|
||||
switch (state.irqs.last_irq) {
|
||||
case VTIMER_IRQ:
|
||||
_timer.handle_irq();
|
||||
_timer.handle_irq(state);
|
||||
break;
|
||||
default:
|
||||
_gic.handle_irq();
|
||||
_gic.handle_irq(state);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::_handle_hyper_call()
|
||||
void Cpu_base::_handle_hyper_call(State &state)
|
||||
{
|
||||
switch(_state.reg(0)) {
|
||||
switch(state.reg(0)) {
|
||||
case Psci::PSCI_VERSION:
|
||||
_state.reg(0, Psci::VERSION);
|
||||
state.reg(0, Psci::VERSION);
|
||||
return;
|
||||
case Psci::MIGRATE_INFO_TYPE:
|
||||
_state.reg(0, Psci::NOT_SUPPORTED);
|
||||
state.reg(0, Psci::NOT_SUPPORTED);
|
||||
return;
|
||||
case Psci::PSCI_FEATURES:
|
||||
_state.reg(0, Psci::NOT_SUPPORTED);
|
||||
state.reg(0, Psci::NOT_SUPPORTED);
|
||||
return;
|
||||
case Psci::CPU_ON_32: [[fallthrough]];
|
||||
case Psci::CPU_ON:
|
||||
_vm.cpu((unsigned)_state.reg(1), [&] (Cpu & cpu) {
|
||||
cpu.state().ip = _state.reg(2);
|
||||
cpu.state().reg(0, _state.reg(3));
|
||||
cpu.run();
|
||||
_vm.cpu((unsigned)state.reg(1), [&] (Cpu & cpu) {
|
||||
State & local_state = cpu.state();
|
||||
cpu.initialize_boot(local_state, state.reg(2), state.reg(3));
|
||||
cpu.set_ready();
|
||||
});
|
||||
_state.reg(0, Psci::SUCCESS);
|
||||
state.reg(0, Psci::SUCCESS);
|
||||
return;
|
||||
default:
|
||||
Genode::warning("unknown hypercall! ", cpu_id());
|
||||
dump();
|
||||
dump(state);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::_handle_data_abort()
|
||||
void Cpu_base::_handle_data_abort(State &state)
|
||||
{
|
||||
_vm.bus().handle_memory_access(*static_cast<Cpu*>(this));
|
||||
_state.ip += sizeof(Genode::uint32_t);
|
||||
_vm.bus().handle_memory_access(state, *static_cast<Cpu *>(this));
|
||||
state.ip += sizeof(Genode::uint32_t);
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::_update_state()
|
||||
void Cpu_base::_update_state(State &state)
|
||||
{
|
||||
if (!_gic.pending_irq()) return;
|
||||
if (!_gic.pending_irq(state)) return;
|
||||
|
||||
_active = true;
|
||||
_timer.cancel_timeout();
|
||||
}
|
||||
|
||||
unsigned Cpu_base::cpu_id() const { return _vcpu_id; }
|
||||
void Cpu_base::run() { _vm_vcpu.run(); }
|
||||
void Cpu_base::pause() { _vm_vcpu.pause(); }
|
||||
bool Cpu_base::active() const { return _active; }
|
||||
Cpu_base::State & Cpu_base::state() const { return _state; }
|
||||
Gic::Gicd_banked & Cpu_base::gic() { return _gic; }
|
||||
|
||||
|
||||
@ -197,6 +211,5 @@ Cpu_base::Cpu_base(Vm & vm,
|
||||
_heap(heap),
|
||||
_vm_handler(*this, ep, *this, &Cpu_base::_handle_nothing),
|
||||
_vm_vcpu(_vm_session, heap, _vm_handler, _exit_config),
|
||||
_state(*((State*)(&_vm_vcpu.state()))),
|
||||
_gic(*this, gic, bus),
|
||||
_timer(env, ep, _gic.irq(VTIMER_IRQ), *this) { }
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM cpu object
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-07-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -16,6 +17,7 @@
|
||||
|
||||
#include <exception.h>
|
||||
#include <generic_timer.h>
|
||||
#include <state.h>
|
||||
|
||||
#include <base/env.h>
|
||||
#include <base/heap.h>
|
||||
@ -33,12 +35,6 @@ class Vmm::Cpu_base
|
||||
{
|
||||
public:
|
||||
|
||||
struct State : Genode::Vm_state
|
||||
{
|
||||
addr_t reg(addr_t idx) const;
|
||||
void reg(addr_t idx, addr_t v);
|
||||
};
|
||||
|
||||
struct Esr : Genode::Register<sizeof(addr_t)*8>
|
||||
{
|
||||
struct Ec : Bitfield<26, 6>
|
||||
@ -65,28 +61,55 @@ class Vmm::Cpu_base
|
||||
unsigned cpu_id);
|
||||
|
||||
unsigned cpu_id() const;
|
||||
void run();
|
||||
void pause();
|
||||
bool active() const;
|
||||
State & state() const;
|
||||
Gic::Gicd_banked & gic();
|
||||
void dump();
|
||||
void handle_exception();
|
||||
void dump(State & state);
|
||||
void handle_exception(State &state);
|
||||
void recall();
|
||||
void initialize_boot(Genode::addr_t ip,
|
||||
void initialize_boot(State &state,
|
||||
Genode::addr_t ip,
|
||||
Genode::addr_t dtb);
|
||||
virtual void setup_state(State &) { };
|
||||
|
||||
virtual ~Cpu_base() = default;
|
||||
|
||||
State & state() {
|
||||
return _state->ref;
|
||||
}
|
||||
|
||||
template<typename FN>
|
||||
void with_state(FN const & fn)
|
||||
{
|
||||
_vm_vcpu.with_state(fn);
|
||||
}
|
||||
|
||||
void set_ready() {
|
||||
_cpu_ready.up();
|
||||
}
|
||||
|
||||
template <typename FUNC>
|
||||
void handle_signal(FUNC handler)
|
||||
{
|
||||
if (active()) {
|
||||
pause();
|
||||
handle_exception();
|
||||
}
|
||||
_vm_vcpu.with_state([this, handler](Vm_state &vmstate) {
|
||||
State & state = static_cast<State &>(vmstate);
|
||||
_state.construct(state);
|
||||
|
||||
handler();
|
||||
_update_state();
|
||||
if (active()) run();
|
||||
try {
|
||||
if (active()) {
|
||||
handle_exception(state);
|
||||
}
|
||||
|
||||
handler(state);
|
||||
_update_state(state);
|
||||
} catch(Exception &e) {
|
||||
Genode::error(e);
|
||||
dump(state);
|
||||
return false;
|
||||
}
|
||||
|
||||
_state.destruct();
|
||||
return active();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -100,12 +123,7 @@ class Vmm::Cpu_base
|
||||
|
||||
void handle()
|
||||
{
|
||||
try {
|
||||
cpu.handle_signal([this] () { (obj.*member)(); });
|
||||
} catch(Exception &e) {
|
||||
Genode::error(e);
|
||||
cpu.dump();
|
||||
}
|
||||
cpu.handle_signal([this] (Vm_state &) { (obj.*member)(); });
|
||||
}
|
||||
|
||||
Signal_handler(Cpu_base & cpu,
|
||||
@ -207,16 +225,20 @@ class Vmm::Cpu_base
|
||||
return (r->_encoding > _encoding); }
|
||||
};
|
||||
|
||||
unsigned _vcpu_id;
|
||||
bool _active { true };
|
||||
Vm & _vm;
|
||||
Genode::Vm_connection & _vm_session;
|
||||
Genode::Heap & _heap;
|
||||
Signal_handler<Cpu_base> _vm_handler;
|
||||
Genode::Vm_connection::Exit_config _exit_config { };
|
||||
Genode::Vm_connection::Vcpu _vm_vcpu;
|
||||
State & _state;
|
||||
Genode::Avl_tree<System_register> _reg_tree {};
|
||||
struct State_container { State &ref; };
|
||||
|
||||
unsigned _vcpu_id;
|
||||
bool _active { true };
|
||||
Vm & _vm;
|
||||
Genode::Vm_connection & _vm_session;
|
||||
Genode::Heap & _heap;
|
||||
Signal_handler<Cpu_base> _vm_handler;
|
||||
Genode::Vm_connection::Exit_config _exit_config { };
|
||||
Genode::Vm_connection::Vcpu _vm_vcpu;
|
||||
Genode::Avl_tree<System_register> _reg_tree {};
|
||||
Genode::Constructible<State_container> _state {};
|
||||
Semaphore _cpu_ready {};
|
||||
|
||||
|
||||
|
||||
/***********************
|
||||
@ -227,14 +249,15 @@ class Vmm::Cpu_base
|
||||
Generic_timer _timer;
|
||||
|
||||
void _handle_nothing() {}
|
||||
bool _handle_sys_reg();
|
||||
void _handle_brk();
|
||||
void _handle_wfi();
|
||||
void _handle_sync();
|
||||
void _handle_irq();
|
||||
void _handle_data_abort();
|
||||
void _handle_hyper_call();
|
||||
void _update_state();
|
||||
void _handle_startup(State &state);
|
||||
bool _handle_sys_reg(State &state);
|
||||
void _handle_brk(State &state);
|
||||
void _handle_wfi(State &state);
|
||||
void _handle_sync(State &state);
|
||||
void _handle_irq(State &state);
|
||||
void _handle_data_abort(State &state);
|
||||
void _handle_hyper_call(State &state);
|
||||
void _update_state(State &state);
|
||||
|
||||
public:
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM ARM Generic timer device model
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-08-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -16,22 +17,28 @@
|
||||
|
||||
using Vmm::Generic_timer;
|
||||
|
||||
bool Generic_timer::_enabled() {
|
||||
return Ctrl::Enabled::get(_cpu.state().timer.control); }
|
||||
bool Generic_timer::_enabled(Vm_state &state)
|
||||
{
|
||||
return Ctrl::Enabled::get(state.timer.control);
|
||||
}
|
||||
|
||||
bool Generic_timer::_masked(Vm_state &state)
|
||||
{
|
||||
return Ctrl::Imask::get(state.timer.control);
|
||||
}
|
||||
|
||||
|
||||
bool Generic_timer::_masked() {
|
||||
return Ctrl::Imask::get(_cpu.state().timer.control); }
|
||||
|
||||
|
||||
bool Generic_timer::_pending() {
|
||||
return Ctrl::Istatus::get(_cpu.state().timer.control); }
|
||||
bool Generic_timer::_pending(Vm_state &state)
|
||||
{
|
||||
return Ctrl::Istatus::get(state.timer.control);
|
||||
}
|
||||
|
||||
|
||||
void Generic_timer::_handle_timeout(Genode::Duration)
|
||||
{
|
||||
_cpu.handle_signal([this] (void) {
|
||||
if (_enabled() && !_masked()) handle_irq();
|
||||
_cpu.handle_signal([this](Vm_state &state) {
|
||||
if (_enabled(state) && !_masked(state))
|
||||
handle_irq(state);
|
||||
});
|
||||
}
|
||||
|
||||
@ -45,20 +52,19 @@ Generic_timer::Generic_timer(Genode::Env & env,
|
||||
_irq(irq),
|
||||
_cpu(cpu)
|
||||
{
|
||||
_cpu.state().timer.irq = true;
|
||||
_irq.handler(*this);
|
||||
}
|
||||
|
||||
|
||||
void Generic_timer::schedule_timeout()
|
||||
void Generic_timer::schedule_timeout(Vm_state &state)
|
||||
{
|
||||
if (_pending()) {
|
||||
handle_irq();
|
||||
if (_pending(state)) {
|
||||
handle_irq(state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_enabled()) {
|
||||
Genode::uint64_t usecs = _usecs_left();
|
||||
if (_enabled(state)) {
|
||||
Genode::uint64_t usecs = _usecs_left(state);
|
||||
if (usecs) {
|
||||
_timeout.schedule(Genode::Microseconds(usecs));
|
||||
} else _handle_timeout(Genode::Duration(Genode::Microseconds(0)));
|
||||
@ -72,23 +78,29 @@ void Generic_timer::cancel_timeout()
|
||||
}
|
||||
|
||||
|
||||
void Generic_timer::handle_irq()
|
||||
void Generic_timer::handle_irq(Vm_state &state)
|
||||
{
|
||||
_irq.assert();
|
||||
_cpu.state().timer.irq = false;
|
||||
state.timer.irq = false;
|
||||
}
|
||||
|
||||
|
||||
void Generic_timer::eoi()
|
||||
{
|
||||
_cpu.state().timer.irq = true;
|
||||
Genode::Vm_state &state = _cpu.state();
|
||||
state.timer.irq = false;
|
||||
};
|
||||
|
||||
|
||||
void Generic_timer::dump()
|
||||
void Generic_timer::dump(Vm_state &state)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
log(" timer.ctl = ", Hex(_cpu.state().timer.control, Hex::PREFIX, Hex::PAD));
|
||||
log(" timer.cmp = ", Hex(_cpu.state().timer.compare, Hex::PREFIX, Hex::PAD));
|
||||
log(" timer.ctl = ", Hex(state.timer.control, Hex::PREFIX, Hex::PAD));
|
||||
log(" timer.cmp = ", Hex(state.timer.compare, Hex::PREFIX, Hex::PAD));
|
||||
}
|
||||
|
||||
void Generic_timer::setup_state(Vm_state &state)
|
||||
{
|
||||
state.timer.irq = true;
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM ARM Generic timer device model
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-08-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -26,6 +27,8 @@ namespace Vmm {
|
||||
class Generic_timer;
|
||||
}
|
||||
|
||||
using Genode::Vm_state;
|
||||
|
||||
class Vmm::Generic_timer : Gic::Irq::Irq_handler
|
||||
{
|
||||
private:
|
||||
@ -44,12 +47,12 @@ class Vmm::Generic_timer : Gic::Irq::Irq_handler
|
||||
|
||||
Genode::uint64_t _ticks_per_ms();
|
||||
|
||||
bool _enabled();
|
||||
bool _masked();
|
||||
bool _pending();
|
||||
bool _enabled(Vm_state &state);
|
||||
bool _masked(Vm_state &state);
|
||||
bool _pending(Vm_state &state);
|
||||
|
||||
void _handle_timeout(Genode::Duration);
|
||||
Genode::uint64_t _usecs_left();
|
||||
Genode::uint64_t _usecs_left(Vm_state &state);
|
||||
|
||||
public:
|
||||
|
||||
@ -58,10 +61,11 @@ class Vmm::Generic_timer : Gic::Irq::Irq_handler
|
||||
Gic::Irq & irq,
|
||||
Cpu_base & cpu);
|
||||
|
||||
void schedule_timeout();
|
||||
void schedule_timeout(Vm_state &state);
|
||||
void cancel_timeout();
|
||||
void handle_irq();
|
||||
void dump();
|
||||
void handle_irq(Vm_state &state);
|
||||
void dump(Vm_state &state);
|
||||
static void setup_state(Vm_state &state);
|
||||
|
||||
|
||||
/*****************
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM ARM Generic Interrupt Controller v2 device model
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-08-05
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -163,29 +164,30 @@ Gic::Irq & Gic::Gicd_banked::irq(unsigned i)
|
||||
}
|
||||
|
||||
|
||||
void Gic::Gicd_banked::handle_irq()
|
||||
void Gic::Gicd_banked::handle_irq(State &state)
|
||||
{
|
||||
unsigned i = _cpu.state().irqs.virtual_irq;
|
||||
unsigned i = state.irqs.virtual_irq;
|
||||
if (i > MAX_IRQ) return;
|
||||
|
||||
irq(i).deassert();
|
||||
|
||||
_cpu.state().irqs.virtual_irq = SPURIOUS;
|
||||
state.irqs.virtual_irq = SPURIOUS;
|
||||
}
|
||||
|
||||
|
||||
bool Gic::Gicd_banked::pending_irq()
|
||||
bool Gic::Gicd_banked::pending_irq(State &state)
|
||||
{
|
||||
Genode::Mutex::Guard guard(big_gic_lock());
|
||||
|
||||
if (_cpu.state().irqs.virtual_irq != SPURIOUS) return true;
|
||||
if (state.irqs.virtual_irq != SPURIOUS)
|
||||
return true;
|
||||
|
||||
Irq * i = _gic._pending_list.highest_enabled();
|
||||
Irq * j = _pending_list.highest_enabled();
|
||||
Irq * n = j;
|
||||
if (i && ((j && j->priority() > i->priority()) || !j)) n = i;
|
||||
if (!n) return false;
|
||||
_cpu.state().irqs.virtual_irq = n->number();
|
||||
state.irqs.virtual_irq = n->number();
|
||||
n->activate();
|
||||
return true;
|
||||
}
|
||||
@ -200,8 +202,6 @@ Gic::Gicd_banked::Gicd_banked(Cpu_base & cpu, Gic & gic, Mmio_bus & bus)
|
||||
for (unsigned i = 0; i < MAX_PPI; i++)
|
||||
_ppi[i].construct(i+MAX_SGI, Irq::PPI, _pending_list);
|
||||
|
||||
_cpu.state().irqs.last_irq = SPURIOUS;
|
||||
_cpu.state().irqs.virtual_irq = SPURIOUS;
|
||||
|
||||
if (gic.version() >= 3) {
|
||||
_rdist.construct(GICR_MMIO_START +
|
||||
@ -211,6 +211,12 @@ Gic::Gicd_banked::Gicd_banked(Cpu_base & cpu, Gic & gic, Mmio_bus & bus)
|
||||
}
|
||||
}
|
||||
|
||||
void Gic::Gicd_banked::setup_state(State &state)
|
||||
{
|
||||
state.irqs.last_irq = SPURIOUS;
|
||||
state.irqs.virtual_irq = SPURIOUS;
|
||||
}
|
||||
|
||||
|
||||
Register Gic::Irq_reg::read(Address_range & access, Cpu & cpu)
|
||||
{
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM ARM Generic Interrupt Controller device model
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-08-05
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -15,6 +16,7 @@
|
||||
#define _SRC__SERVER__VMM__GIC_H_
|
||||
|
||||
#include <mmio.h>
|
||||
#include <state.h>
|
||||
|
||||
#include <base/env.h>
|
||||
#include <drivers/defs/arm_v7.h>
|
||||
@ -134,9 +136,10 @@ class Vmm::Gic : public Vmm::Mmio_device
|
||||
{
|
||||
public:
|
||||
|
||||
Irq & irq(unsigned num);
|
||||
void handle_irq();
|
||||
bool pending_irq();
|
||||
Irq & irq(unsigned num);
|
||||
void handle_irq(State &state);
|
||||
bool pending_irq(State &state);
|
||||
static void setup_state(State &state);
|
||||
|
||||
Gicd_banked(Cpu_base & cpu, Gic & gic, Mmio_bus & bus);
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM mmio abstractions
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-07-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -79,12 +80,10 @@ void Mmio_device::write(Address_range & access, Cpu & cpu, Register value)
|
||||
void Mmio_device::add(Mmio_register & reg) { _registers.add(reg); }
|
||||
|
||||
|
||||
void Vmm::Mmio_bus::handle_memory_access(Vmm::Cpu & cpu)
|
||||
void Vmm::Mmio_bus::handle_memory_access(State &state, Vmm::Cpu &cpu)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
Cpu::State & state = cpu.state();
|
||||
|
||||
struct Iss : Cpu::Esr
|
||||
{
|
||||
struct Write : Bitfield<6, 1> {};
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM mmio abstractions
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-07-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -15,6 +16,7 @@
|
||||
#define _SRC__SERVER__VMM__MMIO_H_
|
||||
|
||||
#include <address_space.h>
|
||||
#include <state.h>
|
||||
|
||||
namespace Vmm {
|
||||
class Cpu;
|
||||
@ -98,7 +100,7 @@ class Vmm::Mmio_device : public Vmm::Address_range
|
||||
|
||||
struct Vmm::Mmio_bus : Vmm::Address_space
|
||||
{
|
||||
void handle_memory_access(Cpu & cpu);
|
||||
void handle_memory_access(State &state, Cpu &cpu);
|
||||
};
|
||||
|
||||
#endif /* _SRC__SERVER__VMM__MMIO_H_ */
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM cpu object
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-07-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -13,13 +14,14 @@
|
||||
#include <cpu.h>
|
||||
#include <vm.h>
|
||||
#include <psci.h>
|
||||
#include <state.h>
|
||||
|
||||
using Vmm::Cpu_base;
|
||||
using Vmm::Cpu;
|
||||
using Vmm::Gic;
|
||||
using namespace Genode;
|
||||
|
||||
addr_t Cpu_base::State::reg(addr_t idx) const
|
||||
addr_t Vmm::State::reg(addr_t idx) const
|
||||
{
|
||||
if (idx > 15) return 0;
|
||||
|
||||
@ -29,7 +31,7 @@ addr_t Cpu_base::State::reg(addr_t idx) const
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::State::reg(addr_t idx, addr_t v)
|
||||
void Vmm::State::reg(addr_t idx, addr_t v)
|
||||
{
|
||||
if (idx > 15) return;
|
||||
|
||||
@ -62,29 +64,30 @@ Cpu_base::System_register::Iss::mask_encoding(access_t v)
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::_handle_brk()
|
||||
void Cpu_base::_handle_brk(State &)
|
||||
{
|
||||
error(__func__, " not implemented yet");
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::handle_exception()
|
||||
void Cpu_base::handle_exception(State & state)
|
||||
{
|
||||
/* check exception reason */
|
||||
switch (_state.cpu_exception) {
|
||||
switch (state.cpu_exception) {
|
||||
case Cpu::NO_EXCEPTION: break;
|
||||
case Cpu::FIQ: [[fallthrough]];
|
||||
case Cpu::IRQ: _handle_irq(); break;
|
||||
case Cpu::TRAP: _handle_sync(); break;
|
||||
case Cpu::IRQ: _handle_irq(state); break;
|
||||
case Cpu::TRAP: _handle_sync(state); break;
|
||||
case VCPU_EXCEPTION_STARTUP: _handle_startup(state); break;
|
||||
default:
|
||||
throw Exception("Curious exception ",
|
||||
_state.cpu_exception, " occured");
|
||||
state.cpu_exception, " occured");
|
||||
}
|
||||
_state.cpu_exception = Cpu::NO_EXCEPTION;
|
||||
state.cpu_exception = Cpu::NO_EXCEPTION;
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::dump()
|
||||
void Cpu_base::dump(State &state)
|
||||
{
|
||||
auto lambda = [] (unsigned i) {
|
||||
switch (i) {
|
||||
@ -100,37 +103,37 @@ void Cpu_base::dump()
|
||||
log("VM state (", _active ? "active" : "inactive", ") :");
|
||||
for (unsigned i = 0; i < 13; i++) {
|
||||
log(" r", i, " = ",
|
||||
Hex(_state.reg(i), Hex::PREFIX, Hex::PAD));
|
||||
Hex(state.reg(i), Hex::PREFIX, Hex::PAD));
|
||||
}
|
||||
log(" sp = ", Hex(_state.sp, Hex::PREFIX, Hex::PAD));
|
||||
log(" lr = ", Hex(_state.lr, Hex::PREFIX, Hex::PAD));
|
||||
log(" ip = ", Hex(_state.ip, Hex::PREFIX, Hex::PAD));
|
||||
log(" cpsr = ", Hex(_state.cpsr, Hex::PREFIX, Hex::PAD));
|
||||
log(" sp = ", Hex(state.sp, Hex::PREFIX, Hex::PAD));
|
||||
log(" lr = ", Hex(state.lr, Hex::PREFIX, Hex::PAD));
|
||||
log(" ip = ", Hex(state.ip, Hex::PREFIX, Hex::PAD));
|
||||
log(" cpsr = ", Hex(state.cpsr, Hex::PREFIX, Hex::PAD));
|
||||
for (unsigned i = 0; i < State::Mode_state::MAX; i++) {
|
||||
log(" sp_", lambda(i), " = ",
|
||||
Hex(_state.mode[i].sp, Hex::PREFIX, Hex::PAD));
|
||||
Hex(state.mode[i].sp, Hex::PREFIX, Hex::PAD));
|
||||
log(" lr_", lambda(i), " = ",
|
||||
Hex(_state.mode[i].lr, Hex::PREFIX, Hex::PAD));
|
||||
Hex(state.mode[i].lr, Hex::PREFIX, Hex::PAD));
|
||||
log(" spsr_", lambda(i), " = ",
|
||||
Hex(_state.mode[i].spsr, Hex::PREFIX, Hex::PAD));
|
||||
Hex(state.mode[i].spsr, Hex::PREFIX, Hex::PAD));
|
||||
}
|
||||
log(" exception = ", _state.cpu_exception);
|
||||
log(" esr_el2 = ", Hex(_state.esr_el2, Hex::PREFIX, Hex::PAD));
|
||||
log(" hpfar_el2 = ", Hex(_state.hpfar_el2, Hex::PREFIX, Hex::PAD));
|
||||
log(" far_el2 = ", Hex(_state.far_el2, Hex::PREFIX, Hex::PAD));
|
||||
log(" hifar = ", Hex(_state.hifar, Hex::PREFIX, Hex::PAD));
|
||||
log(" dfsr = ", Hex(_state.dfsr, Hex::PREFIX, Hex::PAD));
|
||||
log(" ifsr = ", Hex(_state.ifsr, Hex::PREFIX, Hex::PAD));
|
||||
log(" sctrl = ", Hex(_state.sctrl, Hex::PREFIX, Hex::PAD));
|
||||
_timer.dump();
|
||||
log(" exception = ", state.cpu_exception);
|
||||
log(" esr_el2 = ", Hex(state.esr_el2, Hex::PREFIX, Hex::PAD));
|
||||
log(" hpfar_el2 = ", Hex(state.hpfar_el2, Hex::PREFIX, Hex::PAD));
|
||||
log(" far_el2 = ", Hex(state.far_el2, Hex::PREFIX, Hex::PAD));
|
||||
log(" hifar = ", Hex(state.hifar, Hex::PREFIX, Hex::PAD));
|
||||
log(" dfsr = ", Hex(state.dfsr, Hex::PREFIX, Hex::PAD));
|
||||
log(" ifsr = ", Hex(state.ifsr, Hex::PREFIX, Hex::PAD));
|
||||
log(" sctrl = ", Hex(state.sctrl, Hex::PREFIX, Hex::PAD));
|
||||
_timer.dump(state);
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::initialize_boot(addr_t ip, addr_t dtb)
|
||||
void Cpu_base::initialize_boot(State &state, addr_t ip, addr_t dtb)
|
||||
{
|
||||
state().reg(1, 0xffffffff); /* invalid machine type */
|
||||
state().reg(2, dtb);
|
||||
state().ip = ip;
|
||||
state.reg(1, 0xffffffff); /* invalid machine type */
|
||||
state.reg(2, dtb);
|
||||
state.ip = ip;
|
||||
}
|
||||
|
||||
|
||||
@ -153,6 +156,13 @@ addr_t Cpu::Ccsidr::read() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Cpu::setup_state(State &state)
|
||||
{
|
||||
state.cpsr = 0x93; /* el1 mode and IRQs disabled */
|
||||
state.sctrl = 0xc50078;
|
||||
state.vmpidr = (1UL << 31) | cpu_id();
|
||||
}
|
||||
|
||||
|
||||
Cpu::Cpu(Vm & vm,
|
||||
Vm_connection & vm_session,
|
||||
@ -184,7 +194,4 @@ Cpu::Cpu(Vm & vm,
|
||||
_sr_ccsidr (_sr_csselr, _reg_tree),
|
||||
_sr_actlr (1, 0, 0, 1, "ACTLR", true, 0x0, _reg_tree)
|
||||
{
|
||||
_state.cpsr = 0x93; /* el1 mode and IRQs disabled */
|
||||
_state.sctrl = 0xc50078;
|
||||
_state.vmpidr = (1UL << 31) | cpu_id();
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM cpu object
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-07-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -40,9 +41,11 @@ class Vmm::Cpu : public Vmm::Cpu_base
|
||||
DATA_ABORT,
|
||||
IRQ,
|
||||
FIQ,
|
||||
TRAP
|
||||
TRAP,
|
||||
};
|
||||
|
||||
void setup_state(State & state) override;
|
||||
|
||||
private:
|
||||
|
||||
struct Ccsidr : System_register
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM ARM Generic timer device model
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-08-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -28,14 +29,14 @@ Genode::uint64_t Generic_timer::_ticks_per_ms()
|
||||
}
|
||||
|
||||
|
||||
Genode::uint64_t Generic_timer::_usecs_left()
|
||||
Genode::uint64_t Generic_timer::_usecs_left(Vm_state &state)
|
||||
{
|
||||
Genode::uint64_t count;
|
||||
Genode::uint32_t low, high;
|
||||
asm volatile("mrrc p15, 0, %0, %1, c14" : "=r" (low), "=r" (high));
|
||||
count = (Genode::uint64_t)high << 32 | (Genode::uint64_t)low;
|
||||
count -= _cpu.state().timer.offset;
|
||||
if (count > _cpu.state().timer.compare) return 0;
|
||||
return Genode::timer_ticks_to_us(_cpu.state().timer.compare - count,
|
||||
count -= state.timer.offset;
|
||||
if (count > state.timer.compare) return 0;
|
||||
return Genode::timer_ticks_to_us(state.timer.compare - count,
|
||||
_ticks_per_ms());
|
||||
}
|
||||
|
@ -1,16 +1,18 @@
|
||||
/*
|
||||
* \brief VMM cpu object
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-07-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
#include <cpu.h>
|
||||
#include <state.h>
|
||||
#include <vm.h>
|
||||
#include <psci.h>
|
||||
|
||||
@ -19,14 +21,14 @@ using Vmm::Cpu;
|
||||
using Vmm::Gic;
|
||||
using namespace Genode;
|
||||
|
||||
addr_t Cpu_base::State::reg(addr_t idx) const
|
||||
addr_t Vmm::State::reg(addr_t idx) const
|
||||
{
|
||||
if (idx > 30) return 0;
|
||||
return r[idx];
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::State::reg(addr_t idx, addr_t v)
|
||||
void Vmm::State::reg(addr_t idx, addr_t v)
|
||||
{
|
||||
if (idx > 30) return;
|
||||
r[idx] = v;
|
||||
@ -58,40 +60,41 @@ Cpu_base::System_register::Iss::mask_encoding(access_t v)
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::_handle_brk()
|
||||
void Cpu_base::_handle_brk(State & state)
|
||||
{
|
||||
addr_t offset = 0x0;
|
||||
if (!(_state.pstate & 0b100)) {
|
||||
if (!(state.pstate & 0b100)) {
|
||||
offset = 0x400;
|
||||
} else if (_state.pstate & 0b1) {
|
||||
} else if (state.pstate & 0b1) {
|
||||
offset = 0x200;
|
||||
}
|
||||
|
||||
/* only the below 32-bit of system register ESR_EL2 and PSTATE are used */
|
||||
_state.esr_el1 = (uint32_t)_state.esr_el2;
|
||||
_state.spsr_el1 = (uint32_t)_state.pstate;
|
||||
_state.elr_el1 = _state.ip;
|
||||
_state.ip = _state.vbar_el1 + offset;
|
||||
_state.pstate = 0b1111000101;
|
||||
state.esr_el1 = (uint32_t)state.esr_el2;
|
||||
state.spsr_el1 = (uint32_t)state.pstate;
|
||||
state.elr_el1 = state.ip;
|
||||
state.ip = state.vbar_el1 + offset;
|
||||
state.pstate = 0b1111000101;
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::handle_exception()
|
||||
void Cpu_base::handle_exception(State &state)
|
||||
{
|
||||
/* check exception reason */
|
||||
switch (_state.exception_type) {
|
||||
switch (state.exception_type) {
|
||||
case Cpu::NO_EXCEPTION: break;
|
||||
case Cpu::AARCH64_IRQ: _handle_irq(); break;
|
||||
case Cpu::AARCH64_SYNC: _handle_sync(); break;
|
||||
case Cpu::AARCH64_IRQ: _handle_irq(state); break;
|
||||
case Cpu::AARCH64_SYNC: _handle_sync(state); break;
|
||||
case VCPU_EXCEPTION_STARTUP: _handle_startup(state); break;
|
||||
default:
|
||||
throw Exception("Curious exception ",
|
||||
_state.exception_type, " occured");
|
||||
state.exception_type, " occured");
|
||||
}
|
||||
_state.exception_type = Cpu::NO_EXCEPTION;
|
||||
state.exception_type = Cpu::NO_EXCEPTION;
|
||||
}
|
||||
|
||||
|
||||
void Cpu_base::dump()
|
||||
void Cpu_base::dump(State &state)
|
||||
{
|
||||
auto lambda = [] (addr_t exc) {
|
||||
switch (exc) {
|
||||
@ -110,22 +113,24 @@ void Cpu_base::dump()
|
||||
log("VM state (", _active ? "active" : "inactive", ") :");
|
||||
for (unsigned i = 0; i < 31; i++) {
|
||||
log(" r", i, " = ",
|
||||
Hex(_state.r[i], Hex::PREFIX, Hex::PAD));
|
||||
Hex(state.r[i], Hex::PREFIX, Hex::PAD));
|
||||
}
|
||||
log(" sp = ", Hex(_state.sp, Hex::PREFIX, Hex::PAD));
|
||||
log(" ip = ", Hex(_state.ip, Hex::PREFIX, Hex::PAD));
|
||||
log(" sp_el1 = ", Hex(_state.sp_el1, Hex::PREFIX, Hex::PAD));
|
||||
log(" elr_el1 = ", Hex(_state.elr_el1, Hex::PREFIX, Hex::PAD));
|
||||
log(" pstate = ", Hex(_state.pstate, Hex::PREFIX, Hex::PAD));
|
||||
log(" exception = ", _state.exception_type, " (",
|
||||
lambda(_state.exception_type), ")");
|
||||
log(" esr_el2 = ", Hex(_state.esr_el2, Hex::PREFIX, Hex::PAD));
|
||||
_timer.dump();
|
||||
log(" sp = ", Hex(state.sp, Hex::PREFIX, Hex::PAD));
|
||||
log(" ip = ", Hex(state.ip, Hex::PREFIX, Hex::PAD));
|
||||
log(" sp_el1 = ", Hex(state.sp_el1, Hex::PREFIX, Hex::PAD));
|
||||
log(" elr_el1 = ", Hex(state.elr_el1, Hex::PREFIX, Hex::PAD));
|
||||
log(" pstate = ", Hex(state.pstate, Hex::PREFIX, Hex::PAD));
|
||||
log(" exception = ", state.exception_type, " (",
|
||||
lambda(state.exception_type), ")");
|
||||
log(" esr_el2 = ", Hex(state.esr_el2, Hex::PREFIX, Hex::PAD));
|
||||
_timer.dump(state);
|
||||
}
|
||||
|
||||
|
||||
addr_t Cpu::Ccsidr::read() const
|
||||
{
|
||||
State & state = cpu.state();
|
||||
|
||||
struct Clidr : Genode::Register<32>
|
||||
{
|
||||
enum Cache_entry {
|
||||
@ -198,10 +203,25 @@ void Cpu::Icc_sgi1r_el1::write(addr_t v)
|
||||
};
|
||||
|
||||
|
||||
void Cpu_base::initialize_boot(addr_t ip, addr_t dtb)
|
||||
void Cpu_base::initialize_boot(State &state, addr_t ip, addr_t dtb)
|
||||
{
|
||||
state().reg(0, dtb);
|
||||
state().ip = ip;
|
||||
state.reg(0, dtb);
|
||||
state.ip = ip;
|
||||
}
|
||||
|
||||
|
||||
void Cpu::setup_state(State &state)
|
||||
{
|
||||
_sr_id_aa64isar0_el1.write(state.id_aa64isar0_el1);
|
||||
_sr_id_aa64isar1_el1.write(state.id_aa64isar1_el1);
|
||||
_sr_id_aa64mmfr0_el1.write(state.id_aa64mmfr0_el1);
|
||||
_sr_id_aa64mmfr1_el1.write(state.id_aa64mmfr1_el1);
|
||||
_sr_id_aa64mmfr2_el1.write(state.id_aa64mmfr2_el1);
|
||||
_sr_id_aa64pfr0_el1.write( _sr_id_aa64pfr0_el1.reset_value(
|
||||
state.id_aa64pfr0_el1));
|
||||
_sr_clidr_el1.write(state.clidr_el1);
|
||||
state.pstate = 0b1111000101; /* el1 mode and IRQs disabled */
|
||||
state.vmpidr_el2 = cpu_id();
|
||||
}
|
||||
|
||||
|
||||
@ -218,20 +238,20 @@ Cpu::Cpu(Vm & vm,
|
||||
_sr_id_aa64afr1_el1 (3, 0, 0, 5, 5, "ID_AA64AFR1_EL1", false, 0x0, _reg_tree),
|
||||
_sr_id_aa64dfr0_el1 (3, 0, 0, 5, 0, "ID_AA64DFR0_EL1", false, 0x6, _reg_tree),
|
||||
_sr_id_aa64dfr1_el1 (3, 0, 0, 5, 1, "ID_AA64DFR1_EL1", false, 0x0, _reg_tree),
|
||||
_sr_id_aa64isar0_el1(3, 0, 0, 6, 0, "ID_AA64ISAR0_EL1", false, _state.id_aa64isar0_el1, _reg_tree),
|
||||
_sr_id_aa64isar1_el1(3, 0, 0, 6, 1, "ID_AA64ISAR1_EL1", false, _state.id_aa64isar1_el1, _reg_tree),
|
||||
_sr_id_aa64mmfr0_el1(3, 0, 0, 7, 0, "ID_AA64MMFR0_EL1", false, _state.id_aa64mmfr0_el1, _reg_tree),
|
||||
_sr_id_aa64mmfr1_el1(3, 0, 0, 7, 1, "ID_AA64MMFR1_EL1", false, _state.id_aa64mmfr1_el1, _reg_tree),
|
||||
_sr_id_aa64mmfr2_el1(3, 0, 0, 7, 2, "ID_AA64MMFR2_EL1", false, _state.id_aa64mmfr2_el1, _reg_tree),
|
||||
_sr_id_aa64pfr0_el1 (_state.id_aa64pfr0_el1, _reg_tree),
|
||||
_sr_id_aa64isar0_el1(3, 0, 0, 6, 0, "ID_AA64ISAR0_EL1", false, 0x0, _reg_tree),
|
||||
_sr_id_aa64isar1_el1(3, 0, 0, 6, 1, "ID_AA64ISAR1_EL1", false, 0x0, _reg_tree),
|
||||
_sr_id_aa64mmfr0_el1(3, 0, 0, 7, 0, "ID_AA64MMFR0_EL1", false, 0x0, _reg_tree),
|
||||
_sr_id_aa64mmfr1_el1(3, 0, 0, 7, 1, "ID_AA64MMFR1_EL1", false, 0x0, _reg_tree),
|
||||
_sr_id_aa64mmfr2_el1(3, 0, 0, 7, 2, "ID_AA64MMFR2_EL1", false, 0x0, _reg_tree),
|
||||
_sr_id_aa64pfr0_el1 (0x0, _reg_tree),
|
||||
_sr_id_aa64pfr1_el1 (3, 0, 0, 4, 1, "ID_AA64PFR1_EL1", false, 0x0, _reg_tree),
|
||||
_sr_id_aa64zfr0_el1 (3, 0, 0, 4, 4, "ID_AA64ZFR0_EL1", false, 0x0, _reg_tree),
|
||||
_sr_aidr_el1 (3, 0, 1, 0, 7, "AIDR_EL1", false, 0x0, _reg_tree),
|
||||
_sr_revidr_el1 (3, 0, 0, 0, 6, "REVIDR_EL1", false, 0x0, _reg_tree),
|
||||
_sr_clidr_el1 (3, 0, 1, 0, 1, "CLIDR_EL1", false, _state.clidr_el1, _reg_tree),
|
||||
_sr_clidr_el1 (3, 0, 1, 0, 1, "CLIDR_EL1", false, 0x0, _reg_tree),
|
||||
_sr_csselr_el1 (3, 0, 2, 0, 0, "CSSELR_EL1", true, 0x0, _reg_tree),
|
||||
_sr_ctr_el0 (_reg_tree),
|
||||
_sr_ccsidr_el1 (_sr_csselr_el1, _state, _reg_tree),
|
||||
_sr_ccsidr_el1 (_sr_csselr_el1, *this, _reg_tree),
|
||||
_sr_pmuserenr_el0 (3, 9, 3, 14, 0, "PMUSEREN_EL0", true, 0x0, _reg_tree),
|
||||
_sr_dbgbcr0 (2, 0, 0, 0, 5, "DBGBCR_EL1", true, 0x0, _reg_tree),
|
||||
_sr_dbgbvr0 (2, 0, 0, 0, 4, "DBGBVR_EL1", true, 0x0, _reg_tree),
|
||||
@ -241,7 +261,4 @@ Cpu::Cpu(Vm & vm,
|
||||
_sr_osdlr (2, 1, 0, 3, 4, "OSDLR_EL1", true, 0x0, _reg_tree),
|
||||
_sr_oslar (2, 1, 0, 0, 4, "OSLAR_EL1", true, 0x0, _reg_tree),
|
||||
_sr_sgi1r_el1 (_reg_tree, vm)
|
||||
{
|
||||
_state.pstate = 0b1111000101; /* el1 mode and IRQs disabled */
|
||||
_state.vmpidr_el2 = cpu_id();
|
||||
}
|
||||
{ }
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM cpu object
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-07-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -40,9 +41,11 @@ class Vmm::Cpu : public Vmm::Cpu_base
|
||||
AARCH32_IRQ = 0x680,
|
||||
AARCH32_FIQ = 0x700,
|
||||
AARCH32_SERROR = 0x780,
|
||||
NO_EXCEPTION = 0xffff
|
||||
NO_EXCEPTION = 0xffff,
|
||||
};
|
||||
|
||||
void setup_state(State & state) override;
|
||||
|
||||
private:
|
||||
|
||||
class Id_aa64pfr0 : public System_register,
|
||||
@ -57,7 +60,9 @@ class Vmm::Cpu : public Vmm::Cpu_base
|
||||
struct Ras : Bitfield<28, 4> { enum { NOT_IMPLEMENTED }; };
|
||||
struct Sve : Bitfield<32, 4> { enum { NOT_IMPLEMENTED }; };
|
||||
|
||||
access_t _reset_value(access_t orig)
|
||||
public:
|
||||
|
||||
access_t reset_value(access_t orig)
|
||||
{
|
||||
El0::set(orig, El0::AARCH64_ONLY);
|
||||
El1::set(orig, El1::AARCH64_ONLY);
|
||||
@ -68,24 +73,22 @@ class Vmm::Cpu : public Vmm::Cpu_base
|
||||
return orig;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Id_aa64pfr0(Genode::uint64_t id_aa64pfr0,
|
||||
Genode::Avl_tree<System_register> & tree)
|
||||
: System_register(3, 0, 0, 4, 0, "ID_AA64PFR0_EL1", false,
|
||||
_reset_value(id_aa64pfr0), tree) {}
|
||||
reset_value(id_aa64pfr0), tree) {}
|
||||
};
|
||||
|
||||
struct Ccsidr : System_register
|
||||
{
|
||||
System_register & csselr;
|
||||
State & state;
|
||||
Cpu & cpu;
|
||||
|
||||
Ccsidr(System_register &csselr,
|
||||
State & state,
|
||||
Cpu & cpu,
|
||||
Genode::Avl_tree<System_register> & tree)
|
||||
: System_register(3, 0, 1, 0, 0, "CCSIDR_EL1", false, 0x0, tree),
|
||||
csselr(csselr), state(state) {}
|
||||
csselr(csselr), cpu(cpu) {}
|
||||
|
||||
virtual Genode::addr_t read() const override;
|
||||
};
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM ARM Generic timer device model
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-08-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -28,12 +29,12 @@ Genode::uint64_t Generic_timer::_ticks_per_ms()
|
||||
}
|
||||
|
||||
|
||||
Genode::uint64_t Generic_timer::_usecs_left()
|
||||
Genode::uint64_t Generic_timer::_usecs_left(Vm_state &state)
|
||||
{
|
||||
Genode::uint64_t count;
|
||||
asm volatile("mrs %0, cntpct_el0" : "=r" (count));
|
||||
count -= _cpu.state().timer.offset;
|
||||
if (count > _cpu.state().timer.compare) return 0;
|
||||
return Genode::timer_ticks_to_us(_cpu.state().timer.compare - count,
|
||||
count -= state.timer.offset;
|
||||
if (count > state.timer.compare) return 0;
|
||||
return Genode::timer_ticks_to_us(state.timer.compare - count,
|
||||
_ticks_per_ms());
|
||||
}
|
||||
|
32
repos/os/src/server/vmm/state.h
Normal file
32
repos/os/src/server/vmm/state.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* \brief vCPU state
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2023-06-22
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__SERVER__VMM__STATE_H_
|
||||
#define _SRC__SERVER__VMM__STATE_H_
|
||||
|
||||
#include <cpu/vm_state_virtualization.h>
|
||||
|
||||
using Genode::addr_t;
|
||||
using Genode::Vm_state;
|
||||
|
||||
namespace Genode { struct Vcpu_state : Vm_state { }; };
|
||||
|
||||
namespace Vmm {
|
||||
struct State : Genode::Vcpu_state
|
||||
{
|
||||
addr_t reg(addr_t idx) const;
|
||||
void reg(addr_t idx, addr_t v);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _SRC__SERVER__VMM__STATE_H_ */
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM example for ARMv8 virtualization
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-07-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -161,10 +162,7 @@ Vm::Vm(Genode::Env & env, Heap & heap, Config & config)
|
||||
|
||||
Genode::log("Start virtual machine ...");
|
||||
|
||||
Cpu & cpu = boot_cpu();
|
||||
cpu.initialize_boot(_ram.base() + KERNEL_OFFSET,
|
||||
_ram.base() + _dtb_offset());
|
||||
cpu.run();
|
||||
boot_cpu();
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief VMM example for ARMv8 virtualization
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2019-07-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
* Copyright (C) 2019-2023 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -96,6 +97,14 @@ class Vmm::Vm
|
||||
for (Cpu_entry * ce = _cpu_list.first(); ce; ce = ce->next())
|
||||
func(ce->cpu);
|
||||
}
|
||||
|
||||
addr_t dtb_addr() {
|
||||
return _ram.base() + _dtb_offset();
|
||||
}
|
||||
|
||||
addr_t kernel_addr() {
|
||||
return _ram.base() + KERNEL_OFFSET;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SRC__SERVER__VMM__VM_H_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user