diff --git a/os/run/vmm.run b/os/run/vmm.run
new file mode 100644
index 0000000000..39a1af756f
--- /dev/null
+++ b/os/run/vmm.run
@@ -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 {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image "core init vmm linux initrd.gz"
diff --git a/os/src/server/vmm/README b/os/src/server/vmm/README
new file mode 100644
index 0000000000..6afb8fc340
--- /dev/null
+++ b/os/src/server/vmm/README
@@ -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= vexpress_tz_defconfig
+! make ARCH=arm CROSS_COMPILE=
\ No newline at end of file
diff --git a/os/src/server/vmm/include/atag.h b/os/src/server/vmm/include/atag.h
new file mode 100644
index 0000000000..03fec3d46d
--- /dev/null
+++ b/os/src/server/vmm/include/atag.h
@@ -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
+#include
+
+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
+ 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();
+ _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();
+ _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();
+ _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();
+ _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_ */
diff --git a/os/src/server/vmm/include/bp_147.h b/os/src/server/vmm/include/bp_147.h
new file mode 100644
index 0000000000..82fc9f9198
--- /dev/null
+++ b/os/src/server/vmm/include/bp_147.h
@@ -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
+
+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
+ struct Tzpcdecprot0 : public Register
+ {
+ struct Pl341_apb : Register::template Bitfield<0,1> {};
+ struct Pl354_apb : Register::template Bitfield<1,1> {};
+ struct Scc : Register::template Bitfield<2,1> {};
+ struct Dual_timer : Register::template Bitfield<4,1> {};
+ struct Watchdog : Register::template Bitfield<5,1> {};
+ struct Tzpc : Register::template Bitfield<6,1> {};
+ struct Pl351_apb : Register::template Bitfield<7,1> {};
+ struct Fast_pl301_apb : Register::template Bitfield<9,1> {};
+ struct Slow_pl301_apb : Register::template Bitfield<10,1> {};
+ struct Dmc_tzasc : Register::template Bitfield<12,1> {};
+ struct Nmc_tzasc : Register::template Bitfield<12,1> {};
+ struct Smc_tzasc : Register::template Bitfield<13,1> {};
+ struct Debug_apb_phs : Register::template Bitfield<14,1> {};
+ };
+
+ /**
+ * Decode Protection 1 Registers
+ */
+ template
+ struct Tzpcdecprot1 : public Register
+ {
+ struct External_axi_slave_port
+ : Register::template Bitfield<0,1> {};
+ /* SMC access */
+ struct Pl354_axi
+ : Register::template Bitfield<1,1> {};
+ struct Pl351_axi
+ : Register::template Bitfield<2,1> {};
+ struct Entire_apb
+ : Register::template Bitfield<3,1> {};
+ struct Pl111_configuration_port
+ : Register::template Bitfield<4,1> {};
+ struct Axi_ram
+ : Register::template Bitfield<5,1> {};
+ /* DDR RAM access */
+ struct Pl341_axi
+ : Register::template Bitfield<6,1> {};
+ /* ACP access */
+ struct Cortexa9_coherency_port
+ : Register::template Bitfield<8,1> {};
+ struct Entire_slow_axi_system
+ : Register::template Bitfield<9,1> {};
+ };
+
+ /**
+ * Decode Protection 2 Registers
+ */
+ template
+ struct Tzpcdecprot2 : public Register
+ {
+ struct External_master_tz : Register::template Bitfield<0,1> {};
+ struct Dap_tz_override : Register::template Bitfield<1,1> {};
+ struct Pl111_master_tz : Register::template Bitfield<2,1> {};
+ struct Dmc_tzasc_lockdown : Register::template Bitfield<3,1> {};
+ struct Nmc_tzasc_lockdown : Register::template Bitfield<4,1> {};
+ struct Smc_tzasc_lockdown : Register::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::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_ */
diff --git a/os/src/server/vmm/include/sp810.h b/os/src/server/vmm/include/sp810.h
new file mode 100644
index 0000000000..d5e87224ce
--- /dev/null
+++ b/os/src/server/vmm/include/sp810.h
@@ -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
+
+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(); }
+ bool timer1() { return read(); }
+
+ void enable_timer0() { write(1); }
+ void enable_timer1() { write(1); }
+ };
+}
+
+#endif /* _BASE_HW__SRC__SERVER__VMM__SP810_H_ */
diff --git a/os/src/server/vmm/include/sys_reg.h b/os/src/server/vmm/include/sys_reg.h
new file mode 100644
index 0000000000..ff11129dbe
--- /dev/null
+++ b/os/src/server/vmm/include/sys_reg.h
@@ -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
+
+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(); }
+
+ uint32_t misc_flags() { return read(); }
+
+ void osc1(uint32_t mhz)
+ {
+ write(0);
+ write(mhz);
+ write(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()) ;
+ }
+
+ void dvi_source(uint32_t site)
+ {
+ if (site > 2) {
+ PERR("Invalid site value %u ignored", site);
+ return;
+ }
+ write(0);
+ write(site);
+ write(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()) ;
+ }
+
+ void dvi_mode(uint32_t mode)
+ {
+ if (mode > 4) {
+ PERR("Invalid dvi mode %u ignored", mode);
+ return;
+ }
+ write(0);
+ write(mode);
+ write(Sys_cfg_ctrl::Function::bits(0xb) |
+ Sys_cfg_ctrl::Write::bits(1) |
+ Sys_cfg_ctrl::Start::bits(1));
+ while (!read()) ;
+ }
+
+ uint32_t mci_status() { return read(); }
+ };
+}
+
+#endif /* _BASE_HW__SRC__SERVER__VMM__SYS_REG_H_ */
diff --git a/os/src/server/vmm/include/tsc_380.h b/os/src/server/vmm/include/tsc_380.h
new file mode 100644
index 0000000000..c095c9c5dc
--- /dev/null
+++ b/os/src/server/vmm/include/tsc_380.h
@@ -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
+
+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
+ struct Region_low : public Register
+ {
+ enum { MASK = ~0UL << 15 };
+ };
+
+ template
+ struct Region_high : public Register { };
+
+ template
+ struct Region_attr : public Register
+ {
+ struct Enable :
+ Register::template Bitfield<0, 1> { };
+ struct Size :
+ Register::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::template Bitfield<8, 1> { };
+ struct Subreg1 :
+ Register::template Bitfield<9, 1> { };
+ struct Subreg2 :
+ Register::template Bitfield<10, 1> { };
+ struct Subreg3 :
+ Register::template Bitfield<11, 1> { };
+ struct Subreg4 :
+ Register::template Bitfield<12, 1> { };
+ struct Subreg5 :
+ Register::template Bitfield<13, 1> { };
+ struct Subreg6 :
+ Register::template Bitfield<14, 1> { };
+ struct Subreg7 :
+ Register::template Bitfield<15, 1> { };
+ struct Normal_write :
+ Register::template Bitfield<28, 1> { };
+ struct Normal_read :
+ Register::template Bitfield<29, 1> { };
+ struct Secure_write :
+ Register::template Bitfield<30, 1> { };
+ struct Secure_read :
+ Register::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 >(0x10000000);
+ write >(0x10008000);
+ write::Enable>(1);
+ write::Size>(Region_attr::Size::SZ_32K);
+ write::Normal_read>(1);
+ write::Normal_write>(1);
+ write::Secure_read>(1);
+ write::Secure_write>(1);
+ write::Subreg0>(1);
+ write::Subreg1>(1);
+ write::Subreg2>(1);
+ write::Subreg3>(1);
+
+ /* Access to UART3, and WDT */
+ write >(0x10008000);
+ write >(0x10010000);
+ write::Enable>(1);
+ write::Size>(Region_attr::Size::SZ_32K);
+ write::Normal_read>(1);
+ write::Normal_write>(1);
+ write::Secure_read>(1);
+ write::Secure_write>(1);
+ write::Subreg0>(1);
+ write::Subreg1>(1);
+ write::Subreg2>(1);
+ write::Subreg3>(1);
+ write::Subreg5>(1);
+ write::Subreg6>(1);
+
+ /* Access to SP804, and RTC */
+ write >(0x10010000);
+ write >(0x10018000);
+ write::Enable>(1);
+ write::Size>(Region_attr::Size::SZ_32K);
+ write::Normal_read>(1);
+ write::Normal_write>(1);
+ write::Secure_read>(1);
+ write::Secure_write>(1);
+ write::Subreg0>(1);
+ write::Subreg3>(1);
+ write::Subreg4>(1);
+ write::Subreg5>(1);
+ write::Subreg6>(1);
+
+ /* Access to Ethernet and USB */
+ write >(0x4e000000);
+ write >(0x50000000);
+ write::Enable>(1);
+ write::Size>(Region_attr::Size::SZ_32M);
+ write::Normal_read>(1);
+ write::Normal_write>(1);
+ write::Secure_read>(1);
+ write::Secure_write>(1);
+
+ /* clear interrupts */
+ write(0x3);
+ }
+
+ void* last_failed_access() {
+ void *ret = (void*) read();
+ write(0x3);
+ return ret;
+ }
+ };
+
+}
+
+#endif /* _BASE_HW__SRC__SERVER__VMM__TSC_380_H_ */
diff --git a/os/src/server/vmm/main.cc b/os/src/server/vmm/main.cc
new file mode 100644
index 0000000000..f53d82138b
--- /dev/null
+++ b/os/src/server/vmm/main.cc
@@ -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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* local includes */
+#include
+#include
+#include
+#include
+#include
+
+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;
+}
diff --git a/os/src/server/vmm/target.mk b/os/src/server/vmm/target.mk
new file mode 100644
index 0000000000..ae63a0b1fa
--- /dev/null
+++ b/os/src/server/vmm/target.mk
@@ -0,0 +1,5 @@
+TARGET = vmm
+REQUIRES = trustzone platform_vea9x4
+LIBS = env cxx elf signal
+SRC_CC = main.cc
+INC_DIR += $(PRG_DIR)/include
\ No newline at end of file