os: move tz_vmm example to imx repository

Ref genodelabs/genode#5252
This commit is contained in:
Stefan Kalkowski 2024-06-19 13:43:05 +02:00 committed by Norman Feske
parent 5a8d149fe3
commit 6162eae9e0
20 changed files with 0 additions and 1675 deletions

View File

@ -1,77 +0,0 @@
#
# \brief Virtual-machine monitor demo
# \author Stefan Kalkowski
# \author Martin Stein
# \date 2012-06-25
#
assert_spec hw
if {![have_board imx53_qsb_tz]} {
puts "\n Run script is not supported on this platform. \n"
exit 0
}
build { core init lib/ld server/tz_vmm }
create_boot_directory
# compose config
install_config {
<config verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="VM"/>
</parent-provides>
<default-route>
<any-service><any-child/><parent/></any-service>
</default-route>
<default caps="100"/>
<start name="imx53_qsb_tz_vmm">
<resource name="RAM" quantum="10M"/>
</start>
</config> }
# download and add linux
cd bin
set linux_uri "http://genode.org/files/images/imx53_qsb/linux_trustzone.bin"
if {![file exists linux]} {
puts "Download linux binary ..."
exec >& /dev/null wget -c -O linux $linux_uri
}
exec >& /dev/null wget -O linux.md5 $linux_uri.md5
exec md5sum -c linux.md5
# download and add initrd
set initrd_uri "http://genode.org/files/images/imx53_qsb/initrd.gz"
if {![file exists initrd.gz]} {
puts "Download initramfs ..."
exec >& /dev/null wget -c -O initrd.gz $initrd_uri
}
exec >& /dev/null wget -O initrd.gz.md5 $initrd_uri.md5
exec md5sum -c initrd.gz.md5
cd ..
build_boot_image [list {*}[build_artifacts] linux initrd.gz]
# execute and wait for console
run_genode_until {.*\/ #.*} 220
set serial_id [output_spawn_id]
# wait for network to settle down
send -i $serial_id "sleep 5\n"
# test network
send -i $serial_id "ping 1.1.1.1\n"
run_genode_until "64 bytes from 1.1.1.1:.*\n" 30 $serial_id

View File

@ -1,9 +0,0 @@
This is a small example virtual machine monitor, that uses the base-hw kernel
as secure-world micro-hypervisor on ARM TrustZone platforms. The VMM
configures TrustZone hardware in a way, that allows a guest to access nearly
all devices, and the DDR-RAM. Only few resources needed by the kernel (timer,
SRAM) aren't accessable by the virtual-machine.
Moreover, the VMM prepares the guest memory with a Linux image, and ramdisk,
and boots it. For the Linux guest to work properly a small patch, and tweaked
configuration is needed.

View File

@ -1,317 +0,0 @@
/*
* \brief Paravirtualized access to block devices for VMs
* \author Martin Stein
* \author Benjamin Lamowski
* \date 2015-10-23
*/
/*
* Copyright (C) 2015-2023 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* local includes */
#include <block_driver.h>
/* Genode includes */
#include <util/construct_at.h>
#include <util/xml_node.h>
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(Env &env,
Xml_node node,
Range_allocator &alloc,
Id_space<Device> &id_space,
Id id,
Vm_base &vm)
:
_vm(vm), _name(node.attribute_value("name", Name())),
_irq(node.attribute_value("irq", ~(unsigned)0)),
_irq_handler(env.ep(), *this, &Device::_handle_irq),
_session(env, &alloc, TX_BUF_SIZE, _name.string()),
_id_space_elem(*this, id_space, id)
{
if (_name == Name() || _irq == ~(unsigned)0) {
throw Invalid(); }
}
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(Env &env,
Xml_node config,
Allocator &alloc,
Vm_base &vm) : _dev_alloc(&alloc)
{
config.for_each_sub_node("block", [&] (Xml_node node) {
try { new (alloc) Device(env, node, _dev_alloc, _devs,
Device::Id { _dev_count++ }, vm); }
catch (Device::Invalid) { error("invalid block device"); }
});
}
void Block_driver::_name(Vm_base &vm, Vcpu_state &state)
{
_dev_apply(Device::Id { state.r2 },
[&] (Device &dev) { copy_cstring((char *)_buf, dev.name().string(), _buf_size); },
[&] () { ((char *)_buf)[0] = 0; });
}
void Block_driver::_block_count(Vm_base &vm, Vcpu_state &state)
{
_dev_apply(Device::Id { state.r2 },
[&] (Device &dev) { state.r0 = dev.block_count(); },
[&] () { state.r0 = 0; });
}
void Block_driver::_block_size(Vm_base &vm, Vcpu_state &state)
{
_dev_apply(Device::Id { state.r2 },
[&] (Device &dev) { state.r0 = dev.block_size(); },
[&] () { state.r0 = 0; });
}
void Block_driver::_queue_size(Vm_base &vm, Vcpu_state &state)
{
_dev_apply(Device::Id { state.r2 },
[&] (Device &dev) { state.r0 = dev.session().tx()->bulk_buffer_size(); },
[&] () { state.r0 = 0; });
}
void Block_driver::_writeable(Vm_base &vm, Vcpu_state &state)
{
_dev_apply(Device::Id { state.r2 },
[&] (Device &dev) { state.r0 = dev.writeable(); },
[&] () { state.r0 = false; });
}
void Block_driver::_irq(Vm_base &vm, Vcpu_state &state)
{
_dev_apply(Device::Id { state.r2 },
[&] (Device &dev) { state.r0 = dev.irq(); },
[&] () { state.r0 = ~(unsigned)0; });
}
void Block_driver::_buffer(Vm_base &vm, Vcpu_state &state)
{
addr_t const buf_base = state.r2;
_buf_size = state.r3;
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, Vcpu_state &state)
{
auto dev_func = [&] (Device &dev) {
try {
size_t const size = state.r3;
void *const req = (void*)state.r4;
Packet_descriptor pkt = dev.session().alloc_packet(size);
void *addr = dev.session().tx()->packet_content(pkt);
dev.cache().insert(addr, req);
state.r0 = (long)addr;
state.r1 = 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 { state.r2 }, dev_func, [&] () {
state.r0 = 0;
state.r1 = 0;
});
}
void Block_driver::_submit_request(Vm_base &vm, Vcpu_state &state)
{
auto dev_func = [&] (Device &dev) {
off_t const queue_offset = state.r3;
size_t const size = state.r4;
bool const write = state.r7;
void *const dst = (void *)state.r8;
unsigned long long const disc_offset =
(unsigned long long)state.r5 << 32 | state.r6;
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 { state.r2 }, dev_func, [] () { });
}
void Block_driver::_collect_reply(Vm_base &vm, Vcpu_state &state)
{
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()) {
state.r0 = 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<Reply>(_buf, req, write, dat_size, dat);
dev.session().tx()->release_packet(pkt);
state.r0 = 1;
};
_dev_apply(Device::Id { state.r2 }, dev_func, [&] () { state.r0 = -1; });
}
void Block_driver::handle_smc(Vm_base &vm, Vcpu_state &state)
{
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 (state.r1) {
case DEVICE_COUNT: state.r0 = _dev_count; break;
case BLOCK_COUNT: _block_count(vm, state); break;
case BLOCK_SIZE: _block_size(vm, state); break;
case WRITEABLE: _writeable(vm, state); break;
case QUEUE_SIZE: _queue_size(vm, state); break;
case IRQ: _irq(vm, state); break;
case START_CALLBACK: _devs.for_each<Device>([&] (Device &dev)
{ dev.start_irq_handling(); }); break;
case NEW_REQUEST: _new_request(vm, state); break;
case SUBMIT_REQUEST: _submit_request(vm, state); break;
case COLLECT_REPLY: _collect_reply(vm, state); break;
case BUFFER: _buffer(vm, state); break;
case NAME: _name(vm, state); break;
default:
error("unknown block-driver function ", state.r1);
throw Vm_base::Exception_handling_failed();
}
}

View File

@ -1,201 +0,0 @@
/**
* \brief Arm boot descriptor tags (ATAGs).
* \author Stefan Kalkowski
* \date 2012-07-30
*
* Based on the code example of Vincent Sanders (published under BSD licence):
* http://www.simtec.co.uk/products/SWLINUX/files/booting_article.html
*/
/*
* 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 Affero General Public License version 3.
*/
#ifndef _SRC__SERVER__VMM__INCLUDE__ATAG_H_
#define _SRC__SERVER__VMM__INCLUDE__ATAG_H_
#include <base/stdint.h>
#include <util/string.h>
class Atag {
private:
enum atags {
ATAG_NONE = 0x00000000,
ATAG_CORE = 0x54410001,
ATAG_MEM = 0x54410002,
ATAG_VIDEOTEXT = 0x54410003,
ATAG_RAMDISK = 0x54410004,
ATAG_INITRD2 = 0x54420005,
ATAG_SERIAL = 0x54410006,
ATAG_REVISION = 0x54410007,
ATAG_VIDEOLFB = 0x54410008,
ATAG_CMDLINE = 0x54410009,
};
struct atag_header {
Genode::uint32_t size;
Genode::uint32_t tag;
};
struct atag_core {
Genode::uint32_t flags;
Genode::uint32_t pagesize;
Genode::uint32_t rootdev;
};
struct atag_mem {
Genode::uint32_t size;
Genode::uint32_t start;
};
struct atag_videotext {
Genode::uint8_t x;
Genode::uint8_t y;
Genode::uint16_t video_page;
Genode::uint8_t video_mode;
Genode::uint8_t video_cols;
Genode::uint16_t video_ega_bx;
Genode::uint8_t video_lines;
Genode::uint8_t video_isvga;
Genode::uint16_t video_points;
};
struct atag_ramdisk {
Genode::uint32_t flags;
Genode::uint32_t size;
Genode::uint32_t start;
};
struct atag_initrd2 {
Genode::uint32_t start;
Genode::uint32_t size;
};
struct atag_serialnr {
Genode::uint32_t low;
Genode::uint32_t high;
};
struct atag_revision {
Genode::uint32_t rev;
};
struct atag_videolfb {
Genode::uint16_t lfb_width;
Genode::uint16_t lfb_height;
Genode::uint16_t lfb_depth;
Genode::uint16_t lfb_linelength;
Genode::uint32_t lfb_base;
Genode::uint32_t lfb_size;
Genode::uint8_t red_size;
Genode::uint8_t red_pos;
Genode::uint8_t green_size;
Genode::uint8_t green_pos;
Genode::uint8_t blue_size;
Genode::uint8_t blue_pos;
Genode::uint8_t rsvd_size;
Genode::uint8_t rsvd_pos;
};
struct atag_cmdline {
char cmdline[1];
};
struct atag {
struct atag_header hdr;
union {
struct atag_core core;
struct atag_mem mem;
struct atag_videotext videotext;
struct atag_ramdisk ramdisk;
struct atag_initrd2 initrd2;
struct atag_serialnr serialnr;
struct atag_revision revision;
struct atag_videolfb videolfb;
struct atag_cmdline cmdline;
} u;
};
struct atag *_params; /* used to point at the current tag */
inline void _next() {
_params = ((struct atag *)((Genode::uint32_t *)(_params)
+ _params->hdr.size)); }
template <typename TAG>
Genode::size_t _size() {
return ((sizeof(struct atag_header) + sizeof(TAG)) >> 2); }
public:
Atag(void* base) : _params((struct atag *)base)
{
_params->hdr.tag = ATAG_CORE;
_params->hdr.size = _size<struct atag_core>();
_params->u.core.flags = 1;
_params->u.core.pagesize = 0x1000;
_params->u.core.rootdev = 0;
_next();
}
void setup_ramdisk_tag(Genode::size_t size)
{
_params->hdr.tag = ATAG_RAMDISK;
_params->hdr.size = _size<struct atag_ramdisk>();
_params->u.ramdisk.flags = 0;
_params->u.ramdisk.size = size;
_params->u.ramdisk.start = 0;
_next();
}
void setup_initrd2_tag(Genode::addr_t start, Genode::size_t size)
{
_params->hdr.tag = ATAG_INITRD2;
_params->hdr.size = _size<struct atag_initrd2>();
_params->u.initrd2.start = start;
_params->u.initrd2.size = size;
_next();
}
void setup_rev_tag(Genode::addr_t rev)
{
_params->hdr.tag = ATAG_REVISION;
_params->hdr.size = _size<struct atag_revision>();
_params->u.revision.rev = rev;
_next();
}
void setup_mem_tag(Genode::addr_t start, Genode::size_t len)
{
_params->hdr.tag = ATAG_MEM;
_params->hdr.size = _size<struct atag_mem>();
_params->u.mem.start = start;
_params->u.mem.size = len;
_next();
}
void setup_cmdline_tag(const char * line)
{
int len = Genode::strlen(line);
if(!len)
return;
_params->hdr.tag = ATAG_CMDLINE;
_params->hdr.size = (sizeof(struct atag_header) + len + 1 + 4) >> 2;
Genode::copy_cstring(_params->u.cmdline.cmdline, line, len + 1);
_next();
}
void setup_end_tag(void)
{
_params->hdr.tag = ATAG_NONE;
_params->hdr.size = 0;
}
};
#endif /* _SRC__SERVER__VMM__INCLUDE__ATAG_H_ */

View File

@ -1,158 +0,0 @@
/*
* \brief Paravirtualized access to block devices for VMs
* \author Martin Stein
* \author Benjamin Lamowski
* \date 2015-10-23
*/
/*
* Copyright (C) 2015-2023 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _BLOCK_DRIVER_H_
#define _BLOCK_DRIVER_H_
/* Genode includes */
#include <block_session/connection.h>
#include <base/allocator_avl.h>
/* local includes */
#include <vm_base.h>
namespace Genode {
class Xml_node;
class Block_driver;
}
class Genode::Block_driver
{
private:
/*
* Noncopyable
*/
Block_driver(Block_driver const &);
Block_driver &operator = (Block_driver const &);
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<Device>::Id;
using Name = String<64>;
private:
Request_cache _cache { };
Vm_base &_vm;
Name const _name;
unsigned const _irq;
Signal_handler<Device> _irq_handler;
Block::Connection<> _session;
Id_space<Device>::Element _id_space_elem;
Block::Session::Info const _info { _session.info() };
public:
void _handle_irq() { _vm.inject_irq(_irq); }
public:
struct Invalid : Exception { };
Device(Env &env,
Xml_node node,
Range_allocator &alloc,
Id_space<Device> &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 _info.block_size; }
size_t block_count() const { return _info.block_count; }
bool writeable() const { return _info.writeable; }
Name const &name() const { return _name; }
unsigned irq() const { return _irq; }
};
void *_buf = nullptr;
size_t _buf_size = 0;
Id_space<Device> _devs;
unsigned _dev_count = 0;
Allocator_avl _dev_alloc;
void _buf_to_pkt(void *dst, size_t sz);
void _name(Vm_base &vm, Vcpu_state &state);
void _block_count(Vm_base &vm, Vcpu_state &state);
void _block_size(Vm_base &vm, Vcpu_state &state);
void _queue_size(Vm_base &vm, Vcpu_state &state);
void _writeable(Vm_base &vm, Vcpu_state &state);
void _irq(Vm_base &vm, Vcpu_state &state);
void _buffer(Vm_base &vm, Vcpu_state &state);
void _device_count(Vm_base &vm, Vcpu_state &state);
void _new_request(Vm_base &vm, Vcpu_state &state);
void _submit_request(Vm_base &vm, Vcpu_state &state);
void _collect_reply(Vm_base &vm, Vcpu_state &state);
template <typename DEV_FUNC, typename ERR_FUNC>
void _dev_apply(Device::Id id,
DEV_FUNC const &dev_func,
ERR_FUNC const &err_func)
{
try { _devs.apply<Device>(id, [&] (Device &dev) { dev_func(dev); }); }
catch (Id_space<Device>::Unknown_id) {
error("unknown block device ", id);
err_func();
}
catch (Device_function_failed) { err_func(); }
}
public:
void handle_smc(Vm_base &vm, Vcpu_state &state);
Block_driver(Env &env,
Xml_node config,
Allocator &alloc,
Vm_base &vm);
};
#endif /* _BLOCK_DRIVER_H_ */

