Implement VMM for Linux in VEA9x4 normal-world

This commit is contained in:
Stefan Kalkowski 2012-10-10 17:31:22 +02:00
parent 8393ac6895
commit 4a92eb5660
9 changed files with 1104 additions and 0 deletions

39
os/run/vmm.run Normal file
View File

@ -0,0 +1,39 @@
#
# \brief Virtual-machine monitor demo
# \author Stefan Kalkowski
# \date 2012-06-25
#
if {![have_spec trustzone]} {
puts "\nThe VMM support base-hw for Versatile Express with TrustZone support only\n"
exit 0
}
build "core init server/vmm"
create_boot_directory
install_config {
<config verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
<service name="VM"/>
</parent-provides>
<default-route>
<any-service><any-child/><parent/></any-service>
</default-route>
<start name="vmm">
<resource name="RAM" quantum="4M"/>
</start>
</config>
}
build_boot_image "core init vmm linux initrd.gz"

17
os/src/server/vmm/README Normal file
View File

@ -0,0 +1,17 @@
This is a small example virtual machine monitor, that uses the base-hw kernel
as TrustZone micro-hypervisor on the ARM Versatile Express CT A9x4 platform.
The VMM configures TrustZone Protection Controller and Address Space Controller
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. Please checkout the following branch to test it:
https://github.com/skalk/linux/tree/vexpress-tz
To build linux do:
! make ARCH=arm CROSS_COMPILE=<path_to_cross_compiler> vexpress_tz_defconfig
! make ARCH=arm CROSS_COMPILE=<path_to_cross_compiler>

View File

