From c9f7e9dbb254913d6ba5cbef8ddf3dac908804a6 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Thu, 5 Jan 2017 20:42:16 +0100 Subject: [PATCH] tz_vmm: update to new API and clean up * get rid of printf * use exceptions instead of error codes * use Id_space instead of the individual block device registry * use Cstring instead of char const* * move method definitions > 1 line to .cc files * rename Block Block_driver and Serial Serial_driver to avoid name clashes with the Genode namespace and thereby simplify the code * use lambdas for Block device lookup and apply * switch to the Component framework * don't use env(), config(), ... and hand over env to each connection * use Attached_mmio and Attached_rom/ram_dataspace instead of manual solutions Fixes #2223 --- repos/os/lib/mk/spec/imx53/tz_vmm.inc | 2 +- repos/os/run/tz_vmm.run | 2 +- repos/os/src/server/tz_vmm/block.cc | 602 ------------------ repos/os/src/server/tz_vmm/block_driver.cc | 315 +++++++++ repos/os/src/server/tz_vmm/include/block.h | 73 --- .../src/server/tz_vmm/include/block_driver.h | 154 +++++ repos/os/src/server/tz_vmm/include/mmu.h | 16 +- repos/os/src/server/tz_vmm/include/ram.h | 22 +- repos/os/src/server/tz_vmm/include/serial.h | 53 -- .../src/server/tz_vmm/include/serial_driver.h | 46 ++ repos/os/src/server/tz_vmm/include/vm_base.h | 251 +++----- repos/os/src/server/tz_vmm/serial.cc | 60 -- repos/os/src/server/tz_vmm/serial_driver.cc | 47 ++ repos/os/src/server/tz_vmm/spec/imx53/m4if.h | 15 +- repos/os/src/server/tz_vmm/spec/imx53/main.cc | 160 ++--- .../os/src/server/tz_vmm/spec/imx53_qsb/vm.cc | 31 +- .../os/src/server/tz_vmm/spec/imx53_qsb/vm.h | 80 +-- .../src/server/tz_vmm/spec/usb_armory/vm.cc | 30 +- .../os/src/server/tz_vmm/spec/usb_armory/vm.h | 61 +- repos/os/src/server/tz_vmm/vm_base.cc | 131 ++++ 20 files changed, 970 insertions(+), 1181 deletions(-) delete mode 100644 repos/os/src/server/tz_vmm/block.cc create mode 100644 repos/os/src/server/tz_vmm/block_driver.cc delete mode 100644 repos/os/src/server/tz_vmm/include/block.h create mode 100644 repos/os/src/server/tz_vmm/include/block_driver.h delete mode 100644 repos/os/src/server/tz_vmm/include/serial.h create mode 100644 repos/os/src/server/tz_vmm/include/serial_driver.h delete mode 100644 repos/os/src/server/tz_vmm/serial.cc create mode 100644 repos/os/src/server/tz_vmm/serial_driver.cc create mode 100644 repos/os/src/server/tz_vmm/vm_base.cc diff --git a/repos/os/lib/mk/spec/imx53/tz_vmm.inc b/repos/os/lib/mk/spec/imx53/tz_vmm.inc index 2620ec269..50abab75a 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 500b74ec0..1bfc676db 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 6fd762bad..000000000 --- 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 000000000..475ae9569 --- /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 a1bbec09a..000000000 --- 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 000000000..87d32781b --- /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 e7231e485..bf733a409 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 6fce1f8da..bdeb23b13 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 d09ac159a..000000000 --- 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 000000000..a08d4442b --- /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 65b5d76a0..b1cd11469 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 15bbda38e..000000000 --- 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 000000000..66e1f281a --- /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 dde6b596e..a4e7a96bf 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 86d6caa8e..546235c1a 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 7b366da59..d5696ba9e 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 58f753270..39ce3f6bd 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 5eda791ca..557841eda 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 071f55ef7..4b6f79090 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 000000000..f0b7474de --- /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; +}