View File

@ -1,93 +0,0 @@
/*
* \brief Virtual Machine Monitor MMU definition
* \author Stefan Kalkowski
* \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 Affero General Public License version 3.
*/
#ifndef _SRC__SERVER__VMM__INCLUDE__MMU_H_
#define _SRC__SERVER__VMM__INCLUDE__MMU_H_
/* base includes */
#include <cpu/vcpu_state_trustzone.h>
/* local includes */
#include <ram.h>
class Mmu
{
private:
Genode::Vcpu_state &_state;
Ram const &_ram;
unsigned _n_bits() { return _state.ttbrc & 0x7; }
bool _ttbr0(Genode::addr_t mva) {
return (!_n_bits() || !(mva >> (32 - _n_bits()))); }
Genode::addr_t _first_level(Genode::addr_t va)
{
if (!_ttbr0(va))
return ((_state.ttbr[1] & 0xffffc000) |
((va >> 18) & 0xffffc));
unsigned shift = 14 - _n_bits();
return (((_state.ttbr[0] >> shift) << shift) |
(((va << _n_bits()) >> (18 + _n_bits())) & 0x3ffc));
}
Genode::addr_t _page(Genode::addr_t fe, Genode::addr_t va)
{
enum Type { FAULT, LARGE, SMALL };
Genode::addr_t se = *((Genode::addr_t*)_ram.va(((fe & (~0UL << 10)) |
((va >> 10) & 0x3fc))));
switch (se & 0x3) {
case FAULT:
return 0;
case LARGE:
return ((se & (~0UL << 16)) | (va & (~0UL >> 16)));
default:
return ((se & (~0UL << 12)) | (va & (~0UL >> 20)));
}
return 0;
}
Genode::addr_t _section(Genode::addr_t fe, Genode::addr_t va) {
return ((fe & 0xfff00000) | (va & 0xfffff)); }
Genode::addr_t _supersection(Genode::addr_t fe, Genode::addr_t va)
{
Genode::warning(__func__, " not implemented yet!");
return 0;
}
public:
Mmu(Genode::Vcpu_state &state, Ram const &ram)
: _state(state), _ram(ram) {}
Genode::addr_t phys_addr(Genode::addr_t va)
{
enum Type { FAULT, PAGETABLE, SECTION };
Genode::addr_t fe = *((Genode::addr_t*)_ram.va(_first_level(va)));
switch (fe & 0x3) {
case PAGETABLE:
return _page(fe, va);
case SECTION:
return (fe & 0x40000) ? _supersection(fe, va)
: _section(fe, va);
}
return 0;
}
};
#endif /* _SRC__SERVER__VMM__INCLUDE__MMU_H_ */

