mirror of
https://github.com/genodelabs/genode.git
synced 2025-03-24 04:55:42 +00:00
hw_arndale: setup ARM hypervisor mode
To enable support of hardware virtualization for ARM on the Arndale board, the cpu needs to be prepared to enter the non-secure mode, as long as it does not already run in it. Therefore, especially the interrupt controller and some TrustZone specific system registers need to be prepared. Moreover, the exception vector for the hypervisor needs to be set up properly, before booting normally in the supervisor mode of the non-secure world. Ref #1405
This commit is contained in:
parent
e7dad39016
commit
07c8d1652e
@ -8,8 +8,5 @@
|
||||
INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a15
|
||||
INC_DIR += $(REP_DIR)/src/core/include/spec/arm_gic
|
||||
|
||||
# add C++ sources
|
||||
SRC_CC += spec/arm_gic/pic.cc
|
||||
|
||||
# include less specific configuration
|
||||
include $(REP_DIR)/lib/mk/arm_v7/core.inc
|
||||
|
12
repos/base-hw/lib/mk/platform_arndale/core.mk
Normal file
12
repos/base-hw/lib/mk/platform_arndale/core.mk
Normal file
@ -0,0 +1,12 @@
|
||||
#
|
||||
# \brief Build config for Genodes core process
|
||||
# \author Stefan Kalkowski
|
||||
# \date 2015-02-09
|
||||
#
|
||||
|
||||
# add C++ sources
|
||||
SRC_CC += spec/arndale/board.cc
|
||||
SRC_CC += spec/arndale/pic.cc
|
||||
|
||||
# include less specific configuration
|
||||
include $(REP_DIR)/lib/mk/exynos5/core.inc
|
12
repos/base-hw/lib/mk/platform_odroid_xu/core.mk
Normal file
12
repos/base-hw/lib/mk/platform_odroid_xu/core.mk
Normal file
@ -0,0 +1,12 @@
|
||||
#
|
||||
# \brief Build config for Genodes core process
|
||||
# \author Stefan Kalkowski
|
||||
# \date 2015-02-09
|
||||
#
|
||||
|
||||
# add C++ sources
|
||||
SRC_CC += spec/exynos5/board.cc
|
||||
SRC_CC += spec/arm_gic/pic.cc
|
||||
|
||||
# include less specific configuration
|
||||
include $(REP_DIR)/lib/mk/exynos5/core.inc
|
@ -221,10 +221,19 @@ class Genode::Arm
|
||||
*/
|
||||
struct Psr : Register<32>
|
||||
{
|
||||
static constexpr access_t usr = 16;
|
||||
static constexpr access_t svc = 19;
|
||||
/**
|
||||
* CPU mode
|
||||
*/
|
||||
struct M : Bitfield<0,5>
|
||||
{
|
||||
enum {
|
||||
USR = 16,
|
||||
SVC = 19,
|
||||
MON = 22,
|
||||
HYP = 26,
|
||||
};
|
||||
};
|
||||
|
||||
struct M : Bitfield<0,5> { }; /* CPU mode */
|
||||
struct F : Bitfield<6,1> { }; /* FIQ disable */
|
||||
struct I : Bitfield<7,1> { }; /* IRQ disable */
|
||||
struct A : Bitfield<8,1> { }; /* async. abort disable */
|
||||
@ -260,7 +269,7 @@ class Genode::Arm
|
||||
{
|
||||
access_t v = 0;
|
||||
init_common(v);
|
||||
M::set(v, usr);
|
||||
M::set(v, M::USR);
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -271,7 +280,7 @@ class Genode::Arm
|
||||
{
|
||||
access_t v = 0;
|
||||
init_common(v);
|
||||
M::set(v, svc);
|
||||
M::set(v, M::SVC);
|
||||
I::set(v, 1);
|
||||
return v;
|
||||
}
|
||||
@ -418,7 +427,7 @@ class Genode::Arm
|
||||
/**
|
||||
* Returns true if current execution context is running in user mode
|
||||
*/
|
||||
static bool is_user() { return Psr::M::get(Psr::read()) == Psr::usr; }
|
||||
static bool is_user() { return Psr::M::get(Psr::read()) == Psr::M::USR; }
|
||||
|
||||
/**
|
||||
* Invalidate all entries of all instruction caches
|
||||
|
@ -51,8 +51,12 @@ class Genode::Arm_gic_distributor : public Mmio
|
||||
/**
|
||||
* Control register
|
||||
*/
|
||||
struct Ctlr : Register<0x000, 32> {
|
||||
struct Enable : Bitfield<0,1> { }; };
|
||||
struct Ctlr : Register<0x000, 32>
|
||||
{
|
||||
struct Enable : Bitfield<0,1> { };
|
||||
struct Enable_grp0 : Bitfield<0,1> { };
|
||||
struct Enable_grp1 : Bitfield<1,1> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Controller type register
|
||||
|
@ -141,14 +141,19 @@ namespace Genode
|
||||
|
||||
class Genode::Arm_v7 : public Arm
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
|
||||
/**
|
||||
* Secure configuration register
|
||||
*/
|
||||
struct Scr : Register<32>
|
||||
{
|
||||
struct Ns : Bitfield<0, 1> { }; /* not secure */
|
||||
struct Ns : Bitfield<0, 1> { }; /* not secure */
|
||||
struct Fw : Bitfield<4, 1> { }; /* F bit writeable */
|
||||
struct Aw : Bitfield<5, 1> { }; /* A bit writeable */
|
||||
struct Scd : Bitfield<7, 1> { }; /* smc call disable */
|
||||
struct Hce : Bitfield<8, 1> { }; /* hyp call enable */
|
||||
struct Sif : Bitfield<9, 1> { }; /* secure instruction fetch */
|
||||
|
||||
/**
|
||||
* Read register value
|
||||
@ -159,6 +164,15 @@ class Genode::Arm_v7 : public Arm
|
||||
asm volatile ("mrc p15, 0, %[v], c1, c1, 0" : [v]"=r"(v) ::);
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write register value
|
||||
*/
|
||||
static void write(access_t const v)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %[v], c1, c1, 0 \n"
|
||||
"isb" : : [v] "r" (v));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -168,6 +182,14 @@ class Genode::Arm_v7 : public Arm
|
||||
{
|
||||
struct Cpnsae10 : Bitfield<10, 1> { };
|
||||
struct Cpnsae11 : Bitfield<11, 1> { };
|
||||
|
||||
/**
|
||||
* Write register value
|
||||
*/
|
||||
static void write(access_t const v)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %[v], c1, c1, 2" : : [v] "r" (v));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -216,8 +238,6 @@ class Genode::Arm_v7 : public Arm
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Invalidate all branch predictions
|
||||
*/
|
||||
@ -255,37 +275,6 @@ class Genode::Arm_v7 : public Arm
|
||||
finish_init_phys_kernel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wether we are in secure mode
|
||||
*/
|
||||
static bool secure_mode()
|
||||
{
|
||||
if (!Board::SECURITY_EXTENSION) return 0;
|
||||
return !Scr::Ns::get(Scr::read());
|
||||
}
|
||||
|
||||
|
||||
/******************************
|
||||
** Trustzone specific API **
|
||||
******************************/
|
||||
|
||||
/**
|
||||
* Set exception-vector's address for monitor mode to 'a'
|
||||
*/
|
||||
static void mon_exception_entry_at(addr_t const a) {
|
||||
asm volatile ("mcr p15, 0, %[rd], c12, c0, 1" : : [rd] "r" (a)); }
|
||||
|
||||
/**
|
||||
* Enable access of co-processors cp10 and cp11 from non-secure mode.
|
||||
*/
|
||||
static inline void allow_coprocessor_nonsecure()
|
||||
{
|
||||
Nsacr::access_t v = 0;
|
||||
Nsacr::Cpnsae10::set(v, 1);
|
||||
Nsacr::Cpnsae11::set(v, 1);
|
||||
asm volatile ("mcr p15, 0, %[v], c1, c1, 2" : : [v] "r" (v));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish all previous data transfers
|
||||
*/
|
||||
@ -306,6 +295,37 @@ class Genode::Arm_v7 : public Arm
|
||||
* Wait for the next interrupt as cheap as possible
|
||||
*/
|
||||
static void wait_for_interrupt() { asm volatile ("wfi"); }
|
||||
|
||||
|
||||
/******************************
|
||||
** Trustzone specific API **
|
||||
******************************/
|
||||
|
||||
/**
|
||||
* Wether we are in secure mode
|
||||
*/
|
||||
static bool secure_mode()
|
||||
{
|
||||
if (!Board::SECURITY_EXTENSION) return 0;
|
||||
return !Scr::Ns::get(Scr::read());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set exception-vector's address for monitor mode to 'a'
|
||||
*/
|
||||
static void mon_exception_entry_at(addr_t const a) {
|
||||
asm volatile ("mcr p15, 0, %[rd], c12, c0, 1" : : [rd] "r" (a)); }
|
||||
|
||||
|
||||
/***********************************
|
||||
** Virtualization specific API **
|
||||
***********************************/
|
||||
|
||||
/**
|
||||
* Set exception-vector's address for hypervisor mode to 'a'
|
||||
*/
|
||||
static void hyp_exception_entry_at(void * a) {
|
||||
asm volatile ("mcr p15, 4, %[rd], c12, c0, 0" :: [rd] "r" (a)); }
|
||||
};
|
||||
|
||||
|
||||
@ -332,7 +352,7 @@ void Genode::Arm::invalidate_data_caches()
|
||||
Genode::Arm::Psr::access_t Genode::Arm::Psr::init_user_with_trustzone()
|
||||
{
|
||||
access_t v = 0;
|
||||
M::set(v, usr);
|
||||
M::set(v, M::USR);
|
||||
I::set(v, 1);
|
||||
A::set(v, 1);
|
||||
return v;
|
||||
|
@ -34,7 +34,7 @@ namespace Kernel { using Genode::Cpu_lazy_state; }
|
||||
|
||||
class Genode::Cpu : public Arm_v7
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
|
||||
/**
|
||||
* Translation table base control register
|
||||
@ -66,7 +66,13 @@ class Genode::Cpu : public Arm_v7
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* Non-secure access control register
|
||||
*/
|
||||
struct Nsacr : Arm_v7::Nsacr
|
||||
{
|
||||
struct Ns_smp : Bitfield<18,1> { };
|
||||
};
|
||||
|
||||
/**
|
||||
* Translation table base register 0 (64-bit format)
|
||||
|
@ -25,7 +25,7 @@ namespace Genode
|
||||
|
||||
static void outer_cache_invalidate() { }
|
||||
static void outer_cache_flush() { }
|
||||
static void prepare_kernel() { }
|
||||
static void prepare_kernel();
|
||||
|
||||
/**
|
||||
* Tell secondary CPUs to start execution from instr. pointer 'ip'
|
||||
|
@ -229,6 +229,9 @@ extern "C" void init_kernel_up()
|
||||
/* initialize all CPU objects */
|
||||
cpu_pool();
|
||||
|
||||
/* initialize PIC */
|
||||
pic();
|
||||
|
||||
/* go multiprocessor mode */
|
||||
Cpu::start_secondary_cpus(&_start_secondary_cpus);
|
||||
}
|
||||
@ -289,6 +292,9 @@ extern "C" void init_kernel_mp()
|
||||
Cpu::invalidate_instr_caches();
|
||||
Cpu::data_synchronization_barrier();
|
||||
|
||||
/* locally initialize interrupt controller */
|
||||
pic()->init_cpu_local();
|
||||
|
||||
/* initialize CPU in physical mode */
|
||||
Cpu::init_phys_kernel();
|
||||
|
||||
@ -319,9 +325,8 @@ extern "C" void init_kernel_mp()
|
||||
*/
|
||||
perf_counter()->enable();
|
||||
|
||||
/* locally initialize interrupt controller */
|
||||
/* enable timer interrupt */
|
||||
unsigned const cpu = Cpu::executing_id();
|
||||
pic()->init_cpu_local();
|
||||
pic()->unmask(Timer::interrupt_id(cpu), cpu);
|
||||
|
||||
/* do further initialization only as primary CPU */
|
||||
|
@ -236,6 +236,16 @@
|
||||
.endm /* _kernel_to_vm */
|
||||
|
||||
|
||||
/**
|
||||
* Enter kernel after hypervisor call
|
||||
*/
|
||||
.macro _hyp_to_kernel exception_type
|
||||
cps #SVC_MODE
|
||||
mov r0, #\exception_type
|
||||
1: b 1b
|
||||
.endm /* _hyp_to_kernel */
|
||||
|
||||
|
||||
/**********************************
|
||||
** Linked into the text section **
|
||||
**********************************/
|
||||
@ -400,7 +410,7 @@
|
||||
ldm sp, {r0, r1, pc}^
|
||||
|
||||
/*
|
||||
* On vm exceptions the CPU has to jump to one of the following
|
||||
* On TrustZone exceptions the CPU has to jump to one of the following
|
||||
* 7 entry vectors to switch to a kernel context.
|
||||
*/
|
||||
.p2align 5
|
||||
@ -429,6 +439,30 @@
|
||||
_mt_vm_entry_pic:
|
||||
_kernel_to_vm
|
||||
|
||||
/*
|
||||
* On virtualization exceptions the CPU has to jump to one of the following
|
||||
* 7 entry vectors to switch to a kernel context.
|
||||
*/
|
||||
.p2align 4
|
||||
.global _hyp_kernel_entry
|
||||
_hyp_kernel_entry:
|
||||
b _hyp_rst_entry
|
||||
b _hyp_und_entry /* undefined instruction */
|
||||
b _hyp_svc_entry /* hypervisor call */
|
||||
b _hyp_pab_entry /* prefetch abort */
|
||||
b _hyp_dab_entry /* data abort */
|
||||
b _hyp_trp_entry /* hypervisor trap */
|
||||
b _hyp_irq_entry /* interrupt request */
|
||||
_hyp_to_kernel 7 /* fast interrupt request */
|
||||
|
||||
_hyp_rst_entry: _hyp_to_kernel 0
|
||||
_hyp_und_entry: _hyp_to_kernel 1
|
||||
_hyp_svc_entry: _hyp_to_kernel 2
|
||||
_hyp_pab_entry: _hyp_to_kernel 3
|
||||
_hyp_dab_entry: _hyp_to_kernel 4
|
||||
_hyp_trp_entry: _hyp_to_kernel 5
|
||||
_hyp_irq_entry: _hyp_to_kernel 6
|
||||
|
||||
/* end of the mode transition code */
|
||||
.global _mt_end
|
||||
_mt_end:
|
||||
|
83
repos/base-hw/src/core/spec/arndale/board.cc
Normal file
83
repos/base-hw/src/core/spec/arndale/board.cc
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* \brief Board-specific code for Arndale
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2015-02-09
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
/* core includes */
|
||||
#include <board.h>
|
||||
#include <cpu.h>
|
||||
|
||||
/* hypervisor exception vector address */
|
||||
extern void* _hyp_kernel_entry;
|
||||
|
||||
|
||||
static inline void prepare_nonsecure_world()
|
||||
{
|
||||
using Nsacr = Genode::Cpu::Nsacr;
|
||||
using Cpsr = Genode::Cpu::Psr;
|
||||
using Scr = Genode::Cpu::Scr;
|
||||
|
||||
/* if we are already in HYP mode we're done (depends on u-boot version) */
|
||||
if (Cpsr::M::get(Cpsr::read()) == Cpsr::M::HYP)
|
||||
return;
|
||||
|
||||
/*
|
||||
* enable coprocessor 10 + 11 access and SMP bit access in auxiliary control
|
||||
* register for non-secure world
|
||||
*/
|
||||
Nsacr::access_t nsacr = 0;
|
||||
Nsacr::Cpnsae10::set(nsacr, 1);
|
||||
Nsacr::Cpnsae11::set(nsacr, 1);
|
||||
Nsacr::Ns_smp::set(nsacr, 1);
|
||||
Nsacr::write(nsacr);
|
||||
|
||||
asm volatile (
|
||||
"msr sp_mon, sp \n" /* copy current mode's sp */
|
||||
"msr lr_mon, lr \n" /* copy current mode's lr */
|
||||
"cps #22 \n" /* switch to monitor mode */
|
||||
);
|
||||
|
||||
Scr::access_t scr = 0;
|
||||
Scr::Ns::set(scr, 1);
|
||||
Scr::Fw::set(scr, 1);
|
||||
Scr::Aw::set(scr, 1);
|
||||
Scr::Scd::set(scr, 1);
|
||||
Scr::Hce::set(scr, 1);
|
||||
Scr::Sif::set(scr, 1);
|
||||
Scr::write(scr);
|
||||
}
|
||||
|
||||
|
||||
static inline void switch_to_supervisor_mode()
|
||||
{
|
||||
using Psr = Genode::Cpu::Psr;
|
||||
|
||||
Psr::access_t psr = 0;
|
||||
Psr::M::set(psr, Psr::M::SVC);
|
||||
Psr::F::set(psr, 1);
|
||||
Psr::I::set(psr, 1);
|
||||
|
||||
asm volatile (
|
||||
"msr sp_svc, sp \n" /* copy current mode's sp */
|
||||
"msr lr_svc, lr \n" /* copy current mode's lr */
|
||||
"msr elr_hyp, lr \n" /* copy current mode's lr to hyp lr */
|
||||
"msr spsr_cxfs, %[psr] \n" /* set psr for supervisor mode */
|
||||
"eret \n" /* exception return */
|
||||
:: [psr] "r" (psr));
|
||||
}
|
||||
|
||||
|
||||
void Genode::Board::prepare_kernel()
|
||||
{
|
||||
prepare_nonsecure_world();
|
||||
Genode::Cpu::hyp_exception_entry_at(&_hyp_kernel_entry);
|
||||
switch_to_supervisor_mode();
|
||||
}
|
59
repos/base-hw/src/core/spec/arndale/pic.cc
Normal file
59
repos/base-hw/src/core/spec/arndale/pic.cc
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* \brief Programmable interrupt controller for core
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-10-24
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* core includes */
|
||||
#include <pic.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
void Pic::_init()
|
||||
{
|
||||
/* disable device */
|
||||
_distr.write<Distr::Ctlr>(0);
|
||||
|
||||
/* configure every shared peripheral interrupt */
|
||||
for (unsigned i = min_spi; i <= _max_irq; i++) {
|
||||
/* mark as non-secure */
|
||||
_distr.write<Distr::Igroupr::Group_status>(1, i);
|
||||
_distr.write<Distr::Icfgr::Edge_triggered>(0, i);
|
||||
_distr.write<Distr::Ipriorityr::Priority>(0, i);
|
||||
}
|
||||
/* enable device */
|
||||
Distr::Ctlr::access_t v = 0;
|
||||
Distr::Ctlr::Enable_grp0::set(v, 1);
|
||||
Distr::Ctlr::Enable_grp1::set(v, 1);
|
||||
_distr.write<Distr::Ctlr>(v);
|
||||
}
|
||||
|
||||
|
||||
void Pic::init_cpu_local()
|
||||
{
|
||||
_cpui.write<Cpui::Ctlr>(0);
|
||||
|
||||
/* mark software-generated IRQs as being non-secure */
|
||||
for (unsigned i = 0; i < min_spi; i++)
|
||||
_distr.write<Distr::Igroupr::Group_status>(1, i);
|
||||
|
||||
/* disable the priority filter */
|
||||
_cpui.write<Cpui::Pmr::Priority>(_distr.min_priority());
|
||||
|
||||
/* disable preemption of IRQ handling by other IRQs */
|
||||
_cpui.write<Cpui::Bpr::Binary_point>(~0);
|
||||
|
||||
/* enable device */
|
||||
Cpui::Ctlr::access_t v = 0;
|
||||
Cpui::Ctlr::Enable_grp0::set(v, 1);
|
||||
Cpui::Ctlr::Enable_grp1::set(v, 1);
|
||||
Cpui::Ctlr::Fiq_en::set(v, 1);
|
||||
_cpui.write<Cpui::Ctlr>(v);
|
||||
}
|
17
repos/base-hw/src/core/spec/exynos5/board.cc
Normal file
17
repos/base-hw/src/core/spec/exynos5/board.cc
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* \brief Board-specific code for Exynos5 boards
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2015-02-09
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
/* core includes */
|
||||
#include <board.h>
|
||||
|
||||
void Genode::Board::prepare_kernel() { }
|
@ -39,8 +39,11 @@ void Kernel::init_trustzone(Pic * pic)
|
||||
/* set exception vector entry */
|
||||
Cpu::mon_exception_entry_at((Genode::addr_t)&_mon_kernel_entry);
|
||||
|
||||
/* enable coprocessor access for TZ VMs */
|
||||
Cpu::allow_coprocessor_nonsecure();
|
||||
/* enable coprocessor 10 + 11 access for TZ VMs */
|
||||
Cpu::Nsacr::access_t v = 0;
|
||||
Cpu::Nsacr::Cpnsae10::set(v, 1);
|
||||
Cpu::Nsacr::Cpnsae11::set(v, 1);
|
||||
Cpu::Nsacr::write(v);
|
||||
|
||||
/* configure non-secure interrupts */
|
||||
for (unsigned i = 0; i < Pic::NR_OF_IRQ; i++) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user