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.
This commit is contained in:
Stefan Kalkowski 2012-10-02 14:27:32 +02:00
parent 965ffc1df2
commit 8393ac6895
40 changed files with 1184 additions and 265 deletions

View File

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

View File

@ -33,7 +33,7 @@ namespace Genode {
long priority = Cpu_session::DEFAULT_PRIORITY,
unsigned long affinity = 0)
: Connection<Vm_session>(
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()) { }
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,7 @@
#
# \brief Platform implementations specific for base-hw and VEA9X4
# \author Stefan Kalkowski
# \date 2012-10-04
#
LIBS += vea9x4_platform_support

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<Distr::Icddcr::Enable>(0);
_cpu.write<Cpu::Iccicr::Enable>(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<Distr::Icdicr::Edge_triggered>(0, i);
_distr.write<Distr::Icdipr::Priority>(max_prio, i);
_distr.write<Distr::Icdiptr::Cpu_targets>(Distr::Icdiptr::Cpu_targets::ALL, i);
}
/* disable the priority filter */
_cpu.write<Cpu::Iccpmr::Priority>(min_prio);
/* disable preemption of interrupt handling by interrupts */
_cpu.write<Cpu::Iccbpr::Binary_point>(
Cpu::Iccbpr::Binary_point::NO_PREEMPTION);
/* enable device */
_distr.write<Distr::Icddcr::Enable>(1);
_cpu.write<Cpu::Iccicr::Enable>(1);
}
};
/**

View File

@ -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<Distr::Icddcr::Enable>(0);
_cpu.write<Cpu::Iccicr::Enable>(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<Distr::Icdicr::Edge_triggered>(0, i);
_distr.write<Distr::Icdipr::Priority>(max_prio, i);
_distr.write<Distr::Icdiptr::Cpu_targets>(Distr::Icdiptr::Cpu_targets::ALL, i);
}
/* disable the priority filter */
_cpu.write<Cpu::Iccpmr::Priority>(min_prio);
/* disable preemption of interrupt handling by interrupts */
_cpu.write<Cpu::Iccbpr::Binary_point>(
Cpu::Iccbpr::Binary_point::NO_PREEMPTION);
/* enable device */
_distr.write<Distr::Icddcr::Enable>(1);
_cpu.write<Cpu::Iccicr::Enable>(1);
}
_last_taken_request(SPURIOUS_ID) { }
/**
* Get the ID of the last interrupt request

View File

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

View File

@ -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 <root/component.h>
/* core includes */
#include <vm_session_component.h>
namespace Genode {
class Vm_root : public Root_component<Vm_session_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<Vm_session_component>(session_ep, md_alloc),
_ram_alloc(ram_alloc){ }
};
}
#endif /* _CORE__INCLUDE__VM_ROOT_H_ */

View File

@ -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 <base/allocator.h>
#include <base/rpc_server.h>
#include <vm_session/vm_session.h>
#include <dataspace/capability.h>
/* Core includes */
#include <dataspace_component.h>
namespace Genode {
class Vm_session_component : public Rpc_object<Vm_session>
{
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_ */

View File

@ -24,6 +24,7 @@
/* Genode includes */
#include <base/signal.h>
#include <cpu/cpu_state.h>
#include <util/fifo.h>
#include <util/avl_tree.h>
@ -32,11 +33,11 @@
#include <platform_thread.h>
#include <assert.h>
#include <software_tlb.h>
#include <trustzone.h>
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<Thread> Cpu_scheduler;
typedef Scheduler<Schedule_context> 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<Thread, MAX_THREADS>,
public Cpu_scheduler::Entry,
public Schedule_context,
public Fifo<Thread>::Element,
public Ipc_node,
public Irq_owner,
public Fifo<Thread>::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<Genode::Cpu_state*>(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<Vm, MAX_VMS>,
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();
}

View File

@ -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 <kernel_support.h>
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);
}

View File

@ -81,4 +81,3 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}

View File

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

View File

@ -79,4 +79,3 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}

View File

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

View File

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

View File

@ -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 <trustzone.h>
void Kernel::trustzone_initialization(Pic *pic) { }

View File

@ -80,4 +80,3 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}

View File

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

View File

@ -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 <kernel_support.h>
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);
}

View File

@ -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 <cortex_a9/cpu/core.h>
#include <pic/pl390_base.h>
/**
* 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<Distr::Icdicr::Edge_triggered>(0, i);
_distr.write<Distr::Icdipr::Priority>(0, i);
_distr.write<Distr::Icdiptr::Cpu_targets>(Distr::Icdiptr::Cpu_targets::ALL, i);
}
/* disable the priority filter */
_cpu.write<Cpu::Iccpmr::Priority>(0xff);
/* signal secure IRQ via FIQ interface */
_cpu.write<Cpu::Iccicr>(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>(Cpu::Iccbpr::Binary_point::NO_PREEMPTION);
/* enable device */
_distr.write<Distr::Icddcr>(Distr::Icddcr::Enable::bits(1));
}
/**
* Mark interrupt i unsecure
*/
void unsecure(unsigned i) {
_distr.write<Distr::Icdisr::Nonsecure>(1, i); }
};
/**
* Kernel timer
*/
class Timer : public Cortex_a9::Private_timer { };
}
#endif /* _SRC__CORE__VEA9X4__TRUSTZONE__KERNEL_SUPPORT_H_ */

View File

@ -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 <base/service.h>
/* Core includes */
#include <platform.h>
#include <platform_services.h>
#include <vm_root.h>
/*
* 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);
}

View File

@ -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 <drivers/board.h>
/* Core includes */
#include <platform.h>
#include <pic/pl390_base.h>
#include <cortex_a9/cpu/core.h>
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;
}

View File

@ -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 <trustzone.h>
#include <kernel_support.h>
/* 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
}

View File

@ -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 <util/string.h>
#include <util/arg_string.h>
#include <root/root.h>
#include <cpu/cpu_state.h>
/* Core includes */
#include <vm_session_component.h>
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<Dataspace>(_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);
}

View File

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

View File

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