View File

@ -1,52 +0,0 @@
/*
* \brief Virtual Machine Monitor RAM definition
* \author Stefan Kalkowski
* \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 Affero General Public License version 3.
*/
#ifndef _SRC__SERVER__VMM__INCLUDE__RAM_H_
#define _SRC__SERVER__VMM__INCLUDE__RAM_H_
/* Genode includes */
#include <base/attached_io_mem_dataspace.h>
#include <base/stdint.h>
#include <base/exception.h>
class Ram {
private:
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::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<void>()) { }
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) const
{
if ((phys < _base) || (phys > (_base + _size)))
throw Invalid_addr();
return _local + (phys - _base);
}
};
#endif /* _SRC__SERVER__VMM__INCLUDE__RAM_H_ */

View File

@ -1,48 +0,0 @@
/*
* \brief Paravirtualized access to serial device for a Trustzone VM
* \author Martin Stein
* \author Benjamin Lamowski
* \date 2015-10-23
*/
/*
* Copyright (C) 2015-2023 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SERIAL_DRIVER_H_
#define _SERIAL_DRIVER_H_
/* Genode includes */
#include <base/attached_ram_dataspace.h>
/* local includes */
#include <vm_base.h>
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<char>()[_off++] = c; }
void _flush();
void _send(Vm_base &vm, Vcpu_state &state);
public:
void handle_smc(Vm_base &vm, Vcpu_state &state);
Serial_driver(Ram_allocator &ram, Region_map &local_rm)
: _buf(ram, local_rm, BUF_SIZE) { }
};
#endif /* _SERIAL_DRIVER_H_ */