@ -0,0 +1,193 @@
/**
* \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 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__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_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::strncpy(_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

@ -0,0 +1,130 @@
/*
* \brief Driver for the Trustzone Protection Controller BP147
* \author Stefan Kalkowski
* \date 2012-07-04
*/
/*
* Copyright (C) 2012 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 _BASE_HW__SRC__SERVER__VMM__BP_147_H_
#define _BASE_HW__SRC__SERVER__VMM__BP_147_H_
/* Genode includes */
#include <util/mmio.h>
namespace Genode
{
class Bp_147 : Mmio
{
private:
/**
* Secure RAM Region Size Register
*/
struct Tzpcr0size : public Register<0x00, 32>
{
struct R0size : Bitfield<0,10> { };
};
/**
* Decode Protection 0 Registers
*/
template <off_t OFF>
struct Tzpcdecprot0 : public Register<OFF, 32>
{
struct Pl341_apb : Register<OFF, 32>::template Bitfield<0,1> {};
struct Pl354_apb : Register<OFF, 32>::template Bitfield<1,1> {};
struct Scc : Register<OFF, 32>::template Bitfield<2,1> {};
struct Dual_timer : Register<OFF, 32>::template Bitfield<4,1> {};
struct Watchdog : Register<OFF, 32>::template Bitfield<5,1> {};
struct Tzpc : Register<OFF, 32>::template Bitfield<6,1> {};
struct Pl351_apb : Register<OFF, 32>::template Bitfield<7,1> {};
struct Fast_pl301_apb : Register<OFF, 32>::template Bitfield<9,1> {};
struct Slow_pl301_apb : Register<OFF, 32>::template Bitfield<10,1> {};
struct Dmc_tzasc : Register<OFF, 32>::template Bitfield<12,1> {};
struct Nmc_tzasc : Register<OFF, 32>::template Bitfield<12,1> {};
struct Smc_tzasc : Register<OFF, 32>::template Bitfield<13,1> {};
struct Debug_apb_phs : Register<OFF, 32>::template Bitfield<14,1> {};
};
/**
* Decode Protection 1 Registers
*/
template <off_t OFF>
struct Tzpcdecprot1 : public Register<OFF, 32>
{
struct External_axi_slave_port
: Register<OFF, 32>::template Bitfield<0,1> {};
/* SMC access */
struct Pl354_axi
: Register<OFF, 32>::template Bitfield<1,1> {};
struct Pl351_axi
: Register<OFF, 32>::template Bitfield<2,1> {};
struct Entire_apb
: Register<OFF, 32>::template Bitfield<3,1> {};
struct Pl111_configuration_port
: Register<OFF, 32>::template Bitfield<4,1> {};
struct Axi_ram
: Register<OFF, 32>::template Bitfield<5,1> {};
/* DDR RAM access */
struct Pl341_axi
: Register<OFF, 32>::template Bitfield<6,1> {};
/* ACP access */
struct Cortexa9_coherency_port
: Register<OFF, 32>::template Bitfield<8,1> {};
struct Entire_slow_axi_system
: Register<OFF, 32>::template Bitfield<9,1> {};
};
/**
* Decode Protection 2 Registers
*/
template <off_t OFF>
struct Tzpcdecprot2 : public Register<OFF, 32>
{
struct External_master_tz : Register<OFF, 32>::template Bitfield<0,1> {};
struct Dap_tz_override : Register<OFF, 32>::template Bitfield<1,1> {};
struct Pl111_master_tz : Register<OFF, 32>::template Bitfield<2,1> {};
struct Dmc_tzasc_lockdown : Register<OFF, 32>::template Bitfield<3,1> {};
struct Nmc_tzasc_lockdown : Register<OFF, 32>::template Bitfield<4,1> {};
struct Smc_tzasc_lockdown : Register<OFF, 32>::template Bitfield<5,1> {};
};
struct Tzpcdecprot0stat : Tzpcdecprot0<0x800> {};
struct Tzpcdecprot0set : Tzpcdecprot0<0x804> {};
struct Tzpcdecprot0clr : Tzpcdecprot0<0x808> {};
struct Tzpcdecprot1stat : Tzpcdecprot1<0x80c> {};
struct Tzpcdecprot1set : Tzpcdecprot1<0x810> {};
struct Tzpcdecprot1clr : Tzpcdecprot1<0x814> {};
struct Tzpcdecprot2stat : Tzpcdecprot2<0x818> {};
struct Tzpcdecprot2set : Tzpcdecprot2<0x81c> {};
struct Tzpcdecprot2clr : Tzpcdecprot2<0x820> {};
public:
Bp_147(addr_t const base) : Mmio(base)
{
/**
* Configure TZPC to allow non-secure AXI signals to
* Static Memory Controller (SMC),
* Dynamic Memory Controller (DMC),
* Accelerator Coherency Port (ACP), and
* PL111 configuration registers
*/
write<Tzpcdecprot1set>(
Tzpcdecprot1set::Pl341_axi::bits(1) |
Tzpcdecprot1set::Pl354_axi::bits(1) |
Tzpcdecprot1set::Cortexa9_coherency_port::bits(1) |
Tzpcdecprot1set::Pl111_configuration_port::bits(1));
}
};
}
#endif /* _BASE_HW__SRC__SERVER__VMM__BP_147_H_ */

View File

@ -0,0 +1,45 @@
/*
* \brief Driver for the SP810 system controller
* \author Stefan Kalkowski
* \date 2012-09-21
*/
/*
* Copyright (C) 2012 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 _BASE_HW__SRC__SERVER__VMM__810_H_
#define _BASE_HW__SRC__SERVER__VMM__810_H_
/* Genode includes */
#include <util/mmio.h>
namespace Genode
{
class Sp810 : Mmio
{
private:
struct Ctrl : public Register<0, 32>
{
struct Timer0_enable : Bitfield<15,1> {};
struct Timer1_enable : Bitfield<17,1> {};
};
public:
Sp810(addr_t const base) : Mmio(base) {}
bool timer0() { return read<Ctrl::Timer0_enable>(); }
bool timer1() { return read<Ctrl::Timer0_enable>(); }
void enable_timer0() { write<Ctrl::Timer0_enable>(1); }
void enable_timer1() { write<Ctrl::Timer0_enable>(1); }
};
}
#endif /* _BASE_HW__SRC__SERVER__VMM__SP810_H_ */

View File

