mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-10 21:01:49 +00:00
vmm: add i.MX53 platform as target (ref #954)
This commit is contained in:
parent
6f136bef7a
commit
a7d7337b16
@ -103,6 +103,9 @@ namespace Genode
|
||||
IIM_BASE = 0x63f98000,
|
||||
IIM_SIZE = 0x00004000,
|
||||
|
||||
M4IF_BASE = 0x63fd8000,
|
||||
M4IF_SIZE = 0x00001000,
|
||||
|
||||
/* wether board provides security extension */
|
||||
SECURITY_EXTENSION = 1,
|
||||
|
||||
|
61
os/src/server/vmm/imx53/m4if.h
Normal file
61
os/src/server/vmm/imx53/m4if.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* \brief Driver for the Multi Master Multi Memory Interface
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-11-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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__M4IF_H_
|
||||
#define _SRC__SERVER__VMM__INCLUDE__M4IF_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/mmio.h>
|
||||
|
||||
class M4if : Genode::Mmio
|
||||
{
|
||||
private:
|
||||
|
||||
struct Wm_reg0_ddr0_start : public Register<0xec, 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_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::addr_t const base) : Genode::Mmio(base) {}
|
||||
|
||||
void set_region(Genode::addr_t addr, Genode::size_t size)
|
||||
{
|
||||
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 ack_irq() { write<Wm_reg0_irq::Status_ddr0>(1); }
|
||||
|
||||
Genode::addr_t violation_addr() { return read<Wm_reg0_addr>(); }
|
||||
};
|
||||
|
||||
#endif /* _SRC__SERVER__VMM__INCLUDE__M4IF_H_ */
|
138
os/src/server/vmm/imx53/main.cc
Normal file
138
os/src/server/vmm/imx53/main.cc
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* \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/env.h>
|
||||
#include <base/sleep.h>
|
||||
#include <base/thread.h>
|
||||
#include <drivers/board_base.h>
|
||||
#include <drivers/trustzone.h>
|
||||
|
||||
/* local includes */
|
||||
#include <vm.h>
|
||||
#include <atag.h>
|
||||
#include <m4if.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
enum {
|
||||
KERNEL_OFFSET = 0x8000,
|
||||
MACH_TYPE_TABLET = 3011,
|
||||
MACH_TYPE_QSB = 3273,
|
||||
BOARD_REV_TABLET = 0x53321,
|
||||
};
|
||||
|
||||
|
||||
static const char* cmdline_tablet =
|
||||
"console=ttymxc0,115200 androidboot.console=ttymxc0 lpj=4997120 \
|
||||
video=mxcdi1fb:RGB666,XGA gpu_memory=64M";
|
||||
|
||||
|
||||
namespace Vmm {
|
||||
class Vmm;
|
||||
}
|
||||
|
||||
|
||||
class Vmm::Vmm : public Thread<8192>
|
||||
{
|
||||
private:
|
||||
|
||||
Signal_receiver _sig_rcv;
|
||||
Signal_context _vm_context;
|
||||
Vm *_vm;
|
||||
Io_mem_connection _m4if_io_mem;
|
||||
M4if _m4if;
|
||||
|
||||
void _handle_hypervisor_call()
|
||||
{
|
||||
/* check device number*/
|
||||
switch (_vm->state()->r0) {
|
||||
default:
|
||||
PERR("Unknown hypervisor call!");
|
||||
_vm->dump();
|
||||
};
|
||||
}
|
||||
|
||||
bool _handle_data_abort()
|
||||
{
|
||||
_vm->dump();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _handle_vm()
|
||||
{
|
||||
/* check exception reason */
|
||||
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()
|
||||
{
|
||||
_vm->sig_handler(_sig_rcv.manage(&_vm_context));
|
||||
_vm->start();
|
||||
|
||||
while (true) {
|
||||
Signal s = _sig_rcv.wait_for_signal();
|
||||
if (s.context() == &_vm_context) {
|
||||
if (_handle_vm())
|
||||
_vm->run();
|
||||
} else {
|
||||
PWRN("Invalid context");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Vmm(Vm *vm)
|
||||
: Thread<8192>("vmm"),
|
||||
_vm(vm),
|
||||
_m4if_io_mem(Board_base::M4IF_BASE, Board_base::M4IF_SIZE),
|
||||
_m4if((addr_t)env()->rm_session()->attach(_m4if_io_mem.dataspace()))
|
||||
{
|
||||
_m4if.set_region(Trustzone::SECURE_RAM_BASE,
|
||||
Trustzone::SECURE_RAM_SIZE);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
static Vm vm("linux", "initrd.gz", cmdline_tablet,
|
||||
Trustzone::NONSECURE_RAM_BASE, Trustzone::NONSECURE_RAM_SIZE,
|
||||
KERNEL_OFFSET, MACH_TYPE_TABLET, BOARD_REV_TABLET);
|
||||
static Vmm::Vmm vmm(&vm);
|
||||
|
||||
PINF("Start virtual machine ...");
|
||||
vmm.start();
|
||||
|
||||
sleep_forever();
|
||||
return 0;
|
||||
}
|
5
os/src/server/vmm/imx53/target.mk
Normal file
5
os/src/server/vmm/imx53/target.mk
Normal file
@ -0,0 +1,5 @@
|
||||
TARGET = vmm
|
||||
REQUIRES = trustzone platform_imx53
|
||||
LIBS = base
|
||||
SRC_CC = main.cc
|
||||
INC_DIR += $(PRG_DIR) $(PRG_DIR)/../include
|
@ -162,6 +162,14 @@ class Atag {
|
||||
_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;
|
||||
|
@ -1,130 +0,0 @@
|
||||
/*
|
||||
* \brief Driver for the Trustzone Protection Controller BP147
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-07-04
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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_ */
|
91
os/src/server/vmm/include/mmu.h
Normal file
91
os/src/server/vmm/include/mmu.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* \brief Virtual Machine Monitor MMU definition
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-06-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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__MMU_H_
|
||||
#define _SRC__SERVER__VMM__INCLUDE__MMU_H_
|
||||
|
||||
/* local includes */
|
||||
#include <vm_state.h>
|
||||
#include <ram.h>
|
||||
|
||||
class Mmu
|
||||
{
|
||||
private:
|
||||
|
||||
Vm_state *_state;
|
||||
Ram *_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)
|
||||
{
|
||||
PWRN("Not implemented yet!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Mmu(Vm_state *state, Ram *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_ */
|
48
os/src/server/vmm/include/ram.h
Normal file
48
os/src/server/vmm/include/ram.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* \brief Virtual Machine Monitor RAM definition
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-06-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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__RAM_H_
|
||||
#define _SRC__SERVER__VMM__INCLUDE__RAM_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/stdint.h>
|
||||
#include <base/exception.h>
|
||||
|
||||
class Ram {
|
||||
|
||||
private:
|
||||
|
||||
Genode::addr_t _base;
|
||||
Genode::size_t _size;
|
||||
Genode::addr_t _local;
|
||||
|
||||
public:
|
||||
|
||||
class Invalid_addr : Genode::Exception {};
|
||||
|
||||
Ram(Genode::addr_t addr, Genode::size_t sz, Genode::addr_t local)
|
||||
: _base(addr), _size(sz), _local(local) { }
|
||||
|
||||
Genode::addr_t base() { return _base; }
|
||||
Genode::size_t size() { return _size; }
|
||||
Genode::addr_t local() { return _local; }
|
||||
|
||||
Genode::addr_t va(Genode::addr_t phys)
|
||||
{
|
||||
if ((phys < _base) || (phys > (_base + _size)))
|
||||
throw Invalid_addr();
|
||||
return _local + (phys - _base);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SRC__SERVER__VMM__INCLUDE__RAM_H_ */
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* \brief Driver for the SP810 system controller
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-09-21
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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_ */
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* \brief Driver for the Motherboard Express system registers
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-09-21
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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_ */
|
@ -1,212 +0,0 @@
|
||||
/*
|
||||
* \brief Driver for the CoreLink Trustzone Address Space Controller TSC-380
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-07-04
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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_ */
|
193
os/src/server/vmm/include/vm.h
Normal file
193
os/src/server/vmm/include/vm.h
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* \brief Virtual Machine Monitor VM definition
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-06-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__SERVER__VMM__INCLUDE__VM_H_
|
||||
#define _SRC__SERVER__VMM__INCLUDE__VM_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/elf.h>
|
||||
#include <dataspace/client.h>
|
||||
#include <io_mem_session/connection.h>
|
||||
#include <rom_session/connection.h>
|
||||
#include <vm_session/connection.h>
|
||||
|
||||
/* local includes */
|
||||
#include <mmu.h>
|
||||
#include <atag.h>
|
||||
|
||||
class Vm {
|
||||
|
||||
private:
|
||||
|
||||
enum {
|
||||
ATAG_OFFSET = 0x100,
|
||||
INITRD_OFFSET = 0x1000000,
|
||||
};
|
||||
|
||||
Genode::Vm_connection _vm_con;
|
||||
Genode::Rom_connection _kernel_rom;
|
||||
Genode::Rom_connection _initrd_rom;
|
||||
Genode::Dataspace_client _kernel_cap;
|
||||
Genode::Dataspace_client _initrd_cap;
|
||||
const char* _cmdline;
|
||||
Vm_state *_state;
|
||||
Genode::Io_mem_connection _ram_iomem;
|
||||
Ram _ram;
|
||||
Genode::addr_t _kernel_offset;
|
||||
unsigned long _mach_type;
|
||||
unsigned long _board_rev;
|
||||
|
||||
void _load_kernel()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
addr_t addr = env()->rm_session()->attach(_kernel_cap);
|
||||
memcpy((void*)(_ram.local() + _kernel_offset),
|
||||
(void*)addr, _kernel_cap.size());
|
||||
_state->ip = _ram.base() + _kernel_offset;
|
||||
env()->rm_session()->detach((void*)addr);
|
||||
}
|
||||
|
||||
void _load_initrd()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
addr_t addr = env()->rm_session()->attach(_initrd_cap);
|
||||
memcpy((void*)(_ram.local() + INITRD_OFFSET),
|
||||
(void*)addr, _initrd_cap.size());
|
||||
env()->rm_session()->detach((void*)addr);
|
||||
}
|
||||
|
||||
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_cap.size());
|
||||
if (_board_rev)
|
||||
tag.setup_rev_tag(_board_rev);
|
||||
tag.setup_end_tag();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Vm(const char *kernel, const char *initrd, const char *cmdline,
|
||||
Genode::addr_t ram_base, Genode::size_t ram_size,
|
||||
Genode::addr_t kernel_offset, unsigned long mach_type,
|
||||
unsigned long board_rev = 0)
|
||||
: _kernel_rom(kernel),
|
||||
_initrd_rom(initrd),
|
||||
_kernel_cap(_kernel_rom.dataspace()),
|
||||
_initrd_cap(_initrd_rom.dataspace()),
|
||||
_cmdline(cmdline),
|
||||
_state((Vm_state*)Genode::env()->rm_session()->attach(_vm_con.cpu_state())),
|
||||
_ram_iomem(ram_base, ram_size),
|
||||
_ram(ram_base, ram_size, (Genode::addr_t)Genode::env()->rm_session()->attach(_ram_iomem.dataspace())),
|
||||
_kernel_offset(kernel_offset),
|
||||
_mach_type(mach_type),
|
||||
_board_rev(board_rev) { }
|
||||
|
||||
void start()
|
||||
{
|
||||
Genode::memset((void*)_state, 0, sizeof(Vm_state));
|
||||
_load_kernel();
|
||||
_load_initrd();
|
||||
_prepare_atag();
|
||||
_state->cpsr = 0x93; /* SVC mode and IRQs disabled */
|
||||
_state->r1 = _mach_type;
|
||||
_state->r2 = _ram.base() + ATAG_OFFSET; /* ATAG addr */
|
||||
}
|
||||
|
||||
void sig_handler(Genode::Signal_context_capability sig_cap) {
|
||||
_vm_con.exception_handler(sig_cap); }
|
||||
|
||||
void run() { _vm_con.run(); }
|
||||
void pause() { _vm_con.pause(); }
|
||||
|
||||
void dump()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
const char * const modes[] =
|
||||
{ "und", "svc", "abt", "irq", "fiq" };
|
||||
const char * const exc[] =
|
||||
{ "invalid", "reset", "undefined", "smc", "pf_abort",
|
||||
"data_abort", "irq", "fiq" };
|
||||
|
||||
printf("Cpu state:\n");
|
||||
printf(" Register Virt Phys\n");
|
||||
printf("---------------------------------\n");
|
||||
printf(" r0 = %08lx [%08lx]\n",
|
||||
_state->r0, va_to_pa(_state->r0));
|
||||
printf(" r1 = %08lx [%08lx]\n",
|
||||
_state->r1, va_to_pa(_state->r1));
|
||||
printf(" r2 = %08lx [%08lx]\n",
|
||||
_state->r2, va_to_pa(_state->r2));
|
||||
printf(" r3 = %08lx [%08lx]\n",
|
||||
_state->r3, va_to_pa(_state->r3));
|
||||
printf(" r4 = %08lx [%08lx]\n",
|
||||
_state->r4, va_to_pa(_state->r4));
|
||||
printf(" r5 = %08lx [%08lx]\n",
|
||||
_state->r5, va_to_pa(_state->r5));
|
||||
printf(" r6 = %08lx [%08lx]\n",
|
||||
_state->r6, va_to_pa(_state->r6));
|
||||
printf(" r7 = %08lx [%08lx]\n",
|
||||
_state->r7, va_to_pa(_state->r7));
|
||||
printf(" r8 = %08lx [%08lx]\n",
|
||||
_state->r8, va_to_pa(_state->r8));
|
||||
printf(" r9 = %08lx [%08lx]\n",
|
||||
_state->r9, va_to_pa(_state->r9));
|
||||
printf(" r10 = %08lx [%08lx]\n",
|
||||
_state->r10, va_to_pa(_state->r10));
|
||||
printf(" r11 = %08lx [%08lx]\n",
|
||||
_state->r11, va_to_pa(_state->r11));
|
||||
printf(" r12 = %08lx [%08lx]\n",
|
||||
_state->r12, va_to_pa(_state->r12));
|
||||
printf(" sp = %08lx [%08lx]\n",
|
||||
_state->sp, va_to_pa(_state->sp));
|
||||
printf(" lr = %08lx [%08lx]\n",
|
||||
_state->lr, va_to_pa(_state->lr));
|
||||
printf(" ip = %08lx [%08lx]\n",
|
||||
_state->ip, va_to_pa(_state->ip));
|
||||
printf(" cpsr = %08lx\n", _state->cpsr);
|
||||
for (unsigned i = 0;
|
||||
i < Vm_state::Mode_state::MAX; i++) {
|
||||
printf(" sp_%s = %08lx [%08lx]\n", modes[i],
|
||||
_state->mode[i].sp, va_to_pa(_state->mode[i].sp));
|
||||
printf(" lr_%s = %08lx [%08lx]\n", modes[i],
|
||||
_state->mode[i].lr, va_to_pa(_state->mode[i].lr));
|
||||
printf(" spsr_%s = %08lx [%08lx]\n", modes[i],
|
||||
_state->mode[i].spsr, va_to_pa(_state->mode[i].spsr));
|
||||
}
|
||||
printf(" ttbr0 = %08lx\n", _state->ttbr[0]);
|
||||
printf(" ttbr1 = %08lx\n", _state->ttbr[1]);
|
||||
printf(" ttbrc = %08lx\n", _state->ttbrc);
|
||||
printf(" dfar = %08lx [%08lx]\n",
|
||||
_state->dfar, va_to_pa(_state->dfar));
|
||||
printf(" exception = %s\n", exc[_state->cpu_exception]);
|
||||
}
|
||||
|
||||
Genode::addr_t va_to_pa(Genode::addr_t va)
|
||||
{
|
||||
try {
|
||||
Mmu mmu(_state, &_ram);
|
||||
return mmu.phys_addr(va);
|
||||
} catch(Ram::Invalid_addr) {}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Vm_state *state() const { return _state; }
|
||||
Ram *ram() { return &_ram; }
|
||||
};
|
||||
|
||||
#endif /* _SRC__SERVER__VMM__INCLUDE__VM_H_ */
|
27
os/src/server/vmm/include/vm_state.h
Normal file
27
os/src/server/vmm/include/vm_state.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* \brief Virtual Machine Monitor VM state definition
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-06-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__SERVER__VMM__INCLUDE__VM_STATE_H_
|
||||
#define _SRC__SERVER__VMM__INCLUDE__VM_STATE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <cpu/cpu_state.h>
|
||||
|
||||
struct Vm_state : Genode::Cpu_state_modes
|
||||
{
|
||||
Genode::addr_t dfar; /* data fault address */
|
||||
Genode::addr_t ttbr[2]; /* translation table base regs */
|
||||
Genode::addr_t ttbrc; /* translation table base control */
|
||||
};
|
||||
|
||||
#endif /* _SRC__SERVER__VMM__INCLUDE__VM_STATE_H_ */
|
@ -1,371 +0,0 @@
|
||||
/*
|
||||
* \brief Virtual Machine Monitor
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-06-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2008-2013 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->r1 = 2272; /* MACH_TYPE vexpress board */
|
||||
_state->r2 = _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");
|
||||
printf(" r0 = %08lx\n", _state->r0);
|
||||
printf(" r1 = %08lx\n", _state->r1);
|
||||
printf(" r2 = %08lx\n", _state->r2);
|
||||
printf(" r3 = %08lx\n", _state->r3);
|
||||
printf(" r4 = %08lx\n", _state->r4);
|
||||
printf(" r5 = %08lx\n", _state->r5);
|
||||
printf(" r6 = %08lx\n", _state->r6);
|
||||
printf(" r7 = %08lx\n", _state->r7);
|
||||
printf(" r8 = %08lx\n", _state->r8);
|
||||
printf(" r9 = %08lx\n", _state->r9);
|
||||
printf(" r10 = %08lx\n", _state->r10);
|
||||
printf(" r11 = %08lx\n", _state->r11);
|
||||
printf(" r12 = %08lx\n", _state->r12);
|
||||
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()->r2;
|
||||
uint32_t data = _vm->state()->r0;
|
||||
|
||||
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()->r1) {
|
||||
case SP810_ENABLE:
|
||||
_sp810.enable_timer0();
|
||||
_sp810.enable_timer1();
|
||||
break;
|
||||
case CPU_ID:
|
||||
_vm->state()->r0 = 0x0c000191; // Coretile A9 ID
|
||||
break;
|
||||
case SYS_COUNTER:
|
||||
_vm->state()->r0 = _sys.counter();
|
||||
break;
|
||||
case MISC_FLAGS:
|
||||
_vm->state()->r0 = _sys.misc_flags();
|
||||
break;
|
||||
case SYS_CTRL:
|
||||
_sys_ctrl();
|
||||
break;
|
||||
case MCI_STATUS:
|
||||
_vm->state()->r0 = _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)
|
||||
: Thread("vmm_signal_handler"),
|
||||
_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;
|
||||
}
|
126
os/src/server/vmm/vea9x4/bp_147.h
Normal file
126
os/src/server/vmm/vea9x4/bp_147.h
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* \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>
|
||||
|
||||
class Bp_147 : Genode::Mmio
|
||||
{
|
||||
private:
|
||||
|
||||
/**
|
||||
* Secure RAM Region Size Register
|
||||
*/
|
||||
struct Tzpcr0size : public Register<0x00, 32>
|
||||
{
|
||||
struct R0size : Bitfield<0,10> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode Protection 0 Registers
|
||||
*/
|
||||
template <Genode::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 <Genode::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 <Genode::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(Genode::addr_t const base) : Genode::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_ */
|
207
os/src/server/vmm/vea9x4/main.cc
Normal file
207
os/src/server/vmm/vea9x4/main.cc
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* \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 <vm.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
namespace Vmm {
|
||||
class Vmm;
|
||||
}
|
||||
|
||||
class Vmm::Vmm : public 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()->r2;
|
||||
uint32_t data = _vm->state()->r0;
|
||||
|
||||
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()->r1) {
|
||||
case SP810_ENABLE:
|
||||
_sp810.enable_timer0();
|
||||
_sp810.enable_timer1();
|
||||
break;
|
||||
case CPU_ID:
|
||||
_vm->state()->r0 = 0x0c000191; // Coretile A9 ID
|
||||
break;
|
||||
case SYS_COUNTER:
|
||||
_vm->state()->r0 = _sys.counter();
|
||||
break;
|
||||
case MISC_FLAGS:
|
||||
_vm->state()->r0 = _sys.misc_flags();
|
||||
break;
|
||||
case SYS_CTRL:
|
||||
_sys_ctrl();
|
||||
break;
|
||||
case MCI_STATUS:
|
||||
_vm->state()->r0 = _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,
|
||||
KERNEL_OFFSET = 0x8000,
|
||||
MACH_TYPE = 2272,
|
||||
};
|
||||
|
||||
static const char* cmdline = "console=ttyAMA0,38400n8 root=/dev/ram0 lpj=1554432";
|
||||
static Vm vm("linux", "initrd.gz", cmdline, MAIN_MEM_START, MAIN_MEM_SIZE,
|
||||
KERNEL_OFFSET, MACH_TYPE);
|
||||
static Vmm::Vmm vmm(TSC_VEA9X4_BASE, TPC_VEA9X4_BASE,
|
||||
SYS_VEA9X4_BASE, SP810_VEA9X4_BASE, &vm);
|
||||
|
||||
PINF("Start virtual machine");
|
||||
vmm.start();
|
||||
|
||||
sleep_forever();
|
||||
return 0;
|
||||
}
|
41
os/src/server/vmm/vea9x4/sp810.h
Normal file
41
os/src/server/vmm/vea9x4/sp810.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* \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>
|
||||
|
||||
class Sp810 : Genode::Mmio
|
||||
{
|
||||
private:
|
||||
|
||||
struct Ctrl : public Register<0, 32>
|
||||
{
|
||||
struct Timer0_enable : Bitfield<15,1> {};
|
||||
struct Timer1_enable : Bitfield<17,1> {};
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Sp810(Genode::addr_t const base) : Genode::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_ */
|
100
os/src/server/vmm/vea9x4/sys_reg.h
Normal file
100
os/src/server/vmm/vea9x4/sys_reg.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* \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>
|
||||
|
||||
class Sys_reg : Genode::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(Genode::addr_t const base) : Genode::Mmio(base) {}
|
||||
|
||||
Genode::uint32_t counter() { return read<Sys_24mhz>(); }
|
||||
|
||||
Genode::uint32_t misc_flags() { return read<Sys_misc>(); }
|
||||
|
||||
void osc1(Genode::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(Genode::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(Genode::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>()) ;
|
||||
}
|
||||
|
||||
Genode::uint32_t mci_status() { return read<Sys_mci>(); }
|
||||
};
|
||||
|
||||
#endif /* _BASE_HW__SRC__SERVER__VMM__SYS_REG_H_ */
|
@ -2,4 +2,4 @@ TARGET = vmm
|
||||
REQUIRES = trustzone platform_vea9x4
|
||||
LIBS = base
|
||||
SRC_CC = main.cc
|
||||
INC_DIR += $(PRG_DIR)/include
|
||||
INC_DIR += $(PRG_DIR) $(PRG_DIR)/../include
|
207
os/src/server/vmm/vea9x4/tsc_380.h
Normal file
207
os/src/server/vmm/vea9x4/tsc_380.h
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* \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>
|
||||
|
||||
class Tsc_380 : Genode::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 <Genode::off_t OFF>
|
||||
struct Region_low : public Register<OFF + REGION_LOW_OFF, 32>
|
||||
{
|
||||
enum { MASK = ~0UL << 15 };
|
||||
};
|
||||
|
||||
template <Genode::off_t OFF>
|
||||
struct Region_high : public Register<OFF + REGION_HIGH_OFF, 32> { };
|
||||
|
||||
template <Genode::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(Genode::addr_t const base) : Genode::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_ */
|
Loading…
x
Reference in New Issue
Block a user