From 8393ac689580bf0f13a9d5ea0cae26979d70b59e Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Tue, 2 Oct 2012 14:27:32 +0200 Subject: [PATCH] base-hw: implement vm_session for TrustZone * Introduces Schedule_context * Use fast-interrupts or normal interrupts * Add mode-transition between secure/non-secure world * Limit system resources for Genode apps due to non-secure world This commit implements the newly introduced Vm session interface to be used on top of TrustZone capable Armv7 CPUs. Therefore a new Schedule_context is introduced in the kernel. Threads and Vms are both Schedule_contexts used by the scheduler. In contrast to a thread a vm uses a different assembler mode switch to the non-secure, virtual world, as well as another exception is used, when the non-secure world is left. For both worlds to co-exist the interrupt-controller needs to be configured, so that the secure (Genode) world uses fast-interrupts only, and the non-secure world only legacy interrupts. The only TrustZone capable platform the base-hw kernel works on top of is the CoreTile Express 9x4 for the Versatile Express motherboard. For a virtual machine working properly on top some platform resources must be reserved. Therefore there exist two flavours of this platform now, one with the 'trustzone' spec-variable enabled, and one without. If 'trustzone' is specified most platform resources (DDR-RAM, and most IRQs) are reserved for the Vm and not available to the secure Genode world. --- base-hw/include/kernel/syscalls.h | 36 +++ base-hw/include/vm_session/connection.h | 2 +- base-hw/lib/mk/core_support.inc | 7 +- .../lib/mk/platform_panda_a2/core_support.mk | 2 + .../mk/platform_panda_a2/platform_support.mk | 5 +- base-hw/lib/mk/platform_pbxa9/core_support.mk | 2 + .../lib/mk/platform_pbxa9/platform_support.mk | 17 ++ .../lib/mk/platform_vea9x4/core_support.mk | 7 +- .../mk/platform_vea9x4/platform_support.mk | 7 + .../lib/mk/trustzone/vea9x4_core_support.mk | 17 ++ .../mk/trustzone/vea9x4_platform_support.mk | 17 ++ base-hw/lib/mk/vea9x4_core_support.mk | 10 + base-hw/lib/mk/vea9x4_platform_support.mk | 14 + base-hw/run/env | 7 +- base-hw/src/core/arm_v7a/crt0.s | 10 - base-hw/src/core/arm_v7a/mode_transition.s | 272 +++++++++++++----- base-hw/src/core/include/cortex_a9/cpu/core.h | 60 ++-- .../core/include/cortex_a9/kernel_support.h | 30 +- base-hw/src/core/include/pic/pl390_base.h | 52 ++-- base-hw/src/core/include/trustzone.h | 25 ++ base-hw/src/core/include/vm_root.h | 56 ++++ .../src/core/include/vm_session_component.h | 73 +++++ base-hw/src/core/kernel.cc | 268 +++++++++++------ base-hw/src/core/kernel_support.cc | 23 ++ base-hw/src/core/panda_a2/platform_support.cc | 1 - base-hw/src/core/panda_a2/target.mk | 9 + base-hw/src/core/pbxa9/platform_support.cc | 1 - base-hw/src/core/pbxa9/target.mk | 9 + base-hw/src/core/{target.mk => target.inc} | 2 - base-hw/src/core/trustzone.cc | 16 ++ base-hw/src/core/vea9x4/platform_support.cc | 1 - base-hw/src/core/vea9x4/target.mk | 13 + .../core/vea9x4/trustzone/kernel_support.cc | 24 ++ .../core/vea9x4/trustzone/kernel_support.h | 82 ++++++ .../vea9x4/trustzone/platform_services.cc | 35 +++ .../core/vea9x4/trustzone/platform_support.cc | 88 ++++++ .../src/core/vea9x4/trustzone/trustzone.cc | 42 +++ base-hw/src/core/vm_session_component.cc | 70 +++++ base/include/arm/cpu/cpu_state.h | 24 +- base/include/platform/vea9x4/drivers/board.h | 13 + 40 files changed, 1184 insertions(+), 265 deletions(-) create mode 100644 base-hw/lib/mk/platform_pbxa9/platform_support.mk create mode 100644 base-hw/lib/mk/platform_vea9x4/platform_support.mk create mode 100644 base-hw/lib/mk/trustzone/vea9x4_core_support.mk create mode 100644 base-hw/lib/mk/trustzone/vea9x4_platform_support.mk create mode 100644 base-hw/lib/mk/vea9x4_core_support.mk create mode 100644 base-hw/lib/mk/vea9x4_platform_support.mk create mode 100644 base-hw/src/core/include/trustzone.h create mode 100644 base-hw/src/core/include/vm_root.h create mode 100644 base-hw/src/core/include/vm_session_component.h create mode 100644 base-hw/src/core/kernel_support.cc create mode 100644 base-hw/src/core/panda_a2/target.mk create mode 100644 base-hw/src/core/pbxa9/target.mk rename base-hw/src/core/{target.mk => target.inc} (95%) create mode 100644 base-hw/src/core/trustzone.cc create mode 100644 base-hw/src/core/vea9x4/target.mk create mode 100644 base-hw/src/core/vea9x4/trustzone/kernel_support.cc create mode 100644 base-hw/src/core/vea9x4/trustzone/kernel_support.h create mode 100644 base-hw/src/core/vea9x4/trustzone/platform_services.cc create mode 100644 base-hw/src/core/vea9x4/trustzone/platform_support.cc create mode 100644 base-hw/src/core/vea9x4/trustzone/trustzone.cc create mode 100644 base-hw/src/core/vm_session_component.cc diff --git a/base-hw/include/kernel/syscalls.h b/base-hw/include/kernel/syscalls.h index 3604ed9088..a5bc76903c 100644 --- a/base-hw/include/kernel/syscalls.h +++ b/base-hw/include/kernel/syscalls.h @@ -68,6 +68,10 @@ namespace Kernel NEW_SIGNAL_CONTEXT = 21, AWAIT_SIGNAL = 22, SUBMIT_SIGNAL = 23, + + /* vm specific */ + NEW_VM = 25, + RUN_VM = 26, }; /** @@ -83,6 +87,7 @@ namespace Kernel Genode::size_t pd_size(); Genode::size_t signal_context_size(); Genode::size_t signal_receiver_size(); + Genode::size_t vm_size(); /** * Get alignment constraints of the kernel objects @@ -433,6 +438,37 @@ namespace Kernel */ inline void submit_signal(unsigned long context_id, int num) { syscall(SUBMIT_SIGNAL, (Syscall_arg)context_id, (Syscall_arg)num); } + + + /** + * Create a new vm that is stopped initially + * + * \param dst physical base of an appropriate portion of memory + * that is thereupon allocated to the kernel + * \param state location of the cpu state of the VM + * \param context_id ID of the targeted signal context + * + * \retval >0 ID of the new vm + * \retval 0 if no new vm was created + * + * Restricted to core threads. Regaining of the supplied memory is not + * supported by now. + */ + inline int new_vm(void * const dst, void * const state, + unsigned long context_id) + { + return syscall(NEW_VM, (Syscall_arg)dst, (Syscall_arg)state, + (Syscall_arg)context_id); + } + + + /** + * Execute a virtual-machine (again) + * + * \param id ID of the targeted vm + */ + inline void run_vm(unsigned long const id = 0) { + syscall(RUN_VM, (Syscall_arg)id); } } #endif /* _INCLUDE__KERNEL__SYSCALLS_H_ */ diff --git a/base-hw/include/vm_session/connection.h b/base-hw/include/vm_session/connection.h index 3a28139d3f..94071e11da 100644 --- a/base-hw/include/vm_session/connection.h +++ b/base-hw/include/vm_session/connection.h @@ -33,7 +33,7 @@ namespace Genode { long priority = Cpu_session::DEFAULT_PRIORITY, unsigned long affinity = 0) : Connection( - session("priority=0x%lx, affinity=0x%lx, ram_quota=8K, label=\"%s\"", + session("priority=0x%lx, affinity=0x%lx, ram_quota=16K, label=\"%s\"", priority, affinity, label)), Vm_session_client(cap()) { } }; diff --git a/base-hw/lib/mk/core_support.inc b/base-hw/lib/mk/core_support.inc index a981d8895c..c2063a1a1d 100644 --- a/base-hw/lib/mk/core_support.inc +++ b/base-hw/lib/mk/core_support.inc @@ -12,9 +12,10 @@ INC_DIR += $(BOARD_DIR) $(REP_DIR)/src/core/include $(REP_DIR)/include \ CC_OPT += -DCORE_MAIN=_main # add C++ sources -SRC_CC += platform_support.cc kernel.cc rm_session_support.cc +SRC_CC += kernel.cc rm_session_support.cc kernel_support.cc trustzone.cc + +LIBS += platform_support # declare source paths -vpath platform_support.cc $(BOARD_DIR) -vpath % $(REP_DIR)/src/core +vpath %.cc $(REP_DIR)/src/core diff --git a/base-hw/lib/mk/platform_panda_a2/core_support.mk b/base-hw/lib/mk/platform_panda_a2/core_support.mk index 60ab9f316f..6ad7963466 100644 --- a/base-hw/lib/mk/platform_panda_a2/core_support.mk +++ b/base-hw/lib/mk/platform_panda_a2/core_support.mk @@ -7,6 +7,8 @@ # declare location of core files that are board specific BOARD_DIR = $(REP_DIR)/src/core/panda_a2 +SRC_CC = trustzone.cc + # include generic parts of core support include $(REP_DIR)/lib/mk/core_support.inc diff --git a/base-hw/lib/mk/platform_panda_a2/platform_support.mk b/base-hw/lib/mk/platform_panda_a2/platform_support.mk index cc4a186932..521c0b917a 100644 --- a/base-hw/lib/mk/platform_panda_a2/platform_support.mk +++ b/base-hw/lib/mk/platform_panda_a2/platform_support.mk @@ -9,8 +9,9 @@ INC_DIR += $(REP_DIR)/src/core/include \ $(BASE_DIR)/src/core/include # add C++ sources -SRC_CC += platform_support.cc +SRC_CC += platform_services.cc platform_support.cc # declare source paths -vpath % $(REP_DIR)/src/core/panda_a2 +vpath platform_services.cc $(BASE_DIR)/src/core +vpath platform_support.cc $(REP_DIR)/src/core/panda_a2 diff --git a/base-hw/lib/mk/platform_pbxa9/core_support.mk b/base-hw/lib/mk/platform_pbxa9/core_support.mk index 0a908f3053..eaed22f02a 100644 --- a/base-hw/lib/mk/platform_pbxa9/core_support.mk +++ b/base-hw/lib/mk/platform_pbxa9/core_support.mk @@ -7,6 +7,8 @@ # declare location of core files that are board specific BOARD_DIR = $(REP_DIR)/src/core/pbxa9 +SRC_CC = trustzone.cc + # include generic part of core support include $(REP_DIR)/lib/mk/core_support.inc diff --git a/base-hw/lib/mk/platform_pbxa9/platform_support.mk b/base-hw/lib/mk/platform_pbxa9/platform_support.mk new file mode 100644 index 0000000000..83b29ccc46 --- /dev/null +++ b/base-hw/lib/mk/platform_pbxa9/platform_support.mk @@ -0,0 +1,17 @@ +# +# \brief Platform implementations specific for base-hw and PBXA9 +# \author Stefan Kalkowski +# \date 2012-10-04 +# + +# add include paths +INC_DIR += $(REP_DIR)/src/core/include \ + $(BASE_DIR)/src/core/include + +# add C++ sources +SRC_CC += platform_services.cc platform_support.cc + +# declare source paths +vpath platform_services.cc $(BASE_DIR)/src/core +vpath platform_support.cc $(REP_DIR)/src/core/pbxa9 + diff --git a/base-hw/lib/mk/platform_vea9x4/core_support.mk b/base-hw/lib/mk/platform_vea9x4/core_support.mk index 51a9cf5dd6..4cab7ef5c2 100644 --- a/base-hw/lib/mk/platform_vea9x4/core_support.mk +++ b/base-hw/lib/mk/platform_vea9x4/core_support.mk @@ -4,9 +4,4 @@ # \date 2012-04-27 # -# declare location of core files that are board specific -BOARD_DIR = $(REP_DIR)/src/core/vea9x4 - -# include generic part of core support -include $(REP_DIR)/lib/mk/core_support.inc - +LIBS += vea9x4_core_support diff --git a/base-hw/lib/mk/platform_vea9x4/platform_support.mk b/base-hw/lib/mk/platform_vea9x4/platform_support.mk new file mode 100644 index 0000000000..bdcd6665ff --- /dev/null +++ b/base-hw/lib/mk/platform_vea9x4/platform_support.mk @@ -0,0 +1,7 @@ +# +# \brief Platform implementations specific for base-hw and VEA9X4 +# \author Stefan Kalkowski +# \date 2012-10-04 +# + +LIBS += vea9x4_platform_support \ No newline at end of file diff --git a/base-hw/lib/mk/trustzone/vea9x4_core_support.mk b/base-hw/lib/mk/trustzone/vea9x4_core_support.mk new file mode 100644 index 0000000000..05897d8185 --- /dev/null +++ b/base-hw/lib/mk/trustzone/vea9x4_core_support.mk @@ -0,0 +1,17 @@ +# +# \brief Trustzone support for VEA9X4 with TZ enabled +# \author Stefan Kalkowski +# \date 2012-10-10 +# + +BOARD_DIR = $(REP_DIR)/src/core/vea9x4 + +INC_DIR += $(BOARD_DIR)/trustzone + +# declare source paths +vpath kernel_support.cc $(BOARD_DIR)/trustzone +vpath trustzone.cc $(BOARD_DIR)/trustzone + +# include generic part of core support +include $(REP_DIR)/lib/mk/core_support.inc + diff --git a/base-hw/lib/mk/trustzone/vea9x4_platform_support.mk b/base-hw/lib/mk/trustzone/vea9x4_platform_support.mk new file mode 100644 index 0000000000..39d9c7179f --- /dev/null +++ b/base-hw/lib/mk/trustzone/vea9x4_platform_support.mk @@ -0,0 +1,17 @@ +# +# \brief Platform implementations specific for base-hw and VEA9X4 (TrustZone) +# \author Stefan Kalkowski +# \date 2012-10-04 +# + +# add include paths +INC_DIR += $(REP_DIR)/src/core/include \ + $(BASE_DIR)/src/core/include + +SRC_CC = platform_services.cc \ + platform_support.cc \ + vm_session_component.cc + +vpath platform_support.cc $(REP_DIR)/src/core/vea9x4/trustzone +vpath platform_services.cc $(REP_DIR)/src/core/vea9x4/trustzone +vpath vm_session_component.cc $(REP_DIR)/src/core \ No newline at end of file diff --git a/base-hw/lib/mk/vea9x4_core_support.mk b/base-hw/lib/mk/vea9x4_core_support.mk new file mode 100644 index 0000000000..1e3a484cd1 --- /dev/null +++ b/base-hw/lib/mk/vea9x4_core_support.mk @@ -0,0 +1,10 @@ +# +# \brief Trustzone support for VEA9X4 with TZ disabled +# \author Stefan Kalkowski +# \date 2012-10-10 +# + +BOARD_DIR = $(REP_DIR)/src/core/vea9x4 + +# include generic part of core support +include $(REP_DIR)/lib/mk/core_support.inc diff --git a/base-hw/lib/mk/vea9x4_platform_support.mk b/base-hw/lib/mk/vea9x4_platform_support.mk new file mode 100644 index 0000000000..b971052dfc --- /dev/null +++ b/base-hw/lib/mk/vea9x4_platform_support.mk @@ -0,0 +1,14 @@ +# +# \brief Platform implementations specific for base-hw and VEA9X4 +# \author Stefan Kalkowski +# \date 2012-10-04 +# + +# add include paths +INC_DIR += $(REP_DIR)/src/core/include \ + $(BASE_DIR)/src/core/include + +SRC_CC = platform_support.cc platform_services.cc + +vpath platform_support.cc $(REP_DIR)/src/core/vea9x4 +vpath platform_services.cc $(BASE_DIR)/src/core diff --git a/base-hw/run/env b/base-hw/run/env index def0e0a1e0..d7923d4e07 100644 --- a/base-hw/run/env +++ b/base-hw/run/env @@ -199,15 +199,16 @@ proc build_boot_image {binaries} { } # preserve stand-alone core for debugging - exec mv core/core core/core.standalone + exec cp -L bin/core core/core.standalone # apply the new 'boot_modules.s' to 'core' to create single boot image apply_boot_modules_to_core $boot_modules - exec mv core/core [run_dir]/image.elf + exec cp -L bin/core [run_dir]/image.elf exec [cross_dev_prefix]strip [run_dir]/image.elf # remove stripped binaries and retrieve stand-alone core - exec mv core/core.standalone core/core + exec cp core/core.standalone bin/core + exec rm core/core.standalone exec rm -r [run_dir]/genode } diff --git a/base-hw/src/core/arm_v7a/crt0.s b/base-hw/src/core/arm_v7a/crt0.s index 1d0cb22616..39b3f9b4db 100644 --- a/base-hw/src/core/arm_v7a/crt0.s +++ b/base-hw/src/core/arm_v7a/crt0.s @@ -42,11 +42,6 @@ ldr sp, =_kernel_stack_high bl kernel - /* jump to code that kernel has designated for when he has returned */ - ldr r1, =_call_after_kernel - ldr r1, [r1] - add pc, r1, #0 - /* handle for dynamic symbol objects */ .align 3 .global __dso_handle @@ -54,11 +49,6 @@ .section .bss - /* instruction pointer wich gets loaded when kernel returns */ - .align 3 - .global _call_after_kernel - _call_after_kernel: .long 0 - /* kernel stack */ .align 3 .space 64*1024 diff --git a/base-hw/src/core/arm_v7a/mode_transition.s b/base-hw/src/core/arm_v7a/mode_transition.s index 93fac505bc..f0f244a457 100644 --- a/base-hw/src/core/arm_v7a/mode_transition.s +++ b/base-hw/src/core/arm_v7a/mode_transition.s @@ -1,6 +1,7 @@ /* - * \brief Transition between kernel and userland + * \brief Transition between kernel/userland, and secure/non-secure world * \author Martin stein + * \author Stefan Kalkowski * \date 2011-11-15 */ @@ -11,14 +12,6 @@ * under the terms of the GNU General Public License version 2. */ -/** - * Invalidate all entries of the branch predictor array - */ -.macro _flush_branch_predictor - mcr p15, 0, sp, c7, c5, 6 - isb -.endm - /** * Switch from an interrupted user context to a kernel context * @@ -34,6 +27,11 @@ * user mode at this point. */ + /* when not in FIQ mode disable FIQs */ + .if \exception_type != 6 + cpsid f + .endif + /************************************************ ** We're still in the user protection domain, ** ** so we must avoid access to kernel memory ** @@ -43,20 +41,20 @@ adr sp, _mt_kernel_context_begin ldr sp, [sp, #18*4] mcr p15, 0, sp, c13, c0, 1 - _flush_branch_predictor /* load kernel section table */ adr sp, _mt_kernel_context_begin ldr sp, [sp, #19*4] mcr p15, 0, sp, c2, c0, 0 - _flush_branch_predictor + isb + dsb /******************************************* ** Now it's save to access kernel memory ** *******************************************/ /* get user context pointer */ - ldr sp, _mt_user_context_ptr + ldr sp, _mt_context_ptr /* * Save user r0 ... r12. We explicitely target user registers @@ -98,9 +96,144 @@ add r0, r0, #13*4 ldmia r0, {sp, lr, pc} +.endm /* _user_to_kernel_pic */ + + +/** + * Switch from kernel context to a user context + */ +.macro _kernel_to_user_pic + + /* get user context pointer */ + ldr lr, _mt_context_ptr + + /* buffer user pc */ + ldr r0, [lr, #15*4] + adr r1, _mt_buffer + str r0, [r1] + + /* buffer user psr */ + ldr r0, [lr, #16*4] + msr spsr, r0 + + /* load user r0 ... r12 */ + ldmia lr, {r0-r12} + + /* load user sp and lr */ + add sp, lr, #13*4 + ldmia sp, {sp,lr}^ + + /* get user contextidr and section table */ + ldr sp, [lr, #18*4] + ldr lr, [lr, #19*4] + + /******************************************************** + ** From now on, until we leave kernel mode, we must ** + ** avoid access to memory that is not mapped globally ** + ********************************************************/ + + /* apply user contextidr and section table */ + mcr p15, 0, sp, c13, c0, 1 + mcr p15, 0, lr, c2, c0, 0 + isb + dsb + + /* load user pc (implies application of the user psr) */ + adr lr, _mt_buffer + ldmia lr, {pc}^ + +.endm /* _kernel_to_user_pic */ + + +.macro _fiq_check_prior_mode + mrs r8, spsr /* load fiq-spsr */ + and r8, #31 + cmp r8, #16 /* check whether we come from user-mode */ + beq 1f + mrs r8, spsr /* enable fiq-ignore bit */ + orr r8, #64 + msr spsr, r8 + subs pc, lr, #4 /* resume previous exception */ +1: +.endm /* _fiq_check_prior_mode */ + +/** + * Save sp, lr and spsr register banks of specified exception mode + */ +.macro _save_bank mode + cps #\mode /* switch to given mode */ + mrs r1, spsr /* store mode-specific spsr */ + stmia r0!, {r1,sp,lr} /* store mode-specific sp and lr */ +.endm /* _save_bank mode */ + + +/** + * Switch from an interrupted vm to the kernel context + * + * \param exception_type immediate exception type ID + * \param pc_adjust immediate value that gets subtracted from the + * vm's PC before it gets saved + */ +.macro _vm_to_kernel exception_type, pc_adjust + ldr sp, _mt_context_ptr /* load context pointer */ + stmia sp, {r0-lr}^ /* save user regs r0-r12,sp,lr */ + add r0, sp, #15*4 + .if \pc_adjust != 0 /* adjust pc if necessary */ + sub lr, lr, #\pc_adjust + .endif + stmia r0!, {lr} /* save pc */ + mrs r1, spsr /* spsr to r0 */ + mov r2, #\exception_type /* exception reason to r1 */ + stmia r0!, {r1-r2} /* save spsr, and exception reason */ + mov r1, #0 + mcr p15, 0, r1, c1, c1, 0 /* disable non-secure bit */ + _save_bank 27 /* save undefined banks */ + _save_bank 19 /* save supervisor banks */ + _save_bank 23 /* save abort banks */ + _save_bank 18 /* save irq banks */ + _save_bank 17 /* save fiq banks */ + stmia r0!, {r8-r12} /* save fiq r8-r12 */ + cps #19 /* switch to supervisor mode */ + adr r0, _mt_kernel_context_begin /* get kernel context pointer */ + add r0, r0, #13*4 /* load kernel context */ + ldmia r0, {sp,lr,pc} +.endm /* _vm_to_kernel */ + + +/** + * Restore sp, lr and spsr register banks of specified exception mode + */ +.macro _restore_bank mode + cps #\mode /* switch to given mode */ + ldmia r0!, {r1,sp,lr} /* load mode-specific sp, lr, and spsr into r1 */ + msr spsr_cxfs, r1 /* load mode-specific spsr */ .endm +/** + * Switch from kernel context to a vm + */ +.macro _kernel_to_vm + ldr r0, _mt_context_ptr /* get vm context pointer */ + add r0, r0, #18*4 /* add offset of banked modes */ + _restore_bank 27 /* load undefined banks */ + _restore_bank 19 /* load supervisor banks */ + _restore_bank 23 /* load abort banks */ + _restore_bank 18 /* load irq banks */ + _restore_bank 17 /* load fiq banks */ + ldmia r0!, {r8 - r12} /* load fiq r8-r12 */ + cps #22 /* switch to monitor mode */ + ldr sp, _mt_context_ptr /* get vm context pointer */ + ldmia sp, {r0-lr}^ /* load user r0-r12,sp,lr */ + ldr lr, [sp, #16*4] /* load vm's cpsr to lr */ + msr spsr_cxfs, lr /* save cpsr to be load when switching */ + mov lr, #13 + mcr p15, 0, lr, c1, c1, 0 /* enable EA, FIQ, and NS bit in SCTRL */ + ldr lr, [sp, #15*4] /* load vm's ip */ + subs pc, lr, #0 +.endm /* _kernel_to_vm */ + + .section .text /* @@ -110,7 +243,7 @@ * To enable such switching, the kernel context must be stored within this * region, thus one should map it solely accessable for privileged modes. */ - .align 3 + .p2align 12 /* page-aligned */ .global _mode_transition_begin _mode_transition_begin: @@ -118,88 +251,79 @@ * On user exceptions the CPU has to jump to one of the following * 7 entry vectors to switch to a kernel context. */ - .align 3 .global _mt_kernel_entry_pic _mt_kernel_entry_pic: - b _rst_entry /* reset */ - b _und_entry /* undefined instruction */ - b _svc_entry /* supervisor call */ - b _pab_entry /* prefetch abort */ - b _dab_entry /* data abort */ - nop /* reserved */ - b _irq_entry /* interrupt request */ - b _fiq_entry /* fast interrupt request */ + b _rst_entry /* reset */ + b _und_entry /* undefined instruction */ + b _svc_entry /* supervisor call */ + b _pab_entry /* prefetch abort */ + b _dab_entry /* data abort */ + nop /* reserved */ + b _irq_entry /* interrupt request */ + _fiq_check_prior_mode /* fast interrupt request */ + _user_to_kernel_pic 6, 4 /* PICs that switch from an user exception to the kernel */ - _rst_entry: _user_to_kernel_pic 1, 0 - _und_entry: _user_to_kernel_pic 2, 4 - _svc_entry: _user_to_kernel_pic 3, 0 - _pab_entry: _user_to_kernel_pic 4, 4 - _dab_entry: _user_to_kernel_pic 5, 8 - _irq_entry: _user_to_kernel_pic 6, 4 - _fiq_entry: _user_to_kernel_pic 7, 4 + _rst_entry: _user_to_kernel_pic 0, 0 + _und_entry: _user_to_kernel_pic 1, 4 + _svc_entry: _user_to_kernel_pic 2, 0 + _pab_entry: _user_to_kernel_pic 3, 4 + _dab_entry: _user_to_kernel_pic 4, 8 + _irq_entry: _user_to_kernel_pic 5, 4 /* kernel must jump to this point to switch to a user context */ - .align 3 + .p2align 2 .global _mt_user_entry_pic _mt_user_entry_pic: - - /* get user context pointer */ - ldr lr, _mt_user_context_ptr - - /* buffer user pc */ - ldr r0, [lr, #15*4] - adr r1, _mt_buffer - str r0, [r1] - - /* buffer user psr */ - ldr r0, [lr, #16*4] - msr spsr, r0 - - /* load user r0 ... r12 */ - ldmia lr, {r0-r12} - - /* load user sp and lr */ - add sp, lr, #13*4 - ldmia sp, {sp,lr}^ - - /* get user contextidr and section table */ - ldr sp, [lr, #18*4] - ldr lr, [lr, #19*4] - - /******************************************************** - ** From now on, until we leave kernel mode, we must ** - ** avoid access to memory that is not mapped globally ** - ********************************************************/ - - /* apply user contextidr and section table */ - mcr p15, 0, sp, c13, c0, 1 - mcr p15, 0, lr, c2, c0, 0 - _flush_branch_predictor - - /* load user pc (implies application of the user psr) */ - adr lr, _mt_buffer - ldmia lr, {pc}^ + _kernel_to_user_pic /* leave some space for the kernel context */ - .align 3 + .p2align 2 .global _mt_kernel_context_begin _mt_kernel_context_begin: .space 32*4 .global _mt_kernel_context_end _mt_kernel_context_end: - /* pointer to the user context backup space */ - .align 3 - .global _mt_user_context_ptr - _mt_user_context_ptr: .long 0 + /* pointer to the context backup space */ + .p2align 2 + .global _mt_context_ptr + _mt_context_ptr: .long 0 /* a local word-sized buffer */ - .align 3 + .p2align 2 .global _mt_buffer _mt_buffer: .long 0 - .align 3 .global _mode_transition_end _mode_transition_end: + /* + * On vm exceptions the CPU has to jump to one of the following + * 7 entry vectors to switch to a kernel context. + */ + .p2align 2 + .global _mon_kernel_entry + _mon_kernel_entry: + b _mon_rst_entry /* reset */ + b _mon_und_entry /* undefined instruction */ + b _mon_svc_entry /* supervisor call */ + b _mon_pab_entry /* prefetch abort */ + b _mon_dab_entry /* data abort */ + nop /* reserved */ + b _mon_irq_entry /* interrupt request */ + _vm_to_kernel 6, 4 /* fast interrupt request */ + + /* PICs that switch from a vm exception to the kernel */ + _mon_rst_entry: _vm_to_kernel 0, 0 + _mon_und_entry: _vm_to_kernel 1, 4 + _mon_svc_entry: _vm_to_kernel 2, 0 + _mon_pab_entry: _vm_to_kernel 3, 4 + _mon_dab_entry: _vm_to_kernel 4, 8 + _mon_irq_entry: _vm_to_kernel 5, 4 + + /* kernel must jump to this point to switch to a vm */ + .p2align 2 + .global _mon_vm_entry + _mon_vm_entry: + _kernel_to_vm diff --git a/base-hw/src/core/include/cortex_a9/cpu/core.h b/base-hw/src/core/include/cortex_a9/cpu/core.h index 898cc5d488..59168f16b4 100644 --- a/base-hw/src/core/include/cortex_a9/cpu/core.h +++ b/base-hw/src/core/include/cortex_a9/cpu/core.h @@ -473,13 +473,7 @@ namespace Genode /** * Constructor */ - User_context() - { - /* Execute in usermode with IRQ's enabled and FIQ's and - * asynchronous aborts disabled */ - cpsr = Cpsr::M::bits(Cpsr::M::USER) | Cpsr::F::bits(1) | - Cpsr::I::bits(0) | Cpsr::A::bits(1); - } + User_context(void); /*************************************************** ** Communication between user and context holder ** @@ -502,33 +496,6 @@ namespace Genode unsigned user_arg_6() const { return r[6]; } unsigned user_arg_7() const { return r[7]; } - /** - * Determine wich type of exception occured on this context lastly - * - * \return 0 If the exception is unknown by the kernel - * 1 If the exception is an interrupt - * 2 If the exception is a pagefault - * 3 If the exception is a syscall - */ - unsigned exception() const - { - /* map all CPU-exception types to kernel-exception types */ - enum { INVALID = 0, INTERRUPT = 1, PAGEFAULT = 2, SYSCALL = 3 }; - static unsigned cpu_excpt_to_excpt[MAX_CPU_EXCEPTION + 1] = { - INVALID, /* 0 */ - INVALID, /* 1 */ - INVALID, /* 2 */ - SYSCALL, /* 3 */ - PAGEFAULT, /* 4 */ - PAGEFAULT, /* 5 */ - INTERRUPT, /* 6 */ - INVALID /* 7 */ - }; - /* determine exception type */ - if (cpu_exception > MAX_CPU_EXCEPTION) return INVALID; - return cpu_excpt_to_excpt[cpu_exception]; - } - /** * Does a pagefault exist and originate from a lack of translation? * @@ -684,6 +651,31 @@ namespace Genode :: [asid]"r"(Contextidr::Asid::masked(process_id)) : ); flush_branch_prediction(); } + + + /****************************** + ** Trustzone specific API ** + ******************************/ + + /** + * Set the exception-vector's base-address for the monitor mode + * software stack. + * + * \param addr address of the exception vector's base + */ + static inline void mon_exception_entry_at(addr_t addr) + { + asm volatile ("mcr p15, 0, %0, c12, c0, 1" : : "r" (addr)); + } + + /** + * Enable access of co-processors cp10 and cp11 from non-secure mode. + */ + static inline void allow_coprocessor_nonsecure(void) + { + uint32_t val = (1 << 10) | (1 << 11); + asm volatile ("mcr p15, 0, %0, c1, c1, 2" : : "r" (val)); + } }; } diff --git a/base-hw/src/core/include/cortex_a9/kernel_support.h b/base-hw/src/core/include/cortex_a9/kernel_support.h index 6a679fc8c0..a128faafb2 100644 --- a/base-hw/src/core/include/cortex_a9/kernel_support.h +++ b/base-hw/src/core/include/cortex_a9/kernel_support.h @@ -41,7 +41,35 @@ namespace Kernel */ Pic() : Pl390_base(Cortex_a9::PL390_DISTRIBUTOR_MMIO_BASE, Cortex_a9::PL390_CPU_MMIO_BASE) - { } + { + /* disable device */ + _distr.write(0); + _cpu.write(0); + mask(); + + /* supported priority range */ + unsigned const min_prio = _distr.min_priority(); + unsigned const max_prio = _distr.max_priority(); + + /* configure every shared peripheral interrupt */ + for (unsigned i=MIN_SPI; i <= _max_interrupt; i++) + { + _distr.write(0, i); + _distr.write(max_prio, i); + _distr.write(Distr::Icdiptr::Cpu_targets::ALL, i); + } + + /* disable the priority filter */ + _cpu.write(min_prio); + + /* disable preemption of interrupt handling by interrupts */ + _cpu.write( + Cpu::Iccbpr::Binary_point::NO_PREEMPTION); + + /* enable device */ + _distr.write(1); + _cpu.write(1); + } }; /** diff --git a/base-hw/src/core/include/pic/pl390_base.h b/base-hw/src/core/include/pic/pl390_base.h index 736d85bd7c..07dad4e2e6 100644 --- a/base-hw/src/core/include/pic/pl390_base.h +++ b/base-hw/src/core/include/pic/pl390_base.h @@ -60,6 +60,14 @@ namespace Genode struct Cpu_number : Bitfield<5,3> { }; }; + /** + * Interrupt security registers + */ + struct Icdisr : Register_array<0x80, 32, MAX_INTERRUPT_ID+1, 1> + { + struct Nonsecure : Bitfield<0, 1> { }; + }; + /** * Interrupt set enable registers */ @@ -152,7 +160,7 @@ namespace Genode struct Enable_ns : Bitfield<1,1> { }; struct Ack_ctl : Bitfield<2,1> { }; struct Fiq_en : Bitfield<3,1> { }; - struct Sbpr : Bitfield<4,1> { }; + struct Cbpr : Bitfield<4,1> { }; }; /** @@ -192,6 +200,17 @@ namespace Genode struct Cpu_id : Bitfield<10,3> { }; }; + /** + * Non-secure Binary point register + */ + struct Iccabpr : Register<0x1c, 32> + { + struct Binary_point : Bitfield<0,3> + { + enum { NO_PREEMPTION = 7 }; + }; + }; + } _cpu; unsigned const _max_interrupt; @@ -206,36 +225,7 @@ namespace Genode _distr(distributor), _cpu(cpu_interface), _max_interrupt(_distr.max_interrupt()), - _last_taken_request(SPURIOUS_ID) - { - /* disable device */ - _distr.write(0); - _cpu.write(0); - mask(); - - /* supported priority range */ - unsigned const min_prio = _distr.min_priority(); - unsigned const max_prio = _distr.max_priority(); - - /* configure every shared peripheral interrupt */ - for (unsigned i=MIN_SPI; i <= _max_interrupt; i++) - { - _distr.write(0, i); - _distr.write(max_prio, i); - _distr.write(Distr::Icdiptr::Cpu_targets::ALL, i); - } - - /* disable the priority filter */ - _cpu.write(min_prio); - - /* disable preemption of interrupt handling by interrupts */ - _cpu.write( - Cpu::Iccbpr::Binary_point::NO_PREEMPTION); - - /* enable device */ - _distr.write(1); - _cpu.write(1); - } + _last_taken_request(SPURIOUS_ID) { } /** * Get the ID of the last interrupt request diff --git a/base-hw/src/core/include/trustzone.h b/base-hw/src/core/include/trustzone.h new file mode 100644 index 0000000000..8b8039e890 --- /dev/null +++ b/base-hw/src/core/include/trustzone.h @@ -0,0 +1,25 @@ +/* + * \brief TrustZone specific functions + * \author Stefan Kalkowski + * \date 2012-10-10 + */ + +/* + * Copyright (C) 2012 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. + */ + +#ifndef _CORE__INCLUDE__TRUSTZONE_H_ +#define _CORE__INCLUDE__TRUSTZONE_H_ + +namespace Kernel { + + class Pic; + + + void trustzone_initialization(Pic *pic); +} + +#endif /* _CORE__INCLUDE__TRUSTZONE_H_ */ diff --git a/base-hw/src/core/include/vm_root.h b/base-hw/src/core/include/vm_root.h new file mode 100644 index 0000000000..12d846b540 --- /dev/null +++ b/base-hw/src/core/include/vm_root.h @@ -0,0 +1,56 @@ +/* + * \brief Vm root interface + * \author Stefan Kalkowski + * \date 2012-10-08 + */ + +/* + * Copyright (C) 2012 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. + */ + +#ifndef _CORE__INCLUDE__VM_ROOT_H_ +#define _CORE__INCLUDE__VM_ROOT_H_ + +/* Genode includes */ +#include + +/* core includes */ +#include + +namespace Genode { + + class Vm_root : public Root_component + { + private: + + Range_allocator *_ram_alloc; + + protected: + + Vm_session_component *_create_session(const char *args) + { + size_t ram_quota = Arg_string::find_arg(args, "ram_quota").long_value(0); + return new (md_alloc()) + Vm_session_component(ep(), _ram_alloc, ram_quota); + } + + public: + + /** + * Constructor + * + * \param session_ep entrypoint managing vm_session components + * \param md_alloc meta-data allocator to be used by root component + */ + Vm_root(Rpc_entrypoint *session_ep, + Allocator *md_alloc, + Range_allocator *ram_alloc) + : Root_component(session_ep, md_alloc), + _ram_alloc(ram_alloc){ } + }; +} + +#endif /* _CORE__INCLUDE__VM_ROOT_H_ */ diff --git a/base-hw/src/core/include/vm_session_component.h b/base-hw/src/core/include/vm_session_component.h new file mode 100644 index 0000000000..dffa6fbc2d --- /dev/null +++ b/base-hw/src/core/include/vm_session_component.h @@ -0,0 +1,73 @@ +/* + * \brief Core-specific instance of the VM session interface + * \author Stefan Kalkowski + * \date 2012-10-08 + */ + +/* + * Copyright (C) 2012 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. + */ + +#ifndef _CORE__INCLUDE__VM_SESSION_COMPONENT_H_ +#define _CORE__INCLUDE__VM_SESSION_COMPONENT_H_ + +/* Genode includes */ +#include +#include +#include +#include + +/* Core includes */ +#include + +namespace Genode { + + class Vm_session_component : public Rpc_object + { + private: + + Rpc_entrypoint *_ds_ep; + Range_allocator *_ram_alloc; + unsigned long _vm_id; + void *_vm; + addr_t _ds_addr; + Dataspace_component _ds; + Dataspace_capability _ds_cap; + + static size_t _ds_size() { + return align_addr(sizeof(Cpu_state_modes), + get_page_size_log2()); } + + addr_t _alloc_ds(size_t *ram_quota) + { + addr_t addr; + if (_ds_size() > *ram_quota || + !_ram_alloc->alloc_aligned(_ds_size(), (void**)&addr, + get_page_size_log2())) + throw Root::Quota_exceeded(); + *ram_quota -= _ds_size(); + return addr; + } + + public: + + Vm_session_component(Rpc_entrypoint *ds_ep, + Range_allocator *ram_alloc, + size_t ram_quota); + ~Vm_session_component(); + + + /************************** + ** Vm session interface ** + **************************/ + + Dataspace_capability cpu_state(void) { return _ds_cap; } + void exception_handler(Signal_context_capability handler); + void run(void); + }; +} + +#endif /* _CORE__INCLUDE__VM_SESSION_COMPONENT_H_ */ diff --git a/base-hw/src/core/kernel.cc b/base-hw/src/core/kernel.cc index 50e24a75d4..315b5f863d 100644 --- a/base-hw/src/core/kernel.cc +++ b/base-hw/src/core/kernel.cc @@ -24,6 +24,7 @@ /* Genode includes */ #include +#include #include #include @@ -32,11 +33,11 @@ #include #include #include +#include using namespace Kernel; /* get core configuration */ -extern Genode::addr_t _call_after_kernel; extern Genode::Native_utcb * _main_utcb; extern int _kernel_stack_high; extern "C" void CORE_MAIN(); @@ -45,8 +46,8 @@ extern "C" void CORE_MAIN(); extern int _mode_transition_begin; extern int _mode_transition_end; extern int _mt_user_entry_pic; -extern int _mt_kernel_entry_pic; -extern Genode::addr_t _mt_user_context_ptr; +extern int _mon_vm_entry; +extern Genode::addr_t _mt_context_ptr; extern Genode::addr_t _mt_kernel_context_begin; extern Genode::addr_t _mt_kernel_context_end; @@ -72,6 +73,7 @@ namespace Kernel MAX_THREADS = 256, MAX_SIGNAL_RECEIVERS = 256, MAX_SIGNAL_CONTEXTS = 256, + MAX_VMS = 4, }; /** @@ -710,16 +712,18 @@ namespace Kernel } }; + + class Schedule_context; + /** - * Provides the mode transition PIC in a configurable and mappable manner + * Controls the mode transition code * - * Initially there exists only the code that switches between kernelmode - * and usermode. It must be present in a continuous region that is located - * at an arbitray RAM address. Its size must not exceed the smallest page - * size supported by the MMU. The Code must be position independent. This - * control then duplicates the code to an aligned region and declares a - * virtual region, where the latter has to be mapped to in every PD, to - * ensure appropriate kernel invokation on CPU interrupts. + * The code that switches between kernel/user mode must not exceed the + * smallest page size supported by the MMU. The Code must be position + * independent. This code has to be mapped to in every PD, to ensure + * appropriate kernel invokation on CPU interrupts. + * This class controls the settings like kernel, user, and vm states + * that are handled by the PIC mode transition code. */ struct Mode_transition_control { @@ -731,32 +735,14 @@ namespace Kernel ALIGNM_LOG2 = SIZE_LOG2, }; - /* writeable, page-aligned backing store */ - char _payload[SIZE] __attribute__((aligned(1 << ALIGNM_LOG2))); - - /* labels within the aligned mode transition PIC */ - Cpu::Context * * const _user_context_ptr; - Cpu::Context * const _kernel_context; addr_t const _virt_user_entry; - addr_t const _virt_kernel_entry; /** * Constructor */ Mode_transition_control() : - _user_context_ptr((Cpu::Context * *)((addr_t)_payload + - ((addr_t)&_mt_user_context_ptr - - (addr_t)&_mode_transition_begin))), - - _kernel_context((Cpu::Context *)((addr_t)_payload + - ((addr_t)&_mt_kernel_context_begin - - (addr_t)&_mode_transition_begin))), - _virt_user_entry(VIRT_BASE + ((addr_t)&_mt_user_entry_pic - - (addr_t)&_mode_transition_begin)), - - _virt_kernel_entry(VIRT_BASE + ((addr_t)&_mt_kernel_entry_pic - - (addr_t)&_mode_transition_begin)) + (addr_t)&_mode_transition_begin)) { /* check if mode transition PIC fits into aligned region */ addr_t const pic_begin = (addr_t)&_mode_transition_begin; @@ -768,37 +754,28 @@ namespace Kernel addr_t const kc_begin = (addr_t)&_mt_kernel_context_begin; addr_t const kc_end = (addr_t)&_mt_kernel_context_end; size_t const kc_size = kc_end - kc_begin; - assert(sizeof(Cpu::Context) <= kc_size) - - /* fetch mode transition PIC */ - unsigned * dst = (unsigned *)_payload; - unsigned * src = (unsigned *)pic_begin; - while ((addr_t)src < pic_end) *dst++ = *src++; + assert(sizeof(Cpu::Context) <= kc_size); /* try to set CPU exception entry accordingly */ - assert(!Cpu::exception_entry_at(_virt_kernel_entry)) + assert(!Cpu::exception_entry_at(VIRT_BASE)); } - /** - * Set next usermode-context pointer - */ - void user_context(Cpu::Context * const c) { *_user_context_ptr = c; } - /** * Fetch next kernelmode context */ - void fetch_kernel_context(Cpu::Context * const c) - { *_kernel_context = *c; } + void fetch_kernel_context(Cpu::Context * const c) { + memcpy(&_mt_kernel_context_begin, c, sizeof(Cpu::Context)); } /** * Page aligned physical base of the mode transition PIC */ - addr_t phys_base() { return (addr_t)_payload; } + addr_t phys_base() { return (addr_t)&_mode_transition_begin; } /** - * Virtual pointer to the usermode entry PIC + * Jump to the usermode entry PIC */ - addr_t virt_user_entry() { return _virt_user_entry; } + void virt_user_entry() { + ((void(*)(void))_virt_user_entry)(); } }; @@ -1093,9 +1070,17 @@ namespace Kernel static Timer * timer() { static Timer _object; return &_object; } - class Thread; + class Schedule_context; - typedef Scheduler Cpu_scheduler; + typedef Scheduler Cpu_scheduler; + + class Schedule_context : public Cpu_scheduler::Entry + { + public: + + virtual void handle_exception() = 0; + virtual void scheduled_next() = 0; + }; /** @@ -1116,15 +1101,23 @@ namespace Kernel unsigned core_id() { return core()->id(); } + class Thread; + + void handle_pagefault(Thread * const); + void handle_syscall(Thread * const); + void handle_interrupt(void); + void handle_invalid_excpt(void); + + /** * Kernel object that represents a Genode thread */ class Thread : public Cpu::User_context, public Object, - public Cpu_scheduler::Entry, + public Schedule_context, + public Fifo::Element, public Ipc_node, - public Irq_owner, - public Fifo::Element + public Irq_owner { enum State { STOPPED, ACTIVE, AWAIT_IPC, AWAIT_RESUMPTION, AWAIT_IRQ, AWAIT_SIGNAL }; @@ -1132,14 +1125,9 @@ namespace Kernel Platform_thread * const _platform_thread; /* userland object wich * addresses this thread */ State _state; /* thread state, description given at the beginning */ - Pagefault _pagefault; /* last pagefault triggered by this thread */ - Thread * _pager; /* gets informed if thread throws a pagefault */ - unsigned _pd_id; /* ID of the PD this thread runs on */ - Native_utcb * _phys_utcb; /* physical UTCB base */ - Native_utcb * _virt_utcb; /* virtual UTCB base */ /** - * Resume execution of thread + * Resume execution */ void _activate() { @@ -1147,6 +1135,12 @@ namespace Kernel _state = ACTIVE; } + Pagefault _pagefault; /* last pagefault triggered by this thread */ + Thread * _pager; /* gets informed if thread throws a pagefault */ + unsigned _pd_id; /* ID of the PD this thread runs on */ + Native_utcb * _phys_utcb; /* physical UTCB base */ + Native_utcb * _virt_utcb; /* virtual UTCB base */ + public: void * operator new (size_t, void * p) { return p; } @@ -1275,6 +1269,32 @@ namespace Kernel _activate(); } + void handle_exception() + { + switch(cpu_exception) { + case SUPERVISOR_CALL: + handle_syscall(this); + return; + case PREFETCH_ABORT: + case DATA_ABORT: + handle_pagefault(this); + return; + case INTERRUPT_REQUEST: + case FAST_INTERRUPT_REQUEST: + handle_interrupt(); + return; + default: + handle_invalid_excpt(); + } + } + + void scheduled_next() { + /* set context pointer for mode switch */ + _mt_context_ptr = (addr_t)static_cast(this); + + /* jump to user entry assembler path */ + mtc()->virt_user_entry(); + } /*************** ** Accessors ** @@ -1324,6 +1344,7 @@ namespace Kernel class Signal_receiver; + /** * Specific signal type, owned by a receiver, can be triggered asynchr. */ @@ -1410,6 +1431,57 @@ namespace Kernel } }; + + class Vm : public Object, + public Schedule_context + { + private: + + Genode::Cpu_state_modes * const _state; + Signal_context * const _context; + + public: + + void * operator new (size_t, void * p) { return p; } + + /** + * Constructor + */ + Vm(Genode::Cpu_state_modes * const state, + Signal_context * const context) + : _state(state), _context(context) { } + + void run() { + cpu_scheduler()->insert(this); } + + + /********************** + ** Schedule_context ** + **********************/ + + void handle_exception() + { + switch(_state->cpu_exception) { + case Genode::Cpu_state::INTERRUPT_REQUEST: + case Genode::Cpu_state::FAST_INTERRUPT_REQUEST: + handle_interrupt(); + return; + default: + cpu_scheduler()->remove(this); + _context->trigger_signal(1); + } + } + + void scheduled_next() { + /* set context pointer for mode switch */ + _mt_context_ptr = (addr_t)_state; + + /* jump to assembler path */ + ((void(*)(void))&_mon_vm_entry)(); + } + }; + + /** * Access to static CPU scheduler */ @@ -1449,18 +1521,19 @@ namespace Kernel size_t signal_context_size() { return sizeof(Signal_context); } size_t signal_receiver_size() { return sizeof(Signal_receiver); } unsigned pd_alignm_log2() { return Pd::ALIGNM_LOG2; } + size_t vm_size() { return sizeof(Vm); } /** * Handle the occurence of an unknown exception */ - void handle_invalid_excpt(Thread * const) { assert(0); } + void handle_invalid_excpt() { assert(0); } /** * Handle an interrupt request */ - void handle_interrupt(Thread * const) + void handle_interrupt() { /* determine handling for specific interrupt */ unsigned irq; @@ -1886,7 +1959,48 @@ namespace Kernel assert(c); /* trigger signal at context */ - c->trigger_signal(user->user_arg_2()); + c->trigger_signal(1); + } + + + /** + * Do specific syscall for 'user', for details see 'syscall.h' + */ + void do_new_vm(Thread * const user) + { + /* check permissions */ + assert(user->pd_id() == core_id()); + + /* dispatch arguments */ + void * const allocator = (void * const)user->user_arg_1(); + Genode::Cpu_state_modes * const state = + (Genode::Cpu_state_modes * const)user->user_arg_2(); + Signal_context * const context = + Signal_context::pool()->object(user->user_arg_3()); + assert(context); + + /* create vm */ + Vm * const vm = new (allocator) Vm(state, context); + + /* return vm id */ + user->user_arg_0((Syscall_ret)vm->id()); + } + + + /** + * Do specific syscall for 'user', for details see 'syscall.h' + */ + void do_run_vm(Thread * const user) + { + /* check permissions */ + assert(user->pd_id() == core_id()); + + /* get targeted vm via its id */ + Vm * const vm = Vm::pool()->object(user->user_arg_1()); + assert(vm); + + /* run targeted vm */ + vm->run(); } @@ -1928,6 +2042,8 @@ namespace Kernel /* 22 */ do_await_signal, /* 23 */ do_submit_signal, /* 24 */ do_delete_thread, + /* 25 */ do_new_vm, + /* 26 */ do_run_vm, }; enum { MAX_SYSCALL = sizeof(handle_sysc)/sizeof(handle_sysc[0]) - 1 }; @@ -1954,30 +2070,12 @@ extern "C" void kernel() /* update how much time the last user has consumed */ user_time = timer_value < user_time ? user_time - timer_value : 0; - /* map exception types to exception-handler functions */ - typedef void (*Exception_handler)(Thread * const); - static Exception_handler const handle_excpt[] = - { - /* exception ID */ /* handler */ - /*--------------*/ /*---------*/ - /* 0 */ handle_invalid_excpt, - /* 1 */ handle_interrupt, - /* 2 */ handle_pagefault, - /* 3 */ handle_syscall - }; /* handle exception that interrupted the last user */ - Thread * const user = cpu_scheduler()->current_entry(); - enum { MAX_EXCPT = sizeof(handle_excpt)/sizeof(handle_excpt[0]) - 1 }; - unsigned const e = user->exception(); - if (e > MAX_EXCPT) handle_invalid_excpt(user); - else handle_excpt[e](user); + cpu_scheduler()->current_entry()->handle_exception(); /* kernel initialization */ } else { - /* tell the code that called kernel, what to do when kernel returns */ - _call_after_kernel = mtc()->virt_user_entry(); - /* compose core address space */ addr_t a = 0; while (1) @@ -2001,7 +2099,6 @@ extern "C" void kernel() /* compose kernel CPU context */ static Cpu::Context kernel_context; kernel_context.instruction_ptr((addr_t)kernel); - kernel_context.return_ptr(mtc()->virt_user_entry()); kernel_context.stack_ptr((addr_t)&_kernel_stack_high); /* add kernel to the core PD */ @@ -2010,6 +2107,9 @@ extern "C" void kernel() /* offer the final kernel context to the mode transition page */ mtc()->fetch_kernel_context(&kernel_context); + /* TrustZone initialization code */ + trustzone_initialization(pic()); + /* switch to core address space */ Cpu::enable_mmu(core(), core_id()); @@ -2028,12 +2128,14 @@ extern "C" void kernel() initial_call = false; } /* offer next user context to the mode transition PIC */ - Thread * const next = cpu_scheduler()->next_entry(user_time); - mtc()->user_context(next); + Schedule_context* const next = cpu_scheduler()->next_entry(user_time); /* limit user mode execution in time */ timer()->start_one_shot(user_time); pic()->unmask(Timer::IRQ); + + /* will jump to the context related mode-switch */ + next->scheduled_next(); } diff --git a/base-hw/src/core/kernel_support.cc b/base-hw/src/core/kernel_support.cc new file mode 100644 index 0000000000..d73fb6f654 --- /dev/null +++ b/base-hw/src/core/kernel_support.cc @@ -0,0 +1,23 @@ +/* + * \brief Kernel function implementations specific for Cortex A9 CPUs + * \author Stefan Kalkowski + * \date 2012-10-11 + */ + +/* + * Copyright (C) 2012 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. + */ + +#include + + +Cpu::User_context::User_context() +{ + /* Execute in usermode with IRQ's enabled and FIQ's and + * asynchronous aborts disabled */ + cpsr = Cpsr::M::bits(Cpsr::M::USER) | Cpsr::F::bits(1) | + Cpsr::I::bits(0) | Cpsr::A::bits(1); +} diff --git a/base-hw/src/core/panda_a2/platform_support.cc b/base-hw/src/core/panda_a2/platform_support.cc index d9d6462258..db85348336 100644 --- a/base-hw/src/core/panda_a2/platform_support.cc +++ b/base-hw/src/core/panda_a2/platform_support.cc @@ -81,4 +81,3 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i) }; return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0; } - diff --git a/base-hw/src/core/panda_a2/target.mk b/base-hw/src/core/panda_a2/target.mk new file mode 100644 index 0000000000..750304edcc --- /dev/null +++ b/base-hw/src/core/panda_a2/target.mk @@ -0,0 +1,9 @@ +# +# \brief Pandaboard-specific makefile for core +# \author Stefan Kalkowski +# \date 2012-10-04 +# + +REQUIRES = platform_panda_a2 + +include $(REP_DIR)/src/core/target.inc diff --git a/base-hw/src/core/pbxa9/platform_support.cc b/base-hw/src/core/pbxa9/platform_support.cc index 89e8af40fa..a0402907f5 100644 --- a/base-hw/src/core/pbxa9/platform_support.cc +++ b/base-hw/src/core/pbxa9/platform_support.cc @@ -79,4 +79,3 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i) }; return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0; } - diff --git a/base-hw/src/core/pbxa9/target.mk b/base-hw/src/core/pbxa9/target.mk new file mode 100644 index 0000000000..96b06e24b6 --- /dev/null +++ b/base-hw/src/core/pbxa9/target.mk @@ -0,0 +1,9 @@ +# +# \brief PBXA9-specific makefile for core +# \author Stefan Kalkowski +# \date 2012-10-04 +# + +REQUIRES = platform_pbxa9 + +include $(REP_DIR)/src/core/target.inc diff --git a/base-hw/src/core/target.mk b/base-hw/src/core/target.inc similarity index 95% rename from base-hw/src/core/target.mk rename to base-hw/src/core/target.inc index 3c113e1ce1..b03720fbc7 100644 --- a/base-hw/src/core/target.mk +++ b/base-hw/src/core/target.inc @@ -36,7 +36,6 @@ SRC_CC += _main.cc \ platform.cc \ platform_pd.cc \ platform_thread.cc \ - platform_services.cc \ ram_session_component.cc \ ram_session_support.cc \ rm_session_component.cc \ @@ -52,7 +51,6 @@ vpath io_mem_session_component.cc $(GEN_CORE_DIR) vpath io_mem_session_support.cc $(GEN_CORE_DIR) vpath main.cc $(GEN_CORE_DIR) vpath pd_session_component.cc $(GEN_CORE_DIR) -vpath platform_services.cc $(GEN_CORE_DIR) vpath ram_session_component.cc $(GEN_CORE_DIR) vpath rm_session_component.cc $(GEN_CORE_DIR) vpath rom_session_component.cc $(GEN_CORE_DIR) diff --git a/base-hw/src/core/trustzone.cc b/base-hw/src/core/trustzone.cc new file mode 100644 index 0000000000..1e9c64e3b0 --- /dev/null +++ b/base-hw/src/core/trustzone.cc @@ -0,0 +1,16 @@ +/* + * \brief TrustZone specific functions for non-TZ case + * \author Stefan Kalkowski + * \date 2012-10-10 + */ + +/* + * Copyright (C) 2012 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. + */ + +#include + +void Kernel::trustzone_initialization(Pic *pic) { } diff --git a/base-hw/src/core/vea9x4/platform_support.cc b/base-hw/src/core/vea9x4/platform_support.cc index bddbd50bdc..ad641a7162 100644 --- a/base-hw/src/core/vea9x4/platform_support.cc +++ b/base-hw/src/core/vea9x4/platform_support.cc @@ -80,4 +80,3 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i) }; return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0; } - diff --git a/base-hw/src/core/vea9x4/target.mk b/base-hw/src/core/vea9x4/target.mk new file mode 100644 index 0000000000..06769e5df5 --- /dev/null +++ b/base-hw/src/core/vea9x4/target.mk @@ -0,0 +1,13 @@ +# +# \brief VEA9x4-specific makefile for core +# \author Stefan Kalkowski +# \date 2012-10-04 +# + +REQUIRES = platform_vea9x4 + +ifeq ($(filter-out $(SPECS),trustzone),) +LD_TEXT_ADDR = 0x48000000 +endif + +include $(REP_DIR)/src/core/target.inc diff --git a/base-hw/src/core/vea9x4/trustzone/kernel_support.cc b/base-hw/src/core/vea9x4/trustzone/kernel_support.cc new file mode 100644 index 0000000000..c2145f391b --- /dev/null +++ b/base-hw/src/core/vea9x4/trustzone/kernel_support.cc @@ -0,0 +1,24 @@ +/* + * \brief Kernel-specific implementations for Versatile Express with TZ + * \author Stefan Kalkowski + * \date 2012-10-11 + */ + +/* + * Copyright (C) 2012 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 + + +Genode::Cortex_a9::User_context::User_context() +{ + /* Execute in usermode with FIQ's enabled and IRQ's and + * asynchronous aborts disabled */ + cpsr = Cpsr::M::bits(Cpsr::M::USER) | Cpsr::F::bits(0) | + Cpsr::I::bits(1) | Cpsr::A::bits(1); +} diff --git a/base-hw/src/core/vea9x4/trustzone/kernel_support.h b/base-hw/src/core/vea9x4/trustzone/kernel_support.h new file mode 100644 index 0000000000..5573842fe0 --- /dev/null +++ b/base-hw/src/core/vea9x4/trustzone/kernel_support.h @@ -0,0 +1,82 @@ +/* + * \brief Kernel support specific for the Versatile VEA9X4 + * \author Stefan Kalkowski + * \date 2012-10-11 + */ + +/* + * Copyright (C) 2012 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. + */ + +#ifndef _SRC__CORE__VEA9X4__TRUSTZONE__KERNEL_SUPPORT_H_ +#define _SRC__CORE__VEA9X4__TRUSTZONE__KERNEL_SUPPORT_H_ + +/* Core includes */ +#include +#include + +/** + * CPU driver + */ +class Cpu : public Genode::Cortex_a9 { }; + +namespace Kernel +{ + /* import Genode types */ + typedef Genode::Cortex_a9 Cortex_a9; + typedef Genode::Pl390_base Pl390_base; + + /** + * Kernel interrupt-controller + */ + class Pic : public Pl390_base + { + public: + + /** + * Constructor + */ + Pic() : Pl390_base(Cortex_a9::PL390_DISTRIBUTOR_MMIO_BASE, + Cortex_a9::PL390_CPU_MMIO_BASE) + { + /* configure every shared peripheral interrupt */ + for (unsigned i=MIN_SPI; i <= _max_interrupt; i++) { + _distr.write(0, i); + _distr.write(0, i); + _distr.write(Distr::Icdiptr::Cpu_targets::ALL, i); + } + + /* disable the priority filter */ + _cpu.write(0xff); + + /* signal secure IRQ via FIQ interface */ + _cpu.write(Cpu::Iccicr::Enable_s::bits(1) | + Cpu::Iccicr::Enable_ns::bits(1) | + Cpu::Iccicr::Fiq_en::bits(1)); + + /* use whole band of prios */ + _cpu.write(Cpu::Iccbpr::Binary_point::NO_PREEMPTION); + + /* enable device */ + _distr.write(Distr::Icddcr::Enable::bits(1)); + } + + /** + * Mark interrupt i unsecure + */ + void unsecure(unsigned i) { + _distr.write(1, i); } + }; + + /** + * Kernel timer + */ + class Timer : public Cortex_a9::Private_timer { }; +} + + +#endif /* _SRC__CORE__VEA9X4__TRUSTZONE__KERNEL_SUPPORT_H_ */ + diff --git a/base-hw/src/core/vea9x4/trustzone/platform_services.cc b/base-hw/src/core/vea9x4/trustzone/platform_services.cc new file mode 100644 index 0000000000..b67d6bdc79 --- /dev/null +++ b/base-hw/src/core/vea9x4/trustzone/platform_services.cc @@ -0,0 +1,35 @@ +/* + * \brief Platform specific services for base-hw and VEA9X4 (TrustZone) + * \author Stefan Kalkowski + * \date 2012-10-26 + */ + +/* + * Copyright (C) 2012 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. + */ + +/* Genode includes */ +#include + +/* Core includes */ +#include +#include +#include + + +/* + * Add TrustZone specific vm service + */ +void Genode::platform_add_local_services(Genode::Rpc_entrypoint *ep, + Genode::Sliced_heap *sh, + Genode::Service_registry *ls) +{ + using namespace Genode; + + static Vm_root vm_root(ep, sh, platform()->ram_alloc()); + static Local_service vm_ls(Vm_session::service_name(), &vm_root); + ls->insert(&vm_ls); +} diff --git a/base-hw/src/core/vea9x4/trustzone/platform_support.cc b/base-hw/src/core/vea9x4/trustzone/platform_support.cc new file mode 100644 index 0000000000..cd6b90c27b --- /dev/null +++ b/base-hw/src/core/vea9x4/trustzone/platform_support.cc @@ -0,0 +1,88 @@ +/* + * \brief Platform implementations specific for base-hw and VEA9X4 + * \author Martin Stein + * \date 2012-04-27 + */ + +/* + * Copyright (C) 2012 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. + */ + +/* Genode includes */ +#include + +/* Core includes */ +#include +#include +#include + +using namespace Genode; + + +Native_region * Platform::_ram_regions(unsigned const i) +{ + static Native_region _regions[] = + { + { Board::SRAM_BASE, Board::SRAM_SIZE } + }; + return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0; +} + + +Native_region * Platform::_irq_regions(unsigned const i) +{ + static Native_region _regions[] = + { + { 0, 34 }, + { 37, 3 }, + { 46, 1 }, + { 49, Pl390_base::MAX_INTERRUPT_ID - 49 } + }; + return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0; +} + + +Native_region * Platform::_core_only_irq_regions(unsigned const i) +{ + static Native_region _regions[] = + { + /* Core timer */ + { Cortex_a9::PRIVATE_TIMER_IRQ, 1 }, + + /* Core UART */ + { Board::PL011_0_IRQ, 1 } + }; + return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0; +} + + +Native_region * Platform::_mmio_regions(unsigned const i) +{ + static Native_region _regions[] = + { + { Board::SMB_CS7_BASE, Board::SMB_CS7_SIZE }, + { Board::SMB_CS0_TO_CS6_BASE, Board::SMB_CS0_TO_CS6_SIZE }, + { Board::LOCAL_DDR2_BASE, Board::LOCAL_DDR2_SIZE }, + { Board::TZASC_MMIO_BASE, Board::TZASC_MMIO_SIZE }, + { Board::TZPC_MMIO_BASE, Board::TZPC_MMIO_SIZE }, + }; + return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0; +} + + +Native_region * Platform::_core_only_mmio_regions(unsigned const i) +{ + static Native_region _regions[] = + { + /* Core timer and PIC */ + { Board::CORTEX_A9_PRIVATE_MEM_BASE, + Board::CORTEX_A9_PRIVATE_MEM_SIZE }, + + /* Core UART */ + { Board::PL011_0_MMIO_BASE, Board::PL011_0_MMIO_SIZE } + }; + return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0; +} diff --git a/base-hw/src/core/vea9x4/trustzone/trustzone.cc b/base-hw/src/core/vea9x4/trustzone/trustzone.cc new file mode 100644 index 0000000000..1c9d57b626 --- /dev/null +++ b/base-hw/src/core/vea9x4/trustzone/trustzone.cc @@ -0,0 +1,42 @@ +/* + * \brief TrustZone specific functions for Versatile Express + * \author Stefan Kalkowski + * \date 2012-10-10 + */ + +/* + * Copyright (C) 2012 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 + +/* monitor exception vector address */ +extern int _mon_kernel_entry; + + +void Kernel::trustzone_initialization(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(); + + /* set unsecure IRQs */ + pic->unsecure(34); //Timer 0/1 + pic->unsecure(35); //Timer 2/3 + pic->unsecure(36); //RTC + pic->unsecure(40); //UART3 + pic->unsecure(41); //MCI0 + pic->unsecure(42); //MCI1 + pic->unsecure(43); //AACI + pic->unsecure(44); //KMI0 + pic->unsecure(45); //KMI1 + pic->unsecure(47); //ETHERNET + pic->unsecure(48); //USB +} diff --git a/base-hw/src/core/vm_session_component.cc b/base-hw/src/core/vm_session_component.cc new file mode 100644 index 0000000000..9b90ca43d4 --- /dev/null +++ b/base-hw/src/core/vm_session_component.cc @@ -0,0 +1,70 @@ +/* + * \brief Vm_session_component for base-hw + * \author Stefan Kalkowski + * \date 2012-10-08 + */ + +/* + * Copyright (C) 2012 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. + */ + +/* Genode includes */ +#include +#include +#include +#include + +/* Core includes */ +#include + +using namespace Genode; + + +void Vm_session_component::exception_handler(Signal_context_capability handler) +{ + if (_vm_id) { + PWRN("Cannot register exception_handler repeatedly"); + return; + } + + _vm_id = Kernel::new_vm(_vm, (void*)_ds.core_local_addr(), handler.dst()); +} + + +void Vm_session_component::run(void) +{ + if (!_vm_id) { + PWRN("No exception handler registered!"); + return; + } + Kernel::run_vm(_vm_id); +} + + +Vm_session_component::Vm_session_component(Rpc_entrypoint *ds_ep, + Range_allocator *ram_alloc, + size_t ram_quota) +: _ds_ep(ds_ep), _ram_alloc(ram_alloc), _vm_id(0), + _ds_addr(_alloc_ds(&ram_quota)), + _ds(_ds_size(), _ds_addr, _ds_addr, false, true, 0), + _ds_cap(static_cap_cast(_ds_ep->manage(&_ds))) +{ + /* alloc needed memory */ + if (Kernel::vm_size() > ram_quota || + !_ram_alloc->alloc(Kernel::vm_size(), &_vm)) + throw Root::Quota_exceeded(); +} + + +Vm_session_component::~Vm_session_component() +{ + /* dissolve VM dataspace from service entry point */ + _ds_ep->dissolve(&_ds); + + /* free region in allocator */ + _ram_alloc->free((void*)_ds.core_local_addr()); + _ram_alloc->free(_vm); +} diff --git a/base/include/arm/cpu/cpu_state.h b/base/include/arm/cpu/cpu_state.h index 8b5f934857..3428071b4b 100644 --- a/base/include/arm/cpu/cpu_state.h +++ b/base/include/arm/cpu/cpu_state.h @@ -25,14 +25,14 @@ namespace Genode { * Native exception types */ enum Cpu_exception { - RESET = 1, - UNDEFINED_INSTRUCTION = 2, - SUPERVISOR_CALL = 3, - PREFETCH_ABORT = 4, - DATA_ABORT = 5, - INTERRUPT_REQUEST = 6, - FAST_INTERRUPT_REQUEST = 7, - MAX_CPU_EXCEPTION = FAST_INTERRUPT_REQUEST, + RESET, + UNDEFINED_INSTRUCTION, + SUPERVISOR_CALL, + PREFETCH_ABORT, + DATA_ABORT, + INTERRUPT_REQUEST, + FAST_INTERRUPT_REQUEST, + MAX_CPU_EXCEPTION, }; enum { MAX_GPR = 13 }; @@ -62,13 +62,13 @@ namespace Genode { MAX }; - uint32_t sp; /* banked stack pointer */ - uint32_t lr; /* banked link register */ - uint32_t spsr; /* saved program status register */ + addr_t spsr; /* saved program status register */ + addr_t sp; /* banked stack pointer */ + addr_t lr; /* banked link register */ }; Mode_state mode[Mode_state::MAX]; /* exception mode registers */ - uint32_t fiq_r[5]; /* fast-interrupt mode r8-r12 */ + addr_t fiq_r[5]; /* fast-interrupt mode r8-r12 */ }; } diff --git a/base/include/platform/vea9x4/drivers/board.h b/base/include/platform/vea9x4/drivers/board.h index 1ee9644fba..7e653fe5b4 100644 --- a/base/include/platform/vea9x4/drivers/board.h +++ b/base/include/platform/vea9x4/drivers/board.h @@ -26,6 +26,7 @@ namespace Genode enum { /* static memory bus */ + SMB_CS2_BASE = 0x48000000, SMB_CS7_BASE = 0x10000000, SMB_CS7_SIZE = 0x20000, SMB_CS0_TO_CS6_BASE = 0x40000000, @@ -46,6 +47,14 @@ namespace Genode /* clocks */ TCREF_CLOCK = 66670*1000, + /* TrustZone Address Space Controller */ + TZASC_MMIO_BASE = 0x100ec000, + TZASC_MMIO_SIZE = 0x1000, + + /* TrustZone Protection Controller */ + TZPC_MMIO_BASE = 0x100e6000, + TZPC_MMIO_SIZE = 0x1000, + /* CPU */ CORTEX_A9_PRIVATE_MEM_BASE = 0x1e000000, CORTEX_A9_PRIVATE_MEM_SIZE = 0x2000, @@ -55,6 +64,10 @@ namespace Genode /* RAM */ LOCAL_DDR2_BASE = 0x60000000, LOCAL_DDR2_SIZE = 0x40000000, + + /* SRAM */ + SRAM_BASE = SMB_CS2_BASE, + SRAM_SIZE = 0x01ffffff, }; }; }