View File

@ -1,114 +0,0 @@
/*
* \brief Virtual Machine Monitor VM definition
* \author Stefan Kalkowski
* \author Martin Stein
* \author Benjamin Lamowski
* \date 2012-06-25
*/
/*
* Copyright (C) 2012-2023 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VM_BASE_H_
#define _VM_BASE_H_
/* Genode includes */
#include <dataspace/client.h>
#include <rom_session/connection.h>
#include <vm_session/connection.h>
#include <vm_session/handler.h>
#include <util/noncopyable.h>
#include <cpu/vcpu_state_trustzone.h>
/* local includes */
#include <ram.h>
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, Interface
{
public:
using Kernel_name = String<32>;
using Command_line = String<64>;
private:
Vm_base(Vm_base const &);
Vm_base &operator = (Vm_base const &);
protected:
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_connection::Exit_config _exit_config { };
Vm_connection::Vcpu _vcpu;
void _load_kernel(Vcpu_state &);
virtual void _load_kernel_surroundings() = 0;
virtual addr_t _board_info_offset() const = 0;
public:
struct Inject_irq_failed : Exception { };
struct Exception_handling_failed : Exception { };
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,
Allocator &alloc,
Vcpu_handler_base &handler);
void start(Vcpu_state &);
void dump(Vcpu_state &);
void inject_irq(unsigned irq);
addr_t va_to_pa(Vcpu_state &state, addr_t va);
Ram const &ram() const { return _ram; }
template<typename FN>
void with_state(FN const & fn)
{
_vcpu.with_state(fn);
}
};
#endif /* _VM_BASE_H_ */

