Nested init on i.MX31 via base_hw. Rework base_hw.

Implies support for the ARMv6 architecture through 'base-hw'.

Get rid of 'base/include/drivers' expect of 'base/include/drivers/uart'.

Merge with the support for trustzone on VEA9X4 that came from
Stefan Kalkowski.

Leave board drivers in 'base/include/platform'.

Rework structure of the other drivers that were moved to
'base_hw/src/core' and those that came with the trustzone support.

Beautify further stuff in 'base_hw'.

Test 'nested_init' with 'hw_imx31' (hardware) and 'hw_panda_a2' (hardware),
'demo' and 'signal' with 'hw_pbxa9' (qemu) and 'hw_vea9x4'
(hardware, no trustzone), and 'vmm' with 'hw_vea9x4'
(hardware, with trustzone).
This commit is contained in:
Martin Stein
2012-10-23 17:12:09 +02:00
committed by Norman Feske
parent 5b4edeb031
commit 31d57a6257
87 changed files with 3959 additions and 1391 deletions

View File

@ -0,0 +1,163 @@
/*
* \brief Syscall-framework implementation for ARM
* \author Martin stein
* \date 2011-11-30
*
* The code in this file is compliant to the general ARM instruction- and
* register-set but the semantics are tested only on ARMv6 and ARMv7 by now.
*/
/*
* Copyright (C) 2011-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 <kernel/syscalls.h>
using namespace Kernel;
/******************************************************************
** Inline assembly templates for syscalls with 1 to 6 arguments **
******************************************************************/
#define SYSCALL_6_ASM_OPS \
"mov r5, #0 \n" \
"add r5, %[arg_5] \n" \
SYSCALL_5_ASM_OPS
#define SYSCALL_5_ASM_OPS \
"mov r4, #0 \n" \
"add r4, %[arg_4] \n" \
SYSCALL_4_ASM_OPS
#define SYSCALL_4_ASM_OPS \
"mov r3, #0 \n" \
"add r3, %[arg_3] \n" \
SYSCALL_3_ASM_OPS
#define SYSCALL_3_ASM_OPS \
"mov r2, #0 \n" \
"add r2, %[arg_2] \n" \
SYSCALL_2_ASM_OPS
#define SYSCALL_2_ASM_OPS \
"mov r1, #0 \n" \
"add r1, %[arg_1] \n" \
SYSCALL_1_ASM_OPS
#define SYSCALL_1_ASM_OPS \
"mov r0, #0 \n" \
"add r0, %[arg_0] \n" \
"swi 0 \n" \
"mov %[result], #0 \n" \
"add %[result], r0 "
/*****************************************************************************
** Inline assembly "writeable" template-args for syscalls with 1 to 6 args **
*****************************************************************************/
#define SYSCALL_6_ASM_WRITE [arg_5] "+r" (arg_5), SYSCALL_5_ASM_WRITE
#define SYSCALL_5_ASM_WRITE [arg_4] "+r" (arg_4), SYSCALL_4_ASM_WRITE
#define SYSCALL_4_ASM_WRITE [arg_3] "+r" (arg_3), SYSCALL_3_ASM_WRITE
#define SYSCALL_3_ASM_WRITE [arg_2] "+r" (arg_2), SYSCALL_2_ASM_WRITE
#define SYSCALL_2_ASM_WRITE [arg_1] "+r" (arg_1), SYSCALL_1_ASM_WRITE
#define SYSCALL_1_ASM_WRITE \
[arg_0] "+r" (arg_0), \
[result] "+r" (result)
/**********************************************************************
** Inline assembly clobber lists for syscalls with 1 to 6 arguments **
**********************************************************************/
#define SYSCALL_6_ASM_CLOBBER "r5", SYSCALL_5_ASM_CLOBBER
#define SYSCALL_5_ASM_CLOBBER "r4", SYSCALL_4_ASM_CLOBBER
#define SYSCALL_4_ASM_CLOBBER "r3", SYSCALL_3_ASM_CLOBBER
#define SYSCALL_3_ASM_CLOBBER "r2", SYSCALL_2_ASM_CLOBBER
#define SYSCALL_2_ASM_CLOBBER "r1", SYSCALL_1_ASM_CLOBBER
#define SYSCALL_1_ASM_CLOBBER "r0"
/************************************
** Syscalls with 1 to 6 arguments **
************************************/
Syscall_ret Kernel::syscall(Syscall_arg arg_0)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_1_ASM_OPS
: SYSCALL_1_ASM_WRITE
:: SYSCALL_1_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_2_ASM_OPS
: SYSCALL_2_ASM_WRITE
:: SYSCALL_2_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_3_ASM_OPS
: SYSCALL_3_ASM_WRITE
:: SYSCALL_3_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_4_ASM_OPS
: SYSCALL_4_ASM_WRITE
:: SYSCALL_4_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_5_ASM_OPS
: SYSCALL_5_ASM_WRITE
:: SYSCALL_5_ASM_CLOBBER);
return result;
}
Syscall_ret Kernel::syscall(Syscall_arg arg_0,
Syscall_arg arg_1,
Syscall_arg arg_2,
Syscall_arg arg_3,
Syscall_arg arg_4,
Syscall_arg arg_5)
{
Syscall_ret result = 0;
asm volatile(SYSCALL_6_ASM_OPS
: SYSCALL_6_ASM_WRITE
:: SYSCALL_6_ASM_CLOBBER);
return result;
}

View File

@ -1,5 +1,5 @@
/*
* \brief Dummy version of a boot modules file to enable a 'core' standalone image
* \brief Dummy boot-modules-file to enable a 'core' standalone image
* \author Martin Stein
* \date 2011-12-16
*/
@ -31,3 +31,4 @@ _boot_module_headers_end:
.global _boot_modules_end
_boot_modules_end:

View File

@ -1,8 +1,11 @@
/*
* \brief Startup code for the Genode Kernel on ARM
* \brief Startup code for core on ARM
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2011-10-01
*
* The code in this file is compliant to the general ARM instruction- and
* register-set but the semantics are tested only on ARMv6 and ARMv7 by now.
*/
/*
@ -12,6 +15,15 @@
* under the terms of the GNU General Public License version 2.
*/
/**
* Do no operation for 'count' cycles
*/
.macro _nop count
.rept \count
mov r8, r8
.endr
.endm
.section .text
/* ELF entry symbol */
@ -19,9 +31,7 @@
_start:
/* idle a little initially because 'u-boot' likes it this way */
.rept 8
nop
.endr
_nop 8
/* zero-fill BSS segment */
.extern _bss_start
@ -36,12 +46,19 @@
cmp r0, r1
bne 1b
/* enable C++ to prepare the first kernel run */
ldr sp, =_kernel_stack_high
bl init_phys_kernel
/* call kernel routine */
.extern kernel
_start_kernel:
ldr sp, =_kernel_stack_high
bl kernel
/* catch erroneous kernel return */
2: b 2b
/* handle for dynamic symbol objects */
.align 3
.global __dso_handle
@ -55,7 +72,7 @@
.global _kernel_stack_high
_kernel_stack_high:
/* main thread UTCB pointer for the Genode thread API */
/* main-thread UTCB-pointer for the Genode thread-API */
.align 3
.global _main_utcb
_main_utcb: .long 0

View File

