mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-20 06:07:59 +00:00
parent
5a8d149fe3
commit
6162eae9e0
@ -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
|
@ -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.
|
@ -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();
|
||||
}
|
||||
}
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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); }
|
||||
}
|
@ -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_ */
|
@ -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); }
|
@ -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 =
|
@ -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
|
@ -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();
|
||||
}
|
@ -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_ */
|
@ -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
|
@ -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());
|
||||
}
|
@ -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_ */
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user