View File

@ -1,48 +0,0 @@
/*
* \brief Paravirtualized access to serial device for a Trustzone VM
* \author Martin Stein
* \author Benjamin Lamowski
* \date 2015-10-23
*/
/*
* Copyright (C) 2015-2023 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* local includes */
#include <serial_driver.h>
using namespace Genode;
void Serial_driver::_flush()
{
_push(0);
log("[vm] ", _buf.local_addr<char const>());
_off = 0;
}
void Serial_driver::_send(Vm_base &vm, Vcpu_state &state)
{
char const c = state.r2;
if (c == '\n') {
_flush();
} else {
_push(c); }
if (_off == BUF_SIZE - 1) {
_flush(); }
}
void Serial_driver::handle_smc(Vm_base &vm, Vcpu_state &state)
{
enum { SEND = 0 };
switch (state.r1) {
case SEND: _send(vm, state); break;
default: error("unknown serial-driver function ", state.r1); }
}

View File

@ -1,91 +0,0 @@
/*
* \brief Driver for the Multi Master Multi Memory Interface
* \author Stefan Kalkowski
* \date 2012-11-06
*/
/*
* 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 Affero General Public License version 3.
*/
#ifndef _M4IF_H_
#define _M4IF_H_
/* Genode includes */
#include <os/attached_mmio.h>
class M4if : Genode::Attached_mmio<0x11c>
{
private:
enum { SZ_256MB = 1024 * 1024 * 256 };
struct Protection_boundary_crossed {};
struct Wm_reg0_ddr0_start : public Register<0xec, 32>
{
struct Addr : Bitfield<0,20> {};
struct Enable : Bitfield<31,1> {};
};
struct Wm_reg0_ddr1_start : public Register<0xf0, 32>
{
struct Addr : Bitfield<0,20> {};
struct Enable : Bitfield<31,1> {};
};
struct Wm_reg0_ddr0_end : public Register<0x10c, 32>
{
struct Addr : Bitfield<0,20> {};
};
struct Wm_reg0_ddr1_end : public Register<0x110, 32>
{
struct Addr : Bitfield<0,20> {};
};
struct Wm_reg0_irq : public Register<0x114, 32>
{
struct Status_ddr0 : Bitfield<6,1> {};
struct Enable : Bitfield<31,1> {};
};
struct Wm_reg0_addr : public Register<0x118, 32> {};
public:
M4if(Genode::Env &env, Genode::Byte_range_ptr const &range)
: Attached_mmio(env, range) { }
void set_region0(Genode::addr_t addr, Genode::size_t size)
{
if (size > SZ_256MB) throw Protection_boundary_crossed();
write<Wm_reg0_ddr0_end::Addr>((addr+size-1) >> 12);
write<Wm_reg0_ddr0_start>(
Wm_reg0_ddr0_start::Addr::bits(addr >> 12) |
Wm_reg0_ddr0_start::Enable::bits(1));
write<Wm_reg0_irq::Enable>(1);
}
void set_region1(Genode::addr_t addr, Genode::size_t size)
{
if (size > SZ_256MB) throw Protection_boundary_crossed();
write<Wm_reg0_ddr1_end::Addr>((addr+size-1) >> 12);
write<Wm_reg0_ddr1_start>(
Wm_reg0_ddr1_start::Addr::bits(addr >> 12) |
Wm_reg0_ddr1_start::Enable::bits(1));
write<Wm_reg0_irq::Enable>(1);
}
void ack_irq() { write<Wm_reg0_irq::Status_ddr0>(1); }
Genode::addr_t violation_addr() { return read<Wm_reg0_addr>(); }
};
#endif /* _M4IF_H_ */