@ -0,0 +1,104 @@
/*
* \brief Driver for the Motherboard Express system registers
* \author Stefan Kalkowski
* \date 2012-09-21
*/
/*
* Copyright (C) 2012 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 _BASE_HW__SRC__SERVER__VMM__SYS_REG_H_
#define _BASE_HW__SRC__SERVER__VMM__SYS_REG_H_
/* Genode includes */
#include <util/mmio.h>
namespace Genode
{
class Sys_reg : Mmio
{
private:
struct Sys_mci : public Register<0x48, 32> {};
struct Sys_24mhz : public Register<0x5c, 32> {};
struct Sys_misc : public Register<0x60, 32> {};
struct Sys_cfg_data : public Register<0xa0, 32, true> {};
struct Sys_cfg_ctrl : public Register<0xa4, 32, true>
{
struct Device : Bitfield<0,12> { };
struct Position : Bitfield<12,4> { };
struct Site : Bitfield<16,2> { };
struct Function : Bitfield<20,6> { };
struct Write : Bitfield<30,1> { };
struct Start : Bitfield<31,1> { };
};
struct Sys_cfg_stat : public Register<0xa8, 32>
{
struct Complete : Bitfield<0,1> { };
struct Error : Bitfield<1,1> { };
};
public:
Sys_reg(addr_t const base) : Mmio(base) {}
uint32_t counter() { return read<Sys_24mhz>(); }
uint32_t misc_flags() { return read<Sys_misc>(); }
void osc1(uint32_t mhz)
{
write<Sys_cfg_stat::Complete>(0);
write<Sys_cfg_data>(mhz);
write<Sys_cfg_ctrl>(Sys_cfg_ctrl::Device::bits(1) |
Sys_cfg_ctrl::Site::bits(1) |
Sys_cfg_ctrl::Function::bits(1) |
Sys_cfg_ctrl::Write::bits(1) |
Sys_cfg_ctrl::Start::bits(1));
while (!read<Sys_cfg_stat::Complete>()) ;
}
void dvi_source(uint32_t site)
{
if (site > 2) {
PERR("Invalid site value %u ignored", site);
return;
}
write<Sys_cfg_stat::Complete>(0);
write<Sys_cfg_data>(site);
write<Sys_cfg_ctrl>(Sys_cfg_ctrl::Site::bits(1) |
Sys_cfg_ctrl::Function::bits(0x7) |
Sys_cfg_ctrl::Write::bits(1) |
Sys_cfg_ctrl::Start::bits(1));
while (!read<Sys_cfg_stat::Complete>()) ;
}
void dvi_mode(uint32_t mode)
{
if (mode > 4) {
PERR("Invalid dvi mode %u ignored", mode);
return;
}
write<Sys_cfg_stat::Complete>(0);
write<Sys_cfg_data>(mode);
write<Sys_cfg_ctrl>(Sys_cfg_ctrl::Function::bits(0xb) |
Sys_cfg_ctrl::Write::bits(1) |
Sys_cfg_ctrl::Start::bits(1));
while (!read<Sys_cfg_stat::Complete>()) ;
}
uint32_t mci_status() { return read<Sys_mci>(); }
};
}
#endif /* _BASE_HW__SRC__SERVER__VMM__SYS_REG_H_ */

View File

