/* * \brief VMM cpu object * \author Stefan Kalkowski * \date 2019-07-18 */ /* * Copyright (C) 2019 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. */ #include #include #include using Vmm::Cpu_base; using Vmm::Cpu; using Vmm::Gic; Genode::uint64_t Cpu_base::State::reg(unsigned idx) const { if (idx > 15) return 0; Genode::uint32_t * r = (Genode::uint32_t*)this; r += idx; return *r; } void Cpu_base::State::reg(unsigned idx, Genode::uint64_t v) { if (idx > 15) return; Genode::uint32_t * r = (Genode::uint32_t*)this; r += idx; *r = v; } Cpu_base::System_register::Iss::access_t Cpu_base::System_register::Iss::value(unsigned op0, unsigned crn, unsigned op1, unsigned crm, unsigned op2) { access_t v = 0; Crn::set(v, crn); Crm::set(v, crm); Opcode1::set(v, op1); Opcode2::set(v, op2); return v; }; Cpu_base::System_register::Iss::access_t Cpu_base::System_register::Iss::mask_encoding(access_t v) { return Crm::masked(v) | Crn::masked(v) | Opcode1::masked(v) | Opcode2::masked(v); } void Cpu_base::_handle_brk() { Genode::error(__func__, " not implemented yet"); } void Cpu_base::handle_exception() { /* check exception reason */ switch (_state.cpu_exception) { case Cpu::NO_EXCEPTION: break; case Cpu::FIQ: [[fallthrough]]; case Cpu::IRQ: _handle_irq(); break; case Cpu::TRAP: _handle_sync(); break; default: throw Exception("Curious exception ", _state.cpu_exception, " occured"); } _state.cpu_exception = Cpu::NO_EXCEPTION; } void Cpu_base::dump() { using namespace Genode; auto lambda = [] (unsigned i) { switch (i) { case 0: return "und"; case 1: return "svc"; case 2: return "abt"; case 3: return "irq"; case 4: return "fiq"; default: return "unknown"; }; }; log("VM state (", _active ? "active" : "inactive", ") :"); for (unsigned i = 0; i < 13; i++) { log(" r", i, " = ", Hex(_state.reg(i), Hex::PREFIX, Hex::PAD)); } log(" sp = ", Hex(_state.sp, Hex::PREFIX, Hex::PAD)); log(" lr = ", Hex(_state.lr, Hex::PREFIX, Hex::PAD)); log(" ip = ", Hex(_state.ip, Hex::PREFIX, Hex::PAD)); log(" cpsr = ", Hex(_state.cpsr, Hex::PREFIX, Hex::PAD)); for (unsigned i = 0; i < State::Mode_state::MAX; i++) { log(" sp_", lambda(i), " = ", Hex(_state.mode[i].sp, Hex::PREFIX, Hex::PAD)); log(" lr_", lambda(i), " = ", Hex(_state.mode[i].lr, Hex::PREFIX, Hex::PAD)); log(" spsr_", lambda(i), " = ", Hex(_state.mode[i].spsr, Hex::PREFIX, Hex::PAD)); } log(" exception = ", _state.cpu_exception); log(" esr_el2 = ", Hex(_state.esr_el2, Hex::PREFIX, Hex::PAD)); log(" hpfar_el2 = ", Hex(_state.hpfar_el2, Hex::PREFIX, Hex::PAD)); log(" far_el2 = ", Hex(_state.far_el2, Hex::PREFIX, Hex::PAD)); log(" hifar = ", Hex(_state.hifar, Hex::PREFIX, Hex::PAD)); log(" dfsr = ", Hex(_state.dfsr, Hex::PREFIX, Hex::PAD)); log(" ifsr = ", Hex(_state.ifsr, Hex::PREFIX, Hex::PAD)); log(" sctrl = ", Hex(_state.sctrl, Hex::PREFIX, Hex::PAD)); _timer.dump(); } void Cpu_base::initialize_boot(Genode::addr_t ip, Genode::addr_t dtb) { state().reg(1, 0xffffffff); /* invalid machine type */ state().reg(2, dtb); state().ip = ip; } Genode::addr_t Cpu::Ccsidr::read() const { struct Csselr : Genode::Register<32> { struct Level : Bitfield<1, 4> {}; }; enum { INVALID = 0xffffffff }; unsigned level = Csselr::Level::get(csselr.read()); if (level > 6) { Genode::warning("Invalid Csselr value!"); return INVALID; } return 0; } Cpu::Cpu(Vm & vm, Genode::Vm_connection & vm_session, Mmio_bus & bus, Gic & gic, Genode::Env & env, Genode::Heap & heap, Genode::Entrypoint & ep) : Cpu_base(vm, vm_session, bus, gic, env, heap, ep), _sr_midr (0, 0, 0, 0, "MIDR", false, 0x412fc0f1, _reg_tree), _sr_mpidr (0, 0, 0, 5, "MPIDR", false, 1<<31|cpu_id(), _reg_tree), _sr_mmfr0 (0, 0, 1, 4, "MMFR0", false, 0x10201105, _reg_tree), _sr_mmfr1 (0, 0, 1, 5, "MMFR1", false, 0x20000000, _reg_tree), _sr_mmfr2 (0, 0, 1, 6, "MMFR2", false, 0x01240000, _reg_tree), _sr_mmfr3 (0, 0, 1, 7, "MMFR3", false, 0x02102211, _reg_tree), _sr_isar0 (0, 0, 2, 0, "ISAR0", false, 0x02101110, _reg_tree), _sr_isar1 (0, 0, 2, 1, "ISAR1", false, 0x13112111, _reg_tree), _sr_isar2 (0, 0, 2, 2, "ISAR2", false, 0x21232041, _reg_tree), _sr_isar3 (0, 0, 2, 3, "ISAR3", false, 0x11112131, _reg_tree), _sr_isar4 (0, 0, 2, 4, "ISAR4", false, 0x10011142, _reg_tree), _sr_isar5 (0, 0, 2, 5, "ISAR5", false, 0x0, _reg_tree), _sr_pfr0 (0, 0, 1, 0, "PFR0", false, 0x00001131, _reg_tree), _sr_pfr1 (0, 0, 1, 1, "PFR1", false, 0x00011011, _reg_tree), _sr_clidr (0, 1, 0, 1, "CLIDR", false, 0xa200023, _reg_tree), _sr_csselr (0, 2, 0, 0, "CSSELR", true, 0x0, _reg_tree), _sr_ctr (0, 0, 0, 1, "CTR", true, 0x8444c004, _reg_tree), _sr_revidr (0, 0, 0, 6, "REVIDR", true, 0x0, _reg_tree), _sr_ccsidr (_sr_csselr, _reg_tree), _sr_actlr (1, 0, 0, 1, "ACTLR", true, 0x0, _reg_tree) { _state.cpsr = 0x93; /* el1 mode and IRQs disabled */ _state.sctrl = 0xc50078; }