View File

@ -1,118 +0,0 @@
/*
* \brief Virtual Machine Monitor
* \author Stefan Kalkowski
* \author Martin Stein
* \author Benjamin Lamowski
* \date 2012-06-25
*/
/*
* Copyright (C) 2008-2023 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/attached_rom_dataspace.h>
#include <base/heap.h>
#include <base/component.h>
#include <drivers/defs/imx53.h>
#include <drivers/defs/imx53_trustzone.h>
/* local includes */
#include <vm.h>
#include <m4if.h>
#include <serial_driver.h>
#include <block_driver.h>
using namespace Genode;
class Main
{
private:
enum {
KERNEL_OFFSET = 0x8000,
MACHINE_TABLET = 3011,
MACHINE_QSB = 3273,
BOARD_TABLET = 0x53321,
BOARD_QSB = 0,
};
Env &_env;
Vm::Kernel_name const _kernel_name { "linux" };
Vm::Command_line const _cmd_line { "console=ttymxc0,115200" };
Attached_rom_dataspace _config { _env, "config" };
Vcpu_handler<Main> _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),
_heap, _exception_handler };
M4if _m4if { _env, {(char *)Imx53::M4IF_BASE, Imx53::M4IF_SIZE} };
Serial_driver _serial { _env.ram(), _env.rm() };
Block_driver _block { _env, _config.xml(), _heap, _vm };
void _handle_smc(Vcpu_state &state)
{
enum {
FRAMEBUFFER = 0,
INPUT = 1,
SERIAL = 2,
BLOCK = 3,
};
switch (state.r0) {
case FRAMEBUFFER: break;
case INPUT: break;
case SERIAL: _serial.handle_smc(_vm, state); break;
case BLOCK: _block.handle_smc(_vm, state); break;
default:
error("unknown hypervisor call ", state.r0);
throw Vm::Exception_handling_failed();
};
}
void _handle_data_abort()
{
error("failed to handle data abort");
throw Vm::Exception_handling_failed();
}
void _handle_exception()
{
_vm.with_state([this](Vcpu_state &state) {
_vm.on_vmm_entry();
try {
switch (state.cpu_exception) {
case Cpu_state::DATA_ABORT: _handle_data_abort(); break;
case Cpu_state::SUPERVISOR_CALL: _handle_smc(state); break;
case VCPU_EXCEPTION_STARTUP: _vm.start(state); break;
default:
error("unknown exception ", state.cpu_exception);
throw Vm::Exception_handling_failed();
}
}
catch (Vm::Exception_handling_failed) { _vm.dump(state); }
_vm.on_vmm_exit();
return true;
});
};
public:
Main(Env &env) : _env(env)
{
log("Start virtual machine ...");
_m4if.set_region0(Trustzone::SECURE_RAM_BASE,
Trustzone::SECURE_RAM_SIZE);
}
};
void Component::construct(Env &env) { static Main main(env); }