@ -0,0 +1,234 @@
/*
* \brief Transition between kernel and userland
* \author Martin stein
* \date 2011-11-15
*/
/*
* Copyright (C) 2011-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.
*/
/**
* Invalidate all entries of the branch prediction cache
*
* FIXME branch prediction shall not be activated for now because we have no
* support for instruction barriers. The manual says that one should
* implement this via 'swi 0xf00000', but when we do this in SVC mode it
* pollutes our SP and this is not acceptable with the current mode
* transition implementation
*/
.macro _flush_branch_predictor
mcr p15, 0, sp, c7, c5, 6
/* swi 0xf00000 */
.endm
/**
* Switch from an interrupted user context to a kernel context
*
* \param exception_type immediate exception type ID
* \param pc_adjust immediate value that gets subtracted from the
* user PC before it gets saved
*/
.macro _user_to_kernel_pic exception_type, pc_adjust
/*
* We expect that privileged modes are never interrupted by an
* exception. Thus we can assume that we always come from
* user mode at this point.
*/
/************************************************
** We're still in the user protection domain, **
** so we must avoid access to kernel memory **
************************************************/
/* load kernel cidr */
adr sp, _mt_master_context_begin
ldr sp, [sp, #18*4]
mcr p15, 0, sp, c13, c0, 1
_flush_branch_predictor
/* load kernel section table */
adr sp, _mt_master_context_begin
ldr sp, [sp, #19*4]
mcr p15, 0, sp, c2, c0, 0
_flush_branch_predictor
/*******************************************
** Now it's save to access kernel memory **
*******************************************/
/* get user context pointer */
ldr sp, _mt_client_context_ptr
/*
* Save user r0 ... r12. We explicitely target user registers
* via '^' because we might be in FIQ exception-mode where
* some of them are banked. Doesn't affect other modes.
*/
stmia sp, {r0-r12}^
/* save user lr and sp */
add r0, sp, #13*4
stmia r0, {sp,lr}^
/* adjust and save user pc */
.if \pc_adjust != 0
sub lr, lr, #\pc_adjust
.endif
str lr, [sp, #15*4]
/* save user psr */
mrs r0, spsr
str r0, [sp, #16*4]
/* save type of exception that interrupted the user */
mov r0, #\exception_type
str r0, [sp, #17*4]
/*
* Switch to supervisor mode
*
* FIXME This is done due to incorrect behavior when running the kernel
* high-level-code in FIQ-exception mode. Please debug this behavior
* and remove this switch.
*/
cps #19
/* get kernel context pointer */
adr r0, _mt_master_context_begin
/* load kernel context */
add r0, r0, #13*4
ldmia r0, {sp, lr, pc}
.endm
.section .text
/*
* The mode transition PIC switches between a kernel context and a user
* context and thereby between their address spaces. Due to the latter
* it must be mapped executable to the same region in every address space.
* To enable such switching, the kernel context must be stored within this
* region, thus one should map it solely accessable for privileged modes.
*/
.p2align 12
.global _mode_transition_begin
_mode_transition_begin:
/*
* On user exceptions the CPU has to jump to one of the following
* 7 entry vectors to switch to a kernel context.
*/
.global _mt_kernel_entry_pic
_mt_kernel_entry_pic:
b _rst_entry /* 0x00: reset */
b _und_entry /* 0x04: undefined instruction */
b _swi_entry /* 0x08: software interrupt */
b _pab_entry /* 0x0c: prefetch abort */
b _dab_entry /* 0x10: data abort */
nop /* 0x14: reserved */
b _irq_entry /* 0x18: interrupt request */
b _fiq_entry /* 0x1c: fast interrupt request */
/* 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
_swi_entry:
/*
* FIXME fast SWI routines pollute the SVC SP but we have
* to call them especially in SVC mode
*/
/* check if SWI requests a fast service routine */
/* ldr sp, [r14, #-0x4]
and sp, sp, #0xffffff
*/
/* fast "instruction barrier" service routine */
/* cmp sp, #0xf00000
bne _mt_slow_swi
movs pc, r14
*/
/* slow high level service routine */
_mt_slow_swi:
_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
/* kernel must jump to this point to switch to a user context */
.p2align 2
.global _mt_user_entry_pic
_mt_user_entry_pic:
/* get user context pointer */
ldr lr, _mt_client_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 cidr 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}^
/* leave some space for the kernel context */
.p2align 2
.global _mt_master_context_begin
_mt_master_context_begin: .space 32*4
.global _mt_master_context_end
_mt_master_context_end:
/* pointer to the context backup space */
.p2align 2
.global _mt_client_context_ptr
_mt_client_context_ptr: .long 0
/* a local word-sized buffer */
.p2align 2
.global _mt_buffer
_mt_buffer: .long 0
.p2align 2
.global _mode_transition_end
_mode_transition_end:
/* FIXME this exists only because _vm_mon_entry pollutes kernel.cc */
.global _mon_vm_entry
_mon_vm_entry:
1: b 1b

View File

@ -12,6 +12,7 @@
* under the terms of the GNU General Public License version 2.
*/
/**
* Switch from an interrupted user context to a kernel context
*
@ -37,13 +38,14 @@
** so we must avoid access to kernel memory **
************************************************/
/* load kernel contextidr */
adr sp, _mt_kernel_context_begin
/* load kernel cidr */
adr sp, _mt_master_context_begin
ldr sp, [sp, #18*4]
mcr p15, 0, sp, c13, c0, 1
isb
/* load kernel section table */
adr sp, _mt_kernel_context_begin
adr sp, _mt_master_context_begin
ldr sp, [sp, #19*4]
mcr p15, 0, sp, c2, c0, 0
isb
@ -54,7 +56,7 @@
*******************************************/
/* get user context pointer */
ldr sp, _mt_context_ptr
ldr sp, _mt_client_context_ptr
/*
* Save user r0 ... r12. We explicitely target user registers
@ -90,7 +92,7 @@
cps #19
/* get kernel context pointer */
adr r0, _mt_kernel_context_begin
adr r0, _mt_master_context_begin
/* load kernel context */
add r0, r0, #13*4
@ -105,7 +107,7 @@
.macro _kernel_to_user_pic
/* get user context pointer */
ldr lr, _mt_context_ptr
ldr lr, _mt_client_context_ptr
/* buffer user pc */
ldr r0, [lr, #15*4]
@ -154,7 +156,7 @@
orr r8, #64
msr spsr, r8
subs pc, lr, #4 /* resume previous exception */
1:
1:
.endm /* _fiq_check_prior_mode */
/**
@ -168,14 +170,14 @@
/**
* Switch from an interrupted vm to the kernel context
* 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 */
ldr sp, _mt_client_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 */
@ -194,7 +196,7 @@
_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 */
adr r0, _mt_master_context_begin /* get kernel context pointer */
add r0, r0, #13*4 /* load kernel context */
ldmia r0, {sp,lr,pc}
.endm /* _vm_to_kernel */
@ -211,10 +213,10 @@
/**
* Switch from kernel context to a vm
* Switch from kernel context to a VM
*/
.macro _kernel_to_vm
ldr r0, _mt_context_ptr /* get vm context pointer */
ldr r0, _mt_client_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 */
@ -223,7 +225,7 @@
_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 */
ldr sp, _mt_client_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 */
@ -254,23 +256,23 @@
.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 */
_fiq_check_prior_mode /* fast interrupt request */
_user_to_kernel_pic 6, 4
b _rst_entry /* 0x00: reset */
b _und_entry /* 0x04: undefined instruction */
b _svc_entry /* 0x08: supervisor call */
b _pab_entry /* 0x0c: prefetch abort */
b _dab_entry /* 0x10: data abort */
nop /* 0x14: reserved */
b _irq_entry /* 0x18: interrupt request */
_fiq_check_prior_mode /* 0x1c: fast interrupt request */
_user_to_kernel_pic 7, 4
/* PICs that switch from an user exception to the kernel */
_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
_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
/* kernel must jump to this point to switch to a user context */
.p2align 2
@ -280,15 +282,15 @@
/* leave some space for the kernel context */
.p2align 2
.global _mt_kernel_context_begin
_mt_kernel_context_begin: .space 32*4
.global _mt_kernel_context_end
_mt_kernel_context_end:
.global _mt_master_context_begin
_mt_master_context_begin: .space 32*4
.global _mt_master_context_end
_mt_master_context_end:
/* pointer to the context backup space */
.p2align 2
.global _mt_context_ptr
_mt_context_ptr: .long 0
.global _mt_client_context_ptr
_mt_client_context_ptr: .long 0
/* a local word-sized buffer */
.p2align 2
@ -302,7 +304,7 @@
* On vm exceptions the CPU has to jump to one of the following
* 7 entry vectors to switch to a kernel context.
*/
.p2align 2
.p2align 4
.global _mon_kernel_entry
_mon_kernel_entry:
b _mon_rst_entry /* reset */
@ -312,15 +314,15 @@
b _mon_dab_entry /* data abort */
nop /* reserved */
b _mon_irq_entry /* interrupt request */
_vm_to_kernel 6, 4 /* fast interrupt request */
_vm_to_kernel 7, 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
_mon_rst_entry: _vm_to_kernel 1, 0
_mon_und_entry: _vm_to_kernel 2, 4
_mon_svc_entry: _vm_to_kernel 3, 0
_mon_pab_entry: _vm_to_kernel 4, 4
_mon_dab_entry: _vm_to_kernel 5, 8
_mon_irq_entry: _vm_to_kernel 6, 4
/* kernel must jump to this point to switch to a vm */
.p2align 2

View File

@ -0,0 +1,21 @@
/*
* \brief Platform specific parts of kernel
* \author Martin Stein
* \date 2012-04-23
*/
/*
* 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__KERNEL_SUPPORT_H_
#define _SRC__CORE__KERNEL_SUPPORT_H_
/* local includes */
#include <arm1136/kernel_support.h>
#endif /* _SRC__CORE__KERNEL_SUPPORT_H_ */

View File

@ -0,0 +1,96 @@
/*
* \brief Platform implementations specific for base-hw and i.MX31
* \author Norman Feske
* \date 2012-08-30
*/
/*
* 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>
#include <imx31/pic.h>
/* core includes */
#include <platform.h>
using namespace Genode;
Native_region * Platform::_ram_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ Board::CSD0_SDRAM_BASE, Board::CSD0_SDRAM_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Imx31::Pic::MAX_INTERRUPT_ID + 1 }
};
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 */
{ Board::EPIT_1_IRQ, 1 },
/* core UART */
{ Board::UART_1_IRQ, 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Native_region * Platform::_mmio_regions(unsigned const i)
{
static Native_region _regions[] =
{
/*
* The address range below 0x30000000 is used for secure ROM, ROM, and
* internal RAM.
*/
{ 0x30000000, 0x50000000 },
/*
* The address range between 0x8000000 and 0x9fffffff is designated for
* SDRAM. The remaining address range is populated with peripherals.
*/
{ 0xa0000000, 0x24000000 }
};
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 UART */
{ Board::UART_1_MMIO_BASE, Board::UART_1_MMIO_SIZE },
/* core timer */
{ Board::EPIT_1_MMIO_BASE, Board::EPIT_1_MMIO_SIZE },
/* interrupt controller */
{ Board::AVIC_MMIO_BASE, Board::AVIC_MMIO_SIZE },
/* bus interface controller */
{ Board::AIPS_1_MMIO_BASE, Board::AIPS_1_MMIO_SIZE },
{ Board::AIPS_2_MMIO_BASE, Board::AIPS_2_MMIO_SIZE },
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}

View File

@ -0,0 +1,26 @@
/*
* \brief Software TLB controls specific for the i.MX31
* \author Norman Feske
* \date 2012-08-30
*/
/*
* 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__IMX31__SOFTWARE_TLB_H_
#define _SRC__CORE__IMX31__SOFTWARE_TLB_H_
/* Genode includes */
#include <arm/v6/section_table.h>
/**
* Software TLB controls
*/
class Software_tlb : public Arm_v6::Section_table { };
#endif /* _SRC__CORE__IMX31__SOFTWARE_TLB_H_ */

View File

@ -0,0 +1,11 @@
#
# \brief Makefile for core
# \author Martin Stein
# \date 2012-10-04
#
# declare wich specs must be given to build this target
REQUIRES = platform_imx31
# include less specific target parts
include $(REP_DIR)/src/core/target.inc

View File

@ -0,0 +1,660 @@
/*
* \brief Simple driver for the ARM core
* \author Martin stein
* \date 2012-09-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 _INCLUDE__ARM__CPU_H_
#define _INCLUDE__ARM__CPU_H_
/* Genode includes */
#include <util/register.h>
#include <cpu/cpu_state.h>
namespace Arm
{
using namespace Genode;
/**
* ARM core
*/
struct Cpu
{
enum {
TTBCR_N = 0,
EXCEPTION_ENTRY = 0xffff0000,
DATA_ACCESS_ALIGNM = 4,
};
/**
* Cache type register
*/
struct Ctr : Register<32>
{
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c0, c0, 1" : [v]"=r"(v) :: );
return v;
}
};
/**
* System control register
*/
struct Sctlr : Register<32>
{
struct M : Bitfield<0,1> { }; /* enable MMU */
struct A : Bitfield<1,1> { }; /* strict data addr. alignment on */
struct C : Bitfield<2,1> { }; /* enable L1 data cache */
struct Z : Bitfield<11,1> { }; /* enable program flow prediction */
struct I : Bitfield<12,1> { }; /* enable L1 instruction-cache */
struct V : Bitfield<13,1> /* select exception-entry base */
{
enum { XFFFF0000 = 1 };
};
struct Rr : Bitfield<14,1> /* replacement strategy */
{
enum { RANDOM = 0 };
};
struct Fi : Bitfield<21,1> { }; /* enable fast IRQ config */
struct Ve : Bitfield<24,1> /* interrupt vector config */
{
enum { FIXED = 0 };
};
struct Ee : Bitfield<25,1> { }; /* raise CPSR.E on exceptions */
/**
* Value for the switch to virtual mode in kernel
*/
static access_t init_virt_kernel()
{
return M::bits(1) |
A::bits(0) |
C::bits(0) |
Z::bits(0) |
I::bits(0) |
V::bits(V::XFFFF0000) |
Rr::bits(Rr::RANDOM) |
Fi::bits(0) |
Ve::bits(Ve::FIXED) |
Ee::bits(0);
}
/**
* Value for the initial kernel entry
*/
static access_t init_phys_kernel()
{
return M::bits(0) |
A::bits(0) |
C::bits(0) |
Z::bits(0) |
I::bits(0) |
V::bits(V::XFFFF0000) |
Rr::bits(Rr::RANDOM) |
Fi::bits(0) |
Ve::bits(Ve::FIXED) |
Ee::bits(0);
}
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c1, c0, 0" : [v]"=r"(v) :: );
return v;
}
/**
* Write register value
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c1, c0, 0" :: [v]"r"(v) : );
}
};
/**
* Translation table base control register
*/
struct Ttbcr : Register<32>
{
struct N : Bitfield<0, 3> { }; /* base address width */
/**
* Write register, only in privileged CPU mode
*/
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %[v], c2, c0, 2" :: [v]"r"(v) : ); }
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c2, c0, 2" : [v]"=r"(v) :: );
return v;
}
/**
* Value for the switch to virtual mode in kernel
*/
static access_t init_virt_kernel() { return N::bits(TTBCR_N); }
};
/**
* Translation table base register 0
*/
struct Ttbr0 : Register<32>
{
struct Irgn_1 : Bitfield<0,1> /* inner cachable mode */
{
enum { NON_CACHEABLE = 0 };
};
struct S : Bitfield<1,1> { }; /* shareable */
struct Rgn : Bitfield<3, 2> /* outer cachable attributes */
{
enum { NON_CACHEABLE = 0 };
};
struct Ba : Bitfield<14-TTBCR_N, 18+TTBCR_N> { }; /* translation
* table base */
/**
* Write register, only in privileged CPU mode
*/
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %[v], c2, c0, 0" :: [v]"r"(v) : ); }
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c2, c0, 0" : [v]"=r"(v) :: );
return v;
}
/**
* Value for the switch to virtual mode in kernel
*
* \param sect_table pointer to initial section table
*/
static access_t init_virt_kernel(addr_t const sect_table)
{
return S::bits(0) |
Irgn_1::bits(Irgn_1::NON_CACHEABLE) |
Rgn::bits(Rgn::NON_CACHEABLE) |
Ba::masked((addr_t)sect_table);
}
};
/**
* Domain access control register
*/
struct Dacr : Register<32>
{
enum Dx_values { NO_ACCESS = 0, CLIENT = 1 };
/**
* Access values for the 16 available domains
*/
struct D0 : Bitfield<0,2> { };
struct D1 : Bitfield<2,2> { };
struct D2 : Bitfield<4,2> { };
struct D3 : Bitfield<6,2> { };
struct D4 : Bitfield<8,2> { };
struct D5 : Bitfield<10,2> { };
struct D6 : Bitfield<12,2> { };
struct D7 : Bitfield<14,2> { };
struct D8 : Bitfield<16,2> { };
struct D9 : Bitfield<18,2> { };
struct D10 : Bitfield<20,2> { };
struct D11 : Bitfield<22,2> { };
struct D12 : Bitfield<24,2> { };
struct D13 : Bitfield<26,2> { };
struct D14 : Bitfield<28,2> { };
struct D15 : Bitfield<30,2> { };
/**
* Write register, only in privileged CPU mode
*/
static void write(access_t const v) {
asm volatile ("mcr p15, 0, %[v], c3, c0, 0" :: [v]"r"(v) : ); }
/**
* Initialize for Genodes operational mode
*/
static access_t init_virt_kernel()
{
return D0::bits(CLIENT) | D1::bits(NO_ACCESS) |
D2::bits(NO_ACCESS) | D3::bits(NO_ACCESS) |
D4::bits(NO_ACCESS) | D5::bits(NO_ACCESS) |
D6::bits(NO_ACCESS) | D7::bits(NO_ACCESS) |
D8::bits(NO_ACCESS) | D9::bits(NO_ACCESS) |
D10::bits(NO_ACCESS) | D11::bits(NO_ACCESS) |
D12::bits(NO_ACCESS) | D13::bits(NO_ACCESS) |
D14::bits(NO_ACCESS) | D15::bits(NO_ACCESS);
}
};
/**
* Context identification register
*/
struct Cidr : Register<32>
{
/**
* Write register value
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c13, c0, 1" :: [v]"r"(v) : );
}
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c13, c0, 1" : [v]"=r"(v) :: );
return v;
}
};
/**
* Program status register
*/
struct Psr : Register<32>
{
struct M : Bitfield<0,5> /* processor mode */
{
enum { USER = 0b10000, SUPERVISOR = 0b10011 };
};
struct T : Bitfield<5,1> /* instruction state */
{
enum { ARM = 0 };
};
struct F : Bitfield<6,1> { }; /* FIQ disable */
struct I : Bitfield<7,1> { }; /* IRQ disable */
struct A : Bitfield<8,1> { }; /* asynchronous abort disable */
struct E : Bitfield<9,1> /* load/store endianess */
{
enum { LITTLE = 0 };
};
struct J : Bitfield<24,1> /* instruction state */
{
enum { ARM = 0 };
};
/**
* Read register
*/
static access_t read()
{
access_t v;
asm volatile ("mrs %[v], cpsr" : [v] "=r" (v) : : );
return v;
}
/**
* Write register
*/
static void write(access_t const v) {
asm volatile ("msr cpsr, %[v]" : : [v] "r" (v) : ); }
/**
* Initial value for a user execution context with trustzone
*
* FIXME: This function should not be declared in 'Arm' but in
* 'Arm_v7', but for now the declaration is necessary
* because of 'User_context::User_context()'.
*/
inline static access_t init_user_with_trustzone();
/**
* Initial value for an userland execution context
*/
static access_t init_user()
{
return M::bits(M::USER) |
T::bits(T::ARM) |
F::bits(1) |
I::bits(0) |
A::bits(1) |
E::bits(E::LITTLE) |
J::bits(J::ARM);
}
/**
* Initial value for the kernel execution context
*/
static access_t init_kernel()
{
return M::bits(M::SUPERVISOR) |
T::bits(T::ARM) |
F::bits(1) |
I::bits(1) |
A::bits(1) |
E::bits(E::LITTLE) |
J::bits(J::ARM);
}
};
/**
* Common parts of fault status registers
*/
struct Fsr : Register<32>
{
/**
* Fault status encoding
*/
enum Fault_status
{
SECTION_TRANSLATION = 5,
PAGE_TRANSLATION = 7,
};
struct Fs_3_0 : Bitfield<0, 4> { }; /* fault status */
struct Fs_4 : Bitfield<10, 1> { }; /* fault status */
};
/**
* Instruction fault status register
*/
struct Ifsr : Fsr
{
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c5, c0, 1" : [v]"=r"(v) :: );
return v;
}
/**
* Read fault status
*/
static Fault_status fault_status()
{
access_t const v = read();
return (Fault_status)(Fs_3_0::get(v) |
(Fs_4::get(v) << Fs_3_0::WIDTH));
}
};
/**
* Data fault status register
*/
struct Dfsr : Fsr
{
struct Wnr : Bitfield<11, 1> { }; /* write not read bit */
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c5, c0, 0" : [v]"=r"(v) :: );
return v;
}
/**
* Read fault status
*/
static Fault_status fault_status() {
access_t const v = read();
return (Fault_status)(Fs_3_0::get(v) |
(Fs_4::get(v) << Fs_3_0::WIDTH));
}
};
/**
* Data fault address register
*/
struct Dfar : Register<32>
{
/**
* Read register value
*/
static access_t read() {
access_t v;
asm volatile ("mrc p15, 0, %[v], c6, c0, 0" : [v]"=r"(v) :: );
return v;
}
};
/**
* Extend basic CPU state by members relevant for 'base-hw' only
*/
struct Context : Cpu_state
{
/**********************************************************
** The offset and width of any of these classmembers is **
** silently expected to be this way by several assembly **
** files. So take care if you attempt to change them. **
**********************************************************/
uint32_t cidr; /* context ID register backup */
uint32_t section_table; /* base address of applied section table */
/***************
** Accessors **
***************/
void software_tlb(addr_t const st) { section_table = st; }
addr_t software_tlb() const { return section_table; }
void protection_domain(unsigned const id) { cidr = id; }
};
/**
* An usermode execution state
*/
struct User_context : Context
{
/**
* Constructor
*/
User_context();
/***************************************************
** Communication between user and context holder **
***************************************************/
void user_arg_0(unsigned const arg) { r0 = arg; }
void user_arg_1(unsigned const arg) { r1 = arg; }
void user_arg_2(unsigned const arg) { r2 = arg; }
void user_arg_3(unsigned const arg) { r3 = arg; }
void user_arg_4(unsigned const arg) { r4 = arg; }
void user_arg_5(unsigned const arg) { r5 = arg; }
void user_arg_6(unsigned const arg) { r6 = arg; }
void user_arg_7(unsigned const arg) { r7 = arg; }
unsigned user_arg_0() const { return r0; }
unsigned user_arg_1() const { return r1; }
unsigned user_arg_2() const { return r2; }
unsigned user_arg_3() const { return r3; }
unsigned user_arg_4() const { return r4; }
unsigned user_arg_5() const { return r5; }
unsigned user_arg_6() const { return r6; }
unsigned user_arg_7() const { return r7; }
/**
* Read a general purpose register
*
* \param id ID of the targeted register
* \param v Holds register value if this returns 1
*/
bool get_gpr(unsigned id, unsigned & v) const
{
switch(id)
{
case 0: v = r0; return 1;
case 1: v = r1; return 1;
case 2: v = r2; return 1;
case 3: v = r3; return 1;
case 4: v = r4; return 1;
case 5: v = r5; return 1;
case 6: v = r6; return 1;
case 7: v = r7; return 1;
case 8: v = r8; return 1;
case 9: v = r9; return 1;
case 10: v = r10; return 1;
case 11: v = r11; return 1;
case 12: v = r12; return 1;
case 13: v = sp; return 1;
case 14: v = lr; return 1;
case 15: v = ip; return 1;
}
return 0;
}
/**
* Override a general purpose register
*
* \param id ID of the targeted register
* \param v Has been written to register if this returns 1
*/
bool set_gpr(unsigned id, unsigned const v)
{
switch(id)
{
case 0: r0 = v; return 1;
case 1: r1 = v; return 1;
case 2: r2 = v; return 1;
case 3: r3 = v; return 1;
case 4: r4 = v; return 1;
case 5: r5 = v; return 1;
case 6: r6 = v; return 1;
case 7: r7 = v; return 1;
case 8: r8 = v; return 1;
case 9: r9 = v; return 1;
case 10: r10 = v; return 1;
case 11: r11 = v; return 1;
case 12: r12 = v; return 1;
case 13: sp = v; return 1;
case 14: lr = v; return 1;
case 15: ip = v; return 1;
}
return 0;
}
/**
* Check if a pagefault has occured due to a translation miss
*
* \param va holds the virtual fault-address if this returns 1
* \param w wether it is a write fault if this returns 1
*/
bool translation_miss(addr_t & va, bool & w) const
{
/* determine fault type */
switch (cpu_exception) {
case PREFETCH_ABORT: {
/* check if fault was caused by a translation miss */
Ifsr::Fault_status const fs = Ifsr::fault_status();
if (fs == Ifsr::SECTION_TRANSLATION ||
fs == Ifsr::PAGE_TRANSLATION)
{
/* fetch fault data */
w = 0;
va = ip;
return 1;
}
return 0; }
case DATA_ABORT: {
/* check if fault was caused by translation miss */
Dfsr::Fault_status const fs = Dfsr::fault_status();
if(fs == Dfsr::SECTION_TRANSLATION ||
fs == Dfsr::PAGE_TRANSLATION)
{
/* fetch fault data */
Dfsr::access_t const dfsr = Dfsr::read();
w = Dfsr::Wnr::get(dfsr);
va = Dfar::read();
return 1;
}
return 0; }
default: return 0;
}
}
};
/**
* Flush all instruction caches
*/
__attribute__((always_inline)) static void flush_instr_caches() {
asm volatile ("mcr p15, 0, %[rd], c7, c5, 0" :: [rd]"r"(0) : ); }
/**
* Flush all data caches
*/
inline static void flush_data_caches();
/**
* Flush all caches
*/
static void flush_caches()
{
flush_data_caches();
flush_instr_caches();
}
/**
* Invalidate all TLB entries of one address space
*
* \param pid ID of the targeted address space
*/
static void flush_tlb_by_pid(unsigned const pid)
{
asm volatile ("mcr p15, 0, %[pid], c8, c7, 2" :: [pid]"r"(pid) : );
flush_caches();
}
/**
* Invalidate all TLB entries
*/
static void flush_tlb()
{
asm volatile ("mcr p15, 0, %[rd], c8, c7, 0" :: [rd]"r"(0) : );
flush_caches();
}
};
}
#endif /* _INCLUDE__ARM__CPU_H_ */

View File

@ -1,5 +1,5 @@
/*
* \brief Driver for Cortex A9 section tables as software TLB
* \brief Driver for ARM section tables
* \author Martin Stein
* \date 2012-02-22
*/
@ -11,20 +11,21 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__DRIVERS__CPU__CORTEX_A9__SECTION_TABLE_H_
#define _INCLUDE__DRIVERS__CPU__CORTEX_A9__SECTION_TABLE_H_
#ifndef _INCLUDE__ARM__SECTION_TABLE_H_
#define _INCLUDE__ARM__SECTION_TABLE_H_
/* Genode includes */
#include <util/register.h>
#include <base/printf.h>
#include <cortex_a9/cpu/core.h>
namespace Genode
namespace Arm
{
using namespace Genode;
/**
* Check if 'p' is aligned to 1 << 'alignm_log2'
*/
bool inline aligned(addr_t const a, unsigned long const alignm_log2)
inline bool aligned(addr_t const a, unsigned long const alignm_log2)
{
return a == ((a >> alignm_log2) << alignm_log2);
}
@ -53,7 +54,6 @@ namespace Genode
};
};
/**
* Permission configuration according to given access rights
*
@ -77,7 +77,7 @@ namespace Genode
Ap_2::bits(Ap_2::KERNEL_RW_OR_NO_ACCESS),
Ap_1_0::bits(Ap_1_0::USER_NO_ACCESS) | /* -k */
Ap_2::bits(Ap_2::KERNEL_RO_ACCESS) }, {
Ap_2::bits(Ap_2::KERNEL_RO_ACCESS) }, {
Ap_1_0::bits(Ap_1_0::KERNEL_AND_USER_SAME_ACCESS) | /* w- */
Ap_2::bits(Ap_2::KERNEL_RW_OR_NO_ACCESS),
@ -91,11 +91,11 @@ namespace Genode
}
/**
* Cortex A9 second level translation table
* Second level translation table
*
* A table is dedicated to either secure or non-secure mode. All
* translations done by this table apply domain 0. They are not shareable
* and have zero-filled memory region attributes.
* translations done by this table apply to domain 0. They are not
* shareable and have zero-filled memory region attributes.
*/
class Page_table
{
@ -197,32 +197,6 @@ namespace Genode
};
};
/**
* Large page descriptor structure
*
* Must always occur as group of 16 consecutive copies, this groups
* must be aligned on a 16 word boundary (Represents 64KB = 16 *
* Small page size)
*/
struct Large_page : Descriptor
{
enum { VIRT_SIZE_LOG2 = _64KB_LOG2,
VIRT_SIZE = 1 << VIRT_SIZE_LOG2,
VIRT_BASE_MASK = ~((1 << VIRT_SIZE_LOG2) - 1) };
struct B : Bitfield<2, 1> { }; /* part of the memory region attributes */
struct C : Bitfield<3, 1> { }; /* part of the memory region attributes */
struct Ap_1_0 : Bitfield<4, 2>, /* access permission bits [1:0] */
Ap_1_0_bitfield { };
struct Ap_2 : Bitfield<9, 1>, /* access permission bits [2] */
Ap_2_bitfield { };
struct S : Bitfield<10, 1> { }; /* shareable bit */
struct Ng : Bitfield<11, 1> { }; /* not global bit */
struct Tex : Bitfield<12, 3> { }; /* part of the memory region attributes */
struct Xn : Bitfield<15, 1> { }; /* execute never bit */
struct Pa_31_16 : Bitfield<16, 16> { }; /* physical address bits [31:16] */
};
/**
* Small page descriptor structure
*/
@ -234,17 +208,17 @@ namespace Genode
VIRT_BASE_MASK = ~((1 << VIRT_SIZE_LOG2) - 1)
};
struct Xn : Bitfield<0, 1> { }; /* execute never bit */
struct B : Bitfield<2, 1> { }; /* part of the memory region attributes */
struct C : Bitfield<3, 1> { }; /* part of the memory region attributes */
struct Ap_1_0 : Bitfield<4, 2>, /* access permission bits [1:0] */
struct Xn : Bitfield<0, 1> { }; /* execute never */
struct B : Bitfield<2, 1> { }; /* mem region attr. */
struct C : Bitfield<3, 1> { }; /* mem region attr. */
struct Ap_1_0 : Bitfield<4, 2>, /* access permission */
Ap_1_0_bitfield { };
struct Tex : Bitfield<6, 3> { }; /* part of the memory region attributes */
struct Ap_2 : Bitfield<9, 1>, /* access permission bits [2] */
struct Tex : Bitfield<6, 3> { }; /* mem region attr. */
struct Ap_2 : Bitfield<9, 1>, /* access permission */
Ap_2_bitfield { };
struct S : Bitfield<10, 1> { }; /* shareable bit */
struct Ng : Bitfield<11, 1> { }; /* not global bit */
struct Pa_31_12 : Bitfield<12, 20> { }; /* physical address bits [31:12] */
struct Pa_31_12 : Bitfield<12, 20> { }; /* physical base */
};
/*
@ -259,12 +233,11 @@ namespace Genode
/**
* Get entry index by virtual offset
*
* \param i is overridden with the resulting index
* \param i is overridden with the index if call returns 0
* \param vo virtual offset relative to the virtual table base
*
* \retval 0 on success
* \retval <0 If virtual offset couldn't be resolved.
* In this case 'i' reside invalid
* \retval <0 translation failed
*/
int _index_by_vo (unsigned long & i, addr_t const vo) const
{
@ -286,13 +259,12 @@ namespace Genode
Page_table()
{
/* check table alignment */
if (!aligned((addr_t)this, ALIGNM_LOG2)
|| (addr_t)this != (addr_t)_entries)
if (!aligned((addr_t)this, ALIGNM_LOG2) ||
(addr_t)this != (addr_t)_entries)
{
PDBG("Insufficient table alignment");
while (1) ;
}
/* start with an empty table */
for (unsigned i = 0; i <= MAX_INDEX; i++)
Descriptor::invalidate(_entries[i]);
@ -341,9 +313,9 @@ namespace Genode
{
/* compose new descriptor value */
Descriptor::access_t entry =
access_permission_bits<Small_page>(w, x, k)
| Small_page::Ng::bits(!g)
| Small_page::Pa_31_12::masked(pa);
access_permission_bits<Small_page>(w, x, k) |
Small_page::Ng::bits(!g) |
Small_page::Pa_31_12::masked(pa);
Descriptor::type(entry, Descriptor::SMALL_PAGE);
/* check if we can we write to the targeted entry */
@ -375,7 +347,7 @@ namespace Genode
* represented by this table
* \param size region size
*/
void remove_region (addr_t const vo, size_t const size)
void remove_region(addr_t const vo, size_t const size)
{
/* traverse all possibly affected entries */
addr_t residual_vo = vo;
@ -389,30 +361,28 @@ namespace Genode
if (_index_by_vo(i, residual_vo)) return;
/* update current entry and recalculate residual region */
switch (Descriptor::type(_entries[i]))
{
case Descriptor::FAULT:
{
switch (Descriptor::type(_entries[i])) {
case Descriptor::FAULT: {
residual_vo = (residual_vo & Fault::VIRT_BASE_MASK)
+ Fault::VIRT_SIZE;
break;
}
case Descriptor::SMALL_PAGE:
{
break; }
case Descriptor::SMALL_PAGE: {
residual_vo = (residual_vo & Small_page::VIRT_BASE_MASK)
+ Small_page::VIRT_SIZE;
Descriptor::invalidate(_entries[i]);
break;
}
case Descriptor::LARGE_PAGE:
{
break; }
case Descriptor::LARGE_PAGE: {
PDBG("Removal of large pages not implemented");
while (1) ;
break;
}
break; }
}
}
return;
}
/**
@ -429,13 +399,13 @@ namespace Genode
} __attribute__((aligned(1<<Page_table::ALIGNM_LOG2)));
/**
* Cortex A9 first level translation table
* First level translation table
*
* A table is dedicated to either secure or non-secure mode. All
* translations done by this table apply domain 0. They are not shareable
* and have zero-filled memory region attributes. The size of this table is
* fixed to such a value that this table translates a space wich is
* addressable by 32 bit.
* translations done by this table apply to domain 0. They are not
* shareable and have zero-filled memory region attributes. The size
* of this table is fixed to such a value that this table translates
* a space wich is addressable by 32 bit.
*/
class Section_table
{
@ -443,6 +413,8 @@ namespace Genode
_16KB_LOG2 = 14,
_1MB_LOG2 = 20,
_16MB_LOG2 = 24,
DOMAIN = 0,
};
public:
@ -458,12 +430,10 @@ namespace Genode
MAX_COSTS_PER_TRANSLATION = sizeof(Page_table),
MAX_TRANSL_SIZE_LOG2 = 20,
MIN_TRANSL_SIZE_LOG2 = 12,
MAX_PAGE_SIZE_LOG2 = 20,
MIN_PAGE_SIZE_LOG2 = 12,
};
protected:
/**
* A first level translation descriptor
*/
@ -474,8 +444,8 @@ namespace Genode
*/
enum Type { FAULT, PAGE_TABLE, SECTION, SUPERSECTION };
struct Type_1 : Bitfield<0, 2> { }; /* entry type encoding 1 */
struct Type_2 : Bitfield<18, 1> { }; /* entry type encoding 2 */
struct Type_1 : Bitfield<0, 2> { }; /* entry type code 1 */
struct Type_2 : Bitfield<18, 1> { }; /* entry type code 2 */
/**
* Get descriptor type of 'v'
@ -538,43 +508,23 @@ namespace Genode
*/
struct Page_table_descriptor : Descriptor
{
struct Ns : Bitfield<3, 1> { }; /* non-secure bit */
struct Domain : Bitfield<5, 4> { }; /* domain field */
struct Pa_31_10 : Bitfield<10, 22> { }; /* physical address bits [31:10] */
struct Domain : Bitfield<5, 4> { }; /* domain */
struct Pa_31_10 : Bitfield<10, 22> { }; /* physical base */
/**
* Compose descriptor value
*/
static access_t create(Page_table * const pt)
{
access_t v = Domain::bits(DOMAIN) |
Pa_31_10::masked((addr_t)pt);
Descriptor::type(v, Descriptor::PAGE_TABLE);
return v;
}
};
/**
* Supersection-descriptor structure
*
* Must always occur as group of 16 consecutive copies, this groups
* must be aligned on a 16 word boundary.
*/
struct Supersection : Descriptor
{
enum {
VIRT_SIZE_LOG2 = _16MB_LOG2,
VIRT_SIZE = 1 << VIRT_SIZE_LOG2,
VIRT_BASE_MASK = ~((1 << VIRT_SIZE_LOG2) - 1)
};
struct B : Bitfield<2, 1> { }; /* part of the memory region attributes */
struct C : Bitfield<3, 1> { }; /* part of the memory region attributes */
struct Xn : Bitfield<4, 1> { }; /* execute never bit */
struct Pa_39_36 : Bitfield<5, 4> { }; /* extendend physical address bits [39:36] */
struct Ap_1_0 : Bitfield<10, 2>, /* access permission bits [1:0] */
Ap_1_0_bitfield { };
struct Tex : Bitfield<12, 3> { }; /* part of the memory region attributes */
struct Ap_2 : Bitfield<15, 1>, /* access permission bits [2] */
Ap_2_bitfield { };
struct S : Bitfield<16, 1> { }; /* shareable bit */
struct Ng : Bitfield<17, 1> { }; /* not global bit */
struct Ns : Bitfield<19, 1> { }; /* non-secure bit */
struct Pa_35_32 : Bitfield<20, 4> { }; /* extendend physical address bits [35:32] */
struct Pa_31_24 : Bitfield<24, 8> { }; /* physical address bits [31:24] */
};
/**
* Section-descriptor structure
* Section translation descriptor
*/
struct Section : Descriptor
{
@ -584,29 +534,42 @@ namespace Genode
VIRT_BASE_MASK = ~((1 << VIRT_SIZE_LOG2) - 1)
};
struct B : Bitfield<2, 1> { }; /* part of the memory region attributes */
struct C : Bitfield<3, 1> { }; /* part of the memory region attributes */
struct Xn : Bitfield<4, 1> { }; /* execute never bit */
struct Domain : Bitfield<5, 4> { }; /* domain field */
struct Ap_1_0 : Bitfield<10, 2>, /* access permission bits [1:0] */
struct B : Bitfield<2, 1> { }; /* mem. region attr. */
struct C : Bitfield<3, 1> { }; /* mem. region attr. */
struct Xn : Bitfield<4, 1> { }; /* execute never bit */
struct Domain : Bitfield<5, 4> { }; /* domain */
struct Ap_1_0 : Bitfield<10, 2>, /* access permission */
Ap_1_0_bitfield { };
struct Tex : Bitfield<12, 3> { }; /* part of the memory region attributes */
struct Ap_2 : Bitfield<15, 1>, /* access permission bits [2] */
struct Tex : Bitfield<12, 3> { }; /* mem. region attr. */
struct Ap_2 : Bitfield<15, 1>, /* access permission */
Ap_2_bitfield { };
struct S : Bitfield<16, 1> { }; /* shareable bit */
struct Ng : Bitfield<17, 1> { }; /* not global bit */
struct Ns : Bitfield<19, 1> { }; /* non-secure bit */
struct Pa_31_20 : Bitfield<20, 12> { }; /* physical address bits [31:20] */
struct S : Bitfield<16, 1> { }; /* shared */
struct Ng : Bitfield<17, 1> { }; /* not global */
struct Pa_31_20 : Bitfield<20, 12> { }; /* physical base */
/**
* Compose descriptor value
*/
static access_t create(bool const w, bool const x,
bool const k, bool const g,
addr_t const pa)
{
access_t v = access_permission_bits<Section>(w, x, k) |
Domain::bits(DOMAIN) |
Ng::bits(!g) |
Pa_31_20::masked(pa);
Descriptor::type(v, Descriptor::SECTION);
return v;
}
};
protected:
/* table payload, must be the first member of this class */
Descriptor::access_t _entries[SIZE/sizeof(Descriptor::access_t)];
enum { MAX_INDEX = sizeof(_entries) / sizeof(_entries[0]) - 1 };
/* if this table dedicated to secure mode or to non-secure mode */
bool _secure;
/**
* Get entry index by virtual offset
*
@ -628,18 +591,17 @@ namespace Genode
public:
/**
* Constructor for a table that adopts current secure mode status
* Constructor
*/
Section_table() : _secure(Cortex_a9::secure_mode_active())
Section_table()
{
/* check table alignment */
/* check for appropriate positioning of the table */
if (!aligned((addr_t)this, ALIGNM_LOG2)
|| (addr_t)this != (addr_t)_entries)
{
PDBG("Insufficient table alignment");
while (1) ;
}
/* start with an empty table */
for (unsigned i = 0; i <= MAX_INDEX; i++)
Descriptor::invalidate(_entries[i]);
@ -657,6 +619,8 @@ namespace Genode
/**
* Insert one atomic translation into this table
*
* \param ST platform specific section-table type
* \param st platform specific section table
* \param vo offset of the virtual region represented
* by the translation within the virtual
* region represented by this table
@ -691,19 +655,23 @@ namespace Genode
* spans the the same virtual range and is not a link to another
* table level.
*/
template <typename ST>
unsigned long insert_translation(addr_t const vo, addr_t const pa,
unsigned long const size_log2,
bool const w, bool const x,
bool const k, bool const g,
ST * const st,
void * const extra_space = 0)
{
typedef typename ST::Section Section;
typedef typename ST::Page_table_descriptor Page_table_descriptor;
/* validate virtual address */
unsigned long i;
if (_index_by_vo (i, vo)) {
PDBG("Invalid virtual offset");
while (1) ;
}
/* select descriptor type by translation size */
if (size_log2 < Section::VIRT_SIZE_LOG2)
{
@ -723,11 +691,9 @@ namespace Genode
}
/* create and link page table */
pt = new (extra_space) Page_table();
_entries[i] = Page_table_descriptor::Ns::bits(!_secure)
| Page_table_descriptor::Pa_31_10::masked((addr_t)pt);
Descriptor::type(_entries[i], Descriptor::PAGE_TABLE);
_entries[i] = Page_table_descriptor::create(pt, st);
}
/* Request additional memory to create a page table */
/* request additional memory to create a page table */
else return Page_table::SIZE_LOG2;
/* insert translation */
@ -738,12 +704,8 @@ namespace Genode
if (size_log2 == Section::VIRT_SIZE_LOG2)
{
/* compose section descriptor */
Descriptor::access_t entry =
access_permission_bits<Section>(w, x, k)
| Section::Ns::bits(!_secure)
| Section::Ng::bits(!g)
| Section::Pa_31_20::masked(pa);
Descriptor::type(entry, Descriptor::SECTION);
Descriptor::access_t entry = Section::create(w, x, k,
g, pa, st);
/* check if we can we write to the targeted entry */
if (Descriptor::valid(_entries[i]))
@ -774,7 +736,7 @@ namespace Genode
* represented by this table
* \param size region size
*/
void remove_region (addr_t const vo, size_t const size)
void remove_region(addr_t const vo, size_t const size)
{
/* traverse all possibly affected entries */
addr_t residual_vo = vo;
@ -806,7 +768,7 @@ namespace Genode
- Section::Pa_31_20::masked(residual_vo);
pt->remove_region(pt_vo, residual_size);
/* Recalculate residual region */
/* recalculate residual region */
residual_vo = (residual_vo & Page_table::VIRT_BASE_MASK)
+ Page_table::VIRT_SIZE;
break;
@ -834,6 +796,7 @@ namespace Genode
* \param base base of regained mem portion if method returns 1
* \param s size of regained mem portion if method returns 1
*
* \retval 1 successfully regained memory
* \retval 0 no more memory to regain
*/
bool regain_memory (void * & base, size_t & s)
@ -860,5 +823,5 @@ namespace Genode
} __attribute__((aligned(1<<Section_table::ALIGNM_LOG2)));
}
#endif /* _INCLUDE__DRIVERS__CPU__CORTEX_A9__SECTION_TABLE_H_ */
#endif /* _INCLUDE__ARM__SECTION_TABLE_H_ */

View File

@ -0,0 +1,174 @@
/*
* \brief Simple driver for the ARMv6 CPU core
* \author Norman Feske
* \date 2012-08-30
*/
/*
* 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 _INCLUDE__ARM_V6__CPU_H_
#define _INCLUDE__ARM_V6__CPU_H_
/* Genode includes */
#include <drivers/board.h>
#include <base/printf.h>
/* core includes */
#include <arm/cpu.h>
namespace Arm_v6
{
using namespace Genode;
/**
* ARMv6 core
*/
struct Cpu : Arm::Cpu
{
/**
* Cache type register
*/
struct Ctr : Arm::Cpu::Ctr
{
struct P : Bitfield<23, 1> { }; /* page mapping restriction on */
};
/**
* System control register
*/
struct Sctlr : Arm::Cpu::Sctlr
{
struct W : Bitfield<3,1> { }; /* enable write buffer */
struct Unused_0 : Bitfield<4,3> { }; /* shall be ones */
struct B : Bitfield<7,1> /* Memory system endianess */
{
enum { LITTLE = 0 };
};
struct S : Bitfield<8,1> { }; /* enbale MMU protection */
struct R : Bitfield<9,1> { }; /* enbale ROM protection */
struct L4 : Bitfield<15,1> { }; /* raise T bit on LOAD-to-PC */
struct Dt : Bitfield<16,1> { }; /* global data TCM enable */
struct It : Bitfield<18,1> { }; /* global instruction TCM enable */
struct U : Bitfield<22,1> { }; /* enable unaligned data access */
struct Xp : Bitfield<23,1> { }; /* disable subpage AP bits */
struct Unused_1 : Bitfield<26,6> { }; /* shall not be modified */
/**
* Get static base value for writes
*/
static access_t base_value() {
return Unused_0::reg_mask() | Unused_1::masked(read()); }
/**
* Value for the switch to virtual mode in kernel
*/
static access_t init_virt_kernel()
{
return base_value() |
Arm::Cpu::Sctlr::init_virt_kernel() |
W::bits(0) |
B::bits(B::LITTLE) |
S::bits(0) |
R::bits(0) |
L4::bits(0) |
Dt::bits(0) |
It::bits(0) |
U::bits(0) |
Xp::bits(1);
}
/**
* Value for the initial kernel entry
*/
static access_t init_phys_kernel()
{
return base_value() |
Arm::Cpu::Sctlr::init_phys_kernel() |
W::bits(0) |
B::bits(B::LITTLE) |
S::bits(0) |
R::bits(0) |
L4::bits(0) |
Dt::bits(1) |
It::bits(1) |
U::bits(0) |
Xp::bits(1);
}
};
/**
* Translation table base control register 0
*/
struct Ttbr0 : Arm::Cpu::Ttbr0
{
struct P : Bitfield<2,1> { }; /* memory controller ECC enabled */
/**
* Value for the switch to virtual mode in kernel
*
* \param section_table initial section table
*/
static access_t init_virt_kernel(addr_t const sect_table)
{
return Arm::Cpu::Ttbr0::init_virt_kernel(sect_table) |
P::bits(0);
}
};
/**
* If page descriptor bits [13:12] are restricted
*/
static bool restricted_page_mappings() {
return Ctr::P::get(Ctr::read()); }
/**
* Configure this module appropriately for the first kernel run
*/
static void init_phys_kernel()
{
::Board::prepare_kernel();
Sctlr::write(Sctlr::init_phys_kernel());
flush_tlb();
/* check for mapping restrictions */
if (restricted_page_mappings()) {
PDBG("Insufficient driver for page tables");
while (1) ;
}
}
/**
* Switch to the virtual mode in kernel
*
* \param section_table section translation table of the initial
* address space this function switches to
* \param process_id process ID of the initial address space
*/
static void init_virt_kernel(addr_t const section_table,
unsigned long const process_id)
{
Cidr::write(process_id);
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init_virt_kernel(section_table));
Ttbcr::write(Ttbcr::init_virt_kernel());
Sctlr::write(Sctlr::init_virt_kernel());
}
};
}
void Arm::Cpu::flush_data_caches() {
asm volatile ("mcr p15, 0, %[rd], c7, c14, 0" :: [rd]"r"(0) : ); }
#endif /* _INCLUDE__ARM_V6__CPU_H_ */

View File

@ -0,0 +1,85 @@
/*
* \brief Driver for ARMv6 section tables
* \author Martin Stein
* \date 2012-02-22
*/
/*
* 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 _INCLUDE__ARM_V6__SECTION_TABLE_H_
#define _INCLUDE__ARM_V6__SECTION_TABLE_H_
/* core includes */
#include <arm/section_table.h>
namespace Arm_v6
{
using namespace Genode;
/**
* First level translation table
*/
class Section_table : public Arm::Section_table
{
public:
/**
* Link to second level translation-table
*/
struct Page_table_descriptor : Arm::Section_table::Page_table_descriptor
{
/**
* Compose descriptor value
*/
static access_t create(Arm::Page_table * const pt,
Section_table *)
{
return Arm::Section_table::Page_table_descriptor::create(pt);
}
};
/**
* Section translation descriptor
*/
struct Section : Arm::Section_table::Section
{
struct P : Bitfield<9, 1> { }; /* enable ECC */
/**
* Compose descriptor value
*/
static access_t create(bool const w, bool const x,
bool const k, bool const g,
addr_t const pa,
Section_table *)
{
return Arm::Section_table::Section::create(w, x, k, g, pa) |
P::bits(0);
}
};
/**
* Insert one atomic translation into this table
*
* For details see 'Arm::Section_table::insert_translation'
*/
unsigned long insert_translation(addr_t const vo, addr_t const pa,
unsigned long const size_log2,
bool const w, bool const x,
bool const k, bool const g,
void * const extra_space = 0)
{
return Arm::Section_table::
insert_translation<Section_table>(vo, pa, size_log2, w,
x, k, g, this, extra_space);
}
};
}
#endif /* _INCLUDE__ARM_V6__SECTION_TABLE_H_ */

View File

@ -0,0 +1,309 @@
/*
* \brief Simple driver for the ARMv7 core
* \author Martin stein
* \date 2011-11-03
*/
/*
* Copyright (C) 2011-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 _INCLUDE__ARM_V7__CPU_H_
#define _INCLUDE__ARM_V7__CPU_H_
/* Genode includes */
#include <drivers/board.h>
/* core includes */
#include <arm/cpu.h>
namespace Arm_v7
{
using namespace Genode;
/**
* ARMv7 core
*/
struct Cpu : Arm::Cpu
{
/**
* Secure configuration register
*/
struct Scr : Register<32>
{
struct Ns : Bitfield<0, 1> { }; /* not secure */
/**
* Read register value
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c1, c1, 0" : [v]"=r"(v) ::);
return v;
}
};
/**
* Non-secure access control register
*/
struct Nsacr : Register<32>
{
/************************************************
** Coprocessor 0-13 non-secure acccess enable **
************************************************/
struct Cpnsae10 : Bitfield<10, 1> { };
struct Cpnsae11 : Bitfield<11, 1> { };
};
/**
* System control register
*/
struct Sctlr : Arm::Cpu::Sctlr
{
struct Unused_0 : Bitfield<3,4> { }; /* shall be ~0 */
struct Sw : Bitfield<10,1> { }; /* support SWP and SWPB */
struct Unused_1 : Bitfield<16,1> { }; /* shall be ~0 */
struct Ha : Bitfield<17,1> { }; /* enable HW access flag */
struct Unused_2 : Bitfield<18,1> { }; /* shall be ~0 */
struct Unused_3 : Bitfield<22,2> { }; /* shall be ~0 */
struct Nmfi : Bitfield<27,1> { }; /* FIQs are non-maskable */
struct Tre : Bitfield<28,1> { }; /* remap TEX[2:1] for OS */
struct Afe : Bitfield<29,1> /* translation access perm. mode */
{
enum { FULL_RANGE_OF_PERMISSIONS = 0 };
};
struct Te : Bitfield<30,1> { }; /* do exceptions in Thumb state */
/**
* Static base value
*/
static access_t base_value()
{
return Unused_0::bits(~0) |
Unused_1::bits(~0) |
Unused_2::bits(~0) |
Unused_3::bits(~0);
}
/**
* Value for the first kernel run
*/
static access_t init_phys_kernel()
{
return base_value() |
Arm::Cpu::Sctlr::init_virt_kernel() |
Sw::bits(0) |
Ha::bits(0) |
Nmfi::bits(0) |
Tre::bits(0);
}
/**
* Value for the switch to virtual mode in kernel
*/
static access_t init_virt_kernel()
{
return base_value() |
Arm::Cpu::Sctlr::init_virt_kernel() |
Sw::bits(0) |
Ha::bits(0) |
Nmfi::bits(0) |
Tre::bits(0);
}
};
/**
* Translation table base register 0
*/
struct Ttbr0 : Arm::Cpu::Ttbr0
{
struct Nos : Bitfield<6,1> { }; /* not outer shareable */
struct Irgn_0 : Bitfield<6,1> /* inner cachable mode */
{
enum { NON_CACHEABLE = 0 };
};
/**
* Value for the switch to virtual mode in kernel
*
* \param sect_table pointer to initial section table
*/
static access_t init_virt_kernel(addr_t const sect_table)
{
return Arm::Cpu::Ttbr0::init_virt_kernel(sect_table) |
Nos::bits(0) |
Irgn_0::bits(Irgn_0::NON_CACHEABLE);
}
};
/**
* Translation table base control register
*/
struct Ttbcr : Arm::Cpu::Ttbcr
{
struct Pd0 : Bitfield<4,1> { }; /* disable walk for TTBR0 */
struct Pd1 : Bitfield<5,1> { }; /* disable walk for TTBR1 */
/**
* Value for the switch to virtual mode in kernel
*/
static access_t init_virt_kernel()
{
return Arm::Cpu::Ttbcr::init_virt_kernel() |
Pd0::bits(0) |
Pd1::bits(0);
}
};
/**
* Switch to the virtual mode in kernel
*
* \param section_table section translation table of the initial
* address space this function switches to
* \param process_id process ID of the initial address space
*/
static void init_virt_kernel(addr_t const section_table,
unsigned long const process_id)
{
Cidr::write(process_id);
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init_virt_kernel(section_table));
Ttbcr::write(Ttbcr::init_virt_kernel());
Sctlr::write(Sctlr::init_virt_kernel());
}
/**
* Configure this module appropriately for the first kernel run
*/
static void init_phys_kernel()
{
Psr::write(Psr::init_kernel());
flush_tlb();
}
/**
* Wether we are in secure mode
*/
static bool secure_mode()
{
if (!Board::SECURITY_EXTENSION) return 0;
return !Cpu::Scr::Ns::get(Cpu::Scr::read());
}
/******************************
** 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 const addr)
{
asm volatile ("mcr p15, 0, %[rd], c12, c0, 1" : : [rd] "r" (addr));
}
/**
* Enable access of co-processors cp10 and cp11 from non-secure mode.
*/
static inline void allow_coprocessor_nonsecure()
{
Nsacr::access_t rd = Nsacr::Cpnsae10::bits(1) |
Nsacr::Cpnsae11::bits(1);
asm volatile ("mcr p15, 0, %[rd], c1, c1, 2" : : [rd] "r" (rd));
}
};
}
/**************
** Arm::Cpu **
**************/
void Arm::Cpu::flush_data_caches()
{
/*
* FIXME This routine is taken from the ARMv7 reference manual by
* applying the inline-assembly framework and replacing 'Loop1'
* with '1:', 'Loop2' with '2:', 'Loop3' with '3:', 'Skip'
* with '4:' and 'Finished' with '5:'. It might get implemented
* with more beauty.
*/
asm volatile (
"mrc p15, 1, r0, c0, c0, 1\n" /* read CLIDR into R0 */
"ands r3, r0, #0x7000000\n"
"mov r3, r3, lsr #23\n" /* cache level value (naturally aligned) */
"beq 5f\n"
"mov r10, #0\n"
"1:\n"
"add r2, r10, r10, lsr #1\n" /* work out 3 x cachelevel */
"mov r1, r0, lsr r2\n" /* bottom 3 bits are the Cache type for this level */
"and r1, r1, #7\n" /* get those 3 bits alone */
"cmp r1, #2\n"
"blt 4f\n" /* no cache or only instruction cache at this level */
"mcr p15, 2, r10, c0, c0, 0\n" /* write CSSELR from R10 */
"isb\n" /* ISB to sync the change to the CCSIDR */
"mrc p15, 1, r1, c0, c0, 0\n" /* read current CCSIDR to R1 */
"and r2, r1, #0x7\n" /* extract the line length field */
"add r2, r2, #4\n" /* add 4 for the line length offset (log2 16 bytes) */
"ldr r4, =0x3ff\n"
"ands r4, r4, r1, lsr #3\n" /* R4 is the max number on the way size (right aligned) */
"clz r5, r4\n" /* R5 is the bit position of the way size increment */
"mov r9, r4\n" /* R9 working copy of the max way size (right aligned) */
"2:\n"
"ldr r7, =0x00007fff\n"
"ands r7, r7, r1, lsr #13\n" /* R7 is the max number of the index size (right aligned) */
"3:\n"
"orr r11, r10, r9, lsl r5\n" /* factor in the way number and cache number into R11 */
"orr r11, r11, r7, lsl r2\n" /* factor in the index number */
"mcr p15, 0, r11, c7, c10, 2\n" /* DCCSW, clean by set/way */
"subs r7, r7, #1\n" /* decrement the index */
"bge 3b\n"
"subs r9, r9, #1\n" /* decrement the way number */
"bge 2b\n"
"4:\n"
"add r10, r10, #2\n" /* increment the cache number */
"cmp r3, r10\n"
"bgt 1b\n"
"dsb\n"
"5:\n"
::: "r0", "r1", "r2", "r3", "r4",
"r5", "r7", "r9", "r10", "r11");
}
Arm::Cpu::Psr::access_t Arm::Cpu::Psr::init_user_with_trustzone()
{
return M::bits(M::USER) |
T::bits(T::ARM) |
F::bits(0) |
I::bits(1) |
A::bits(1) |
E::bits(E::LITTLE) |
J::bits(J::ARM);
}
#endif /* _INCLUDE__ARM_V7__CPU_H_ */

View File

@ -0,0 +1,107 @@
/*
* \brief Driver for ARMv7 section tables
* \author Martin Stein
* \date 2012-02-22
*/
/*
* 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 _INCLUDE__ARM_V7__SECTION_TABLE_H_
#define _INCLUDE__ARM_V7__SECTION_TABLE_H_
/* core includes */
#include <arm/section_table.h>
#include <arm/v7/cpu.h>
namespace Arm_v7
{
using namespace Genode;
/**
* ARMv7 first level translation table
*/
class Section_table : public Arm::Section_table
{
public:
/**
* Link to second level translation-table
*/
struct Page_table_descriptor : Arm::Section_table::Page_table_descriptor
{
struct Ns : Bitfield<3, 1> { }; /* non-secure bit */
/**
* Compose descriptor value
*/
static access_t create(Arm::Page_table * const pt,
Section_table * const st)
{
return Arm::Section_table::Page_table_descriptor::create(pt) |
Ns::bits(!st->secure());
}
};
/**
* Section translation descriptor
*/
struct Section : Arm::Section_table::Section
{
struct Ns : Bitfield<19, 1> { }; /* non-secure bit */
/**
* Compose descriptor value
*/
static access_t create(bool const w, bool const x,
bool const k, bool const g,
addr_t const pa,
Section_table * const st)
{
return Arm::Section_table::Section::create(w, x, k, g, pa) |
Ns::bits(!st->secure());
}
};
protected:
/* if this table is dedicated to secure mode or to non-secure mode */
bool _secure;
public:
/**
* Constructor
*/
Section_table() : _secure(Arm_v7::Cpu::secure_mode()) { }
/**
* Insert one atomic translation into this table
*
* For details see 'Arm::Section_table::insert_translation'
*/
unsigned long insert_translation(addr_t const vo, addr_t const pa,
unsigned long const size_log2,
bool const w, bool const x,
bool const k, bool const g,
void * const extra_space = 0)
{
return Arm::Section_table::
insert_translation<Section_table>(vo, pa, size_log2, w,
x, k, g, this, extra_space);
}
/***************
** Accessors **
***************/
bool secure() { return _secure; }
};
}
#endif /* _INCLUDE__ARM_V7__SECTION_TABLE_H_ */

View File

@ -0,0 +1,54 @@
/*
* \brief Simple driver for the Cortex A9
* \author Martin stein
* \date 2011-11-03
*/
/*
* Copyright (C) 2011-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 _INCLUDE__CORTEX_A9__CPU_H_
#define _INCLUDE__CORTEX_A9__CPU_H_
/* Genode includes */
#include <drivers/board.h>
/* core includes */
#include <arm/v7/cpu.h>
namespace Cortex_a9
{
using namespace Genode;
/**
* Cortex A9 CPU
*/
struct Cpu : Arm_v7::Cpu
{
enum
{
/* common */
CLK = Board::CORTEX_A9_CLOCK, /* CPU interface clock */
PERIPH_CLK = CLK, /* clock for CPU internal components */
/* interrupt controller */
PL390_DISTRIBUTOR_MMIO_BASE = Board::CORTEX_A9_PRIVATE_MEM_BASE + 0x1000,
PL390_DISTRIBUTOR_MMIO_SIZE = 0x1000,
PL390_CPU_MMIO_BASE = Board::CORTEX_A9_PRIVATE_MEM_BASE + 0x100,
PL390_CPU_MMIO_SIZE = 0x100,
/* timer */
PRIVATE_TIMER_MMIO_BASE = Board::CORTEX_A9_PRIVATE_MEM_BASE + 0x600,
PRIVATE_TIMER_MMIO_SIZE = 0x10,
PRIVATE_TIMER_IRQ = 29,
PRIVATE_TIMER_CLK = PERIPH_CLK
};
};
}
#endif /* _INCLUDE__CORTEX_A9__CPU_H_ */

View File

@ -1,683 +0,0 @@
/*
* \brief Simple Driver for the ARM Cortex A9
* \author Martin stein
* \date 2011-11-03
*/
/*
* Copyright (C) 2011-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 _INCLUDE__CORTEX_A9__CPU__CORE_H_
#define _INCLUDE__CORTEX_A9__CPU__CORE_H_
/* Genode includes */
#include <util/register.h>
#include <util/mmio.h>
#include <drivers/board.h>
#include <cpu/cpu_state.h>
#include <cortex_a9/cpu/timer.h>
namespace Genode
{
class Section_table;
/**
* Cortex A9 driver
*/
struct Cortex_a9
{
enum
{
/* common */
DATA_ACCESS_ALIGNM = 4,
CLK = Board::CORTEX_A9_CLOCK, /* CPU interface clock */
PERIPH_CLK = CLK, /* clock for CPU internal components */
MIN_PAGE_SIZE_LOG2 = 12,
MAX_PAGE_SIZE_LOG2 = 20,
HIGHEST_EXCEPTION_ENTRY = 0xffff0000,
/* interrupt controller */
PL390_DISTRIBUTOR_MMIO_BASE = Board::CORTEX_A9_PRIVATE_MEM_BASE + 0x1000,
PL390_DISTRIBUTOR_MMIO_SIZE = 0x1000,
PL390_CPU_MMIO_BASE = Board::CORTEX_A9_PRIVATE_MEM_BASE + 0x100,
PL390_CPU_MMIO_SIZE = 0x100,
/* timer */
PRIVATE_TIMER_MMIO_BASE = Board::CORTEX_A9_PRIVATE_MEM_BASE + 0x600,
PRIVATE_TIMER_MMIO_SIZE = 0x10,
PRIVATE_TIMER_IRQ = 29,
PRIVATE_TIMER_CLK = PERIPH_CLK
};
/**
* CPU local timer module
*/
class Private_timer : public Cortex_a9_timer<PRIVATE_TIMER_CLK>
{
public:
enum { IRQ = PRIVATE_TIMER_IRQ };
/**
* Constructor
*/
Private_timer() :
Cortex_a9_timer<PRIVATE_TIMER_CLK>(PRIVATE_TIMER_MMIO_BASE)
{ }
};
typedef Cortex_a9_timer<PERIPH_CLK> Timer;
/**
* Common parts of fault status registers
*/
struct Fsr : Register<32>
{
/**
* Fault status encoding
*/
enum Fault_status {
SECTION_TRANSLATION_FAULT = 5,
PAGE_TRANSLATION_FAULT = 7,
};
struct Fs_3_0 : Bitfield<0, 4> { }; /* fault status bits [3:0] */
struct Fs_4 : Bitfield<10, 1> { }; /* fault status bits [4] */
};
/**
* Instruction fault status register
*/
struct Ifsr : Fsr
{
/**
* Read register
*/
static access_t read() {
access_t v;
asm volatile ("mrc p15, 0, %[v], c5, c0, 1\n" : [v]"=r"(v) :: );
return v;
}
/**
* Read fault status
*/
static Fault_status fault_status() {
access_t const v = read();
return (Fault_status)(Fs_3_0::get(v) |
(Fs_4::get(v) << Fs_3_0::WIDTH));
}
};
/**
* Instruction fault address register
*/
struct Ifar : Register<32>
{
/**
* Read register
*/
static access_t read() {
access_t v;
asm volatile ("mrc p15, 0, %[v], c6, c0, 2\n" : [v]"=r"(v) :: );
return v;
}
};
/**
* Data fault status register
*/
struct Dfsr : Fsr
{
struct Wnr : Bitfield<11, 1> { }; /* write not read bit */
/**
* Read register
*/
static access_t read() {
access_t v;
asm volatile ("mrc p15, 0, %[v], c5, c0, 0\n" : [v]"=r"(v) :: );
return v;
}
/**
* Read fault status
*/
static Fault_status fault_status() {
access_t const v = read();
return (Fault_status)(Fs_3_0::get(v) | (4<<Fs_4::get(v)));
}
};
/**
* Data fault address register
*/
struct Dfar : Register<32>
{
/**
* Read register
*/
static access_t read() {
access_t v;
asm volatile ("mrc p15, 0, %[v], c6, c0, 0\n" : [v]"=r"(v) :: );
return v;
}
};
/**
* Process identification register
*/
struct Contextidr : Register<32>
{
struct Asid : Bitfield<0,8> { }; /* ID part used by MMU */
struct Procid : Bitfield<8,24> { }; /* ID part used by debug/trace */
/**
* Write whole register
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c13, c0, 1\n" :: [v]"r"(v) : );
}
};
/**
* A system control register
*/
struct Sctlr : Register<32>
{
struct M : Bitfield<0,1> { }; /* MMU enable bit */
struct C : Bitfield<2,1> { }; /* cache enable bit */
struct I : Bitfield<12,1> { }; /* instruction cache enable bit */
struct V : Bitfield<13,1> { }; /* exception vectors bit */
/**
* Read whole register
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c1, c0, 0\n" : [v]"=r"(v) :: );
return v;
};
/**
* Write whole register
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c1, c0, 0\n" :: [v]"r"(v) : );
}
};
/**
* The translation table base control register
*/
struct Ttbcr : Register<32>
{
/**********************
** Always available **
**********************/
struct N : Bitfield<0,3> /* base address width */
{ };
/********************************************
** Only available with security extension **
********************************************/
struct Pd0 : Bitfield<4,1> { }; /* translation table walk disable bit for TTBR0 */
struct Pd1 : Bitfield<5,1> { }; /* translation table walk disable bit for TTBR1 */
/**
* Read whole register, only in privileged CPU mode
*/
static access_t read();
/**
* Write whole register, only in privileged CPU mode
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c2, c0, 2" :: [v]"r"(v) : );
}
};
/**
* The domain access control register
*/
struct Dacr : Register<32>
{
enum Dx_values { NO_ACCESS = 0, CLIENT = 1, MANAGER = 3 };
/**
* Access values for the 16 available domains
*/
struct D0 : Bitfield<0,2> { };
struct D1 : Bitfield<2,2> { };
struct D2 : Bitfield<4,2> { };
struct D3 : Bitfield<6,2> { };
struct D4 : Bitfield<8,2> { };
struct D5 : Bitfield<10,2> { };
struct D6 : Bitfield<12,2> { };
struct D7 : Bitfield<14,2> { };
struct D8 : Bitfield<16,2> { };
struct D9 : Bitfield<18,2> { };
struct D10 : Bitfield<20,2> { };
struct D11 : Bitfield<22,2> { };
struct D12 : Bitfield<24,2> { };
struct D13 : Bitfield<26,2> { };
struct D14 : Bitfield<28,2> { };
struct D15 : Bitfield<30,2> { };
/**
* Write whole register, only in privileged CPU mode
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c3, c0, 0" :: [v]"r"(v) : );
}
};
/**
* Translation table base register 0
*
* Typically for process specific spaces, references first level
* table with a size between 128B and 16KB according to 'Ttbcr::N'.
*/
struct Ttbr0 : Register<32>
{
/**********************
** Always available **
**********************/
struct S : Bitfield<1,1> { }; /* shareable bit */
struct Rgn : Bitfield<3,2> /* region bits */
{
enum { OUTER_NON_CACHEABLE = 0b00,
OUTER_WBACK_WALLOCATE_CACHEABLE = 0b01,
OUTER_WTHROUGH_CACHEABLE = 0b10,
OUTER_WBACK_NO_WALLCOATE_CACHEABLE = 0b11,
};
};
struct Nos : Bitfield<5,1> { }; /* not outer shareable bit */
struct Base_address : Bitfield<14,18> { }; /* translation table base address
(Driver supports only 16KB alignment) */
/***********************************************
** Only available without security extension **
***********************************************/
struct C : Bitfield<0,1> { }; /* cacheable bit */
/********************************************
** Only available with security extension **
********************************************/
struct Irgn_1 : Bitfield<0,1> /* inner region bit 0 */
{
enum { INNER_NON_CACHEABLE = 0b0,
INNER_WBACK_WALLOCATE_CACHEABLE = 0b0,
INNER_WTHROUGH_CACHEABLE = 0b1,
INNER_WBACK_NO_WALLCOATE_CACHEABLE = 0b1,
};
};
struct Irgn_0 : Bitfield<6,1> /* inner region bit 1 */
{
enum { INNER_NON_CACHEABLE = 0b0,
INNER_WBACK_WALLOCATE_CACHEABLE = 0b1,
INNER_WTHROUGH_CACHEABLE = 0b0,
INNER_WBACK_NO_WALLCOATE_CACHEABLE = 0b1,
};
};
/**
* Read whole register, only in privileged CPU mode
*/
static access_t read();
/**
* Write whole register, only in privileged CPU mode
*/
static void write(access_t const v)
{
asm volatile ("mcr p15, 0, %[v], c2, c0, 0" :: [v]"r"(v) : );
}
};
/**
* A current program status register
*/
struct Cpsr : Register<32>
{
struct M : Bitfield<0,5> /* processor mode */
{
enum { /* <Privileged>, <Description> */
USER = 0b10000, /* 0, application code */
FIQ = 0b10001, /* 1, entered at fast interrupt */
IRQ = 0b10010, /* 1, entered at normal interrupt */
SUPERVISOR = 0b10011, /* 1, most kernel code */
MONITOR = 0b10110, /* 1, a secure mode, switch sec./non-sec. */
ABORT = 0b10111, /* 1, entered at aborts */
UNDEFINED = 0b11011, /* 1, entered at instruction-related error */
SYSTEM = 0b11111, /* 1, applications that require privileged */
};
};
struct F : Bitfield<6,1> { }; /* fast interrupt request disable */
struct I : Bitfield<7,1> { }; /* interrupt request disable */
struct A : Bitfield<8,1> { }; /* asynchronous abort disable */
/**
* Read whole register
*/
static access_t read()
{
access_t v;
asm volatile ("mrs %[v], cpsr\n" : [v] "=r" (v) : : );
return v;
}
/**
* Write whole register
*/
static void write(access_t & v)
{
asm volatile ("msr cpsr, %[v]\n" : : [v] "r" (v) : );
}
};
/**
* Secure configuration register
*/
struct Scr : Register<32>
{
struct Ns : Bitfield<0, 1> { }; /* non secure bit */
/**
* Read whole register
*/
static access_t read()
{
access_t v;
asm volatile ("mrc p15, 0, %[v], c1, c1, 0" : [v]"=r"(v) ::);
return v;
}
};
struct Context : Cpu_state
{
uint32_t contextidr; /* contextidr register backup, offset 18*4 */
uint32_t section_table; /* base address of applied section table,
* offset 19*4 */
/***************
** Accessors **
***************/
void software_tlb(Section_table * const st) {
section_table = (addr_t)st; }
Section_table * software_tlb() const {
return (Section_table *)section_table; }
void instruction_ptr(addr_t const p) { ip = p; }
addr_t instruction_ptr() const { return ip; }
void return_ptr(addr_t const p) { lr = p; }
void stack_ptr(addr_t const p) { sp = p; }
void protection_domain(unsigned const id) { contextidr = id; }
/**
* Read a general purpose register
*
* \param id ID of the targeted register
* \param v Holds register value if this returns 1
*/
bool get_gpr(unsigned id, unsigned & v) const
{
if (id >= MAX_GPR) return 0;
v = r[id];
return 1;
}
/**
* Override a general purpose register
*
* \param id ID of the targeted register
* \param v Has been written to register if this returns 1
*/
bool set_gpr(unsigned id, unsigned const v)
{
if (id >= MAX_GPR) return 0;
r[id] = v;
return 1;
}
};
/**
* An usermode execution state
*/
struct User_context : Context
{
/**
* Constructor
*/
User_context(void);
/***************************************************
** Communication between user and context holder **
***************************************************/
void user_arg_0(unsigned const arg) { r[0] = arg; }
void user_arg_1(unsigned const arg) { r[1] = arg; }
void user_arg_2(unsigned const arg) { r[2] = arg; }
void user_arg_3(unsigned const arg) { r[3] = arg; }
void user_arg_4(unsigned const arg) { r[4] = arg; }
void user_arg_5(unsigned const arg) { r[5] = arg; }
void user_arg_6(unsigned const arg) { r[6] = arg; }
void user_arg_7(unsigned const arg) { r[7] = arg; }
unsigned user_arg_0() const { return r[0]; }
unsigned user_arg_1() const { return r[1]; }
unsigned user_arg_2() const { return r[2]; }
unsigned user_arg_3() const { return r[3]; }
unsigned user_arg_4() const { return r[4]; }
unsigned user_arg_5() const { return r[5]; }
unsigned user_arg_6() const { return r[6]; }
unsigned user_arg_7() const { return r[7]; }
/**
* Does a pagefault exist and originate from a lack of translation?
*
* \param va Holds the virtual fault-address if this
* function returns 1
* \param w Indicates wether the fault was caused by a write
* access if this function returns 1
*/
bool translation_miss(addr_t & va, bool & w) const
{
/* determine fault type */
switch (cpu_exception)
{
case PREFETCH_ABORT: {
/* check if fault was caused by a translation miss */
Ifsr::Fault_status const fs = Ifsr::fault_status();
if(fs == Ifsr::SECTION_TRANSLATION_FAULT ||
fs == Ifsr::PAGE_TRANSLATION_FAULT)
{
/* fetch fault data */
w = 0;
va = Ifar::read();
return 1;
}
return 0; }
case DATA_ABORT: {
/* check if fault was caused by translation miss */
Dfsr::Fault_status const fs = Dfsr::fault_status();
if(fs == Dfsr::SECTION_TRANSLATION_FAULT ||
fs == Dfsr::PAGE_TRANSLATION_FAULT)
{
/* fetch fault data */
Dfsr::access_t const dfsr = Dfsr::read();
w = Dfsr::Wnr::get(dfsr);
va = Dfar::read();
return 1;
}
return 0; }
default: return 0;
}
}
};
/**
* Enable interrupt requests
*/
static void enable_irqs()
{
Cpsr::access_t cpsr = Cpsr::read();
Cpsr::I::clear(cpsr);
Cpsr::write(cpsr);
}
/**
* Set CPU exception entry to a given address
*
* \return 0 exception entry set to the given address
* <0 otherwise
*/
static int exception_entry_at(addr_t a)
{
Sctlr::access_t sctlr = Sctlr::read();
switch (a) {
case 0x0:
Sctlr::V::clear(sctlr);
break;
case 0xffff0000:
Sctlr::V::set(sctlr);
break;
default:
return -1;
}
Sctlr::write(sctlr);
return 0;
}
/**
* Are we in secure mode?
*/
static bool secure_mode_active()
{
if (!Board::CORTEX_A9_SECURITY_EXTENSION) return 0;
return !Scr::Ns::get(Scr::read());
}
/**
* Enable the MMU
*
* \param section_table section translation table of the initial
* address space this function switches to
* \param process_id process ID of the initial address space
*/
static void enable_mmu (Section_table * const section_table,
unsigned long const process_id)
{
/* initialize domains */
Dacr::write (Dacr::D0::bits (Dacr::CLIENT)
| Dacr::D1::bits (Dacr::NO_ACCESS)
| Dacr::D2::bits (Dacr::NO_ACCESS)
| Dacr::D3::bits (Dacr::NO_ACCESS)
| Dacr::D4::bits (Dacr::NO_ACCESS)
| Dacr::D5::bits (Dacr::NO_ACCESS)
| Dacr::D6::bits (Dacr::NO_ACCESS)
| Dacr::D7::bits (Dacr::NO_ACCESS)
| Dacr::D8::bits (Dacr::NO_ACCESS)
| Dacr::D9::bits (Dacr::NO_ACCESS)
| Dacr::D10::bits (Dacr::NO_ACCESS)
| Dacr::D11::bits (Dacr::NO_ACCESS)
| Dacr::D12::bits (Dacr::NO_ACCESS)
| Dacr::D13::bits (Dacr::NO_ACCESS)
| Dacr::D14::bits (Dacr::NO_ACCESS)
| Dacr::D15::bits (Dacr::NO_ACCESS));
/* switch process ID */
Contextidr::write(process_id);
/* install section table */
Ttbr0::write (Ttbr0::Base_address::masked ((addr_t)section_table));
Ttbcr::write (Ttbcr::N::bits(0)
| Ttbcr::Pd0::bits(0)
| Ttbcr::Pd1::bits(0) );
/* enable MMU without instruction-, data-, or unified caches */
Sctlr::access_t sctlr = Sctlr::read();
Sctlr::M::set(sctlr);
Sctlr::I::clear(sctlr);
Sctlr::C::clear(sctlr);
Sctlr::write(sctlr);
flush_branch_prediction();
}
/**
* Invalidate all entries of the branch predictor array
*
* Must be inline to avoid dependence on the branch predictor.
*/
__attribute__((always_inline)) inline static void flush_branch_prediction()
{
asm volatile ("mcr p15, 0, r0, c7, c5, 6\n"
"isb");
}
/**
* Invalidate at least all TLB entries regarding a specific process
*
* \param process_id ID of the targeted process
*/
static void flush_tlb_by_pid (unsigned const process_id)
{
asm volatile ("mcr p15, 0, %[asid], c8, c7, 2 \n"
:: [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));
}
};
}
#endif /* _INCLUDE__DRIVERS__CPU__CORTEX_A9__CORE_H_ */

View File

@ -1,112 +0,0 @@
/*
* \brief Driver base for the private timer of the ARM Cortex-A9
* \author Martin stein
* \date 2011-12-13
*/
/*
* Copyright (C) 2011-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 _INCLUDE__DRIVERS__CPU__CORTEX_A9__TIMER_H_
#define _INCLUDE__DRIVERS__CPU__CORTEX_A9__TIMER_H_
/* Genode includes */
#include <util/mmio.h>
namespace Genode
{
/**
* Driver base for the private timer of the ARM Cortex-A9
*/
template <unsigned long CLK>
struct Cortex_a9_timer : public Mmio
{
enum { TICS_PER_MS = CLK / 1000, };
/**
* Load value register
*/
struct Load : Register<0x0, 32> { };
/**
* Timer counter value register
*/
struct Counter : Register<0x4, 32> { };
/**
* Timer control register
*/
struct Control : Register<0x8, 32>
{
struct Timer_enable : Bitfield<0,1> { }; /* 1: 'Counter' decrements, 0: 'Counter' stays 0 */
struct Auto_reload : Bitfield<1,1> { }; /* 1: Auto reload mode, 0: One shot mode */
struct Irq_enable : Bitfield<2,1> { }; /* 1: IRQ = 'Interrupt_status::Event' 0: IRQ = 0 */
struct Prescaler : Bitfield<8,8> { }; /* modifies the clock period for the decrementing */
};
/**
* Timer interrupt status register
*/
struct Interrupt_status : Register<0xc, 32>
{
struct Event : Bitfield<0,1> { }; /* 'Event' = !'Counter' */
};
/**
* Constructor, clears the interrupt output
*/
Cortex_a9_timer(addr_t const mmio_base) : Mmio(mmio_base) {
clear_interrupt(); }
/**
* Start a one-shot run
* \param tics native timer value used to assess the delay
* of the timer interrupt as of the call
*/
inline void start_one_shot(uint32_t const tics);
/**
* Translate milliseconds to a native timer value
*/
static uint32_t ms_to_tics(unsigned long const ms) {
return ms * TICS_PER_MS; }
/**
* Stop the timer and return last timer value
*/
unsigned long stop()
{
unsigned long const v = read<Counter>();
write<typename Control::Timer_enable>(0);
return v;
}
/**
* Clear interrupt output line
*/
void clear_interrupt() { write<typename Interrupt_status::Event>(1); }
};
}
template <unsigned long CLOCK>
void Genode::Cortex_a9_timer<CLOCK>::start_one_shot(uint32_t const tics)
{
/* reset timer */
clear_interrupt();
write<Control>(Control::Timer_enable::bits(0) |
Control::Auto_reload::bits(0) |
Control::Irq_enable::bits(1) |
Control::Prescaler::bits(0));
/* load timer and start decrementing */
write<Load>(tics);
write<typename Control::Timer_enable>(1);
}
#endif /* _INCLUDE__DRIVERS__CPU__CORTEX_A9__TIMER_H_ */

View File

@ -14,68 +14,27 @@
#ifndef _CORE__INCLUDE__CORTEX_A9__KERNEL_SUPPORT_H_
#define _CORE__INCLUDE__CORTEX_A9__KERNEL_SUPPORT_H_
/* Core includes */
#include <cortex_a9/cpu/core.h>
#include <pic/pl390_base.h>
/* core includes */
#include <cortex_a9/cpu.h>
#include <cortex_a9/timer.h>
#include <cortex_a9/no_trustzone/pic.h>
/**
* CPU driver
*/
class Cpu : public Genode::Cortex_a9 { };
class Cpu : public Cortex_a9::Cpu { };
namespace Kernel
{
/* import Genode types */
typedef Genode::Cortex_a9 Cortex_a9;
typedef Genode::Pl390_base Pl390_base;
/**
* Kernel interrupt-controller
* Programmable interrupt controller
*/
class Pic : public Pl390_base
{
public:
/**
* Constructor
*/
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);
}
};
class Pic : public Cortex_a9_no_trustzone::Pic { };
/**
* Kernel timer
*/
class Timer : public Cortex_a9::Private_timer { };
class Timer : public Cortex_a9::Timer { };
}
#endif /* _CORE__INCLUDE__CORTEX_A9__KERNEL_SUPPORT_H_ */

View File

@ -0,0 +1,70 @@
/*
* \brief Programmable interrupt controller for core
* \author Martin Stein
* \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 _INCLUDE__CORTEX_A9__NO_TRUSTZONE__PIC_H_
#define _INCLUDE__CORTEX_A9__NO_TRUSTZONE__PIC_H_
/* core includes */
#include <cortex_a9/cpu.h>
#include <cortex_a9/pic.h>
namespace Cortex_a9_no_trustzone
{
using namespace Genode;
/**
* Programmable interrupt controller for core
*/
class Pic : public Cortex_a9::Pic
{
public:
/**
* Constructor
*/
Pic()
{
/* 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);
}
};
}
#endif /* _INCLUDE__CORTEX_A9__NO_TRUSTZONE__PIC_H_ */

View File

@ -1,5 +1,5 @@
/*
* \brief Base driver for the ARM PL390 interrupt controller
* \brief Programmable interrupt controller for core
* \author Martin stein
* \date 2011-10-26
*/
@ -11,19 +11,20 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__DRIVERS__PIC__PL390_BASE_H_
#define _INCLUDE__DRIVERS__PIC__PL390_BASE_H_
#ifndef _INCLUDE__CORTEX_A9__PIC_H_
#define _INCLUDE__CORTEX_A9__PIC_H_
/* Genode includes */
#include <util/mmio.h>
#include <base/printf.h>
namespace Genode
namespace Cortex_a9
{
using namespace Genode;
/**
* Base driver for the ARM PL390 interrupt controller
* Programmable interrupt controller for core
*/
class Pl390_base
class Pic
{
public:
@ -41,7 +42,7 @@ namespace Genode
*/
struct Distr : public Mmio
{
Distr(addr_t const base) : Mmio(base) { }
Distr() : Mmio(Cortex_a9::Cpu::PL390_DISTRIBUTOR_MMIO_BASE) { }
/**
* Distributor control register
@ -145,7 +146,7 @@ namespace Genode
*/
struct Cpu : public Mmio
{
Cpu(addr_t const base) : Mmio(base) { }
Cpu() : Mmio(Cortex_a9::Cpu::PL390_CPU_MMIO_BASE) { }
/**
* CPU interface control register
@ -160,7 +161,7 @@ namespace Genode
struct Enable_ns : Bitfield<1,1> { };
struct Ack_ctl : Bitfield<2,1> { };
struct Fiq_en : Bitfield<3,1> { };
struct Cbpr : Bitfield<4,1> { };
struct Sbpr : Bitfield<4,1> { };
};
/**
@ -221,11 +222,8 @@ namespace Genode
/**
* Constructor, all interrupts get masked
*/
Pl390_base(addr_t const distributor, addr_t const cpu_interface) :
_distr(distributor),
_cpu(cpu_interface),
_max_interrupt(_distr.max_interrupt()),
_last_taken_request(SPURIOUS_ID) { }
Pic() : _max_interrupt(_distr.max_interrupt()),
_last_taken_request(SPURIOUS_ID) { }
/**
* Get the ID of the last interrupt request
@ -270,10 +268,8 @@ namespace Genode
/**
* Unmask interrupt 'i'
*/
void unmask(unsigned const i)
{
_distr.write<Distr::Icdiser::Set_enable>(1, i);
}
void unmask(unsigned const i) {
_distr.write<Distr::Icdiser::Set_enable>(1, i); }
/**
* Mask all interrupts
@ -287,12 +283,10 @@ namespace Genode
/**
* Mask interrupt 'i'
*/
void mask(unsigned const i)
{
_distr.write<Distr::Icdicer::Clear_enable>(1, i);
}
void mask(unsigned const i) {
_distr.write<Distr::Icdicer::Clear_enable>(1, i); }
};
}
#endif /* _INCLUDE__DRIVERS__PIC__PL390_BASE_H_ */
#endif /* _INCLUDE__CORTEX_A9__PIC_H_ */

View File

@ -0,0 +1,131 @@
/*
* \brief Timer for core
* \author Martin stein
* \date 2011-12-13
*/
/*
* Copyright (C) 2011-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 _INCLUDE__CORTEX_A9__TIMER_H_
#define _INCLUDE__CORTEX_A9__TIMER_H_
/* Genode includes */
#include <util/mmio.h>
/* core includes */
#include <cortex_a9/cpu.h>
namespace Cortex_a9
{
/**
* Timer for core
*/
class Timer : public Mmio
{
enum { TICS_PER_MS = Cortex_a9::Cpu::PRIVATE_TIMER_CLK / 1000, };
/**
* Load value register
*/
struct Load : Register<0x0, 32> { };
/**
* Timer counter value register
*/
struct Counter : Register<0x4, 32> { };
/**
* Timer control register
*/
struct Control : Register<0x8, 32>
{
struct Timer_enable : Bitfield<0,1> { }; /* enable counting */
struct Auto_reload : Bitfield<1,1> { }; /* reload at zero */
struct Irq_enable : Bitfield<2,1> { }; /* unmask interrupt */
struct Prescaler : Bitfield<8,8> { }; /* modify frequency */
/**
* Configure for a one-shot
*/
static access_t init_one_shot()
{
return Timer_enable::bits(0) |
Auto_reload::bits(0) |
Irq_enable::bits(1) |
Prescaler::bits(0);
}
};
/**
* Timer interrupt status register
*/
struct Interrupt_status : Register<0xc, 32>
{
struct Event : Bitfield<0,1> { }; /* if counter hit zero */
};
/**
* Stop counting
*/
void _disable() { write<Control::Timer_enable>(0); }
public:
enum { IRQ = Cortex_a9::Cpu::PRIVATE_TIMER_IRQ };
/**
* Constructor, clears the interrupt output
*/
Timer() : Mmio(Cortex_a9::Cpu::PRIVATE_TIMER_MMIO_BASE)
{
_disable();
clear_interrupt();
}
/**
* Start a one-shot run
* \param tics native timer value used to assess the delay
* of the timer interrupt as of the call
*/
inline void start_one_shot(uint32_t const tics)
{
/* reset timer */
clear_interrupt();
write<Control>(Control::init_one_shot());
/* load timer and start decrementing */
write<Load>(tics);
write<Control::Timer_enable>(1);
}
/**
* Translate milliseconds to a native timer value
*/
static uint32_t ms_to_tics(unsigned long const ms) {
return ms * TICS_PER_MS; }
/**
* Stop the timer and return last timer value
*/
unsigned long stop_one_shot()
{
unsigned long const v = read<Counter>();
_disable();
return v;
}
/**
* Clear interrupt output line
*/
void clear_interrupt() {
write<Interrupt_status::Event>(1); }
};
}
#endif /* _INCLUDE__CORTEX_A9__TIMER_H_ */

View File

@ -0,0 +1,99 @@
/*
* \brief Board definitions for core
* \author Martin Stein
* \date 2012-11-01
*/
#ifndef _INCLUDE__IMX31__DRIVERS__BOARD_H_
#define _INCLUDE__IMX31__DRIVERS__BOARD_H_
/* Genode includes */
#include <platform/imx31/drivers/board.h>
namespace Imx31
{
using namespace Genode;
/**
* AHB-lite 2v6 to IP bus interface
*/
class Aips : public Mmio
{
/**
* Configuration of the masters
*/
struct Mpr { enum { ALL_UNBUFFERED_AND_FULLY_TRUSTED = 0x77777777 }; };
struct Mpr1 : Register<0x0, 32>, Mpr { };
struct Mpr2 : Register<0x4, 32>, Mpr { };
/**
* Configuration of the platform peripherals
*/
struct Pacr { enum { ALL_UNBUFFERED_AND_FULLY_UNPROTECTED = 0 }; };
struct Pacr1 : Register<0x20, 32>, Pacr { };
struct Pacr2 : Register<0x24, 32>, Pacr { };
struct Pacr3 : Register<0x28, 32>, Pacr { };
struct Pacr4 : Register<0x2c, 32>, Pacr { };
/**
* Configuration of the off-platform peripherals
*/
struct Opacr1 : Register<0x40, 32>, Pacr { };
struct Opacr2 : Register<0x44, 32>, Pacr { };
struct Opacr3 : Register<0x48, 32>, Pacr { };
struct Opacr4 : Register<0x4c, 32>, Pacr { };
struct Opacr5 : Register<0x50, 32>, Pacr { };
public:
/**
* Constructor
*/
Aips(addr_t const base) : Mmio(base) { }
/**
* Configure this module appropriately for the first kernel run
*/
void prepare_kernel()
{
/* avoid AIPS intervention at any memory access */
write<Mpr1>(Mpr::ALL_UNBUFFERED_AND_FULLY_TRUSTED);
write<Mpr2>(Mpr::ALL_UNBUFFERED_AND_FULLY_TRUSTED);
write<Pacr1>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Pacr2>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Pacr3>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Pacr4>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Opacr1>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Opacr2>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Opacr3>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Opacr4>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
write<Opacr5>(Pacr::ALL_UNBUFFERED_AND_FULLY_UNPROTECTED);
}
};
struct Board : Genode::Board
{
/**
* static AIPS 1 instance
*/
static Aips * aips_1() { static Aips a(AIPS_1_MMIO_BASE); return &a; }
/**
* Static AIPS 2 instance
*/
static Aips * aips_2() { static Aips a(AIPS_2_MMIO_BASE); return &a; }
/**
* Configure this module appropriately for the first kernel run
*/
static void prepare_kernel()
{
aips_1()->prepare_kernel();
aips_2()->prepare_kernel();
}
};
}
typedef Imx31::Board Board;
#endif /* _INCLUDE__IMX31__DRIVERS__BOARD_H_ */

View File

@ -0,0 +1,39 @@
/*
* \brief Kernel support for i.MX31
* \author Norman Feske
* \author Martin Stein
* \date 2012-08-30
*/
/*
* 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__IMX31__KERNEL_SUPPORT_H_
#define _CORE__INCLUDE__IMX31__KERNEL_SUPPORT_H_
/* Genode includes */
#include <arm/v6/cpu.h>
#include <imx31/timer.h>
#include <imx31/pic.h>
struct Cpu : Arm_v6::Cpu { };
namespace Kernel
{
/**
* Programmable interrupt controller
*/
class Pic : public Imx31::Pic { };
/**
* Timer
*/
class Timer : public Imx31::Timer { };
}
#endif /* _CORE__INCLUDE__IMX31__KERNEL_SUPPORT_H_ */

View File

@ -0,0 +1,197 @@
/*
* \brief Programmable interrupt controller for core
* \author Norman Feske
* \author Martin Stein
* \date 2012-08-30
*/
/*
* 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 _INCLUDE__IMX31__PIC_H_
#define _INCLUDE__IMX31__PIC_H_
/* Genode includes */
#include <util/mmio.h>
#include <drivers/board.h>
namespace Imx31
{
using namespace Genode;
/**
* Programmable interrupt controller for core
*/
class Pic : public Mmio
{
/**
* Interrupt control register
*/
struct Intcntl : Register<0x0, 32>
{
struct Nm : Bitfield<18,1> /* IRQ mode */
{
enum { SW_CONTROL = 0 };
};
struct Fiad : Bitfield<19,1> { }; /* FIQ rises prio in arbiter */
struct Niad : Bitfield<20,1> { }; /* IRQ rises prio in arbiter */
struct Fidis : Bitfield<21,1> { }; /* FIQ disable */
struct Nidis : Bitfield<22,1> { }; /* IRQ disable */
struct Abfen : Bitfield<24,1> { }; /* if ABFLAG is sticky */
struct Abflag : Bitfield<25,1> { }; /* rise prio in bus arbiter */
static access_t init_value()
{
return Nm::bits(Nm::SW_CONTROL) |
Fiad::bits(0) |
Niad::bits(0) |
Fidis::bits(0) |
Nidis::bits(0) |
Abfen::bits(0) |
Abflag::bits(0);
}
};
/**
* Normal interrupt mask register
*/
struct Nimask : Register<0x4, 32>
{
enum { NONE_MASKED = ~0 };
};
/**
* Interrupt enable number register
*/
struct Intennum : Register<0x8, 32>
{
struct Enable : Bitfield<0,6> { };
};
/**
* Interrupt disable number register
*/
struct Intdisnum : Register<0xc, 32>
{
struct Disable : Bitfield<0,6> { };
};
/**
* Interrupt enable register
*/
struct Intenableh : Register<0x10, 32> { };
struct Intenablel : Register<0x14, 32> { };
/**
* Interrupt type register
*/
struct Inttype { enum { ALL_IRQS = 0 }; };
struct Inttypeh : Register<0x18, 32> { };
struct Inttypel : Register<0x1c, 32> { };
/**
* Normal interrupt priority registers
*/
struct Nipriority : Register_array<0x20, 32, 8, 32>
{
enum { ALL_LOWEST = 0 };
};
/**
* Interrupt source registers
*/
struct Intsrch : Register<0x48, 32> { };
struct Intsrcl : Register<0x4c, 32> { };
/**
* Normal interrupt pending registers
*/
struct Nipndh : Register<0x58, 32> { };
struct Nipndl : Register<0x5c, 32> { };
/**
* Normal interrupt vector and status register
*/
struct Nivecsr : Register<0x40, 32>
{
struct Nvector : Bitfield<16, 16> { };
};
public:
enum { MAX_INTERRUPT_ID = 63 };
/**
* Constructor, enables all interrupts
*/
Pic() : Mmio(Board::AVIC_MMIO_BASE)
{
mask();
write<Nimask>(Nimask::NONE_MASKED);
write<Intcntl>(Intcntl::init_value());
write<Inttypeh>(Inttype::ALL_IRQS);
write<Inttypel>(Inttype::ALL_IRQS);
for (unsigned i = 0; i < Nipriority::ITEMS; i++)
write<Nipriority>(Nipriority::ALL_LOWEST, i);
}
/**
* Receive a pending request number 'i'
*/
bool take_request(unsigned & i)
{
i = read<Nivecsr::Nvector>();
return valid(i) ? true : false;
}
/**
* Finish the last taken request
*/
void finish_request() {
/* requests disappear by source retraction or masking */ }
/**
* Validate request number 'i'
*/
bool valid(unsigned const i) const {
return i <= MAX_INTERRUPT_ID; }
/**
* Unmask all interrupts
*/
void unmask()
{
write<Intenablel>(~0);
write<Intenableh>(~0);
}
/**
* Mask all interrupts
*/
void mask()
{
write<Intenablel>(0);
write<Intenableh>(0);
}
/**
* Unmask interrupt 'i'
*/
void unmask(unsigned const i) {
if (i <= MAX_INTERRUPT_ID) write<Intennum>(i); }
/**
* Mask interrupt 'i'
*/
void mask(unsigned const i) {
if (i <= MAX_INTERRUPT_ID) write<Intdisnum>(i); }
};
}
#endif /* _INCLUDE__IMX31__PIC_H_ */

View File

@ -0,0 +1,176 @@
/*
* \brief Core timer
* \author Martin Stein
* \author Norman Feske
* \date 2012-08-30
*/
/*
* 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 _INCLUDE__IMX31__TIMER_H_
#define _INCLUDE__IMX31__TIMER_H_
/* Genode includes */
#include <util/mmio.h>
namespace Imx31
{
using namespace Genode;
/**
* Core timer
*/
class Timer : public Mmio
{
enum { TICS_PER_MS = 32 };
/**
* Control register
*/
struct Cr : Register<0x0, 32>
{
struct En : Bitfield<0, 1> { }; /* enable timer */
struct En_mod : Bitfield<1, 1> /* reload or continue on enable */
{
enum { RELOAD = 1 };
};
struct Oci_en : Bitfield<2, 1> { }; /* interrupt on compare */
struct Rld : Bitfield<3, 1> /* reload or roll-over */
{
enum { RELOAD_FROM_LR = 1 };
};
struct Prescaler : Bitfield<4, 12> /* clock input divisor */
{
enum { DIVIDE_BY_1 = 0 };
};
struct Swr : Bitfield<16, 1> { }; /* software reset bit */
struct Iovw : Bitfield<17, 1> { }; /* enable overwrite */
struct Dbg_en : Bitfield<18, 1> { }; /* enable in debug mode */
struct Wait_en : Bitfield<19, 1> { }; /* enable in wait mode */
struct Doz_en : Bitfield<20, 1> { }; /* enable in doze mode */
struct Stop_en : Bitfield<21, 1> { }; /* enable in stop mode */
struct Om : Bitfield<22, 2> /* mode of the output pin */
{
enum { DISCONNECTED = 0 };
};
struct Clk_src : Bitfield<24, 2> /* select clock input */
{
enum { IPG_CLK_32K = 3 };
};
/**
* Register value that configures the timer for a one-shot run
*/
static access_t prepare_one_shot()
{
return En::bits(0) |
En_mod::bits(En_mod::RELOAD) |
Oci_en::bits(1) |
Rld::bits(Rld::RELOAD_FROM_LR) |
Prescaler::bits(Prescaler::DIVIDE_BY_1) |
Swr::bits(0) |
Iovw::bits(0) |
Dbg_en::bits(0) |
Wait_en::bits(0) |
Doz_en::bits(0) |
Stop_en::bits(0) |
Om::bits(Om::DISCONNECTED) |
Clk_src::bits(Clk_src::IPG_CLK_32K);
}
};
/**
* Status register
*/
struct Sr : Register<0x4, 32>
{
struct Ocif : Bitfield<0, 1> { }; /* IRQ status, write 1 clears */
};
struct Lr : Register<0x8, 32> { }; /* load value register */
struct Cmpr : Register<0xc, 32> { }; /* compare value register */
struct Cnt : Register<0x10, 32> { }; /* counter register */
/**
* Disable timer and clear its interrupt output
*/
void _reset()
{
/* wait until ongoing reset operations are finished */
while (read<Cr::Swr>()) ;
/* disable timer */
write<Cr::En>(0);
clear_interrupt();
}
public:
enum { IRQ = Board::EPIT_1_IRQ };
/**
* Constructor
*/
Timer() : Mmio(Board::EPIT_1_MMIO_BASE) { _reset(); }
/**
* Start a one-shot run
*
* \param tics native timer value used to assess the delay
* of the timer interrupt as of the call
*/
void start_one_shot(unsigned const tics)
{
/* stop timer */
_reset();
/* configure timer for a one-shot */
write<Cr>(Cr::prepare_one_shot());
write<Lr>(tics);
write<Cmpr>(0);
/* start timer */
write<Cr::En>(1);
}
/**
* Stop the timer from a one-shot run
*
* \return last native timer value of the one-shot run
*/
unsigned long stop_one_shot()
{
/* disable timer */
write<Cr::En>(0);
/* if the timer has hit zero already return 0 */
return read<Sr::Ocif>() ? 0 : read<Cnt>();
}
/**
* Clear interrupt output line
*/
void clear_interrupt() { write<Sr::Ocif>(1); }
/**
* Translate milliseconds to a native timer value
*/
static unsigned ms_to_tics(unsigned const ms) {
return TICS_PER_MS * ms; }
};
}
#endif /* _INCLUDE__IMX31__TIMER_H_ */

View File

@ -0,0 +1,68 @@
/*
* \brief Programmable interrupt controller for core
* \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 _INCLUDE__VEA9X4_TRUSTZONE__PIC_H_
#define _INCLUDE__VEA9X4_TRUSTZONE__PIC_H_
/* core includes */
#include <cortex_a9/cpu.h>
#include <cortex_a9/pic.h>
namespace Vea9x4_trustzone
{
using namespace Genode;
/**
* Programmable interrupt controller for core
*/
class Pic : public Cortex_a9::Pic
{
public:
/**
* Constructor
*/
Pic()
{
/* 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 const i) {
_distr.write<Distr::Icdisr::Nonsecure>(1, i); }
};
}
#endif /* _INCLUDE__VEA9X4_TRUSTZONE__PIC_H_ */

View File

@ -47,9 +47,9 @@ extern int _mode_transition_begin;
extern int _mode_transition_end;
extern int _mt_user_entry_pic;
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;
extern Genode::addr_t _mt_client_context_ptr;
extern Genode::addr_t _mt_master_context_begin;
extern Genode::addr_t _mt_master_context_end;
namespace Kernel
{
@ -68,7 +68,7 @@ namespace Kernel
/* kernel configuration */
enum {
DEFAULT_STACK_SIZE = 1*1024*1024,
USER_TIME_SLICE_MS = 10,
USER_TIME_SLICE_MS = 100,
MAX_PDS = 256,
MAX_THREADS = 256,
MAX_SIGNAL_RECEIVERS = 256,
@ -720,17 +720,17 @@ namespace Kernel
*
* 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
* independent. This code has to be mapped 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.
* This class controls the settings like kernel, user, and VM states
* that are handled by the mode transition PIC.
*/
struct Mode_transition_control
{
enum {
SIZE_LOG2 = Cpu::MIN_PAGE_SIZE_LOG2,
SIZE_LOG2 = Software_tlb::MIN_PAGE_SIZE_LOG2,
SIZE = 1 << SIZE_LOG2,
VIRT_BASE = Cpu::HIGHEST_EXCEPTION_ENTRY,
VIRT_BASE = Cpu::EXCEPTION_ENTRY,
VIRT_END = VIRT_BASE + SIZE,
ALIGNM_LOG2 = SIZE_LOG2,
};
@ -751,20 +751,17 @@ namespace Kernel
assert(pic_size <= SIZE);
/* check if kernel context fits into the mode transition */
addr_t const kc_begin = (addr_t)&_mt_kernel_context_begin;
addr_t const kc_end = (addr_t)&_mt_kernel_context_end;
addr_t const kc_begin = (addr_t)&_mt_master_context_begin;
addr_t const kc_end = (addr_t)&_mt_master_context_end;
size_t const kc_size = kc_end - kc_begin;
assert(sizeof(Cpu::Context) <= kc_size);
/* try to set CPU exception entry accordingly */
assert(!Cpu::exception_entry_at(VIRT_BASE));
}
/**
* Fetch next kernelmode context
*/
void fetch_kernel_context(Cpu::Context * const c) {
memcpy(&_mt_kernel_context_begin, c, sizeof(Cpu::Context)); }
void fetch_master_context(Cpu::Context * const c) {
memcpy(&_mt_master_context_begin, c, sizeof(Cpu::Context)); }
/**
* Page aligned physical base of the mode transition PIC
@ -836,7 +833,7 @@ namespace Kernel
void append_context(Cpu::Context * const c)
{
c->protection_domain(id());
c->software_tlb((Software_tlb *)this);
c->software_tlb((addr_t)static_cast<Software_tlb *>(this));
}
};
@ -1125,6 +1122,11 @@ 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
@ -1135,12 +1137,6 @@ 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; }
@ -1288,9 +1284,10 @@ namespace Kernel
}
}
void scheduled_next() {
void scheduled_next()
{
/* set context pointer for mode switch */
_mt_context_ptr = (addr_t)static_cast<Genode::Cpu_state*>(this);
_mt_client_context_ptr = (addr_t)static_cast<Genode::Cpu_state*>(this);
/* jump to user entry assembler path */
mtc()->virt_user_entry();
@ -1344,7 +1341,6 @@ namespace Kernel
class Signal_receiver;
/**
* Specific signal type, owned by a receiver, can be triggered asynchr.
*/
@ -1472,9 +1468,10 @@ namespace Kernel
}
}
void scheduled_next() {
void scheduled_next()
{
/* set context pointer for mode switch */
_mt_context_ptr = (addr_t)_state;
_mt_client_context_ptr = (addr_t)_state;
/* jump to assembler path */
((void(*)(void))&_mon_vm_entry)();
@ -1959,7 +1956,7 @@ namespace Kernel
assert(c);
/* trigger signal at context */
c->trigger_signal(1);
c->trigger_signal(user->user_arg_2());
}
@ -2041,9 +2038,9 @@ namespace Kernel
/* 21 */ do_new_signal_context,
/* 22 */ do_await_signal,
/* 23 */ do_submit_signal,
/* 24 */ do_delete_thread,
/* 25 */ do_new_vm,
/* 26 */ do_run_vm,
/* 24 */ do_new_vm,
/* 25 */ do_run_vm,
/* 26 */ do_delete_thread,
};
enum { MAX_SYSCALL = sizeof(handle_sysc)/sizeof(handle_sysc[0]) - 1 };
@ -2054,13 +2051,17 @@ namespace Kernel
}
}
/**
* Prepare the system for the first run of 'kernel'
*/
extern "C" void init_phys_kernel() {
Cpu::init_phys_kernel(); }
/**
* Kernel main routine
*/
extern "C" void kernel()
{
unsigned const timer_value = timer()->stop();
static unsigned user_time = 0;
static bool initial_call = true;
@ -2068,6 +2069,7 @@ extern "C" void kernel()
if (!initial_call)
{
/* update how much time the last user has consumed */
unsigned const timer_value = timer()->stop_one_shot();
user_time = timer_value < user_time ? user_time - timer_value : 0;
/* handle exception that interrupted the last user */
@ -2082,7 +2084,7 @@ extern "C" void kernel()
{
/* map everything except the mode transition region */
enum {
SIZE_LOG2 = Software_tlb::MAX_TRANSL_SIZE_LOG2,
SIZE_LOG2 = Software_tlb::MAX_PAGE_SIZE_LOG2,
SIZE = 1 << SIZE_LOG2,
};
if (mtc()->VIRT_END <= a || mtc()->VIRT_BASE > (a + SIZE - 1))
@ -2098,20 +2100,20 @@ extern "C" void kernel()
}
/* compose kernel CPU context */
static Cpu::Context kernel_context;
kernel_context.instruction_ptr((addr_t)kernel);
kernel_context.stack_ptr((addr_t)&_kernel_stack_high);
kernel_context.ip = (addr_t)kernel;
kernel_context.sp = (addr_t)&_kernel_stack_high;
/* add kernel to the core PD */
core()->append_context(&kernel_context);
/* offer the final kernel context to the mode transition page */
mtc()->fetch_kernel_context(&kernel_context);
mtc()->fetch_master_context(&kernel_context);
/* TrustZone initialization code */
trustzone_initialization(pic());
/* switch to core address space */
Cpu::enable_mmu(core(), core_id());
Cpu::init_virt_kernel((addr_t)static_cast<Software_tlb *>(core()), core_id());
/* create the core main thread */
static Native_utcb cm_utcb;
@ -2120,7 +2122,7 @@ extern "C" void kernel()
static Thread core_main((Platform_thread *)0);
_main_utcb = &cm_utcb;
enum { CM_STACK_SIZE = sizeof(cm_stack)/sizeof(cm_stack[0]) + 1 };
core_main.start((void *)&CORE_MAIN,
core_main.start((void *)CORE_MAIN,
(void *)&cm_stack[CM_STACK_SIZE - 1],
0, core_id(), &cm_utcb, &cm_utcb);
@ -2128,7 +2130,7 @@ extern "C" void kernel()
initial_call = false;
}
/* offer next user context to the mode transition PIC */
Schedule_context* const next = cpu_scheduler()->next_entry(user_time);
Schedule_context * const next = cpu_scheduler()->next_entry(user_time);
/* limit user mode execution in time */
timer()->start_one_shot(user_time);
@ -2167,19 +2169,19 @@ int Thread::start(void *ip, void *sp, unsigned cpu_no,
}
void Thread::init_context(void * const ip, void * const sp,
void Thread::init_context(void * const instr_p, void * const stack_p,
unsigned const pd_id)
{
/* basic thread state */
stack_ptr((addr_t)sp);
instruction_ptr((addr_t)ip);
sp = (addr_t)stack_p;
ip = (addr_t)instr_p;
/* join a pd */
_pd_id = pd_id;
Pd * const pd = Pd::pool()->object(_pd_id);
assert(pd)
protection_domain(pd_id);
software_tlb(pd);
software_tlb((addr_t)static_cast<Software_tlb *>(pd));
}
@ -2191,10 +2193,8 @@ void Thread::pagefault(addr_t const va, bool const w)
/* inform pager through IPC */
assert(_pager);
Software_tlb * const tlb =
static_cast<Software_tlb *>(software_tlb());
_pagefault =
Pagefault(id(), tlb, instruction_ptr(), va, w);
Software_tlb * const tlb = (Software_tlb *)software_tlb();
_pagefault = Pagefault(id(), tlb, ip, va, w);
Ipc_node::send_note(_pager, &_pagefault, sizeof(_pagefault));
}

View File

@ -11,13 +11,8 @@
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel_support.h>
Cpu::User_context::User_context() { cpsr = Psr::init_user(); }
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

@ -15,9 +15,9 @@
#include <drivers/board.h>
/* core includes */
#include <cortex_a9/cpu.h>
#include <cortex_a9/no_trustzone/pic.h>
#include <platform.h>
#include <cortex_a9/cpu/core.h>
#include <pic/pl390_base.h>
using namespace Genode;
@ -37,7 +37,7 @@ Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Pl390_base::MAX_INTERRUPT_ID + 1 }
{ 0, Cortex_a9_no_trustzone::Pic::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
@ -48,7 +48,7 @@ Native_region * Platform::_core_only_irq_regions(unsigned const i)
static Native_region _regions[] =
{
/* core timer */
{ Cortex_a9::PRIVATE_TIMER_IRQ, 1 },
{ Cortex_a9::Cpu::PRIVATE_TIMER_IRQ, 1 },
/* core UART */
{ Board::TL16C750_3_IRQ, 1 }

View File

@ -15,12 +15,12 @@
#define _SRC__CORE__PANDA_A2__SOFTWARE_TLB_H_
/* Genode includes */
#include <cortex_a9/cpu/section_table.h>
#include <arm/v7/section_table.h>
/**
* Software TLB controls
*/
class Software_tlb : public Genode::Section_table { };
class Software_tlb : public Arm_v7::Section_table { };
#endif /* _SRC__CORE__PANDA_A2__SOFTWARE_TLB_H_ */

View File

@ -1,9 +1,12 @@
#
# \brief Pandaboard-specific makefile for core
# \brief Makefile for core
# \author Stefan Kalkowski
# \date 2012-10-04
#
REQUIRES = platform_panda_a2
# declare wich specs must be given to build this target
REQUIRES += platform_panda_a2
# include less specific target parts
include $(REP_DIR)/src/core/target.inc

View File

@ -16,8 +16,9 @@
/* core includes */
#include <platform.h>
#include <cortex_a9/cpu/core.h>
#include <pic/pl390_base.h>
#include <cortex_a9/cpu.h>
#include <cortex_a9/no_trustzone/pic.h>
using namespace Genode;
@ -36,7 +37,7 @@ Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Pl390_base::MAX_INTERRUPT_ID + 1 }
{ 0, Cortex_a9_no_trustzone::Pic::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
@ -47,7 +48,7 @@ Native_region * Platform::_core_only_irq_regions(unsigned const i)
static Native_region _regions[] =
{
/* core timer */
{ Cortex_a9::PRIVATE_TIMER_IRQ, 1 },
{ Cortex_a9::Cpu::PRIVATE_TIMER_IRQ, 1 },
/* core UART */
{ Board::PL011_0_IRQ, 1 }

View File

@ -14,13 +14,13 @@
#ifndef _SRC__CORE__PBXA9__SOFTWARE_TLB_H_
#define _SRC__CORE__PBXA9__SOFTWARE_TLB_H_
/* Genode includes */
#include <cortex_a9/cpu/section_table.h>
/* core includes */
#include <arm/v7/section_table.h>
/**
* Software TLB controls
*/
class Software_tlb : public Genode::Section_table { };
class Software_tlb : public Arm_v7::Section_table { };
#endif /* _SRC__CORE__PBXA9__SOFTWARE_TLB_H_ */

View File

@ -1,9 +1,12 @@
#
# \brief PBXA9-specific makefile for core
# \brief Makefile for core
# \author Stefan Kalkowski
# \date 2012-10-04
#
# declare wich specs must be given to build this target
REQUIRES = platform_pbxa9
# include less specific target parts
include $(REP_DIR)/src/core/target.inc

View File

@ -142,6 +142,10 @@ Platform::Platform() :
printf("-------------------\n");
_io_mem_alloc.raw()->dump_addr_tree();
printf("\n");
printf("IRQ allocator\n");
printf("-------------------\n");
_irq_alloc.raw()->dump_addr_tree();
printf("\n");
printf("ROM filesystem\n");
printf("--------------\n");
_rom_fs.print_fs();

View File

@ -8,11 +8,11 @@
TARGET = core
# use core specific startup library
STARTUP_LIB = startup_core
STARTUP_LIB = core_support
# add library dependencies
LIBS += cxx raw_ipc heap child pager lock console signal raw_server \
syscall startup_core core_support
LIBS += cxx raw_ipc heap child process pager lock console signal raw_server \
syscall core_support
# add include paths
GEN_CORE_DIR = $(BASE_DIR)/src/core

View File

@ -16,8 +16,8 @@
/* Core includes */
#include <platform.h>
#include <cortex_a9/cpu/core.h>
#include <pic/pl390_base.h>
#include <cortex_a9/cpu.h>
#include <cortex_a9/no_trustzone/pic.h>
using namespace Genode;
@ -36,7 +36,7 @@ Native_region * Platform::_irq_regions(unsigned const i)
{
static Native_region _regions[] =
{
{ 0, Pl390_base::MAX_INTERRUPT_ID + 1 }
{ 0, Cortex_a9_no_trustzone::Pic::MAX_INTERRUPT_ID + 1 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
@ -47,7 +47,7 @@ Native_region * Platform::_core_only_irq_regions(unsigned const i)
static Native_region _regions[] =
{
/* Core timer */
{ Cortex_a9::PRIVATE_TIMER_IRQ, 1 },
{ Cortex_a9::Cpu::PRIVATE_TIMER_IRQ, 1 },
/* Core UART */
{ Board::PL011_0_IRQ, 1 }

View File

@ -15,12 +15,12 @@
#define _SRC__CORE__VEA9X4__SOFTWARE_TLB_H_
/* Genode includes */
#include <cortex_a9/cpu/section_table.h>
#include <arm/v7/section_table.h>
/**
* Software TLB controls
*/
class Software_tlb : public Genode::Section_table { };
class Software_tlb : public Arm_v7::Section_table { };
#endif /* _SRC__CORE__VEA9X4__SOFTWARE_TLB_H_ */

View File

@ -1,13 +1,16 @@
#
# \brief VEA9x4-specific makefile for core
# \brief Makefile for core
# \author Stefan Kalkowski
# \date 2012-10-04
#
# declare wich specs must be given to build this target
REQUIRES = platform_vea9x4
# adjust link address of a trustzone text segment
ifeq ($(filter-out $(SPECS),trustzone),)
LD_TEXT_ADDR = 0x48000000
endif
# include less specific target parts
include $(REP_DIR)/src/core/target.inc

View File

@ -14,11 +14,6 @@
/* Core includes */
#include <kernel_support.h>
Cpu::User_context::User_context() {
cpsr = Psr::init_user_with_trustzone(); }
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

@ -15,66 +15,26 @@
#define _SRC__CORE__VEA9X4__TRUSTZONE__KERNEL_SUPPORT_H_
/* Core includes */
#include <cortex_a9/cpu/core.h>
#include <pic/pl390_base.h>
#include <cortex_a9/cpu.h>
#include <cortex_a9/timer.h>
#include <vea9x4_trustzone/pic.h>
/**
* CPU driver
*/
class Cpu : public Genode::Cortex_a9 { };
class Cpu : public Cortex_a9::Cpu { };
namespace Kernel
{
/* import Genode types */
typedef Genode::Cortex_a9 Cortex_a9;
typedef Genode::Pl390_base Pl390_base;
/**
* Kernel interrupt-controller
* Programmable 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); }
};
class Pic : public Vea9x4_trustzone::Pic { };
/**
* Kernel timer
*/
class Timer : public Cortex_a9::Private_timer { };
class Timer : public Cortex_a9::Timer { };
}

View File

@ -16,8 +16,8 @@
/* Core includes */
#include <platform.h>
#include <pic/pl390_base.h>
#include <cortex_a9/cpu/core.h>
#include <vea9x4_trustzone/pic.h>
#include <cortex_a9/cpu.h>
using namespace Genode;
@ -39,7 +39,7 @@ Native_region * Platform::_irq_regions(unsigned const i)
{ 0, 34 },
{ 37, 3 },
{ 46, 1 },
{ 49, Pl390_base::MAX_INTERRUPT_ID - 49 }
{ 49, Vea9x4_trustzone::Pic::MAX_INTERRUPT_ID - 49 }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
@ -50,7 +50,7 @@ Native_region * Platform::_core_only_irq_regions(unsigned const i)
static Native_region _regions[] =
{
/* Core timer */
{ Cortex_a9::PRIVATE_TIMER_IRQ, 1 },
{ Cortex_a9::Cpu::PRIVATE_TIMER_IRQ, 1 },
/* Core UART */
{ Board::PL011_0_IRQ, 1 }

View File

@ -14,6 +14,7 @@
/* Core includes */
#include <trustzone.h>
#include <kernel_support.h>
#include <base/printf.h>
/* monitor exception vector address */
extern int _mon_kernel_entry;

View File

@ -1,5 +1,5 @@
/*
* \brief Vm_session_component for base-hw
* \brief VM session component for 'base-hw'
* \author Stefan Kalkowski
* \date 2012-10-08
*/
@ -17,7 +17,7 @@
#include <root/root.h>
#include <cpu/cpu_state.h>
/* Core includes */
/* core includes */
#include <vm_session_component.h>
using namespace Genode;

View File

@ -17,19 +17,6 @@
.global _start
_start:
/* zero-fill BSS segment but don't pollute thread-entry arguments */
.extern _bss_start
ldr r4, =_bss_start
.extern _bss_end
ldr r3, =_bss_end
mov r2, #0
sub r3, r3, #4
1:
str r2, [r4]
add r4, r4, #4
cmp r4, r3
bne 1b
/* fetch thread-entry arguments to their destinations in BSS */
ldr r1, =_main_utcb
str r0, [r1]
@ -38,8 +25,7 @@
ldr sp, =_main_stack_high
.extern _main
bl _main
1:
b 1b
1: b 1b
/* dynamic symbol object handle */
.align 3