os: transition to new API for vmm (ref #1987)

This commit is contained in:
Stefan Kalkowski 2017-01-06 12:48:59 +01:00 committed by Norman Feske
parent 128cd852b7
commit 15171eaac6
2 changed files with 196 additions and 181 deletions

View File

@ -12,14 +12,13 @@
*/ */
/* Genode includes */ /* Genode includes */
#include <base/attached_ram_dataspace.h>
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <base/exception.h> #include <base/exception.h>
#include <base/log.h> #include <base/log.h>
#include <cpu/cpu_state.h> #include <cpu/cpu_state.h>
#include <drivers/board_base.h> #include <drivers/board_base.h>
#include <io_mem_session/connection.h>
#include <irq_session/connection.h>
#include <os/attached_ram_dataspace.h>
#include <os/attached_rom_dataspace.h>
#include <os/ring_buffer.h> #include <os/ring_buffer.h>
#include <terminal_session/connection.h> #include <terminal_session/connection.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
@ -30,6 +29,7 @@
#include <vm_state.h> #include <vm_state.h>
#include <board.h> #include <board.h>
struct State : Genode::Vm_state struct State : Genode::Vm_state
{ {
Genode::uint32_t midr; Genode::uint32_t midr;
@ -124,7 +124,7 @@ class Vm {
Genode::Attached_rom_dataspace _dtb_rom; Genode::Attached_rom_dataspace _dtb_rom;
Genode::Attached_ram_dataspace _vm_ram; Genode::Attached_ram_dataspace _vm_ram;
Ram _ram; Ram _ram;
State *_state; State & _state;
bool _active = true; bool _active = true;
void _load_kernel() void _load_kernel()
@ -132,7 +132,7 @@ class Vm {
Genode::memcpy((void*)(_ram.local() + KERNEL_OFFSET), Genode::memcpy((void*)(_ram.local() + KERNEL_OFFSET),
_kernel_rom.local_addr<void>(), _kernel_rom.local_addr<void>(),
_kernel_rom.size()); _kernel_rom.size());
_state->ip = _ram.base() + KERNEL_OFFSET; _state.ip = _ram.base() + KERNEL_OFFSET;
} }
void _load_dtb() void _load_dtb()
@ -140,7 +140,7 @@ class Vm {
Genode::memcpy((void*)(_ram.local() + DTB_OFFSET), Genode::memcpy((void*)(_ram.local() + DTB_OFFSET),
_dtb_rom.local_addr<void>(), _dtb_rom.local_addr<void>(),
_dtb_rom.size()); _dtb_rom.size());
_state->r2 = _ram.base() + DTB_OFFSET; _state.r2 = _ram.base() + DTB_OFFSET;
} }
public: public:
@ -172,12 +172,13 @@ class Vm {
Vm(const char *kernel, const char *dtb, Genode::size_t const ram_size, Vm(const char *kernel, const char *dtb, Genode::size_t const ram_size,
Genode::Signal_context_capability sig_cap) Genode::Signal_context_capability sig_cap, Genode::Env & env)
: _kernel_rom(kernel), : _vm_con(env),
_dtb_rom(dtb), _kernel_rom(env, kernel),
_vm_ram(Genode::env()->ram_session(), ram_size, Genode::UNCACHED), _dtb_rom(env, dtb),
_vm_ram(env.ram(), env.rm(), ram_size, Genode::UNCACHED),
_ram(RAM_ADDRESS, ram_size, (Genode::addr_t)_vm_ram.local_addr<void>()), _ram(RAM_ADDRESS, ram_size, (Genode::addr_t)_vm_ram.local_addr<void>()),
_state((State*)Genode::env()->rm_session()->attach(_vm_con.cpu_state())) _state(*((State*)env.rm().attach(_vm_con.cpu_state())))
{ {
Genode::log("ram is at ", Genode::log("ram is at ",
Genode::Hex(Genode::Dataspace_client(_vm_ram.cap()).phys_addr())); Genode::Hex(Genode::Dataspace_client(_vm_ram.cap()).phys_addr()));
@ -189,23 +190,23 @@ class Vm {
void start() void start()
{ {
Genode::memset((void*)_state, 0, sizeof(Genode::Cpu_state_modes)); Genode::memset((void*)&_state, 0, sizeof(Genode::Cpu_state_modes));
_load_kernel(); _load_kernel();
_load_dtb(); _load_dtb();
_state->r1 = MACH_TYPE; _state.r1 = MACH_TYPE;
_state->cpsr = 0x93; /* SVC mode and IRQs disabled */ _state.cpsr = 0x93; /* SVC mode and IRQs disabled */
_state->timer_ctrl = 0; _state.timer_ctrl = 0;
_state->timer_val = 0; _state.timer_val = 0;
_state->timer_irq = false; _state.timer_irq = false;
_state->gic_hcr = 0b101; _state.gic_hcr = 0b101;
_state->gic_vmcr = 0x4c0000; _state.gic_vmcr = 0x4c0000;
_state->gic_apr = 0; _state.gic_apr = 0;
_state->gic_lr[0] = 0; _state.gic_lr[0] = 0;
_state->gic_lr[1] = 0; _state.gic_lr[1] = 0;
_state->gic_lr[2] = 0; _state.gic_lr[2] = 0;
_state->gic_lr[3] = 0; _state.gic_lr[3] = 0;
Genode::log("ready to run"); Genode::log("ready to run");
} }
@ -227,43 +228,69 @@ class Vm {
"data_abort", "irq", "fiq", "trap" }; "data_abort", "irq", "fiq", "trap" };
log("Cpu state:"); log("Cpu state:");
log(" r0 = ", Hex(_state->r0, Hex::PREFIX, Hex::PAD)); log(" r0 = ", Hex(_state.r0, Hex::PREFIX, Hex::PAD));
log(" r1 = ", Hex(_state->r1, Hex::PREFIX, Hex::PAD)); log(" r1 = ", Hex(_state.r1, Hex::PREFIX, Hex::PAD));
log(" r2 = ", Hex(_state->r2, Hex::PREFIX, Hex::PAD)); log(" r2 = ", Hex(_state.r2, Hex::PREFIX, Hex::PAD));
log(" r3 = ", Hex(_state->r3, Hex::PREFIX, Hex::PAD)); log(" r3 = ", Hex(_state.r3, Hex::PREFIX, Hex::PAD));
log(" r4 = ", Hex(_state->r4, Hex::PREFIX, Hex::PAD)); log(" r4 = ", Hex(_state.r4, Hex::PREFIX, Hex::PAD));
log(" r5 = ", Hex(_state->r5, Hex::PREFIX, Hex::PAD)); log(" r5 = ", Hex(_state.r5, Hex::PREFIX, Hex::PAD));
log(" r6 = ", Hex(_state->r6, Hex::PREFIX, Hex::PAD)); log(" r6 = ", Hex(_state.r6, Hex::PREFIX, Hex::PAD));
log(" r7 = ", Hex(_state->r7, Hex::PREFIX, Hex::PAD)); log(" r7 = ", Hex(_state.r7, Hex::PREFIX, Hex::PAD));
log(" r8 = ", Hex(_state->r8, Hex::PREFIX, Hex::PAD)); log(" r8 = ", Hex(_state.r8, Hex::PREFIX, Hex::PAD));
log(" r9 = ", Hex(_state->r9, Hex::PREFIX, Hex::PAD)); log(" r9 = ", Hex(_state.r9, Hex::PREFIX, Hex::PAD));
log(" r10 = ", Hex(_state->r10, Hex::PREFIX, Hex::PAD)); log(" r10 = ", Hex(_state.r10, Hex::PREFIX, Hex::PAD));
log(" r11 = ", Hex(_state->r11, Hex::PREFIX, Hex::PAD)); log(" r11 = ", Hex(_state.r11, Hex::PREFIX, Hex::PAD));
log(" r12 = ", Hex(_state->r12, Hex::PREFIX, Hex::PAD)); log(" r12 = ", Hex(_state.r12, Hex::PREFIX, Hex::PAD));
log(" sp = ", Hex(_state->sp, Hex::PREFIX, Hex::PAD)); log(" sp = ", Hex(_state.sp, Hex::PREFIX, Hex::PAD));
log(" lr = ", Hex(_state->lr, Hex::PREFIX, Hex::PAD)); log(" lr = ", Hex(_state.lr, Hex::PREFIX, Hex::PAD));
log(" ip = ", Hex(_state->ip, Hex::PREFIX, Hex::PAD)); log(" ip = ", Hex(_state.ip, Hex::PREFIX, Hex::PAD));
log(" cpsr = ", Hex(_state->cpsr, Hex::PREFIX, Hex::PAD)); log(" cpsr = ", Hex(_state.cpsr, Hex::PREFIX, Hex::PAD));
for (unsigned i = 0; for (unsigned i = 0;
i < State::Mode_state::MAX; i++) { i < State::Mode_state::MAX; i++) {
log(" sp_", modes[i], " = ", log(" sp_", modes[i], " = ",
Hex(_state->mode[i].sp, Hex::PREFIX, Hex::PAD)); Hex(_state.mode[i].sp, Hex::PREFIX, Hex::PAD));
log(" lr_", modes[i], " = ", log(" lr_", modes[i], " = ",
Hex(_state->mode[i].lr, Hex::PREFIX, Hex::PAD)); Hex(_state.mode[i].lr, Hex::PREFIX, Hex::PAD));
log(" spsr_", modes[i], " = ", log(" spsr_", modes[i], " = ",
Hex(_state->mode[i].spsr, Hex::PREFIX, Hex::PAD)); Hex(_state.mode[i].spsr, Hex::PREFIX, Hex::PAD));
} }
log(" exception = ", exc[_state->cpu_exception]); log(" exception = ", exc[_state.cpu_exception]);
} }
State *state() const { return _state; } State & state() const { return _state; }
}; };
class Vmm class Vmm
{ {
private: private:
template <typename T>
struct Signal_handler : Genode::Signal_handler<Signal_handler<T>>
{
using Base = Genode::Signal_handler<Signal_handler<T>>;
Vmm & vmm;
T & obj;
void (T::*member)();
void handle()
{
try {
vmm.handle_vm([this] () { (obj.*member)(); });
} catch(Vm::Exception &e) {
e.print();
vmm.vm().dump();
}
}
Signal_handler(Vmm & vmm, Genode::Entrypoint &ep, T & o,
void (T::*f)())
: Base(ep, *this, &Signal_handler::handle),
vmm(vmm), obj(o), member(f) {}
};
struct Hsr : Genode::Register<32> struct Hsr : Genode::Register<32>
{ {
struct Ec : Bitfield<26, 6> struct Ec : Bitfield<26, 6>
@ -344,14 +371,14 @@ class Vmm
Register * r = Register * r =
Avl_node<Register>::child(e > _encoding); Avl_node<Register>::child(e > _encoding);
return r ? r->find_by_encoding(e) : 0; return r ? r->find_by_encoding(e) : nullptr;
} }
void write(State * state, Genode::addr_t v) { void write(State & state, Genode::addr_t v) {
state->*_r = (Genode::uint32_t)v; } state.*_r = (Genode::uint32_t)v; }
Genode::addr_t read(State * state) const { Genode::addr_t read(State & state) const {
return (Genode::addr_t)(state->*_r); } return (Genode::addr_t)(state.*_r); }
/************************ /************************
@ -366,14 +393,14 @@ class Vmm
public: public:
bool handle_trap(State *state) bool handle_trap(State & state)
{ {
Iss::access_t v = state->hsr; Iss::access_t v = state.hsr;
Register * reg = _reg_tree.first(); Register * reg = _reg_tree.first();
if (reg) reg = reg->find_by_encoding(Iss::mask_encoding(v)); if (reg) reg = reg->find_by_encoding(Iss::mask_encoding(v));
if (!reg) { if (!reg) {
Genode::error("unknown cp15 access @ ip=", state->ip, ":"); Genode::error("unknown cp15 access @ ip=", state.ip, ":");
Genode::error(Iss::Direction::get(v) ? "read" : "write", Genode::error(Iss::Direction::get(v) ? "read" : "write",
": " ": "
"c15 ", Iss::Opcode1::get(v), " " "c15 ", Iss::Opcode1::get(v), " "
@ -385,16 +412,16 @@ class Vmm
} }
if (Iss::Direction::get(v)) { /* read access */ if (Iss::Direction::get(v)) { /* read access */
*(state->r(Iss::Register::get(v))) = reg->read(state); *(state.r(Iss::Register::get(v))) = reg->read(state);
} else { /* write access */ } else { /* write access */
if (!reg->writeable()) { if (!reg->writeable()) {
Genode::error("writing to cp15 register ", Genode::error("writing to cp15 register ",
reg->name(), " not allowed!"); reg->name(), " not allowed!");
return false; return false;
} }
reg->write(state, *(state->r(Iss::Register::get(v)))); reg->write(state, *(state.r(Iss::Register::get(v))));
} }
state->ip += sizeof(Genode::addr_t); state.ip += sizeof(Genode::addr_t);
return true; return true;
} }
}; };
@ -436,7 +463,7 @@ class Vmm
public: public:
Cp15(State *state) Cp15(State & state)
{ {
for (unsigned i = 0; i < (sizeof(_regs) / sizeof(Register)); for (unsigned i = 0; i < (sizeof(_regs) / sizeof(Register));
i++) { i++) {
@ -470,7 +497,7 @@ class Vmm
const char * const _name; const char * const _name;
const Genode::uint64_t _addr; const Genode::uint64_t _addr;
const Genode::uint64_t _size; const Genode::uint64_t _size;
Vm *_vm; Vm & _vm;
using Error = Vm::Exception; using Error = Vm::Exception;
@ -479,11 +506,9 @@ class Vmm
Device(const char * const name, Device(const char * const name,
const Genode::uint64_t addr, const Genode::uint64_t addr,
const Genode::uint64_t size, const Genode::uint64_t size,
Vm *vm) Vm & vm)
: _name(name), _addr(addr), _size(size), _vm(vm) { } : _name(name), _addr(addr), _size(size), _vm(vm) { }
Device() : Device("undefined", 0, 0, nullptr) {}
Genode::uint64_t addr() { return _addr; } Genode::uint64_t addr() { return _addr; }
Genode::uint64_t size() { return _size; } Genode::uint64_t size() { return _size; }
const char * name() { return _name; } const char * name() { return _name; }
@ -522,35 +547,35 @@ class Vmm
virtual void irq_disabled(unsigned irq) { } virtual void irq_disabled(unsigned irq) { }
virtual void irq_handled (unsigned irq) { } virtual void irq_handled (unsigned irq) { }
void handle_memory_access(State *state) void handle_memory_access(State & state)
{ {
using namespace Genode; using namespace Genode;
if (!Iss::valid(state->hsr)) if (!Iss::valid(state.hsr))
throw Error("Device %s: unknown HSR=%lx", throw Error("Device %s: unknown HSR=%lx",
name(), state->hsr); name(), state.hsr);
bool wr = Iss::Write::get(state->hsr); bool wr = Iss::Write::get(state.hsr);
unsigned idx = Iss::Register::get(state->hsr); unsigned idx = Iss::Register::get(state.hsr);
uint64_t ipa = (uint64_t)state->hpfar << 8; uint64_t ipa = (uint64_t)state.hpfar << 8;
uint64_t off = ipa - addr() + (state->hdfar & ((1 << 13) - 1)); uint64_t off = ipa - addr() + (state.hdfar & ((1 << 13) - 1));
switch (Iss::Access_size::get(state->hsr)) { switch (Iss::Access_size::get(state.hsr)) {
case Iss::Access_size::BYTE: case Iss::Access_size::BYTE:
{ {
uint8_t * p = (uint8_t*)state->r(idx) + (off & 0b11); uint8_t * p = (uint8_t*)state.r(idx) + (off & 0b11);
wr ? write(p, off) : read(p, off); wr ? write(p, off) : read(p, off);
break; break;
} }
case Iss::Access_size::HALFWORD: case Iss::Access_size::HALFWORD:
{ {
uint16_t * p = (uint16_t*) state->r(idx) + (off & 0b1); uint16_t * p = (uint16_t*) state.r(idx) + (off & 0b1);
wr ? write(p, off) : read(p, off); wr ? write(p, off) : read(p, off);
break; break;
} }
case Iss::Access_size::WORD: case Iss::Access_size::WORD:
{ {
uint32_t * p = (uint32_t*) state->r(idx); uint32_t * p = (uint32_t*) state.r(idx);
wr ? write(p, off) : read(p, off); wr ? write(p, off) : read(p, off);
break; break;
} }
@ -571,7 +596,7 @@ class Vmm
return this; return this;
Device *d = Avl_node<Device>::child(a > addr()); Device *d = Avl_node<Device>::child(a > addr());
return d ? d->find_by_addr(a) : 0; return d ? d->find_by_addr(a) : nullptr;
} }
}; };
@ -631,49 +656,49 @@ class Vmm
void _handle_eoi() void _handle_eoi()
{ {
if (!(_vm->state()->gic_misr & 1)) return; if (!(_vm.state().gic_misr & 1)) return;
for (unsigned i = 0; i < State::NR_IRQ; i++) { for (unsigned i = 0; i < State::NR_IRQ; i++) {
if (_vm->state()->gic_eisr & (1 << i)) { if (_vm.state().gic_eisr & (1 << i)) {
unsigned irq = Gich_lr::Virt_id::get(_vm->state()->gic_lr[i]); unsigned irq = Gich_lr::Virt_id::get(_vm.state().gic_lr[i]);
if (irq > MAX_IRQ) if (irq > MAX_IRQ)
throw Error("IRQ out of bounds"); throw Error("IRQ out of bounds");
_vm->state()->gic_lr[i] = 0; _vm.state().gic_lr[i] = 0;
_vm->state()->gic_elrsr0 |= 1 << i; _vm.state().gic_elrsr0 |= 1 << i;
if (irq == TIMER && if (irq == TIMER &&
_irqs[irq].distr_state == Irq::ENABLED) _irqs[irq].distr_state == Irq::ENABLED)
_vm->state()->timer_irq = true; _vm.state().timer_irq = true;
_irqs[irq].cpu_state = Irq::INACTIVE; _irqs[irq].cpu_state = Irq::INACTIVE;
} }
} }
_vm->state()->gic_misr = 0; _vm.state().gic_misr = 0;
} }
void _inject_irq(unsigned irq, bool eoi) void _inject_irq(unsigned irq, bool eoi)
{ {
if (irq == TIMER) if (irq == TIMER)
_vm->state()->timer_irq = false; _vm.state().timer_irq = false;
for (unsigned i = 0; i < State::NR_IRQ; i++) { for (unsigned i = 0; i < State::NR_IRQ; i++) {
if (!(_vm->state()->gic_elrsr0 & (1 << i))) { if (!(_vm.state().gic_elrsr0 & (1 << i))) {
Gich_lr::access_t v = _vm->state()->gic_lr[i]; Gich_lr::access_t v = _vm.state().gic_lr[i];
if (Gich_lr::Virt_id::get(v) == irq) if (Gich_lr::Virt_id::get(v) == irq)
return; return;
} }
} }
for (unsigned i = 0; i < State::NR_IRQ; i++) { for (unsigned i = 0; i < State::NR_IRQ; i++) {
if (!(_vm->state()->gic_elrsr0 & (1 << i))) if (!(_vm.state().gic_elrsr0 & (1 << i)))
continue; continue;
_vm->state()->gic_elrsr0 &= ~(1 << i); _vm.state().gic_elrsr0 &= ~(1 << i);
Gich_lr::access_t v = 0; Gich_lr::access_t v = 0;
Gich_lr::Virt_id::set(v, irq); Gich_lr::Virt_id::set(v, irq);
Gich_lr::Phys_id::set(v, eoi ? 1 << 9 : 0); Gich_lr::Phys_id::set(v, eoi ? 1 << 9 : 0);
Gich_lr::Prio::set(v, 0); Gich_lr::Prio::set(v, 0);
Gich_lr::State::set(v, 0b1); Gich_lr::State::set(v, 0b1);
_vm->state()->gic_lr[i] = v; _vm.state().gic_lr[i] = v;
return; return;
} }
@ -692,7 +717,7 @@ class Vmm
_irqs[irq].device->irq_enabled(irq); _irqs[irq].device->irq_enabled(irq);
if (irq == TIMER) if (irq == TIMER)
_vm->state()->timer_irq = true; _vm.state().timer_irq = true;
} }
void _disable_irq(unsigned irq) void _disable_irq(unsigned irq)
@ -707,7 +732,7 @@ class Vmm
_irqs[irq].device->irq_disabled(irq); _irqs[irq].device->irq_disabled(irq);
if (irq == TIMER) if (irq == TIMER)
_vm->state()->timer_irq = false; _vm.state().timer_irq = false;
} }
public: public:
@ -715,7 +740,7 @@ class Vmm
Gic(const char * const name, Gic(const char * const name,
const Genode::uint64_t addr, const Genode::uint64_t addr,
const Genode::uint64_t size, const Genode::uint64_t size,
Vm *vm) Vm & vm)
: Device(name, addr, size, vm) : Device(name, addr, size, vm)
{ {
for (unsigned i = 0; i <= MAX_IRQ; i++) { for (unsigned i = 0; i <= MAX_IRQ; i++) {
@ -828,12 +853,12 @@ class Vmm
} }
_inject_irq(irq, _irqs[irq].eoi); _inject_irq(irq, _irqs[irq].eoi);
_vm->interrupt(); _vm.interrupt();
} }
void irq_occured() void irq_occured()
{ {
switch(_vm->state()->gic_irq) { switch(_vm.state().gic_irq) {
case Genode::Board_base::VT_MAINTAINANCE_IRQ: case Genode::Board_base::VT_MAINTAINANCE_IRQ:
_handle_eoi(); _handle_eoi();
return; return;
@ -842,7 +867,7 @@ class Vmm
return; return;
default: default:
throw Error("Unknown IRQ %u occured", throw Error("Unknown IRQ %u occured",
_vm->state()->gic_irq); _vm.state().gic_irq);
}; };
} }
}; };
@ -854,14 +879,14 @@ class Vmm
using Board = Genode::Board_base; using Board = Genode::Board_base;
Timer::Connection _timer; Timer::Connection _timer;
Genode::Signal_dispatcher<Generic_timer> _handler; Signal_handler<Generic_timer> _handler;
Gic &_gic; Gic &_gic;
void _timeout(unsigned) void _timeout()
{ {
_vm->state()->timer_ctrl = 5; _vm.state().timer_ctrl = 5;
_vm->state()->timer_val = 0xffffffff; _vm.state().timer_val = 0xffffffff;
_gic.inject_irq(Board::VT_TIMER_IRQ); _gic.inject_irq(Board::VT_TIMER_IRQ);
} }
@ -870,20 +895,22 @@ class Vmm
Generic_timer(const char * const name, Generic_timer(const char * const name,
const Genode::uint64_t addr, const Genode::uint64_t addr,
const Genode::uint64_t size, const Genode::uint64_t size,
Vm *vm, Vmm &vmm,
Genode::Signal_receiver &receiver, Genode::Env &env,
Gic &gic) Gic &gic)
: Device(name, addr, size, vm), : Device(name, addr, size, vmm.vm()),
_handler(receiver, *this, &Generic_timer::_timeout), _timer(env),
_gic(gic) { _handler(vmm, env.ep(), *this, &Generic_timer::_timeout),
_gic(gic)
{
_timer.sigh(_handler); _timer.sigh(_handler);
_gic.register_irq(Board::VT_TIMER_IRQ, this, true); _gic.register_irq(Board::VT_TIMER_IRQ, this, true);
} }
void schedule_timeout() void schedule_timeout()
{ {
if ((_vm->state()->timer_ctrl & 0b101) != 0b101) if ((_vm.state().timer_ctrl & 0b101) != 0b101)
_timer.trigger_once(_vm->state()->timer_val / 24); _timer.trigger_once(_vm.state().timer_val / 24);
} }
}; };
@ -968,8 +995,9 @@ class Vmm
System_register(const char * const name, System_register(const char * const name,
const Genode::uint64_t addr, const Genode::uint64_t addr,
const Genode::uint64_t size, const Genode::uint64_t size,
Vm *vm) Vm & vm,
: Device(name, addr, size, vm) {} Genode::Env & env)
: Device(name, addr, size, vm), _timer(env) {}
void read(Genode::uint32_t * reg, Genode::uint64_t off) void read(Genode::uint32_t * reg, Genode::uint64_t off)
{ {
@ -1064,16 +1092,16 @@ class Vmm
UARTPCELLID3 = 0xffc, UARTPCELLID3 = 0xffc,
}; };
Terminal::Connection _terminal; Terminal::Connection _terminal;
Genode::Signal_dispatcher<Pl011> _handler; Signal_handler<Pl011> _handler;
Gic &_gic; Gic &_gic;
Ring_buffer _rx_buf; Ring_buffer _rx_buf;
Genode::uint16_t _ibrd = 0; Genode::uint16_t _ibrd = 0;
Genode::uint16_t _fbrd = 0; Genode::uint16_t _fbrd = 0;
Genode::uint16_t _lcr_h = 0; Genode::uint16_t _lcr_h = 0;
Genode::uint16_t _imsc = 0b1111; Genode::uint16_t _imsc = 0b1111;
Genode::uint16_t _ris = 0; Genode::uint16_t _ris = 0;
Genode::uint16_t _cr = 0x300; Genode::uint16_t _cr = 0x300;
void _out_char(unsigned char c) { void _out_char(unsigned char c) {
_terminal.write(&c, 1); _terminal.write(&c, 1);
@ -1127,7 +1155,7 @@ class Vmm
_imsc = mask; _imsc = mask;
} }
void _read(unsigned) void _read()
{ {
if (!_terminal.avail()) return; if (!_terminal.avail()) return;
@ -1146,11 +1174,12 @@ class Vmm
Pl011(const char * const name, Pl011(const char * const name,
const Genode::uint64_t addr, const Genode::uint64_t addr,
const Genode::uint64_t size, const Genode::uint64_t size,
Vm *vm, Vmm &vmm,
Genode::Signal_receiver &receiver, Genode::Env &env,
Gic &gic) Gic &gic)
: Device(name, addr, size, vm), : Device(name, addr, size, vmm.vm()),
_handler(receiver, *this, &Pl011::_read), _terminal(env),
_handler(vmm, env.ep(), *this, &Pl011::_read),
_gic(gic) { _gic(gic) {
_terminal.read_avail_sigh(_handler); _terminal.read_avail_sigh(_handler);
_gic.register_irq(Board::PL011_0_IRQ, this, false); _gic.register_irq(Board::PL011_0_IRQ, this, false);
@ -1210,8 +1239,7 @@ class Vmm
}; };
Genode::Signal_receiver _sig_rcv; Signal_handler<Vmm> _vm_handler;
Genode::Signal_dispatcher<Vmm> _vm_handler;
Vm _vm; Vm _vm;
Cp15 _cp15; Cp15 _cp15;
Genode::Avl_tree<Device> _device_tree; Genode::Avl_tree<Device> _device_tree;
@ -1225,29 +1253,29 @@ class Vmm
void _handle_data_abort() void _handle_data_abort()
{ {
Genode::uint64_t ipa = (Genode::uint64_t)_vm.state()->hpfar << 8; Genode::uint64_t ipa = (Genode::uint64_t)_vm.state().hpfar << 8;
Device * device = _device_tree.first() Device * device = _device_tree.first()
? _device_tree.first()->find_by_addr(ipa) : nullptr; ? _device_tree.first()->find_by_addr(ipa) : nullptr;
if (!device) if (!device)
throw Vm::Exception("No device at IPA=%llx", ipa); throw Vm::Exception("No device at IPA=%llx", ipa);
device->handle_memory_access(_vm.state()); device->handle_memory_access(_vm.state());
_vm.state()->ip += sizeof(Genode::addr_t); _vm.state().ip += sizeof(Genode::addr_t);
} }
void _handle_wfi() void _handle_wfi()
{ {
if (_vm.state()->hsr & 1) if (_vm.state().hsr & 1)
throw Vm::Exception("WFE not implemented yet"); throw Vm::Exception("WFE not implemented yet");
_vm.wait_for_interrupt(); _vm.wait_for_interrupt();
_timer.schedule_timeout(); _timer.schedule_timeout();
_vm.state()->ip += sizeof(Genode::addr_t); _vm.state().ip += sizeof(Genode::addr_t);
} }
void _handle_trap() void _handle_trap()
{ {
/* check device number*/ /* check device number*/
switch (Hsr::Ec::get(_vm.state()->hsr)) { switch (Hsr::Ec::get(_vm.state().hsr)) {
case Hsr::Ec::HVC: case Hsr::Ec::HVC:
_handle_hyper_call(); _handle_hyper_call();
break; break;
@ -1262,18 +1290,46 @@ class Vmm
return; return;
default: default:
throw Vm::Exception("Unknown trap: %x", throw Vm::Exception("Unknown trap: %x",
Hsr::Ec::get(_vm.state()->hsr)); Hsr::Ec::get(_vm.state().hsr));
}; };
} }
void _handle_vm(unsigned num) void _handle() {} /* dummy handler */
public:
Vmm(Genode::Env & env)
: _vm_handler(*this, env.ep(), *this, &Vmm::_handle),
_vm("linux", "dtb", 1024 * 1024 * 128, _vm_handler, env),
_cp15(_vm.state()),
_gic ("Gic", 0x2c001000, 0x2000, _vm),
_timer ("Timer", 0x2a430000, 0x1000, *this, env, _gic),
_sys_regs ("System Register", 0x1c010000, 0x1000, _vm, env),
_uart ("Pl011", 0x1c090000, 0x1000, *this, env, _gic)
{
_device_tree.insert(&_gic);
_device_tree.insert(&_sys_regs);
_device_tree.insert(&_uart);
Genode::log("Start virtual machine ...");
_vm.start();
_vm.run();
};
Vm & vm() { return _vm; }
template <typename FUNC>
void handle_vm(FUNC handler)
{ {
if (_vm.active()) { if (_vm.active()) {
_vm.pause();
enum { IRQ = 6, TRAP = 8 }; enum { IRQ = 6, TRAP = 8 };
/* check exception reason */ /* check exception reason */
switch (_vm.state()->cpu_exception) { switch (_vm.state().cpu_exception) {
case IRQ: case IRQ:
_gic.irq_occured(); _gic.irq_occured();
break; break;
@ -1284,53 +1340,12 @@ class Vmm
throw Vm::Exception("Curious exception occured"); throw Vm::Exception("Curious exception occured");
} }
} }
handler();
if (_vm.active()) _vm.run();
} }
public:
Vmm()
: _vm_handler(_sig_rcv, *this, &Vmm::_handle_vm),
_vm("linux", "dtb", 1024 * 1024 * 128, _vm_handler),
_cp15(_vm.state()),
_gic ("Gic", 0x2c001000, 0x2000, &_vm),
_timer ("Timer", 0x2a430000, 0x1000, &_vm, _sig_rcv, _gic),
_sys_regs ("System Register", 0x1c010000, 0x1000, &_vm),
_uart ("Pl011", 0x1c090000, 0x1000, &_vm, _sig_rcv, _gic) { }
void run()
{
using Signal_dispatcher = Genode::Signal_dispatcher_base;
_device_tree.insert(&_gic);
_device_tree.insert(&_sys_regs);
_device_tree.insert(&_uart);
_vm.start();
while (true) {
if (_vm.active()) _vm.run();
Genode::Signal s = _sig_rcv.wait_for_signal();
if (_vm.active() && &_vm_handler != static_cast<Signal_dispatcher*>(s.context())) {
_vm.pause();
_handle_vm(1);
}
static_cast<Signal_dispatcher*>(s.context())->dispatch(s.num());
}
};
void dump() { _vm.dump(); }
}; };
int main()
{
static Vmm vmm;
try { void Component::construct(Genode::Env & env) { static Vmm vmm(env); }
Genode::log("Start virtual machine ...");
vmm.run();
} catch(Vm::Exception &e) {
e.print();
vmm.dump();
return -1;
}
return 0;
}

View File

@ -1,5 +1,5 @@
TARGET = vmm TARGET = vmm
REQUIRES = hw_arndale REQUIRES = arndale hw
LIBS = base LIBS = base
SRC_CC = main.cc SRC_CC = main.cc
INC_DIR += $(PRG_DIR) INC_DIR += $(PRG_DIR)