@ -0,0 +1,212 @@
/*
* \brief Driver for the CoreLink Trustzone Address Space Controller TSC-380
* \author Stefan Kalkowski
* \date 2012-07-04
*/
/*
* Copyright (C) 2012 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 _BASE_HW__SRC__SERVER__VMM__TSC_380_H_
#define _BASE_HW__SRC__SERVER__VMM__TSC_380_H_
/* Genode includes */
#include <util/mmio.h>
namespace Genode
{
class Tsc_380 : Mmio
{
private:
enum {
REGION0_REG_OFF = 0x100,
REGION1_REG_OFF = 0x110,
REGION2_REG_OFF = 0x120,
REGION3_REG_OFF = 0x130,
REGION4_REG_OFF = 0x140,
REGION5_REG_OFF = 0x150,
REGION6_REG_OFF = 0x160,
REGION7_REG_OFF = 0x170,
REGION8_REG_OFF = 0x180,
REGION9_REG_OFF = 0x190,
REGION10_REG_OFF = 0x1a0,
REGION11_REG_OFF = 0x1b0,
REGION12_REG_OFF = 0x1c0,
REGION13_REG_OFF = 0x1d0,
REGION14_REG_OFF = 0x1e0,
REGION15_REG_OFF = 0x1f0,
REGION_LOW_OFF = 0x0,
REGION_HIGH_OFF = 0x4,
REGION_ATTR_OFF = 0x8,
};
/**
* Configuration register
*/
struct Config : public Register<0, 32>
{
struct Region_number : Bitfield<0,4> { };
struct Address_width : Bitfield<8,6> { };
};
struct Irq_status : public Register<0x10, 32>
{
struct Status : Bitfield<0,1> {};
struct Overrun : Bitfield<1,1> {};
};
struct Irq_clear : public Register<0x14, 32>
{
struct Status : Bitfield<0,1> {};
struct Overrun : Bitfield<1,1> {};
};
/**
* Fail address low register
*/
struct Fail_low : public Register<0x20, 32> { };
template <off_t OFF>
struct Region_low : public Register<OFF + REGION_LOW_OFF, 32>
{
enum { MASK = ~0UL << 15 };
};
template <off_t OFF>
struct Region_high : public Register<OFF + REGION_HIGH_OFF, 32> { };
template <off_t OFF>
struct Region_attr : public Register<OFF + REGION_ATTR_OFF, 32>
{
struct Enable :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<0, 1> { };
struct Size :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<1, 6>
{
enum {
SZ_32K = 14,
SZ_64K,
SZ_128K,
SZ_256K,
SZ_512K,
SZ_1M,
SZ_2M,
SZ_4M,
SZ_8M,
SZ_16M,
SZ_32M,
SZ_64M,
SZ_128M,
SZ_256M,
SZ_512M,
SZ_1G,
};
};
struct Subreg0 :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<8, 1> { };
struct Subreg1 :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<9, 1> { };
struct Subreg2 :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<10, 1> { };
struct Subreg3 :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<11, 1> { };
struct Subreg4 :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<12, 1> { };
struct Subreg5 :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<13, 1> { };
struct Subreg6 :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<14, 1> { };
struct Subreg7 :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<15, 1> { };
struct Normal_write :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<28, 1> { };
struct Normal_read :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<29, 1> { };
struct Secure_write :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<30, 1> { };
struct Secure_read :
Register<OFF + REGION_ATTR_OFF, 32>::template Bitfield<31, 1> { };
};
typedef Region_low<0x100> Region0_low;
public:
Tsc_380(addr_t const base) : Mmio(base)
{
/* Access to AACI, MMCI, KMI0/1 */
write<Region_low<REGION15_REG_OFF> >(0x10000000);
write<Region_high<REGION15_REG_OFF> >(0x10008000);
write<Region_attr<REGION15_REG_OFF>::Enable>(1);
write<Region_attr<REGION15_REG_OFF>::Size>(Region_attr<REGION15_REG_OFF>::Size::SZ_32K);
write<Region_attr<REGION15_REG_OFF>::Normal_read>(1);
write<Region_attr<REGION15_REG_OFF>::Normal_write>(1);
write<Region_attr<REGION15_REG_OFF>::Secure_read>(1);
write<Region_attr<REGION15_REG_OFF>::Secure_write>(1);
write<Region_attr<REGION15_REG_OFF>::Subreg0>(1);
write<Region_attr<REGION15_REG_OFF>::Subreg1>(1);
write<Region_attr<REGION15_REG_OFF>::Subreg2>(1);
write<Region_attr<REGION15_REG_OFF>::Subreg3>(1);
/* Access to UART3, and WDT */
write<Region_low<REGION14_REG_OFF> >(0x10008000);
write<Region_high<REGION14_REG_OFF> >(0x10010000);
write<Region_attr<REGION14_REG_OFF>::Enable>(1);
write<Region_attr<REGION14_REG_OFF>::Size>(Region_attr<REGION14_REG_OFF>::Size::SZ_32K);
write<Region_attr<REGION14_REG_OFF>::Normal_read>(1);
write<Region_attr<REGION14_REG_OFF>::Normal_write>(1);
write<Region_attr<REGION14_REG_OFF>::Secure_read>(1);
write<Region_attr<REGION14_REG_OFF>::Secure_write>(1);
write<Region_attr<REGION14_REG_OFF>::Subreg0>(1);
write<Region_attr<REGION14_REG_OFF>::Subreg1>(1);
write<Region_attr<REGION14_REG_OFF>::Subreg2>(1);
write<Region_attr<REGION14_REG_OFF>::Subreg3>(1);
write<Region_attr<REGION14_REG_OFF>::Subreg5>(1);
write<Region_attr<REGION14_REG_OFF>::Subreg6>(1);
/* Access to SP804, and RTC */
write<Region_low<REGION13_REG_OFF> >(0x10010000);
write<Region_high<REGION13_REG_OFF> >(0x10018000);
write<Region_attr<REGION13_REG_OFF>::Enable>(1);
write<Region_attr<REGION13_REG_OFF>::Size>(Region_attr<REGION13_REG_OFF>::Size::SZ_32K);
write<Region_attr<REGION13_REG_OFF>::Normal_read>(1);
write<Region_attr<REGION13_REG_OFF>::Normal_write>(1);
write<Region_attr<REGION13_REG_OFF>::Secure_read>(1);
write<Region_attr<REGION13_REG_OFF>::Secure_write>(1);
write<Region_attr<REGION13_REG_OFF>::Subreg0>(1);
write<Region_attr<REGION13_REG_OFF>::Subreg3>(1);
write<Region_attr<REGION13_REG_OFF>::Subreg4>(1);
write<Region_attr<REGION13_REG_OFF>::Subreg5>(1);
write<Region_attr<REGION13_REG_OFF>::Subreg6>(1);
/* Access to Ethernet and USB */
write<Region_low<REGION12_REG_OFF> >(0x4e000000);
write<Region_high<REGION12_REG_OFF> >(0x50000000);
write<Region_attr<REGION12_REG_OFF>::Enable>(1);
write<Region_attr<REGION12_REG_OFF>::Size>(Region_attr<REGION12_REG_OFF>::Size::SZ_32M);
write<Region_attr<REGION12_REG_OFF>::Normal_read>(1);
write<Region_attr<REGION12_REG_OFF>::Normal_write>(1);
write<Region_attr<REGION12_REG_OFF>::Secure_read>(1);
write<Region_attr<REGION12_REG_OFF>::Secure_write>(1);
/* clear interrupts */
write<Irq_clear>(0x3);
}
void* last_failed_access() {
void *ret = (void*) read<Fail_low>();
write<Irq_clear>(0x3);
return ret;
}
};
}
#endif /* _BASE_HW__SRC__SERVER__VMM__TSC_380_H_ */

