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:
Stefan Kalkowski 2015-02-18 14:41:49 +01:00 committed by Christian Helmuth
parent e7dad39016
commit 07c8d1652e
15 changed files with 316 additions and 55 deletions

View File

@ -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

View 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

View 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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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'

View File

@ -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 */

View File

@ -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:

View 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();
}

View 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);
}

View 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() { }

View File

@ -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++) {