View File

@ -1,9 +0,0 @@
REQUIRES = hw arm_v7
LIBS += base
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
vpath % $(REP_DIR)/src/server/tz_vmm
CC_CXX_WARN_STRICT =

View File

@ -1,5 +0,0 @@
TARGET = imx53_qsb_tz_vmm
INC_DIR += $(REP_DIR)/src/server/tz_vmm/spec/imx53_qsb
SRC_CC += spec/imx53_qsb/vm.cc
include $(REP_DIR)/src/server/tz_vmm/spec/imx53/target.inc

View File

@ -1,40 +0,0 @@
/*
* \brief Virtual Machine implementation
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2015-02-27
*/
/*
* 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 Affero General Public License version 3.
*/
/* Genode includes */
#include <base/attached_rom_dataspace.h>
/* local includes */
#include <vm.h>
using namespace Genode;
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<void>(), 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();
}

View File

@ -1,60 +0,0 @@
/*
* \brief Virtual Machine implementation
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2015-02-27
*/
/*
* 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 Affero General Public License version 3.
*/
#ifndef _VM_H_
#define _VM_H_
/* local includes */
#include <vm_base.h>
#include <atag.h>
namespace Genode { class Vm; }
class Genode::Vm : public Vm_base
{
private:
enum { ATAG_OFFSET = 0x100 };
/*************
** Vm_base **
*************/
void _load_kernel_surroundings();
addr_t _board_info_offset() const { return ATAG_OFFSET; }
public:
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,
Allocator &alloc,
Vcpu_handler_base &handler)
: Vm_base(env, kernel, cmdl, ram, ram_sz, kernel_off, mach, board,
alloc, handler)
{ }
void on_vmm_exit() { }
void on_vmm_entry() { };
};
#endif /* _VM_H_ */