359
os/src/server/vmm/main.cc Normal file
View File

@ -0,0 +1,359 @@
/*
* \brief Virtual Machine Monitor
* \author Stefan Kalkowski
* \date 2012-06-25
*/
/*
* Copyright (C) 2008-2012 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 <base/elf.h>
#include <base/env.h>
#include <base/sleep.h>
#include <base/thread.h>
#include <cpu/cpu_state.h>
#include <io_mem_session/connection.h>
#include <rom_session/connection.h>
#include <vm_session/connection.h>
#include <dataspace/client.h>
/* local includes */
#include <tsc_380.h>
#include <bp_147.h>
#include <sys_reg.h>
#include <sp810.h>
#include <atag.h>
namespace Genode {
class Ram {
private:
addr_t _base;
size_t _size;
addr_t _local;
public:
Ram(addr_t addr, size_t sz)
: _base(addr), _size(sz), _local(0) { }
addr_t base() { return _base; }
size_t size() { return _size; }
addr_t local() { return _local; }
void attach(Dataspace_capability cap) {
_local = (addr_t) env()->rm_session()->attach(cap); }
};
class Vm {
private:
enum {
ATAG_OFFSET = 0x100,
INITRD_OFFSET = 0x800000
};
Vm_connection _vm_con;
Rom_connection _elf_rom;
Rom_connection _initrd_rom;
const char* _cmdline;
size_t _initrd_size;
Cpu_state_modes *_state;
Ram _ram;
Io_mem_connection _ram_iomem;
void _load_elf()
{
/* attach ELF locally */
addr_t elf_addr = env()->rm_session()->attach(_elf_rom.dataspace());
/* setup ELF object and read program entry pointer */
Elf_binary elf((addr_t)elf_addr);
_state->ip = elf.entry();
if (!elf.valid()) {
PWRN("Invalid elf binary!");
return;
}
Elf_segment seg;
for (unsigned n = 0; (seg = elf.get_segment(n)).valid(); ++n) {
if (seg.flags().skip) continue;
addr_t addr = (addr_t)seg.start();
size_t size = seg.mem_size();
if (addr < _ram.base() ||
(addr + size) > (_ram.base() + _ram.size())) {
PWRN("Elf binary doesn't fit into RAM");
return;
}
void *base = (void*) (_ram.local() + (addr - _ram.base()));
addr_t laddr = elf_addr + seg.file_offset();
/* copy contents */
memcpy(base, (void *)laddr, seg.file_size());
/* if writeable region potentially fill with zeros */
if (size > seg.file_size() && seg.flags().w)
memset((void *)((addr_t)base + seg.file_size()),
0, size - seg.file_size());
}
/* detach ELF */
env()->rm_session()->detach((void*)elf_addr);
}
void _load_initrd()
{
addr_t addr = env()->rm_session()->attach(_initrd_rom.dataspace());
memcpy((void*)(_ram.local() + INITRD_OFFSET),
(void*)addr, _initrd_size);
env()->rm_session()->detach((void*)addr);
}
void _prepare_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_size);
tag.setup_end_tag();
}
public:
Vm(const char *kernel, const char *initrd, const char *cmdline,
addr_t ram_base, size_t ram_size)
: _elf_rom(kernel),
_initrd_rom(initrd),
_cmdline(cmdline),
_initrd_size(Dataspace_client(_initrd_rom.dataspace()).size()),
_state((Cpu_state_modes*)env()->rm_session()->attach(_vm_con.cpu_state())),
_ram(ram_base, ram_size),
_ram_iomem(ram_base, ram_size)
{
memset((void*)_state, 0, sizeof(Cpu_state_modes));
_ram.attach(_ram_iomem.dataspace());
}
void start(Signal_context_capability sig_cap)
{
_load_elf();
_load_initrd();
_prepare_atag();
_state->cpsr = 0x93; /* SVC mode and IRQs disabled */
_state->r[1] = 2272; /* MACH_TYPE vexpress board */
_state->r[2] = _ram.base() + ATAG_OFFSET; /* ATAG addr */
_vm_con.exception_handler(sig_cap);
}
void run() { _vm_con.run(); }
void dump()
{
const char * const modes[] =
{ "und", "svc", "abt", "irq", "fiq" };
const char * const exc[] =
{ "reset", "undefined", "smc", "pf_abort",
"data_abort", "irq", "fiq" };
printf("Cpu state:\n");
for (unsigned i = 0; i<13; i++)
printf(" r%x = %08lx\n", i, _state->r[i]);
printf(" sp = %08lx\n", _state->sp);
printf(" lr = %08lx\n", _state->lr);
printf(" ip = %08lx\n", _state->ip);
printf(" cpsr = %08lx\n", _state->cpsr);
for (unsigned i = 0;
i < Cpu_state_modes::Mode_state::MAX; i++) {
printf(" sp_%s = %08lx\n", modes[i], _state->mode[i].sp);
printf(" lr_%s = %08lx\n", modes[i], _state->mode[i].lr);
printf(" spsr_%s = %08lx\n", modes[i], _state->mode[i].spsr);
}
printf(" exception = %s\n", exc[_state->cpu_exception]);
}
Cpu_state_modes *state() const { return _state; }
};
class Vmm : public Genode::Thread<8192>
{
private:
enum Hypervisor_calls {
SP810_ENABLE = 1,
CPU_ID,
SYS_COUNTER,
MISC_FLAGS,
SYS_CTRL,
MCI_STATUS
};
Io_mem_connection _tsc_io_mem;
Io_mem_connection _tpc_io_mem;
Io_mem_connection _sys_io_mem;
Io_mem_connection _sp810_io_mem;
Tsc_380 _tsc;
Bp_147 _tpc;
Sys_reg _sys;
Sp810 _sp810;
Vm *_vm;
void _sys_ctrl()
{
enum {
OSC1 = 0xc0110001,
DVI_SRC = 0xc0710000,
DVI_MODE = 0xc0b00000
};
uint32_t ctrl = _vm->state()->r[2];
uint32_t data = _vm->state()->r[0];
switch(ctrl) {
case OSC1:
_sys.osc1(data);
break;
case DVI_SRC:
_sys.dvi_source(data);
break;
case DVI_MODE:
_sys.dvi_mode(data);
break;
default:
PWRN("Access violation to sys configuration ctrl=%ux", ctrl);
_vm->dump();
}
}
void _handle_hypervisor_call()
{
switch (_vm->state()->r[1]) {
case SP810_ENABLE:
_sp810.enable_timer0();
_sp810.enable_timer1();
break;
case CPU_ID:
_vm->state()->r[0] = 0x0c000191; // Coretile A9 ID
break;
case SYS_COUNTER:
_vm->state()->r[0] = _sys.counter();
break;
case MISC_FLAGS:
_vm->state()->r[0] = _sys.misc_flags();
break;
case SYS_CTRL:
_sys_ctrl();
break;
case MCI_STATUS:
_vm->state()->r[0] = _sys.mci_status();
break;
default:
PERR("Unknown hypervisor call!");
_vm->dump();
}
}
bool _handle_data_abort()
{
PWRN("Vm tried to access %p which isn't allowed",
_tsc.last_failed_access());
_vm->dump();
return false;
}
bool _handle_vm()
{
switch (_vm->state()->cpu_exception) {
case Cpu_state::DATA_ABORT:
if (!_handle_data_abort()) {
PERR("Could not handle data-abort will exit!");
return false;
}
break;
case Cpu_state::SUPERVISOR_CALL:
_handle_hypervisor_call();
break;
default:
PERR("Curious exception occured");
_vm->dump();
return false;
}
return true;
}
protected:
void entry()
{
Signal_receiver sig_rcv;
Signal_context sig_cxt;
Signal_context_capability sig_cap(sig_rcv.manage(&sig_cxt));
_vm->start(sig_cap);
while (true) {
_vm->run();
Signal s = sig_rcv.wait_for_signal();
if (s.context() != &sig_cxt) {
PWRN("Invalid context");
continue;
}
if (!_handle_vm())
return;
}
};
public:
Vmm(addr_t tsc_base, addr_t tpc_base,
addr_t sys_base, addr_t sp810_base,
Vm *vm)
: _tsc_io_mem(tsc_base, 0x1000),
_tpc_io_mem(tpc_base, 0x1000),
_sys_io_mem(sys_base, 0x1000),
_sp810_io_mem(sp810_base, 0x1000),
_tsc((addr_t)env()->rm_session()->attach(_tsc_io_mem.dataspace())),
_tpc((addr_t)env()->rm_session()->attach(_tpc_io_mem.dataspace())),
_sys((addr_t)env()->rm_session()->attach(_sys_io_mem.dataspace())),
_sp810((addr_t)env()->rm_session()->attach(_sp810_io_mem.dataspace())),
_vm(vm) { }
};
}
int main()
{
enum {
SYS_VEA9X4_BASE = 0x10000000,
SP810_VEA9X4_BASE = 0x10001000,
TPC_VEA9X4_BASE = 0x100e6000,
TSC_VEA9X4_BASE = 0x100ec000,
MAIN_MEM_START = 0x80000000,
MAIN_MEM_SIZE = 0x10000000
};
static const char* cmdline = "console=ttyAMA0,38400n8 root=/dev/ram0 lpj=1554432";
static Genode::Vm vm("linux", "initrd.gz", cmdline,
MAIN_MEM_START, MAIN_MEM_SIZE);
static Genode::Vmm vmm(TSC_VEA9X4_BASE, TPC_VEA9X4_BASE,
SYS_VEA9X4_BASE, SP810_VEA9X4_BASE,
&vm);
PINF("Start virtual machine");
vmm.start();
Genode::sleep_forever();
return 0;
}

View File

@ -0,0 +1,5 @@
TARGET = vmm
REQUIRES = trustzone platform_vea9x4
LIBS = env cxx elf signal
SRC_CC = main.cc
INC_DIR += $(PRG_DIR)/include