From 07c8d1652e5a6271f69dacaa5c0d57a80b825b09 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Wed, 18 Feb 2015 14:41:49 +0100 Subject: [PATCH] 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 --- repos/base-hw/lib/mk/cortex_a15/core.inc | 3 - .../lib/mk/exynos5/{core.mk => core.inc} | 0 repos/base-hw/lib/mk/platform_arndale/core.mk | 12 +++ .../base-hw/lib/mk/platform_odroid_xu/core.mk | 12 +++ .../src/core/include/spec/arm/cpu_support.h | 21 +++-- .../src/core/include/spec/arm_gic/pic.h | 8 +- .../core/include/spec/arm_v7/cpu_support.h | 92 +++++++++++-------- .../src/core/include/spec/cortex_a15/cpu.h | 10 +- .../src/core/include/spec/exynos5/board.h | 2 +- repos/base-hw/src/core/kernel/kernel.cc | 9 +- .../src/core/spec/arm_v7/mode_transition.s | 36 +++++++- repos/base-hw/src/core/spec/arndale/board.cc | 83 +++++++++++++++++ repos/base-hw/src/core/spec/arndale/pic.cc | 59 ++++++++++++ repos/base-hw/src/core/spec/exynos5/board.cc | 17 ++++ .../spec/imx53/trustzone/platform_support.cc | 7 +- 15 files changed, 316 insertions(+), 55 deletions(-) rename repos/base-hw/lib/mk/exynos5/{core.mk => core.inc} (100%) create mode 100644 repos/base-hw/lib/mk/platform_arndale/core.mk create mode 100644 repos/base-hw/lib/mk/platform_odroid_xu/core.mk create mode 100644 repos/base-hw/src/core/spec/arndale/board.cc create mode 100644 repos/base-hw/src/core/spec/arndale/pic.cc create mode 100644 repos/base-hw/src/core/spec/exynos5/board.cc diff --git a/repos/base-hw/lib/mk/cortex_a15/core.inc b/repos/base-hw/lib/mk/cortex_a15/core.inc index a1c9b5b907..749ebeeac6 100644 --- a/repos/base-hw/lib/mk/cortex_a15/core.inc +++ b/repos/base-hw/lib/mk/cortex_a15/core.inc @@ -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 diff --git a/repos/base-hw/lib/mk/exynos5/core.mk b/repos/base-hw/lib/mk/exynos5/core.inc similarity index 100% rename from repos/base-hw/lib/mk/exynos5/core.mk rename to repos/base-hw/lib/mk/exynos5/core.inc diff --git a/repos/base-hw/lib/mk/platform_arndale/core.mk b/repos/base-hw/lib/mk/platform_arndale/core.mk new file mode 100644 index 0000000000..543f2548c4 --- /dev/null +++ b/repos/base-hw/lib/mk/platform_arndale/core.mk @@ -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 diff --git a/repos/base-hw/lib/mk/platform_odroid_xu/core.mk b/repos/base-hw/lib/mk/platform_odroid_xu/core.mk new file mode 100644 index 0000000000..3d83cc3a4c --- /dev/null +++ b/repos/base-hw/lib/mk/platform_odroid_xu/core.mk @@ -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 diff --git a/repos/base-hw/src/core/include/spec/arm/cpu_support.h b/repos/base-hw/src/core/include/spec/arm/cpu_support.h index 2e2cef134a..84ce8d4183 100644 --- a/repos/base-hw/src/core/include/spec/arm/cpu_support.h +++ b/repos/base-hw/src/core/include/spec/arm/cpu_support.h @@ -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 diff --git a/repos/base-hw/src/core/include/spec/arm_gic/pic.h b/repos/base-hw/src/core/include/spec/arm_gic/pic.h index c2bf521fda..9f8af3b49f 100644 --- a/repos/base-hw/src/core/include/spec/arm_gic/pic.h +++ b/repos/base-hw/src/core/include/spec/arm_gic/pic.h @@ -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 diff --git a/repos/base-hw/src/core/include/spec/arm_v7/cpu_support.h b/repos/base-hw/src/core/include/spec/arm_v7/cpu_support.h index edd790f2c1..bec851aa8b 100644 --- a/repos/base-hw/src/core/include/spec/arm_v7/cpu_support.h +++ b/repos/base-hw/src/core/include/spec/arm_v7/cpu_support.h @@ -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; diff --git a/repos/base-hw/src/core/include/spec/cortex_a15/cpu.h b/repos/base-hw/src/core/include/spec/cortex_a15/cpu.h index 47275aeb4e..1de217781a 100644 --- a/repos/base-hw/src/core/include/spec/cortex_a15/cpu.h +++ b/repos/base-hw/src/core/include/spec/cortex_a15/cpu.h @@ -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) diff --git a/repos/base-hw/src/core/include/spec/exynos5/board.h b/repos/base-hw/src/core/include/spec/exynos5/board.h index 3c6aad8b96..266d760708 100644 --- a/repos/base-hw/src/core/include/spec/exynos5/board.h +++ b/repos/base-hw/src/core/include/spec/exynos5/board.h @@ -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' diff --git a/repos/base-hw/src/core/kernel/kernel.cc b/repos/base-hw/src/core/kernel/kernel.cc index 70743bbd42..e52cc55edc 100644 --- a/repos/base-hw/src/core/kernel/kernel.cc +++ b/repos/base-hw/src/core/kernel/kernel.cc @@ -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 */ diff --git a/repos/base-hw/src/core/spec/arm_v7/mode_transition.s b/repos/base-hw/src/core/spec/arm_v7/mode_transition.s index bd47095273..b8a46d29c5 100644 --- a/repos/base-hw/src/core/spec/arm_v7/mode_transition.s +++ b/repos/base-hw/src/core/spec/arm_v7/mode_transition.s @@ -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: diff --git a/repos/base-hw/src/core/spec/arndale/board.cc b/repos/base-hw/src/core/spec/arndale/board.cc new file mode 100644 index 0000000000..70722df3b0 --- /dev/null +++ b/repos/base-hw/src/core/spec/arndale/board.cc @@ -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 +#include + +/* 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(); +} diff --git a/repos/base-hw/src/core/spec/arndale/pic.cc b/repos/base-hw/src/core/spec/arndale/pic.cc new file mode 100644 index 0000000000..55c6e69135 --- /dev/null +++ b/repos/base-hw/src/core/spec/arndale/pic.cc @@ -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 + +using namespace Genode; + +void Pic::_init() +{ + /* disable device */ + _distr.write(0); + + /* configure every shared peripheral interrupt */ + for (unsigned i = min_spi; i <= _max_irq; i++) { + /* mark as non-secure */ + _distr.write(1, i); + _distr.write(0, i); + _distr.write(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(v); +} + + +void Pic::init_cpu_local() +{ + _cpui.write(0); + + /* mark software-generated IRQs as being non-secure */ + for (unsigned i = 0; i < min_spi; i++) + _distr.write(1, i); + + /* disable the priority filter */ + _cpui.write(_distr.min_priority()); + + /* disable preemption of IRQ handling by other IRQs */ + _cpui.write(~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(v); +} diff --git a/repos/base-hw/src/core/spec/exynos5/board.cc b/repos/base-hw/src/core/spec/exynos5/board.cc new file mode 100644 index 0000000000..3f28938046 --- /dev/null +++ b/repos/base-hw/src/core/spec/exynos5/board.cc @@ -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 + +void Genode::Board::prepare_kernel() { } diff --git a/repos/base-hw/src/core/spec/imx53/trustzone/platform_support.cc b/repos/base-hw/src/core/spec/imx53/trustzone/platform_support.cc index 339f5c881a..297265da99 100644 --- a/repos/base-hw/src/core/spec/imx53/trustzone/platform_support.cc +++ b/repos/base-hw/src/core/spec/imx53/trustzone/platform_support.cc @@ -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++) {