135 lines
3.8 KiB
C++
135 lines
3.8 KiB
C++
/*
|
|
* \brief Virtual Machine Monitor VM definition
|
|
* \author Stefan Kalkowski
|
|
* \author Martin Stein
|
|
* \date 2012-06-25
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2012-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
/* Genode includes */
|
|
#include <base/attached_rom_dataspace.h>
|
|
|
|
/* local includes */
|
|
#include <vm_base.h>
|
|
#include <mmu.h>
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
void Vm_base::_load_kernel()
|
|
{
|
|
Attached_rom_dataspace kernel(_env, _kernel.string());
|
|
memcpy((void*)(_ram.local() + _kernel_off),
|
|
kernel.local_addr<void>(), kernel.size());
|
|
_state.ip = _ram.base() + _kernel_off;
|
|
}
|
|
|
|
|
|
Vm_base::Vm_base(Env &env,
|
|
Kernel_name const &kernel,
|
|
Command_line const &cmdline,
|
|
addr_t ram_base,
|
|
size_t ram_size,
|
|
off_t kernel_off,
|
|
Machine_type machine,
|
|
Board_revision board,
|
|
Allocator &alloc,
|
|
Vm_handler_base &handler)
|
|
:
|
|
_env(env), _kernel(kernel), _cmdline(cmdline), _kernel_off(kernel_off),
|
|
_machine(machine), _board(board), _ram(env, ram_base, ram_size),
|
|
_vcpu_id(_vm.create_vcpu(alloc, env, handler))
|
|
{
|
|
_state.irq_injection = 0;
|
|
}
|
|
|
|
void Vm_base::start()
|
|
{
|
|
memset((void*)&_state, 0, sizeof(Vm_state));
|
|
_load_kernel();
|
|
_load_kernel_surroundings();
|
|
_state.cpsr = 0x93; /* SVC mode and IRQs disabled */
|
|
_state.r0 = 0;
|
|
_state.r1 = _machine.value;
|
|
_state.r2 = _ram.base() + _board_info_offset();
|
|
}
|
|
|
|
|
|
void Vm_base::inject_irq(unsigned irq)
|
|
{
|
|
if (_state.irq_injection) { throw Inject_irq_failed(); }
|
|
_state.irq_injection = irq;
|
|
}
|
|
|
|
|
|
|
|
void Vm_base::dump()
|
|
{
|
|
char const *mod[] = { "und", "svc", "abt", "irq", "fiq" };
|
|
char const *exc[] = { "invalid", "reset", "undefined", "smc",
|
|
"pf_abort", "data_abort", "irq", "fiq" };
|
|
|
|
auto log_adr_reg = [&] (char const *reg, addr_t val) {
|
|
log(" ", reg, " = ", Hex(val, Hex::PREFIX, Hex::PAD), " ",
|
|
Hex(va_to_pa(val), Hex::PREFIX, Hex::PAD)); };
|
|
|
|
auto log_mod_reg = [&] (char const *reg, addr_t val, char const *mod) {
|
|
log(" ", reg, "_", mod, " = ", Hex(val, Hex::PREFIX, Hex::PAD), " ",
|
|
Hex(va_to_pa(val), Hex::PREFIX, Hex::PAD)); };
|
|
|
|
log("Cpu state:");
|
|
log(" Register Virt Phys");
|
|
log("------------------------------------");
|
|
log_adr_reg("r0 ", _state.r0);
|
|
log_adr_reg("r1 ", _state.r1);
|
|
log_adr_reg("r2 ", _state.r2);
|
|
log_adr_reg("r3 ", _state.r3);
|
|
log_adr_reg("r4 ", _state.r4);
|
|
log_adr_reg("r5 ", _state.r5);
|
|
log_adr_reg("r6 ", _state.r6);
|
|
log_adr_reg("r7 ", _state.r7);
|
|
log_adr_reg("r8 ", _state.r8);
|
|
log_adr_reg("r9 ", _state.r9);
|
|
log_adr_reg("r10 ", _state.r10);
|
|
log_adr_reg("r11 ", _state.r11);
|
|
log_adr_reg("r12 ", _state.r12);
|
|
log_adr_reg("sp ", _state.sp);
|
|
log_adr_reg("lr ", _state.lr);
|
|
log_adr_reg("ip ", _state.ip);
|
|
log_adr_reg("cpsr ", _state.cpsr);
|
|
for (unsigned i = 0; i < Vm_state::Mode_state::MAX; i++) {
|
|
log_mod_reg("sp ", _state.mode[i].sp, mod[i]);
|
|
log_mod_reg("lr ", _state.mode[i].lr, mod[i]);
|
|
log_mod_reg("spsr ", _state.mode[i].spsr, mod[i]);
|
|
}
|
|
log(" ttbr0 = ", Hex(_state.ttbr[0], Hex::PREFIX, Hex::PAD));
|
|
log(" ttbr1 = ", Hex(_state.ttbr[1], Hex::PREFIX, Hex::PAD));
|
|
log(" ttbrc = ", Hex(_state.ttbrc , Hex::PREFIX, Hex::PAD));
|
|
log_adr_reg("dfar ", _state.dfar);
|
|
log(" exception = ", exc[_state.cpu_exception]);
|
|
}
|
|
|
|
|
|
void Vm_base::smc_ret(addr_t const ret_0, addr_t const ret_1)
|
|
{
|
|
_state.r0 = ret_0;
|
|
_state.r1 = ret_1;
|
|
}
|
|
|
|
|
|
addr_t Vm_base::va_to_pa(addr_t va)
|
|
{
|
|
try {
|
|
Mmu mmu(_state, _ram);
|
|
return mmu.phys_addr(va);
|
|
}
|
|
catch(Ram::Invalid_addr) { }
|
|
return 0;
|
|
}
|