diff --git a/repos/os/lib/mk/spec/imx53/tz_vmm.inc b/repos/os/lib/mk/spec/imx53/tz_vmm.inc
index 2620ec2697..50abab75a1 100644
--- a/repos/os/lib/mk/spec/imx53/tz_vmm.inc
+++ b/repos/os/lib/mk/spec/imx53/tz_vmm.inc
@@ -1,5 +1,5 @@
LIBS += base config
-SRC_CC += serial.cc block.cc spec/imx53/main.cc
+SRC_CC += serial_driver.cc block_driver.cc vm_base.cc spec/imx53/main.cc
INC_DIR += $(REP_DIR)/src/server/tz_vmm/spec/imx53
INC_DIR += $(REP_DIR)/src/server/tz_vmm/include
diff --git a/repos/os/run/tz_vmm.run b/repos/os/run/tz_vmm.run
index 500b74ec03..1bfc676db2 100644
--- a/repos/os/run/tz_vmm.run
+++ b/repos/os/run/tz_vmm.run
@@ -178,7 +178,7 @@ append config {
if { $mmc_rootfs } {
append config "
-
+
diff --git a/repos/os/src/server/tz_vmm/block.cc b/repos/os/src/server/tz_vmm/block.cc
deleted file mode 100644
index 6fd762bad5..0000000000
--- a/repos/os/src/server/tz_vmm/block.cc
+++ /dev/null
@@ -1,602 +0,0 @@
-/*
- * \brief Paravirtualized serial device for a Trustzone VM
- * \author Martin Stein
- * \date 2015-10-23
- */
-
-/*
- * Copyright (C) 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.
- */
-
-/* local includes */
-#include
-
-/* Genode includes */
-#include
-#include
-#include
-#include
-#include
-
-using namespace Vmm;
-using namespace Genode;
-
-/**
- * Reply message from VMM to VM regarding a finished block request
- */
-class Reply
-{
- private:
-
- unsigned long _req;
- unsigned long _write;
- unsigned long _data_size;
- unsigned long _data[0];
-
- public:
-
- /**
- * Construct a reply for a given block request
- *
- * \param req request base
- * \param write wether the request wrote
- * \param data_size size of read data
- * \param data_src base of read data if any
- */
- Reply(void * const req, bool const write,
- size_t const data_size, void * const data_src)
- :
- _req((unsigned long)req), _write(write), _data_size(data_size)
- {
- memcpy(_data, data_src, data_size);
- }
-
- /**
- * Return the message size assuming a payload size of 'data_size'
- */
- static size_t size(size_t const data_size) {
- return data_size + sizeof(Reply); }
-
-} __attribute__ ((__packed__));
-
-/**
- * Cache for pending block requests
- */
-class Request_cache
-{
- public:
-
- class Full : public Exception { };
-
- private:
-
- class Entry_not_found : public Exception { };
-
- enum { MAX = Block::Session::TX_QUEUE_SIZE };
-
- struct Entry
- {
- void * pkt;
- void * req;
-
- } _cache[MAX];
-
- unsigned _find(void * const packet)
- {
- for (unsigned i = 0; i < MAX; i++) {
- if (_cache[i].pkt == packet) { return i; }
- }
- throw Entry_not_found();
- }
-
- void _free(unsigned const id) { _cache[id].pkt = 0; }
-
- public:
-
- /**
- * Construct an empty cache
- */
- Request_cache() {
- for (unsigned i = 0; i < MAX; i++) { _free(i); } }
-
- /**
- * Fill a free entry with packet base 'pkt' and request base 'req'
- *
- * \throw Full
- */
- void insert(void * const pkt, void * const req)
- {
- try {
- unsigned const id = _find(0);
- _cache[id] = { pkt, req };
-
- } catch (Entry_not_found) { throw Full(); }
- }
-
- /**
- * Free entry of packet 'pkt' and return corresponding request in 'req'
- */
- void remove(void * const pkt, void ** const req)
- {
- try {
- unsigned const id = _find(pkt);
- *req = _cache[id].req;
- _free(id);
-
- } catch (Entry_not_found) { }
- }
-};
-
-/**
- * A block device that is addressable by the VM
- */
-class Device
-{
- public:
-
- enum {
- TX_BUF_SIZE = 5 * 1024 * 1024,
- MAX_NAME_LEN = 64,
- };
-
- private:
-
- Request_cache _cache;
- Allocator_avl _alloc;
- Block::Connection _session;
- size_t _blk_size;
- Block::sector_t _blk_cnt;
- Block::Session::Operations _blk_ops;
- Native_capability _irq_cap;
- Signal_context _tx;
- char _name[MAX_NAME_LEN];
- unsigned const _irq;
- bool _writeable;
-
- public:
-
- /**
- * Construct a device with name 'name' and interrupt 'irq'
- */
- Device(const char * const name, unsigned const irq)
- :
- _alloc(env()->heap()),
- _session(&_alloc, TX_BUF_SIZE, name), _irq(irq)
- {
- _session.info(&_blk_cnt, &_blk_size, &_blk_ops);
- _writeable = _blk_ops.supported(Block::Packet_descriptor::WRITE);
- strncpy(_name, name, sizeof(_name));
- }
-
- /*
- * Accessors
- */
-
- Request_cache * cache() { return &_cache; }
- Block::Connection * session() { return &_session; }
- Signal_context * context() { return &_tx; }
- size_t block_size() { return _blk_size; }
- size_t block_count() { return _blk_cnt; }
- bool writeable() { return _writeable; }
- const char * name() { return _name; }
- unsigned irq() { return _irq; }
-};
-
-/**
- * Registry of all block devices that are addressable by the VM
- */
-class Device_registry
-{
- public:
-
- class Bad_device_id : public Exception { };
-
- private:
-
- Device ** _devs;
- unsigned _count;
-
- void _init_devs(Xml_node config, unsigned const node_id)
- {
- if (!config.sub_node(node_id).has_type("block")) { return; }
-
- char label[Device::MAX_NAME_LEN];
- config.sub_node(node_id).attribute("label").value(label, sizeof(label));
-
- unsigned irq = ~0;
- config.sub_node(node_id).attribute("irq").value(&irq);
-
- static unsigned dev_id = 0;
- _devs[dev_id] = new (env()->heap()) Device(label, irq);
- dev_id++;
- }
-
- void _init_count(Xml_node config, unsigned const node_id)
- {
- if (!config.sub_node(node_id).has_type("block")) { return; }
- _count++;
- }
-
- void _init()
- {
- Xml_node config = Genode::config()->xml_node();
- size_t node_cnt = config.num_sub_nodes();
-
- for (unsigned i = 0; i < node_cnt; i++) { _init_count(config, i); }
- if (_count == 0) { return; }
-
- size_t const size = _count * sizeof(Device *);
- _devs = (Device **)env()->heap()->alloc(size);
-
- for (unsigned i = 0; i < node_cnt; i++) { _init_devs(config, i); }
- }
-
- Device_registry()
- {
- try { _init(); }
- catch(...) { Genode::error("blk: config parsing error"); }
- }
-
- public:
-
- static Device_registry * singleton()
- {
- static Device_registry s;
- return &s;
- }
-
- /**
- * Return device with ID 'id' if existent
- *
- * \throw Bad_device_id
- */
- Device * dev(unsigned const id) const
- {
- if (id >= _count) { throw Bad_device_id(); }
- return _devs[id];
- }
-
- /*
- * Accessors
- */
-
- unsigned count() const { return _count; }
-};
-
-/**
- * Thread that listens to device interrupts and propagates them to a VM
- */
-class Callback : public Thread_deprecated<8192>
-{
- private:
-
- Lock _ready_lock;
-
- /*
- * FIXME
- * If we want to support multiple VMs at a time, this should be part of
- * the requests that are saved in the device request-cache.
- */
- Vm_base * const _vm;
-
- /*
- * Thread interface
- */
-
- void entry()
- {
- Signal_receiver receiver;
- unsigned const count = Device_registry::singleton()->count();
- for (unsigned i = 0; i < count; i++) {
- Device * const dev = Device_registry::singleton()->dev(i);
- Signal_context_capability cap(receiver.manage(dev->context()));
- dev->session()->tx_channel()->sigh_ready_to_submit(cap);
- dev->session()->tx_channel()->sigh_ack_avail(cap);
- }
-
- _ready_lock.unlock();
-
- while (true) {
- Signal s = receiver.wait_for_signal();
- for (unsigned i = 0; i < count; i++) {
- Device * const dev = Device_registry::singleton()->dev(i);
- if (dev->context() == s.context()) {
-
- /*
- * FIXME
- * If we want to support multiple VMs, this should
- * be read from the corresponding request.
- */
- _vm->inject_irq(dev->irq());
- break;
- }
- }
- }
- }
-
- public:
-
- /**
- * Construct a callback thread for VM 'vm'
- */
- Callback(Vm_base * const vm)
- :
- Thread_deprecated<8192>("blk-signal-thread"),
- _ready_lock(Lock::LOCKED),
- _vm(vm)
- {
- Thread::start();
- _ready_lock.lock();
- }
-};
-
-
-/*
- * Vmm::Block implementation
- */
-
-void Vmm::Block::_buf_to_pkt(void * const dst, size_t const sz)
-{
- if (sz > _buf_size) { throw Oversized_request(); }
- memcpy(dst, _buf, sz);
-}
-
-
-void Vmm::Block::_name(Vm_base * const vm)
-{
- try {
- unsigned const id = vm->smc_arg_2();
- Device * const dev = Device_registry::singleton()->dev(id);
- strncpy((char *)_buf, dev->name(), _buf_size);
-
- } catch (Device_registry::Bad_device_id) {
- Genode::error("bad block device ID");
- }
-}
-
-
-void Vmm::Block::_block_count(Vm_base * const vm)
-{
- try {
- unsigned const id = vm->smc_arg_2();
- Device * const dev = Device_registry::singleton()->dev(id);
- vm->smc_ret(dev->block_count());
-
- } catch (Device_registry::Bad_device_id) {
- Genode::error("bad block device ID");
- vm->smc_ret(0);
- }
-}
-
-
-void Vmm::Block::_block_size(Vm_base * const vm)
-{
- try {
- unsigned const id = vm->smc_arg_2();
- Device * const dev = Device_registry::singleton()->dev(id);
- vm->smc_ret(dev->block_size());
-
- } catch (Device_registry::Bad_device_id) {
- Genode::error("bad block device ID");
- vm->smc_ret(0);
- }
-}
-
-
-void Vmm::Block::_queue_size(Vm_base * const vm)
-{
- try {
- unsigned const id = vm->smc_arg_2();
- Device * const dev = Device_registry::singleton()->dev(id);
- vm->smc_ret(dev->session()->tx()->bulk_buffer_size());
- return;
-
- } catch (Device_registry::Bad_device_id) { Genode::error("bad block device ID"); }
- vm->smc_ret(0);
-}
-
-
-void Vmm::Block::_writeable(Vm_base * const vm)
-{
- try {
- unsigned const id = vm->smc_arg_2();
- Device * const dev = Device_registry::singleton()->dev(id);
- vm->smc_ret(dev->writeable());
-
- } catch (Device_registry::Bad_device_id) {
- Genode::error("bad block device ID");
- vm->smc_ret(0);
- }
-}
-
-
-void Vmm::Block::_irq(Vm_base * const vm)
-{
- try {
- unsigned const id = vm->smc_arg_2();
- Device * const dev = Device_registry::singleton()->dev(id);
- vm->smc_ret(dev->irq());
-
- } catch (Device_registry::Bad_device_id) {
- Genode::error("bad block device ID");
- vm->smc_ret(0);
- }
-}
-
-
-void Vmm::Block::_buffer(Vm_base * const vm)
-{
- addr_t const buf_base = vm->smc_arg_2();
- _buf_size = vm->smc_arg_3();
- addr_t const buf_top = buf_base + _buf_size;
- Ram * const ram = vm->ram();
- addr_t const ram_top = ram->base() + ram->size();
-
- bool buf_err;
- buf_err = buf_top <= buf_base;
- buf_err |= buf_base < ram->base();
- buf_err |= buf_top >= ram_top;
- if (buf_err) {
- Genode::error("illegal block buffer constraints");
- return;
- }
- addr_t const buf_off = buf_base - ram->base();
- _buf = (void *)(ram->local() + buf_off);
-}
-
-
-void Vmm::Block::_start_callback(Vm_base * const vm) {
- static Callback c(vm); }
-
-
-void Vmm::Block::_device_count(Vm_base * const vm)
-{
- vm->smc_ret(Device_registry::singleton()->count());
-}
-
-
-void Vmm::Block::_new_request(Vm_base * const vm)
-{
- unsigned const id = vm->smc_arg_2();
- unsigned long const sz = vm->smc_arg_3();
- void * const req = (void*)vm->smc_arg_4();
- try {
- Device * const dev = Device_registry::singleton()->dev(id);
- ::Block::Connection * session = dev->session();
- ::Block::Packet_descriptor p = session->tx()->alloc_packet(sz);
- void *addr = session->tx()->packet_content(p);
- dev->cache()->insert(addr, req);
- vm->smc_ret((long)addr, p.offset());
-
- } catch (Request_cache::Full) {
- Genode::error("block request cache full");
- vm->smc_ret(0, 0);
-
- } catch (::Block::Session::Tx::Source::Packet_alloc_failed) {
- Genode::error("failed to allocate packet for block request");
- vm->smc_ret(0, 0);
-
- } catch (Device_registry::Bad_device_id) {
- Genode::error("bad block device ID");
- vm->smc_ret(0, 0);
- }
-}
-
-
-void Vmm::Block::_submit_request(Vm_base * const vm)
-{
- unsigned const id = vm->smc_arg_2();
- unsigned long const queue_offset = vm->smc_arg_3();
- unsigned long const size = vm->smc_arg_4();
- int const write = vm->smc_arg_7();
- void * const dst = (void *)vm->smc_arg_8();
-
- unsigned long long const disc_offset =
- (unsigned long long)vm->smc_arg_5() << 32 | vm->smc_arg_6();
-
- try {
- Device * const dev = Device_registry::singleton()->dev(id);
- if (write) { _buf_to_pkt(dst, size); }
-
- size_t sector = disc_offset / dev->block_size();
- size_t sector_cnt = size / dev->block_size();
-
- using ::Block::Packet_descriptor;
- Packet_descriptor p(
- Packet_descriptor(queue_offset, size),
- write ? Packet_descriptor::WRITE : Packet_descriptor::READ,
- sector, sector_cnt
- );
- dev->session()->tx()->submit_packet(p);
-
- } catch (Oversized_request) {
- Genode::error("oversized block request");
-
- } catch (Device_registry::Bad_device_id) {
- Genode::error("bad block device ID");
- }
-}
-
-
-void Vmm::Block::_collect_reply(Vm_base * const vm)
-{
- try {
- /* lookup device */
- unsigned const id = vm->smc_arg_2();
- Device * const dev = Device_registry::singleton()->dev(id);
- ::Block::Connection * const con = dev->session();
-
- /* get next packet/request pair and release invalid packets */
- typedef ::Block::Packet_descriptor Packet;
- void * rq = 0;
- Packet pkt;
- for (; !rq; con->tx()->release_packet(pkt)) {
-
- /* check for packets and tell VM to stop if none available */
- if (!con->tx()->ack_avail()) {
- vm->smc_ret(0);
- return;
- }
- /* lookup request of next packet and free cache slot */
- pkt = con->tx()->get_acked_packet();
- dev->cache()->remove(con->tx()->packet_content(pkt), &rq);
- }
- /* get packet values */
- void * const dat = con->tx()->packet_content(pkt);
- bool const w = pkt.operation() == Packet::WRITE;
- size_t const dat_sz = pkt.size();
-
- /* communicate response, release packet and tell VM to continue */
- if (Reply::size(dat_sz) > _buf_size) { throw Oversized_request(); }
- construct_at(_buf, rq, w, dat_sz, dat);
- con->tx()->release_packet(pkt);
- vm->smc_ret(1);
-
- } catch (Oversized_request) {
- Genode::error("oversized block request");
- vm->smc_ret(-1);
-
- } catch (Device_registry::Bad_device_id) {
- Genode::error("bad block device ID");
- vm->smc_ret(-1);
- }
-}
-
-
-void Vmm::Block::handle(Vm_base * const vm)
-{
- enum {
- DEVICE_COUNT = 0,
- BLOCK_COUNT = 1,
- BLOCK_SIZE = 2,
- WRITEABLE = 3,
- QUEUE_SIZE = 4,
- IRQ = 5,
- START_CALLBACK = 6,
- NEW_REQUEST = 7,
- SUBMIT_REQUEST = 8,
- COLLECT_REPLY = 9,
- BUFFER = 10,
- NAME = 11,
- };
- switch (vm->smc_arg_1()) {
- case DEVICE_COUNT: _device_count(vm); break;
- case BLOCK_COUNT: _block_count(vm); break;
- case BLOCK_SIZE: _block_size(vm); break;
- case WRITEABLE: _writeable(vm); break;
- case QUEUE_SIZE: _queue_size(vm); break;
- case IRQ: _irq(vm); break;
- case START_CALLBACK: _start_callback(vm); break;
- case NEW_REQUEST: _new_request(vm); break;
- case SUBMIT_REQUEST: _submit_request(vm); break;
- case COLLECT_REPLY: _collect_reply(vm); break;
- case BUFFER: _buffer(vm); break;
- case NAME: _name(vm); break;
- default:
- Genode::error("Unknown function ", vm->smc_arg_1(), " requested on VMM block");
- break;
- }
-}
diff --git a/repos/os/src/server/tz_vmm/block_driver.cc b/repos/os/src/server/tz_vmm/block_driver.cc
new file mode 100644
index 0000000000..475ae95697
--- /dev/null
+++ b/repos/os/src/server/tz_vmm/block_driver.cc
@@ -0,0 +1,315 @@
+/*
+ * \brief Paravirtualized access to block devices for VMs
+ * \author Martin Stein
+ * \date 2015-10-23
+ */
+
+/*
+ * Copyright (C) 2015-2017 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.
+ */
+
+/* local includes */
+#include
+
+/* Genode includes */
+#include
+#include
+
+using namespace Genode;
+
+
+/*********************************
+ ** Block_driver::Request_cache **
+ *********************************/
+
+unsigned Block_driver::Request_cache::_find(void *pkt)
+{
+ for (unsigned i = 0; i < NR_OF_ENTRIES; i++) {
+ if (_entries[i].pkt == pkt) {
+ return i; }
+ }
+ throw No_matching_entry();
+}
+
+
+void Block_driver::Request_cache::insert(void *pkt, void *req)
+{
+ try { _entries[_find(nullptr)] = { pkt, req }; }
+ catch (No_matching_entry) { throw Full(); }
+}
+
+
+void Block_driver::Request_cache::remove(void *pkt, void **req)
+{
+ try {
+ unsigned const id = _find(pkt);
+ *req = _entries[id].req;
+ _free(id);
+ }
+ catch (No_matching_entry) { }
+}
+
+
+/**************************
+ ** Block_driver::Device **
+ **************************/
+
+Block_driver::Device::Device(Entrypoint &ep,
+ Xml_node node,
+ Range_allocator &alloc,
+ Id_space &id_space,
+ Id id,
+ Vm_base &vm)
+:
+ _vm(vm), _name(node.attribute_value("name", Name())),
+ _irq(node.attribute_value("irq", ~(unsigned)0)),
+ _irq_handler(ep, *this, &Device::_handle_irq),
+ _session(&alloc, TX_BUF_SIZE, _name.string()),
+ _id_space_elem(*this, id_space, id)
+{
+ if (_name == Name() || _irq == ~(unsigned)0) {
+ throw Invalid(); }
+
+ _session.info(&_blk_cnt, &_blk_size, &_blk_ops);
+ _writeable = _blk_ops.supported(Packet_descriptor::WRITE);
+}
+
+
+void Block_driver::Device::start_irq_handling()
+{
+ _session.tx_channel()->sigh_ready_to_submit(_irq_handler);
+ _session.tx_channel()->sigh_ack_avail(_irq_handler);
+}
+
+
+/******************
+ ** Block_driver **
+ ******************/
+
+Block_driver::Block_driver(Entrypoint &ep,
+ Xml_node config,
+ Allocator &alloc,
+ Vm_base &vm) : _dev_alloc(&alloc)
+{
+ config.for_each_sub_node("block", [&] (Xml_node node) {
+ try { new (alloc) Device(ep, node, _dev_alloc, _devs,
+ Device::Id { _dev_count++ }, vm); }
+ catch (Device::Invalid) { error("invalid block device"); }
+ });
+}
+
+
+void Block_driver::_name(Vm_base &vm)
+{
+ _dev_apply(Device::Id { vm.smc_arg_2() },
+ [&] (Device &dev) { strncpy((char *)_buf, dev.name().string(), _buf_size); },
+ [&] () { ((char *)_buf)[0] = 0; });
+}
+
+
+void Block_driver::_block_count(Vm_base &vm)
+{
+ _dev_apply(Device::Id { vm.smc_arg_2() },
+ [&] (Device &dev) { vm.smc_ret(dev.block_count()); },
+ [&] () { vm.smc_ret(0); });
+}
+
+
+void Block_driver::_block_size(Vm_base &vm)
+{
+ _dev_apply(Device::Id { vm.smc_arg_2() },
+ [&] (Device &dev) { vm.smc_ret(dev.block_size()); },
+ [&] () { vm.smc_ret(0); });
+}
+
+
+void Block_driver::_queue_size(Vm_base &vm)
+{
+ _dev_apply(Device::Id { vm.smc_arg_2() },
+ [&] (Device &dev) { vm.smc_ret(dev.session().tx()->bulk_buffer_size()); },
+ [&] () { vm.smc_ret(0); });
+}
+
+
+void Block_driver::_writeable(Vm_base &vm)
+{
+ _dev_apply(Device::Id { vm.smc_arg_2() },
+ [&] (Device &dev) { vm.smc_ret(dev.writeable()); },
+ [&] () { vm.smc_ret(false); });
+}
+
+
+void Block_driver::_irq(Vm_base &vm)
+{
+ _dev_apply(Device::Id { vm.smc_arg_2() },
+ [&] (Device &dev) { vm.smc_ret(dev.irq()); },
+ [&] () { vm.smc_ret(~(unsigned)0); });
+}
+
+
+void Block_driver::_buffer(Vm_base &vm)
+{
+ addr_t const buf_base = vm.smc_arg_2();
+ _buf_size = vm.smc_arg_3();
+ addr_t const buf_top = buf_base + _buf_size;
+ Ram const &ram = vm.ram();
+ addr_t const ram_top = ram.base() + ram.size();
+
+ bool buf_err;
+ buf_err = buf_top <= buf_base;
+ buf_err |= buf_base < ram.base();
+ buf_err |= buf_top >= ram_top;
+ if (buf_err) {
+ error("illegal block buffer constraints");
+ return;
+ }
+ addr_t const buf_off = buf_base - ram.base();
+ _buf = (void *)(ram.local() + buf_off);
+}
+
+
+void Block_driver::_new_request(Vm_base &vm)
+{
+ auto dev_func = [&] (Device &dev) {
+ try {
+ size_t const size = vm.smc_arg_3();
+ void *const req = (void*)vm.smc_arg_4();
+
+ Packet_descriptor pkt = dev.session().tx()->alloc_packet(size);
+ void *addr = dev.session().tx()->packet_content(pkt);
+ dev.cache().insert(addr, req);
+ vm.smc_ret((long)addr, pkt.offset());
+ }
+ catch (Request_cache::Full) {
+ error("block request cache full");
+ throw Device_function_failed();
+ }
+ catch (Block::Session::Tx::Source::Packet_alloc_failed) {
+ error("failed to allocate packet for block request");
+ throw Device_function_failed();
+ }
+ };
+ _dev_apply(Device::Id { vm.smc_arg_2() }, dev_func, [&] () { vm.smc_ret(0, 0); });
+}
+
+
+void Block_driver::_submit_request(Vm_base &vm)
+{
+ auto dev_func = [&] (Device &dev) {
+
+ off_t const queue_offset = vm.smc_arg_3();
+ size_t const size = vm.smc_arg_4();
+ bool const write = vm.smc_arg_7();
+ void *const dst = (void *)vm.smc_arg_8();
+ unsigned long long const disc_offset =
+ (unsigned long long)vm.smc_arg_5() << 32 | vm.smc_arg_6();
+
+ if (write) {
+ if (size > _buf_size) {
+ error("oversized block request");
+ throw Device_function_failed();
+ }
+ memcpy(dst, _buf, size);
+ }
+ size_t const sector = disc_offset / dev.block_size();
+ size_t const sector_cnt = size / dev.block_size();
+ Packet_descriptor pkt(Packet_descriptor(queue_offset, size),
+ write ? Packet_descriptor::WRITE :
+ Packet_descriptor::READ,
+ sector, sector_cnt);
+
+ dev.session().tx()->submit_packet(pkt);
+ };
+ _dev_apply(Device::Id { vm.smc_arg_2() }, dev_func, [] () { });
+}
+
+
+void Block_driver::_collect_reply(Vm_base &vm)
+{
+ auto dev_func = [&] (Device &dev) {
+
+ struct Reply
+ {
+ unsigned long _req;
+ unsigned long _write;
+ unsigned long _dat_size;
+ unsigned long _dat[0];
+
+ Reply(void *req, bool write, size_t dat_size, void *dat_src)
+ :
+ _req((unsigned long)req), _write(write), _dat_size(dat_size)
+ {
+ memcpy(_dat, dat_src, dat_size);
+ }
+ } __attribute__ ((__packed__));
+
+ /* get next packet/request pair and release invalid packets */
+ void * req = 0;
+ Packet_descriptor pkt;
+ for (; !req; dev.session().tx()->release_packet(pkt)) {
+
+ /* check for packets and tell VM to stop if none available */
+ if (!dev.session().tx()->ack_avail()) {
+ vm.smc_ret(0);
+ return;
+ }
+ /* lookup request of next packet and free cache slot */
+ pkt = dev.session().tx()->get_acked_packet();
+ dev.cache().remove(dev.session().tx()->packet_content(pkt), &req);
+ }
+ /* get packet values */
+ void *const dat = dev.session().tx()->packet_content(pkt);
+ bool const write = pkt.operation() == Packet_descriptor::WRITE;
+ size_t const dat_size = pkt.size();
+
+ /* communicate response, release packet and tell VM to continue */
+ if (dat_size + sizeof(Reply) > _buf_size) {
+ error("oversized block reply");
+ throw Device_function_failed();
+ }
+ construct_at(_buf, req, write, dat_size, dat);
+ dev.session().tx()->release_packet(pkt);
+ vm.smc_ret(1);
+ };
+ _dev_apply(Device::Id { vm.smc_arg_2() }, dev_func, [&] () { vm.smc_ret(-1); });
+}
+
+
+void Block_driver::handle_smc(Vm_base &vm)
+{
+ enum {
+ DEVICE_COUNT = 0,
+ BLOCK_COUNT = 1,
+ BLOCK_SIZE = 2,
+ WRITEABLE = 3,
+ QUEUE_SIZE = 4,
+ IRQ = 5,
+ START_CALLBACK = 6,
+ NEW_REQUEST = 7,
+ SUBMIT_REQUEST = 8,
+ COLLECT_REPLY = 9,
+ BUFFER = 10,
+ NAME = 11,
+ };
+ switch (vm.smc_arg_1()) {
+ case DEVICE_COUNT: vm.smc_ret(_dev_count); break;
+ case BLOCK_COUNT: _block_count(vm); break;
+ case BLOCK_SIZE: _block_size(vm); break;
+ case WRITEABLE: _writeable(vm); break;
+ case QUEUE_SIZE: _queue_size(vm); break;
+ case IRQ: _irq(vm); break;
+ case START_CALLBACK: _devs.for_each([&] (Device &dev)
+ { dev.start_irq_handling(); }); break;
+ case NEW_REQUEST: _new_request(vm); break;
+ case SUBMIT_REQUEST: _submit_request(vm); break;
+ case COLLECT_REPLY: _collect_reply(vm); break;
+ case BUFFER: _buffer(vm); break;
+ case NAME: _name(vm); break;
+ default:
+ error("unknown block-driver function ", vm.smc_arg_1());
+ throw Vm_base::Exception_handling_failed();
+ }
+}
diff --git a/repos/os/src/server/tz_vmm/include/block.h b/repos/os/src/server/tz_vmm/include/block.h
deleted file mode 100644
index a1bbec09a1..0000000000
--- a/repos/os/src/server/tz_vmm/include/block.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * \brief Paravirtualized access to block devices for a Trustzone VM
- * \author Martin Stein
- * \date 2015-10-23
- */
-
-/*
- * Copyright (C) 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.
- */
-
-#ifndef _TZ_VMM__INCLUDE__BLOCK_H_
-#define _TZ_VMM__INCLUDE__BLOCK_H_
-
-/* Genode includes */
-#include
-
-/* local includes */
-#include
-
-namespace Vmm { class Block; }
-
-/**
- * Paravirtualized access to block devices for a Trustzone VM
- */
-class Vmm::Block
-{
- private:
-
- class Oversized_request : public Genode::Exception { };
-
- void * _buf;
- Genode::size_t _buf_size;
-
- void _buf_to_pkt(void * const dst, Genode::size_t const sz);
-
- void _name(Vm_base * const vm);
-
- void _block_count(Vm_base * const vm);
-
- void _block_size(Vm_base * const vm);
-
- void _queue_size(Vm_base * const vm);
-
- void _writeable(Vm_base * const vm);
-
- void _irq(Vm_base * const vm);
-
- void _buffer(Vm_base * const vm);
-
- void _start_callback(Vm_base * const vm);
-
- void _device_count(Vm_base * const vm);
-
- void _new_request(Vm_base * const vm);
-
- void _submit_request(Vm_base * const vm);
-
- void _collect_reply(Vm_base * const vm);
-
- public:
-
- /**
- * Handle Secure Monitor Call of VM 'vm' on VMM block
- */
- void handle(Vm_base * const vm);
-
- Block() : _buf_size(0) { }
-};
-
-#endif /* _TZ_VMM__INCLUDE__BLOCK_H_ */
diff --git a/repos/os/src/server/tz_vmm/include/block_driver.h b/repos/os/src/server/tz_vmm/include/block_driver.h
new file mode 100644
index 0000000000..87d32781b0
--- /dev/null
+++ b/repos/os/src/server/tz_vmm/include/block_driver.h
@@ -0,0 +1,154 @@
+/*
+ * \brief Paravirtualized access to block devices for VMs
+ * \author Martin Stein
+ * \date 2015-10-23
+ */
+
+/*
+ * Copyright (C) 2015-2017 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 _BLOCK_DRIVER_H_
+#define _BLOCK_DRIVER_H_
+
+/* Genode includes */
+#include
+#include
+
+/* local includes */
+#include
+
+namespace Genode {
+
+ class Xml_node;
+ class Block_driver;
+}
+
+
+class Genode::Block_driver
+{
+ private:
+
+ using Packet_descriptor = Block::Packet_descriptor;
+
+ struct Device_function_failed : Exception { };
+
+ class Request_cache
+ {
+ private:
+
+ enum { NR_OF_ENTRIES = Block::Session::TX_QUEUE_SIZE };
+
+ struct No_matching_entry : Exception { };
+
+ struct Entry { void *pkt; void *req; } _entries[NR_OF_ENTRIES];
+
+ unsigned _find(void *packet);
+ void _free(unsigned id) { _entries[id].pkt = 0; }
+
+ public:
+
+ struct Full : Exception { };
+
+ Request_cache() {
+ for (unsigned i = 0; i < NR_OF_ENTRIES; i++) { _free(i); } }
+
+ void insert(void *pkt, void *req);
+ void remove(void *pkt, void **req);
+ };
+
+ class Device
+ {
+ public:
+
+ enum { TX_BUF_SIZE = 5 * 1024 * 1024 };
+
+ using Id = Id_space::Id;
+ using Name = String<64>;
+
+ private:
+
+ Request_cache _cache;
+ Vm_base &_vm;
+ Name const _name;
+ unsigned const _irq;
+ Signal_handler _irq_handler;
+ Block::Connection _session;
+ Id_space::Element _id_space_elem;
+ size_t _blk_size;
+ Block::sector_t _blk_cnt;
+ Block::Session::Operations _blk_ops;
+ bool _writeable;
+
+ public:
+
+ void _handle_irq() { _vm.inject_irq(_irq); }
+
+ public:
+
+ struct Invalid : Exception { };
+
+ Device(Entrypoint &ep,
+ Xml_node node,
+ Range_allocator &alloc,
+ Id_space &id_space,
+ Id id,
+ Vm_base &vm);
+
+ void start_irq_handling();
+
+ Request_cache &cache() { return _cache; }
+ Block::Connection &session() { return _session; }
+ size_t block_size() const { return _blk_size; }
+ size_t block_count() const { return _blk_cnt; }
+ bool writeable() const { return _writeable; }
+ Name const &name() const { return _name; }
+ unsigned irq() const { return _irq; }
+ };
+
+ void *_buf = nullptr;
+ size_t _buf_size = 0;
+ Id_space _devs;
+ unsigned _dev_count = 0;
+ Allocator_avl _dev_alloc;
+
+ void _buf_to_pkt(void *dst, size_t sz);
+ void _name(Vm_base &vm);
+ void _block_count(Vm_base &vm);
+ void _block_size(Vm_base &vm);
+ void _queue_size(Vm_base &vm);
+ void _writeable(Vm_base &vm);
+ void _irq(Vm_base &vm);
+ void _buffer(Vm_base &vm);
+ void _device_count(Vm_base &vm);
+ void _new_request(Vm_base &vm);
+ void _submit_request(Vm_base &vm);
+ void _collect_reply(Vm_base &vm);
+
+ template
+ void _dev_apply(Device::Id id,
+ DEV_FUNC const &dev_func,
+ ERR_FUNC const &err_func)
+ {
+ try { _devs.apply(id, [&] (Device &dev) { dev_func(dev); }); }
+ catch (Id_space::Unknown_id) {
+ error("unknown block device ", id);
+ err_func();
+ }
+ catch (Device_function_failed) { err_func(); }
+ }
+
+ public:
+
+ void handle_smc(Vm_base &vm);
+
+ Block_driver(Entrypoint &ep,
+ Xml_node config,
+ Allocator &alloc,
+ Vm_base &vm);
+};
+
+#endif /* _BLOCK_DRIVER_H_ */
diff --git a/repos/os/src/server/tz_vmm/include/mmu.h b/repos/os/src/server/tz_vmm/include/mmu.h
index e7231e4857..bf733a409c 100644
--- a/repos/os/src/server/tz_vmm/include/mmu.h
+++ b/repos/os/src/server/tz_vmm/include/mmu.h
@@ -22,10 +22,10 @@ class Mmu
{
private:
- Genode::Vm_state *_state;
- Ram *_ram;
+ Genode::Vm_state &_state;
+ Ram const &_ram;
- unsigned _n_bits() { return _state->ttbrc & 0x7; }
+ unsigned _n_bits() { return _state.ttbrc & 0x7; }
bool _ttbr0(Genode::addr_t mva) {
return (!_n_bits() || !(mva >> (32 - _n_bits()))); }
@@ -33,10 +33,10 @@ class Mmu
Genode::addr_t _first_level(Genode::addr_t va)
{
if (!_ttbr0(va))
- return ((_state->ttbr[1] & 0xffffc000) |
+ return ((_state.ttbr[1] & 0xffffc000) |
((va >> 18) & 0xffffc));
unsigned shift = 14 - _n_bits();
- return (((_state->ttbr[0] >> shift) << shift) |
+ return (((_state.ttbr[0] >> shift) << shift) |
(((va << _n_bits()) >> (18 + _n_bits())) & 0x3ffc));
}
@@ -44,7 +44,7 @@ class Mmu
{
enum Type { FAULT, LARGE, SMALL };
- Genode::addr_t se = *((Genode::addr_t*)_ram->va(((fe & (~0UL << 10)) |
+ Genode::addr_t se = *((Genode::addr_t*)_ram.va(((fe & (~0UL << 10)) |
((va >> 10) & 0x3fc))));
switch (se & 0x3) {
case FAULT:
@@ -68,7 +68,7 @@ class Mmu
public:
- Mmu(Genode::Vm_state *state, Ram *ram)
+ Mmu(Genode::Vm_state &state, Ram const &ram)
: _state(state), _ram(ram) {}
@@ -76,7 +76,7 @@ class Mmu
{
enum Type { FAULT, PAGETABLE, SECTION };
- Genode::addr_t fe = *((Genode::addr_t*)_ram->va(_first_level(va)));
+ Genode::addr_t fe = *((Genode::addr_t*)_ram.va(_first_level(va)));
switch (fe & 0x3) {
case PAGETABLE:
return _page(fe, va);
diff --git a/repos/os/src/server/tz_vmm/include/ram.h b/repos/os/src/server/tz_vmm/include/ram.h
index 6fce1f8da0..bdeb23b131 100644
--- a/repos/os/src/server/tz_vmm/include/ram.h
+++ b/repos/os/src/server/tz_vmm/include/ram.h
@@ -15,6 +15,7 @@
#define _SRC__SERVER__VMM__INCLUDE__RAM_H_
/* Genode includes */
+#include
#include
#include
@@ -22,22 +23,25 @@ class Ram {
private:
- Genode::addr_t _base;
- Genode::size_t _size;
- Genode::addr_t _local;
+ Genode::Attached_io_mem_dataspace _ds;
+ Genode::addr_t const _base;
+ Genode::size_t const _size;
+ Genode::addr_t const _local;
public:
class Invalid_addr : Genode::Exception {};
- Ram(Genode::addr_t addr, Genode::size_t sz, Genode::addr_t local)
- : _base(addr), _size(sz), _local(local) { }
+ Ram(Genode::Env &env, Genode::addr_t base, Genode::size_t size)
+ :
+ _ds(env, base, size), _base(base), _size(size),
+ _local((Genode::addr_t)_ds.local_addr()) { }
- Genode::addr_t base() { return _base; }
- Genode::size_t size() { return _size; }
- Genode::addr_t local() { return _local; }
+ Genode::addr_t base() const { return _base; }
+ Genode::size_t size() const { return _size; }
+ Genode::addr_t local() const { return _local; }
- Genode::addr_t va(Genode::addr_t phys)
+ Genode::addr_t va(Genode::addr_t phys) const
{
if ((phys < _base) || (phys > (_base + _size)))
throw Invalid_addr();
diff --git a/repos/os/src/server/tz_vmm/include/serial.h b/repos/os/src/server/tz_vmm/include/serial.h
deleted file mode 100644
index d09ac159a2..0000000000
--- a/repos/os/src/server/tz_vmm/include/serial.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * \brief Paravirtualized access to serial devices for a Trustzone VM
- * \author Martin Stein
- * \date 2015-10-23
- */
-
-/*
- * Copyright (C) 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.
- */
-
-#ifndef _TZ_VMM__INCLUDE__SERIAL_H_
-#define _TZ_VMM__INCLUDE__SERIAL_H_
-
-/* Genode includes */
-#include
-#include
-
-namespace Vmm { class Serial; }
-
-/**
- * Paravirtualized access to serial devices for a Trustzone VM
- */
-class Vmm::Serial : private Genode::Attached_ram_dataspace
-{
- private:
-
- enum {
- BUF_SIZE = 4096,
- WRAP = BUF_SIZE - sizeof(char),
- };
-
- Genode::addr_t _off;
-
- void _push(char const c);
-
- void _flush();
-
- void _send(Vm_base * const vm);
-
- public:
-
- /**
- * Handle Secure Monitor Call of VM 'vm' on VMM serial
- */
- void handle(Vm_base * const vm);
-
- Serial();
-};
-
-#endif /* _TZ_VMM__INCLUDE__SERIAL_H_ */
diff --git a/repos/os/src/server/tz_vmm/include/serial_driver.h b/repos/os/src/server/tz_vmm/include/serial_driver.h
new file mode 100644
index 0000000000..a08d4442bf
--- /dev/null
+++ b/repos/os/src/server/tz_vmm/include/serial_driver.h
@@ -0,0 +1,46 @@
+/*
+ * \brief Paravirtualized access to serial device for a Trustzone VM
+ * \author Martin Stein
+ * \date 2015-10-23
+ */
+
+/*
+ * Copyright (C) 2015-2017 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_DRIVER_H_
+#define _SERIAL_DRIVER_H_
+
+/* Genode includes */
+#include
+
+/* local includes */
+#include
+
+namespace Genode { class Serial_driver; }
+
+
+class Genode::Serial_driver
+{
+ private:
+
+ enum { BUF_SIZE = 4096 };
+
+ Attached_ram_dataspace _buf;
+ addr_t _off = 0;
+
+ void _push(char c) { _buf.local_addr()[_off++] = c; }
+ void _flush();
+ void _send(Vm_base &vm);
+
+ public:
+
+ void handle_smc(Vm_base &vm);
+
+ Serial_driver(Ram_session &ram) : _buf(&ram, BUF_SIZE) { }
+};
+
+#endif /* _SERIAL_DRIVER_H_ */
diff --git a/repos/os/src/server/tz_vmm/include/vm_base.h b/repos/os/src/server/tz_vmm/include/vm_base.h
index 65b5d76a0d..b1cd114698 100644
--- a/repos/os/src/server/tz_vmm/include/vm_base.h
+++ b/repos/os/src/server/tz_vmm/include/vm_base.h
@@ -1,206 +1,119 @@
/*
* \brief Virtual Machine Monitor VM definition
* \author Stefan Kalkowski
+ * \author Martin Stein
* \date 2012-06-25
*/
/*
- * Copyright (C) 2012-2013 Genode Labs GmbH
+ * Copyright (C) 2012-2017 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 _SRC__SERVER__VMM__INCLUDE__VM_H_
-#define _SRC__SERVER__VMM__INCLUDE__VM_H_
+#ifndef _VM_BASE_H_
+#define _VM_BASE_H_
/* Genode includes */
-#include
#include
-#include
#include
#include
+#include
/* local includes */
-#include
+#include
+#include
-class Vm_base {
+namespace Genode
+{
+ class Board_revision;
+ class Vm_base;
+ class Machine_type;
+}
+
+struct Genode::Board_revision
+{
+ unsigned long value;
+
+ explicit Board_revision(unsigned long value) : value(value) { }
+};
+
+
+struct Genode::Machine_type
+{
+ unsigned long value;
+
+ explicit Machine_type(unsigned long value) : value(value) { }
+};
+
+
+class Genode::Vm_base : Noncopyable
+{
+ public:
+
+ using Kernel_name = String<32>;
+ using Command_line = String<64>;
protected:
- Genode::Vm_connection _vm_con;
- Genode::Rom_connection _kernel_rom;
- Genode::Dataspace_client _kernel_cap;
- const char* _cmdline;
- Genode::Vm_state *_state;
- Genode::Io_mem_connection _ram_iomem;
- Ram _ram;
- Genode::addr_t _kernel_offset;
- unsigned long _mach_type;
- unsigned long _board_rev;
+ Env &_env;
+ Kernel_name const &_kernel;
+ Command_line const &_cmdline;
+ off_t const _kernel_off;
+ Machine_type const _machine;
+ Board_revision const _board;
+ Ram const _ram;
+ Vm_connection _vm { _env };
+ Vm_state &_state { *(Vm_state*)_env.rm()
+ .attach(_vm.cpu_state()) };
- void _load_kernel()
- {
- using namespace Genode;
+ void _load_kernel();
- addr_t addr = env()->rm_session()->attach(_kernel_cap);
- memcpy((void*)(_ram.local() + _kernel_offset),
- (void*)addr, _kernel_cap.size());
- _state->ip = _ram.base() + _kernel_offset;
- env()->rm_session()->detach((void*)addr);
- }
-
- virtual void _load_kernel_surroundings() = 0;
- virtual Genode::addr_t _board_info_offset() const = 0;
+ virtual void _load_kernel_surroundings() = 0;
+ virtual addr_t _board_info_offset() const = 0;
public:
- class Inject_irq_failed : public Genode::Exception { };
+ struct Inject_irq_failed : Exception { };
+ struct Exception_handling_failed : Exception { };
- Vm_base(const char *kernel, const char *cmdline,
- Genode::addr_t ram_base, Genode::size_t ram_size,
- Genode::addr_t kernel_offset, unsigned long mach_type,
- unsigned long board_rev = 0)
- : _kernel_rom(kernel),
- _kernel_cap(_kernel_rom.dataspace()),
- _cmdline(cmdline),
- _state((Genode::Vm_state*)Genode::env()->rm_session()->attach(_vm_con.cpu_state())),
- _ram_iomem(ram_base, ram_size),
- _ram(ram_base, ram_size, (Genode::addr_t)Genode::env()->rm_session()->attach(_ram_iomem.dataspace())),
- _kernel_offset(kernel_offset),
- _mach_type(mach_type),
- _board_rev(board_rev)
- {
- _state->irq_injection = 0;
- }
+ Vm_base(Env &env,
+ Kernel_name const &kernel,
+ Command_line const &cmdline,
+ addr_t ram_base,
+ size_t ram_size,
+ off_t kernel_off,
+ Machine_type machine,
+ Board_revision board);
- void start()
- {
- Genode::memset((void*)_state, 0, sizeof(Genode::Vm_state));
- _load_kernel();
- _load_kernel_surroundings();
- _state->cpsr = 0x93; /* SVC mode and IRQs disabled */
- _state->r0 = 0;
- _state->r1 = _mach_type;
- _state->r2 = _ram.base() + _board_info_offset();
- }
+ void exception_handler(Signal_context_capability handler) {
+ _vm.exception_handler(handler); }
- void sig_handler(Genode::Signal_context_capability sig_cap) {
- _vm_con.exception_handler(sig_cap); }
+ void run() { _vm.run(); }
+ void pause() { _vm.pause(); }
- void run() { _vm_con.run(); }
- void pause() { _vm_con.pause(); }
+ void start();
+ void dump();
+ void inject_irq(unsigned irq);
+ addr_t va_to_pa(addr_t va);
- void inject_irq(unsigned const irq)
- {
- if (_state->irq_injection) { throw Inject_irq_failed(); }
- _state->irq_injection = irq;
- }
+ Vm_state const &state() const { return _state; }
+ Ram const &ram() const { return _ram; }
- void dump()
- {
- using namespace Genode;
+ addr_t smc_arg_0() { return _state.r0; }
+ addr_t smc_arg_1() { return _state.r1; }
+ addr_t smc_arg_2() { return _state.r2; }
+ addr_t smc_arg_3() { return _state.r3; }
+ addr_t smc_arg_4() { return _state.r4; }
+ addr_t smc_arg_5() { return _state.r5; }
+ addr_t smc_arg_6() { return _state.r6; }
+ addr_t smc_arg_7() { return _state.r7; }
+ addr_t smc_arg_8() { return _state.r8; }
+ addr_t smc_arg_9() { return _state.r9; }
- const char * const modes[] =
- { "und", "svc", "abt", "irq", "fiq" };
- const char * const exc[] =
- { "invalid", "reset", "undefined", "smc", "pf_abort",
- "data_abort", "irq", "fiq" };
-
- printf("Cpu state:\n");
- printf(" Register Virt Phys\n");
- printf("---------------------------------\n");
- printf(" r0 = %08lx [%08lx]\n",
- _state->r0, va_to_pa(_state->r0));
- printf(" r1 = %08lx [%08lx]\n",
- _state->r1, va_to_pa(_state->r1));
- printf(" r2 = %08lx [%08lx]\n",
- _state->r2, va_to_pa(_state->r2));
- printf(" r3 = %08lx [%08lx]\n",
- _state->r3, va_to_pa(_state->r3));
- printf(" r4 = %08lx [%08lx]\n",
- _state->r4, va_to_pa(_state->r4));
- printf(" r5 = %08lx [%08lx]\n",
- _state->r5, va_to_pa(_state->r5));
- printf(" r6 = %08lx [%08lx]\n",
- _state->r6, va_to_pa(_state->r6));
- printf(" r7 = %08lx [%08lx]\n",
- _state->r7, va_to_pa(_state->r7));
- printf(" r8 = %08lx [%08lx]\n",
- _state->r8, va_to_pa(_state->r8));
- printf(" r9 = %08lx [%08lx]\n",
- _state->r9, va_to_pa(_state->r9));
- printf(" r10 = %08lx [%08lx]\n",
- _state->r10, va_to_pa(_state->r10));
- printf(" r11 = %08lx [%08lx]\n",
- _state->r11, va_to_pa(_state->r11));
- printf(" r12 = %08lx [%08lx]\n",
- _state->r12, va_to_pa(_state->r12));
- printf(" sp = %08lx [%08lx]\n",
- _state->sp, va_to_pa(_state->sp));
- printf(" lr = %08lx [%08lx]\n",
- _state->lr, va_to_pa(_state->lr));
- printf(" ip = %08lx [%08lx]\n",
- _state->ip, va_to_pa(_state->ip));
- printf(" cpsr = %08lx\n", _state->cpsr);
- for (unsigned i = 0;
- i < Genode::Vm_state::Mode_state::MAX; i++) {
- printf(" sp_%s = %08lx [%08lx]\n", modes[i],
- _state->mode[i].sp, va_to_pa(_state->mode[i].sp));
- printf(" lr_%s = %08lx [%08lx]\n", modes[i],
- _state->mode[i].lr, va_to_pa(_state->mode[i].lr));
- printf(" spsr_%s = %08lx [%08lx]\n", modes[i],
- _state->mode[i].spsr, va_to_pa(_state->mode[i].spsr));
- }
- printf(" ttbr0 = %08lx\n", _state->ttbr[0]);
- printf(" ttbr1 = %08lx\n", _state->ttbr[1]);
- printf(" ttbrc = %08lx\n", _state->ttbrc);
- printf(" dfar = %08lx [%08lx]\n",
- _state->dfar, va_to_pa(_state->dfar));
- printf(" exception = %s\n", exc[_state->cpu_exception]);
- }
-
- Genode::addr_t va_to_pa(Genode::addr_t va)
- {
- try {
- Mmu mmu(_state, &_ram);
- return mmu.phys_addr(va);
- } catch(Ram::Invalid_addr) {}
- return 0;
- }
-
- Genode::Vm_state *state() const { return _state; }
- Ram *ram() { return &_ram; }
-
- /*
- * Read accessors for argument values of a Secure Monitor Call
- */
-
- Genode::addr_t smc_arg_0() { return _state->r0; }
- Genode::addr_t smc_arg_1() { return _state->r1; }
- Genode::addr_t smc_arg_2() { return _state->r2; }
- Genode::addr_t smc_arg_3() { return _state->r3; }
- Genode::addr_t smc_arg_4() { return _state->r4; }
- Genode::addr_t smc_arg_5() { return _state->r5; }
- Genode::addr_t smc_arg_6() { return _state->r6; }
- Genode::addr_t smc_arg_7() { return _state->r7; }
- Genode::addr_t smc_arg_8() { return _state->r8; }
- Genode::addr_t smc_arg_9() { return _state->r9; }
-
- /*
- * Write accessors for return values of a Secure Monitor Call
- */
-
- void smc_ret(Genode::addr_t const ret_0)
- {
- _state->r0 = ret_0;
- }
-
- void smc_ret(Genode::addr_t const ret_0, Genode::addr_t const ret_1)
- {
- _state->r0 = ret_0;
- _state->r1 = ret_1;
- }
+ void smc_ret(addr_t const ret_0) { _state.r0 = ret_0; }
+ void smc_ret(addr_t const ret_0, addr_t const ret_1);
};
-#endif /* _SRC__SERVER__VMM__INCLUDE__VM_H_ */
+#endif /* _VM_BASE_H_ */
diff --git a/repos/os/src/server/tz_vmm/serial.cc b/repos/os/src/server/tz_vmm/serial.cc
deleted file mode 100644
index 15bbda38e1..0000000000
--- a/repos/os/src/server/tz_vmm/serial.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * \brief Paravirtualized access to serial devices for a Trustzone VM
- * \author Martin Stein
- * \date 2015-10-23
- */
-
-/*
- * Copyright (C) 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.
- */
-
-/* local includes */
-#include
-
-using namespace Genode;
-using namespace Vmm;
-
-
-void Serial::_push(char const c)
-{
- local_addr()[_off] = c;
- _off += sizeof(char);
-}
-
-
-void Serial::_flush()
-{
- _push(0);
- log("[vm] ", local_addr());
- _off = 0;
-}
-
-
-void Serial::_send(Vm_base * const vm)
-{
- char const c = vm->smc_arg_2();
- if (c == '\n') { _flush(); }
- else { _push(c); }
- if (_off == WRAP) { _flush(); }
-}
-
-
-void Serial::handle(Vm_base * const vm)
-{
- enum { SEND = 0 };
- switch (vm->smc_arg_1()) {
- case SEND: _send(vm); break;
- default:
- Genode::error("Unknown function ", vm->smc_arg_1(), " requested on VMM serial");
- break;
- }
-}
-
-
-Serial::Serial()
-:
- Attached_ram_dataspace(env()->ram_session(), BUF_SIZE), _off(0)
-{ }
diff --git a/repos/os/src/server/tz_vmm/serial_driver.cc b/repos/os/src/server/tz_vmm/serial_driver.cc
new file mode 100644
index 0000000000..66e1f281aa
--- /dev/null
+++ b/repos/os/src/server/tz_vmm/serial_driver.cc
@@ -0,0 +1,47 @@
+/*
+ * \brief Paravirtualized access to serial device for a Trustzone VM
+ * \author Martin Stein
+ * \date 2015-10-23
+ */
+
+/*
+ * Copyright (C) 2015-2017 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.
+ */
+
+/* local includes */
+#include
+
+using namespace Genode;
+
+
+void Serial_driver::_flush()
+{
+ _push(0);
+ log("[vm] ", _buf.local_addr());
+ _off = 0;
+}
+
+
+void Serial_driver::_send(Vm_base &vm)
+{
+ char const c = vm.smc_arg_2();
+ if (c == '\n') {
+ _flush();
+ } else {
+ _push(c); }
+
+ if (_off == BUF_SIZE - 1) {
+ _flush(); }
+}
+
+
+void Serial_driver::handle_smc(Vm_base &vm)
+{
+ enum { SEND = 0 };
+ switch (vm.smc_arg_1()) {
+ case SEND: _send(vm); break;
+ default: error("unknown serial-driver function ", vm.smc_arg_1()); }
+}
diff --git a/repos/os/src/server/tz_vmm/spec/imx53/m4if.h b/repos/os/src/server/tz_vmm/spec/imx53/m4if.h
index dde6b596e8..a4e7a96bfb 100644
--- a/repos/os/src/server/tz_vmm/spec/imx53/m4if.h
+++ b/repos/os/src/server/tz_vmm/spec/imx53/m4if.h
@@ -5,19 +5,19 @@
*/
/*
- * Copyright (C) 2012 Genode Labs GmbH
+ * Copyright (C) 2012-2017 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 _SERVER__TZ_VMM__SPEC__IMX53__M4IF_H_
-#define _SERVER__TZ_VMM__SPEC__IMX53__M4IF_H_
+#ifndef _M4IF_H_
+#define _M4IF_H_
/* Genode includes */
-#include
+#include
-class M4if : Genode::Mmio
+class M4if : Genode::Attached_mmio
{
private:
@@ -58,7 +58,8 @@ class M4if : Genode::Mmio
public:
- M4if(Genode::addr_t const base) : Genode::Mmio(base) {}
+ M4if(Genode::Env &env, Genode::addr_t base, Genode::size_t size)
+ : Genode::Attached_mmio(env, base, size) { }
void set_region0(Genode::addr_t addr, Genode::size_t size)
{
@@ -87,4 +88,4 @@ class M4if : Genode::Mmio
Genode::addr_t violation_addr() { return read(); }
};
-#endif /* _SERVER__TZ_VMM__SPEC__IMX53__M4IF_H_ */
+#endif /* _M4IF_H_ */
diff --git a/repos/os/src/server/tz_vmm/spec/imx53/main.cc b/repos/os/src/server/tz_vmm/spec/imx53/main.cc
index 86d6caa8ea..546235c1a7 100644
--- a/repos/os/src/server/tz_vmm/spec/imx53/main.cc
+++ b/repos/os/src/server/tz_vmm/spec/imx53/main.cc
@@ -1,63 +1,63 @@
/*
* \brief Virtual Machine Monitor
* \author Stefan Kalkowski
+ * \author Martin Stein
* \date 2012-06-25
*/
/*
- * Copyright (C) 2008-2012 Genode Labs GmbH
+ * Copyright (C) 2008-2017 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
-#include
-#include
+#include
+#include
+#include
#include
#include
-#include
/* local includes */
#include
#include
-#include
-#include
+#include
+#include
using namespace Genode;
-enum {
- KERNEL_OFFSET = 0x8000,
- MACH_TYPE_TABLET = 3011,
- MACH_TYPE_QSB = 3273,
- BOARD_REV_TABLET = 0x53321,
-};
-
-static const char* cmdline_tablet = "console=ttymxc0,115200";
-
-void on_vmm_entry();
-void on_vmm_exit();
-
-namespace Vmm {
- class Vmm;
-}
-
-
-class Vmm::Vmm : public Thread_deprecated<8192>
+class Main
{
private:
- Signal_receiver _sig_rcv;
- Signal_context _vm_context;
- Vm *_vm;
- Io_mem_connection _m4if_io_mem;
- M4if _m4if;
- Serial _serial;
- Block _block;
+ enum {
+ KERNEL_OFFSET = 0x8000,
+ MACHINE_TABLET = 3011,
+ MACHINE_QSB = 3273,
+ BOARD_TABLET = 0x53321,
+ BOARD_QSB = 0,
+ };
- void _handle_hypervisor_call()
+ Env &_env;
+ Vm::Kernel_name const _kernel_name { "linux" };
+ Vm::Command_line const _cmd_line { "console=ttymxc0,115200" };
+ Attached_rom_dataspace _config { _env, "config" };
+ Signal_handler _exception_handler { _env.ep(), *this,
+ &Main::_handle_exception };
+
+ Heap _heap { &_env.ram(), &_env.rm() };
+ Vm _vm { _env, _kernel_name, _cmd_line,
+ Trustzone::NONSECURE_RAM_BASE,
+ Trustzone::NONSECURE_RAM_SIZE,
+ KERNEL_OFFSET, Machine_type(MACHINE_QSB),
+ Board_revision(BOARD_QSB) };
+ M4if _m4if { _env, Board_base::M4IF_BASE, Board_base::M4IF_SIZE };
+ Serial_driver _serial { _env.ram() };
+ Block_driver _block { _env.ep(), _config.xml(), _heap, _vm };
+
+ void _handle_smc()
{
enum {
FRAMEBUFFER = 0,
@@ -65,90 +65,52 @@ class Vmm::Vmm : public Thread_deprecated<8192>
SERIAL = 2,
BLOCK = 3,
};
- switch (_vm->smc_arg_0()) {
- case FRAMEBUFFER: break;
- case INPUT: break;
- case SERIAL: _serial.handle(_vm); break;
- case BLOCK: _block.handle(_vm); break;
+ switch (_vm.smc_arg_0()) {
+ case FRAMEBUFFER: break;
+ case INPUT: break;
+ case SERIAL: _serial.handle_smc(_vm); break;
+ case BLOCK: _block.handle_smc(_vm); break;
default:
- Genode::error("unknown hypervisor call!");
- _vm->dump();
+ error("unknown hypervisor call ", _vm.smc_arg_0());
+ throw Vm::Exception_handling_failed();
};
}
- bool _handle_data_abort()
+ void _handle_data_abort()
{
- _vm->dump();
- return false;
+ error("failed to handle data abort");
+ throw Vm::Exception_handling_failed();
}
- bool _handle_vm()
+ void _handle_exception()
{
- /* check exception reason */
- switch (_vm->state()->cpu_exception) {
- case Cpu_state::DATA_ABORT:
- if (!_handle_data_abort()) {
- Genode::error("could not handle data-abort will exit!");
- return false;
+ _vm.on_vmm_entry();
+ try {
+ switch (_vm.state().cpu_exception) {
+ case Cpu_state::DATA_ABORT: _handle_data_abort(); break;
+ case Cpu_state::SUPERVISOR_CALL: _handle_smc(); break;
+ default:
+ error("unknown exception ", _vm.state().cpu_exception);
+ throw Vm::Exception_handling_failed();
}
- break;
- case Cpu_state::SUPERVISOR_CALL:
- _handle_hypervisor_call();
- break;
- default:
- Genode::error("curious exception occured");
- _vm->dump();
- return false;
- }
- return true;
- }
-
- protected:
-
- void entry()
- {
- _vm->sig_handler(_sig_rcv.manage(&_vm_context));
- _vm->start();
- _vm->run();
-
- while (true) {
- Signal s = _sig_rcv.wait_for_signal();
- on_vmm_entry();
- if (s.context() == &_vm_context) {
- if (_handle_vm())
- _vm->run();
- } else {
- Genode::warning("invalid context");
- continue;
- }
- on_vmm_exit();
+ _vm.run();
}
+ catch (Vm::Exception_handling_failed) { _vm.dump(); }
+ _vm.on_vmm_exit();
};
public:
- Vmm(Vm *vm)
- : Thread_deprecated<8192>("vmm"),
- _vm(vm),
- _m4if_io_mem(Board_base::M4IF_BASE, Board_base::M4IF_SIZE),
- _m4if((addr_t)env()->rm_session()->attach(_m4if_io_mem.dataspace()))
+ Main(Env &env) : _env(env)
{
+ log("Start virtual machine ...");
_m4if.set_region0(Trustzone::SECURE_RAM_BASE,
Trustzone::SECURE_RAM_SIZE);
+ _vm.exception_handler(_exception_handler);
+ _vm.start();
+ _vm.run();
}
};
-int main()
-{
- static Vm vm("linux", cmdline_tablet,
- Trustzone::NONSECURE_RAM_BASE, Trustzone::NONSECURE_RAM_SIZE,
- KERNEL_OFFSET, MACH_TYPE_QSB);
- static Vmm::Vmm vmm(&vm);
-
- Genode::log("Start virtual machine ...");
- vmm.start();
-
- sleep_forever();
- return 0;
-}
+void Component::construct(Env &env) { static Main main(env); }
diff --git a/repos/os/src/server/tz_vmm/spec/imx53_qsb/vm.cc b/repos/os/src/server/tz_vmm/spec/imx53_qsb/vm.cc
index 7b366da59f..d5696ba9e2 100644
--- a/repos/os/src/server/tz_vmm/spec/imx53_qsb/vm.cc
+++ b/repos/os/src/server/tz_vmm/spec/imx53_qsb/vm.cc
@@ -1,19 +1,40 @@
/*
- * \brief Virtual machine implementation
+ * \brief Virtual Machine implementation
+ * \author Stefan Kalkowski
* \author Martin Stein
- * \date 2015-06-10
+ * \date 2015-02-27
*/
/*
- * Copyright (C) 2015 Genode Labs GmbH
+ * Copyright (C) 2015-2017 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
+
/* local includes */
#include
-void on_vmm_entry() { }
+using namespace Genode;
-void on_vmm_exit() { }
+
+void Vm::_load_kernel_surroundings()
+{
+ /* load initrd */
+ enum { INITRD_OFFSET = 0x1000000 };
+ Attached_rom_dataspace initrd(_env, "initrd.gz");
+ memcpy((void*)(_ram.local() + INITRD_OFFSET),
+ initrd.local_addr(), initrd.size());
+
+ /* load ATAGs */
+ Atag tag((void*)(_ram.local() + ATAG_OFFSET));
+ tag.setup_mem_tag(_ram.base(), _ram.size());
+ tag.setup_cmdline_tag(_cmdline.string());
+ tag.setup_initrd2_tag(_ram.base() + INITRD_OFFSET, initrd.size());
+ if (_board.value) {
+ tag.setup_rev_tag(_board.value); }
+ tag.setup_end_tag();
+}
diff --git a/repos/os/src/server/tz_vmm/spec/imx53_qsb/vm.h b/repos/os/src/server/tz_vmm/spec/imx53_qsb/vm.h
index 58f7532703..39ce3f6bdd 100644
--- a/repos/os/src/server/tz_vmm/spec/imx53_qsb/vm.h
+++ b/repos/os/src/server/tz_vmm/spec/imx53_qsb/vm.h
@@ -1,78 +1,56 @@
/*
- * \brief Virtual Machine implementation using device trees
+ * \brief Virtual Machine implementation
* \author Stefan Kalkowski
+ * \author Martin Stein
* \date 2015-02-27
*/
/*
- * Copyright (C) 2015 Genode Labs GmbH
+ * Copyright (C) 2015-2017 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 _SERVER__TZ_VMM__SPEC__IMX53_QSB__VM_H_
-#define _SERVER__TZ_VMM__SPEC__IMX53_QSB__VM_H_
+#ifndef _VM_H_
+#define _VM_H_
+/* local includes */
#include
#include
-class Vm : public Vm_base
+namespace Genode { class Vm; }
+
+
+class Genode::Vm : public Vm_base
{
private:
- enum {
- ATAG_OFFSET = 0x100,
- INITRD_OFFSET = 0x1000000,
- };
+ enum { ATAG_OFFSET = 0x100 };
- Genode::Rom_connection _initrd_rom;
- Genode::Dataspace_client _initrd_cap;
- void _load_initrd()
- {
- using namespace Genode;
- addr_t addr = env()->rm_session()->attach(_initrd_cap);
- memcpy((void*)(_ram.local() + INITRD_OFFSET),
- (void*)addr, _initrd_cap.size());
- env()->rm_session()->detach((void*)addr);
- }
+ /*************
+ ** Vm_base **
+ *************/
- void _load_atag()
- {
- Atag tag((void*)(_ram.local() + ATAG_OFFSET));
- tag.setup_mem_tag(_ram.base(), _ram.size());
- tag.setup_cmdline_tag(_cmdline);
- tag.setup_initrd2_tag(_ram.base() + INITRD_OFFSET, _initrd_cap.size());
- if (_board_rev)
- tag.setup_rev_tag(_board_rev);
- tag.setup_end_tag();
- }
+ void _load_kernel_surroundings();
- /*
- * Vm_base interface
- */
-
- void _load_kernel_surroundings()
- {
- _load_initrd();
- _load_atag();
- }
-
- Genode::addr_t _board_info_offset() const { return ATAG_OFFSET; }
+ addr_t _board_info_offset() const { return ATAG_OFFSET; }
public:
- Vm(const char *kernel, const char *cmdline,
- Genode::addr_t ram_base, Genode::size_t ram_size,
- Genode::addr_t kernel_offset, unsigned long mach_type,
- unsigned long board_rev = 0)
- :
- Vm_base(kernel, cmdline, ram_base, ram_size,
- kernel_offset, mach_type, board_rev),
- _initrd_rom("initrd.gz"),
- _initrd_cap(_initrd_rom.dataspace())
- { }
+ Vm(Env &env,
+ Kernel_name const &kernel,
+ Command_line const &cmdl,
+ addr_t ram,
+ size_t ram_sz,
+ off_t kernel_off,
+ Machine_type mach,
+ Board_revision board)
+ : Vm_base(env, kernel, cmdl, ram, ram_sz, kernel_off, mach, board) { }
+
+ void on_vmm_exit() { }
+ void on_vmm_entry() { };
};
-#endif /* _SERVER__TZ_VMM__SPEC__IMX53_QSB__VM_H_ */
+#endif /* _VM_H_ */
diff --git a/repos/os/src/server/tz_vmm/spec/usb_armory/vm.cc b/repos/os/src/server/tz_vmm/spec/usb_armory/vm.cc
index 5eda791ca6..557841edab 100644
--- a/repos/os/src/server/tz_vmm/spec/usb_armory/vm.cc
+++ b/repos/os/src/server/tz_vmm/spec/usb_armory/vm.cc
@@ -1,34 +1,36 @@
/*
- * \brief Virtual machine implementation
+ * \brief Virtual Machine implementation
+ * \author Stefan Kalkowski
* \author Martin Stein
- * \date 2015-06-10
+ * \date 2015-02-27
*/
/*
- * Copyright (C) 2015 Genode Labs GmbH
+ * Copyright (C) 2015-2017 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
+
/* local includes */
#include
-#include
-Gpio::Connection * led()
-{
- static Gpio::Connection led(123);
- return &led;
-}
+using namespace Genode;
-void on_vmm_entry()
+
+void Vm::on_vmm_entry()
{
- led()->direction(Gpio::Session::OUT);
- led()->write(false);
+ _led.direction(Gpio::Session::OUT);
+ _led.write(false);
}
-void on_vmm_exit()
+void Vm::_load_kernel_surroundings()
{
- led()->write(true);
+ Attached_rom_dataspace dtb(_env, "dtb");
+ memcpy((void*)(_ram.local() + DTB_OFFSET), dtb.local_addr(),
+ dtb.size());
}
diff --git a/repos/os/src/server/tz_vmm/spec/usb_armory/vm.h b/repos/os/src/server/tz_vmm/spec/usb_armory/vm.h
index 071f55ef7c..4b6f790908 100644
--- a/repos/os/src/server/tz_vmm/spec/usb_armory/vm.h
+++ b/repos/os/src/server/tz_vmm/spec/usb_armory/vm.h
@@ -1,57 +1,60 @@
/*
- * \brief Virtual Machine implementation using device trees
+ * \brief Virtual Machine implementation
* \author Stefan Kalkowski
+ * \author Martin Stein
* \date 2015-02-27
*/
/*
- * Copyright (C) 2015 Genode Labs GmbH
+ * Copyright (C) 2015-2017 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 _SERVER__TZ_VMM__SPEC__USB_ARMORY__VM_H_
-#define _SERVER__TZ_VMM__SPEC__USB_ARMORY__VM_H_
+#ifndef _VM_H_
+#define _VM_H_
+
+/* Genode includes */
+#include
/* local includes */
#include
-class Vm : public Genode::Rom_connection,
- public Genode::Dataspace_client,
- public Vm_base
+namespace Genode { class Vm; }
+
+
+class Genode::Vm : public Vm_base
{
private:
enum { DTB_OFFSET = 0x1000000 };
- void _load_dtb()
- {
- using namespace Genode;
- addr_t addr = env()->rm_session()->attach(*this);
- memcpy((void*)(_ram.local() + DTB_OFFSET), (void*)addr, size());
- env()->rm_session()->detach((void*)addr);
- }
+ Gpio::Connection _led { _env, 123 };
- /*
- * Vm_base interface
- */
- void _load_kernel_surroundings() { _load_dtb(); }
+ /*************
+ ** Vm_base **
+ *************/
- Genode::addr_t _board_info_offset() const { return DTB_OFFSET; }
+ void _load_kernel_surroundings();
+
+ addr_t _board_info_offset() const { return DTB_OFFSET; }
public:
- Vm(const char *kernel, const char *cmdline,
- Genode::addr_t ram_base, Genode::size_t ram_size,
- Genode::addr_t kernel_offset, unsigned long mach_type,
- unsigned long board_rev = 0)
- : Genode::Rom_connection("dtb"),
- Genode::Dataspace_client(dataspace()),
- Vm_base(kernel, cmdline, ram_base, ram_size,
- kernel_offset, mach_type, board_rev)
- { }
+ Vm(Env &env,
+ Kernel_name const &kernel,
+ Command_line const &cmdl,
+ addr_t ram,
+ size_t ram_sz,
+ off_t kernel_off,
+ Machine_type mach,
+ Board_revision board)
+ : Vm_base(env, kernel, cmdl, ram, ram_sz, kernel_off, mach, board) { }
+
+ void on_vmm_exit() { _led.write(true); }
+ void on_vmm_entry();
};
-#endif /* _SERVER__TZ_VMM__SPEC__USB_ARMORY__VM_H_ */
+#endif /* _VM_H_ */
diff --git a/repos/os/src/server/tz_vmm/vm_base.cc b/repos/os/src/server/tz_vmm/vm_base.cc
new file mode 100644
index 0000000000..f0b7474de6
--- /dev/null
+++ b/repos/os/src/server/tz_vmm/vm_base.cc
@@ -0,0 +1,131 @@
+/*
+ * \brief Virtual Machine Monitor VM definition
+ * \author Stefan Kalkowski
+ * \author Martin Stein
+ * \date 2012-06-25
+ */
+
+/*
+ * Copyright (C) 2012-2017 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
+
+/* local includes */
+#include
+#include
+
+using namespace Genode;
+
+
+void Vm_base::_load_kernel()
+{
+ Attached_rom_dataspace kernel(_env, _kernel.string());
+ memcpy((void*)(_ram.local() + _kernel_off),
+ kernel.local_addr(), kernel.size());
+ _state.ip = _ram.base() + _kernel_off;
+}
+
+
+Vm_base::Vm_base(Env &env,
+ Kernel_name const &kernel,
+ Command_line const &cmdline,
+ addr_t ram_base,
+ size_t ram_size,
+ off_t kernel_off,
+ Machine_type machine,
+ Board_revision board)
+:
+ _env(env), _kernel(kernel), _cmdline(cmdline), _kernel_off(kernel_off),
+ _machine(machine), _board(board), _ram(env, ram_base, ram_size)
+{
+ _state.irq_injection = 0;
+}
+
+void Vm_base::start()
+{
+ memset((void*)&_state, 0, sizeof(Vm_state));
+ _load_kernel();
+ _load_kernel_surroundings();
+ _state.cpsr = 0x93; /* SVC mode and IRQs disabled */
+ _state.r0 = 0;
+ _state.r1 = _machine.value;
+ _state.r2 = _ram.base() + _board_info_offset();
+}
+
+
+void Vm_base::inject_irq(unsigned irq)
+{
+ if (_state.irq_injection) { throw Inject_irq_failed(); }
+ _state.irq_injection = irq;
+}
+
+
+
+void Vm_base::dump()
+{
+ char const *mod[] = { "und", "svc", "abt", "irq", "fiq" };
+ char const *exc[] = { "invalid", "reset", "undefined", "smc",
+ "pf_abort", "data_abort", "irq", "fiq" };
+
+ auto log_adr_reg = [&] (char const *reg, addr_t val) {
+ log(" ", reg, " = ", Hex(val, Hex::PREFIX, Hex::PAD), " ",
+ Hex(va_to_pa(val), Hex::PREFIX, Hex::PAD)); };
+
+ auto log_mod_reg = [&] (char const *reg, addr_t val, char const *mod) {
+ log(" ", reg, "_", mod, " = ", Hex(val, Hex::PREFIX, Hex::PAD), " ",
+ Hex(va_to_pa(val), Hex::PREFIX, Hex::PAD)); };
+
+ log("Cpu state:");
+ log(" Register Virt Phys");
+ log("------------------------------------");
+ log_adr_reg("r0 ", _state.r0);
+ log_adr_reg("r1 ", _state.r1);
+ log_adr_reg("r2 ", _state.r2);
+ log_adr_reg("r3 ", _state.r3);
+ log_adr_reg("r4 ", _state.r4);
+ log_adr_reg("r5 ", _state.r5);
+ log_adr_reg("r6 ", _state.r6);
+ log_adr_reg("r7 ", _state.r7);
+ log_adr_reg("r8 ", _state.r8);
+ log_adr_reg("r9 ", _state.r9);
+ log_adr_reg("r10 ", _state.r10);
+ log_adr_reg("r11 ", _state.r11);
+ log_adr_reg("r12 ", _state.r12);
+ log_adr_reg("sp ", _state.sp);
+ log_adr_reg("lr ", _state.lr);
+ log_adr_reg("ip ", _state.ip);
+ log_adr_reg("cpsr ", _state.cpsr);
+ for (unsigned i = 0; i < Vm_state::Mode_state::MAX; i++) {
+ log_mod_reg("sp ", _state.mode[i].sp, mod[i]);
+ log_mod_reg("lr ", _state.mode[i].lr, mod[i]);
+ log_mod_reg("spsr ", _state.mode[i].spsr, mod[i]);
+ }
+ log(" ttbr0 = ", Hex(_state.ttbr[0], Hex::PREFIX, Hex::PAD));
+ log(" ttbr1 = ", Hex(_state.ttbr[1], Hex::PREFIX, Hex::PAD));
+ log(" ttbrc = ", Hex(_state.ttbrc , Hex::PREFIX, Hex::PAD));
+ log_adr_reg("dfar ", _state.dfar);
+ log(" exception = ", exc[_state.cpu_exception]);
+}
+
+
+void Vm_base::smc_ret(addr_t const ret_0, addr_t const ret_1)
+{
+ _state.r0 = ret_0;
+ _state.r1 = ret_1;
+}
+
+
+addr_t Vm_base::va_to_pa(addr_t va)
+{
+ try {
+ Mmu mmu(_state, _ram);
+ return mmu.phys_addr(va);
+ }
+ catch(Ram::Invalid_addr) { }
+ return 0;
+}