View File

@ -1,5 +0,0 @@
TARGET = usb_armory_tz_vmm
INC_DIR += $(REP_DIR)/src/server/tz_vmm/spec/usb_armory
SRC_CC += spec/usb_armory/vm.cc
include $(REP_DIR)/src/server/tz_vmm/spec/imx53/target.inc

View File

@ -1,36 +0,0 @@
/*
* \brief Virtual Machine implementation
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2015-02-27
*/
/*
* 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 Affero General Public License version 3.
*/
/* Genode includes */
#include <base/attached_rom_dataspace.h>
/* local includes */
#include <vm.h>
using namespace Genode;
void Vm::on_vmm_entry()
{
_led.direction(Gpio::Session::OUT);
_led.write(false);
}
void Vm::_load_kernel_surroundings()
{
Attached_rom_dataspace dtb(_env, "dtb");
memcpy((void*)(_ram.local() + DTB_OFFSET), dtb.local_addr<void>(),
dtb.size());
}

View File

@ -1,64 +0,0 @@
/*
* \brief Virtual Machine implementation
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2015-02-27
*/
/*
* 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 Affero General Public License version 3.
*/
#ifndef _VM_H_
#define _VM_H_
/* Genode includes */
#include <gpio_session/connection.h>
/* local includes */
#include <vm_base.h>
namespace Genode { class Vm; }
class Genode::Vm : public Vm_base
{
private:
enum { DTB_OFFSET = 0x1000000 };
Gpio::Connection _led { _env, 28 };
/*************
** Vm_base **
*************/
void _load_kernel_surroundings();
addr_t _board_info_offset() const { return DTB_OFFSET; }
public:
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,
Allocator &alloc,
Vcpu_handler_base &handler)
: Vm_base(env, kernel, cmdl, ram, ram_sz, kernel_off, mach, board,
alloc, handler)
{ }
void on_vmm_exit() { _led.write(true); }
void on_vmm_entry();
};
#endif /* _VM_H_ */

View File

@ -1,130 +0,0 @@
/*
* \brief Virtual Machine Monitor VM definition
* \author Stefan Kalkowski
* \author Martin Stein
* \author Benjamin Lamowski
* \date 2012-06-25
*/
/*
* Copyright (C) 2012-2023 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/attached_rom_dataspace.h>
/* local includes */
#include <vm_base.h>
#include <mmu.h>
using namespace Genode;
void Vm_base::_load_kernel(Vcpu_state &state)
{
Attached_rom_dataspace kernel(_env, _kernel.string());
memcpy((void*)(_ram.local() + _kernel_off),
kernel.local_addr<void>(), 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,
Allocator &alloc,
Vcpu_handler_base &handler)
:
_env(env), _kernel(kernel), _cmdline(cmdline), _kernel_off(kernel_off),
_machine(machine), _board(board), _ram(env, ram_base, ram_size),
_vcpu(_vm, alloc, handler, _exit_config)
{ }
void Vm_base::start(Vcpu_state &state)
{
memset((void*)&state, 0, sizeof(Vcpu_state));
_load_kernel(state);
_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();
state.irq_injection = 0;
}
void Vm_base::inject_irq(unsigned irq)
{
with_state([this,irq](Vcpu_state &state) {
if (state.irq_injection) { throw Inject_irq_failed(); }
state.irq_injection = irq;
return true;
});
}
void Vm_base::dump(Vcpu_state &state)
{
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(state, 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(state, 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 < Vcpu_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]);
}
addr_t Vm_base::va_to_pa(Vcpu_state & state, addr_t va)
{
try {
Mmu mmu(state, _ram);
return mmu.phys_addr(va);
}
catch(Ram::Invalid_addr) { }
return 0;
}