mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 06:57:51 +00:00
parent
e83849cf99
commit
6a3368ee27
8
base-hw/mk/spec-hw.mk
Normal file
8
base-hw/mk/spec-hw.mk
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
# \brief Offer build configurations that are specific to base-hw
|
||||||
|
# \author Martin Stein
|
||||||
|
# \date 2014-02-26
|
||||||
|
#
|
||||||
|
|
||||||
|
# configure multiprocessor mode
|
||||||
|
CC_OPT += -Wa,--defsym -Wa,PROCESSORS=$(PROCESSORS) -DPROCESSORS=$(PROCESSORS)
|
@ -7,6 +7,9 @@
|
|||||||
# denote wich specs are also fullfilled by this spec
|
# denote wich specs are also fullfilled by this spec
|
||||||
SPECS += hw platform_arndale
|
SPECS += hw platform_arndale
|
||||||
|
|
||||||
|
# configure multiprocessor mode
|
||||||
|
PROCESSORS = 2
|
||||||
|
|
||||||
# add repository relative paths
|
# add repository relative paths
|
||||||
REP_INC_DIR += include/exynos5_uart
|
REP_INC_DIR += include/exynos5_uart
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
# denote wich specs are also fullfilled by this spec
|
# denote wich specs are also fullfilled by this spec
|
||||||
SPECS += hw platform_imx31 epit
|
SPECS += hw platform_imx31 epit
|
||||||
|
|
||||||
|
# configure multiprocessor mode
|
||||||
|
PROCESSORS = 1
|
||||||
|
|
||||||
# set address where to link the text segment at
|
# set address where to link the text segment at
|
||||||
LD_TEXT_ADDR ?= 0x82000000
|
LD_TEXT_ADDR ?= 0x82000000
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
# denote wich specs are also fullfilled by this spec
|
# denote wich specs are also fullfilled by this spec
|
||||||
SPECS += hw platform_imx53 epit
|
SPECS += hw platform_imx53 epit
|
||||||
|
|
||||||
|
# configure multiprocessor mode
|
||||||
|
PROCESSORS = 1
|
||||||
|
|
||||||
# set address where to link the text segment at
|
# set address where to link the text segment at
|
||||||
LD_TEXT_ADDR ?= 0x70010000
|
LD_TEXT_ADDR ?= 0x70010000
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
# denote wich specs are also fullfilled by this spec
|
# denote wich specs are also fullfilled by this spec
|
||||||
SPECS += hw platform_odroid_xu
|
SPECS += hw platform_odroid_xu
|
||||||
|
|
||||||
|
# configure multiprocessor mode
|
||||||
|
PROCESSORS = 1
|
||||||
|
|
||||||
# add repository relative paths
|
# add repository relative paths
|
||||||
REP_INC_DIR += include/exynos5_uart
|
REP_INC_DIR += include/exynos5_uart
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
# denote wich specs are also fullfilled by this spec
|
# denote wich specs are also fullfilled by this spec
|
||||||
SPECS += hw platform_panda
|
SPECS += hw platform_panda
|
||||||
|
|
||||||
|
# configure multiprocessor mode
|
||||||
|
PROCESSORS = 1
|
||||||
|
|
||||||
# set address where to link the text segment at
|
# set address where to link the text segment at
|
||||||
LD_TEXT_ADDR ?= 0x81000000
|
LD_TEXT_ADDR ?= 0x81000000
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
# denote wich specs are also fullfilled by this spec
|
# denote wich specs are also fullfilled by this spec
|
||||||
SPECS += hw platform_pbxa9
|
SPECS += hw platform_pbxa9
|
||||||
|
|
||||||
|
# configure multiprocessor mode
|
||||||
|
PROCESSORS = 1
|
||||||
|
|
||||||
# set address where to link text segment at
|
# set address where to link text segment at
|
||||||
LD_TEXT_ADDR ?= 0x70000000
|
LD_TEXT_ADDR ?= 0x70000000
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
# denote wich specs are also fullfilled by this spec
|
# denote wich specs are also fullfilled by this spec
|
||||||
SPECS += hw platform_rpi
|
SPECS += hw platform_rpi
|
||||||
|
|
||||||
|
# configure multiprocessor mode
|
||||||
|
PROCESSORS = 1
|
||||||
|
|
||||||
# set address where to link the text segment at
|
# set address where to link the text segment at
|
||||||
LD_TEXT_ADDR ?= 0x800000
|
LD_TEXT_ADDR ?= 0x800000
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
# denote wich specs are also fullfilled by this spec
|
# denote wich specs are also fullfilled by this spec
|
||||||
SPECS += hw platform_vea9x4
|
SPECS += hw platform_vea9x4
|
||||||
|
|
||||||
|
# configure multiprocessor mode
|
||||||
|
PROCESSORS = 1
|
||||||
|
|
||||||
# set address where to link text segment at
|
# set address where to link text segment at
|
||||||
LD_TEXT_ADDR ?= 0x01000000
|
LD_TEXT_ADDR ?= 0x01000000
|
||||||
|
|
||||||
|
@ -77,8 +77,7 @@ Thread_event Thread::* Thread::_event(unsigned const id) const
|
|||||||
|
|
||||||
void Thread::_mmu_exception()
|
void Thread::_mmu_exception()
|
||||||
{
|
{
|
||||||
cpu_scheduler()->remove(this);
|
_unschedule(AWAITS_RESUME);
|
||||||
_state = AWAITS_RESUME;
|
|
||||||
if (in_fault(_fault_addr, _fault_writes)) {
|
if (in_fault(_fault_addr, _fault_writes)) {
|
||||||
_fault_tlb = (addr_t)_pd->tlb();
|
_fault_tlb = (addr_t)_pd->tlb();
|
||||||
_fault_signal = _fault.signal_context_id();
|
_fault_signal = _fault.signal_context_id();
|
||||||
@ -87,3 +86,10 @@ void Thread::_mmu_exception()
|
|||||||
}
|
}
|
||||||
PERR("unknown MMU exception");
|
PERR("unknown MMU exception");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************
|
||||||
|
** Kernel::Cpu_context **
|
||||||
|
*************************/
|
||||||
|
|
||||||
|
void Kernel::Cpu_context::_init(size_t const stack_size) { r12 = stack_size; }
|
||||||
|
@ -12,9 +12,33 @@
|
|||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/************
|
||||||
|
** Macros **
|
||||||
|
************/
|
||||||
|
|
||||||
|
.include "macros.s"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get base of the first kernel-stack and the common kernel-stack size
|
||||||
|
*
|
||||||
|
* \param base_dst_reg register that shall receive the stack-area base
|
||||||
|
* \param size_dst_reg register that shall receive the size of a kernel stack
|
||||||
|
*/
|
||||||
|
.macro _get_constraints_of_kernel_stacks base_dst_reg, size_dst_reg
|
||||||
|
|
||||||
|
ldr \base_dst_reg, =kernel_stack
|
||||||
|
ldr \size_dst_reg, =kernel_stack_size
|
||||||
|
ldr \size_dst_reg, [\size_dst_reg]
|
||||||
|
.endm
|
||||||
|
|
||||||
|
|
||||||
.section ".text.crt0"
|
.section ".text.crt0"
|
||||||
|
|
||||||
/* program entry-point */
|
/****************************************
|
||||||
|
** Startup code for primary processor **
|
||||||
|
****************************************/
|
||||||
|
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
|
|
||||||
@ -40,22 +64,29 @@
|
|||||||
b 1b
|
b 1b
|
||||||
2:
|
2:
|
||||||
|
|
||||||
/* prepare the first call of the kernel main-routine */
|
/* setup temporary stack pointer for uniprocessor mode */
|
||||||
ldr sp, =_kernel_stack_high
|
_get_constraints_of_kernel_stacks r0, r1
|
||||||
bl setup_kernel
|
add sp, r0, r1
|
||||||
|
|
||||||
|
/* uniprocessor kernel-initialization which activates multiprocessor */
|
||||||
|
bl init_kernel_uniprocessor
|
||||||
|
|
||||||
|
/***************************************************
|
||||||
|
** Startup code that is common to all processors **
|
||||||
|
***************************************************/
|
||||||
|
|
||||||
|
.global _start_secondary_processors
|
||||||
|
_start_secondary_processors:
|
||||||
|
|
||||||
|
/* setup multiprocessor-aware kernel stack-pointer */
|
||||||
|
_get_constraints_of_kernel_stacks r0, r1
|
||||||
|
_init_kernel_sp r0, r1
|
||||||
|
|
||||||
|
/* do multiprocessor kernel-initialization */
|
||||||
|
bl init_kernel_multiprocessor
|
||||||
|
|
||||||
/* call the kernel main-routine */
|
/* call the kernel main-routine */
|
||||||
ldr sp, =_kernel_stack_high
|
|
||||||
bl kernel
|
bl kernel
|
||||||
|
|
||||||
/* catch erroneous return of the kernel main-routine */
|
/* catch erroneous return of the kernel main-routine */
|
||||||
3: b 3b
|
1: b 1b
|
||||||
|
|
||||||
.section .bss
|
|
||||||
|
|
||||||
/* kernel stack, must be aligned to an 8-byte boundary */
|
|
||||||
.align 3
|
|
||||||
.space 64 * 1024
|
|
||||||
.global _kernel_stack_high
|
|
||||||
_kernel_stack_high:
|
|
||||||
|
|
||||||
|
110
base-hw/src/core/arm/macros.s
Normal file
110
base-hw/src/core/arm/macros.s
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* \brief Macros that are used by multiple assembly files
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2014-01-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.include "macros_arm.s"
|
||||||
|
|
||||||
|
|
||||||
|
/*******************
|
||||||
|
** Common macros **
|
||||||
|
*******************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the top of the kernel stack of this processor and apply it as SP
|
||||||
|
*
|
||||||
|
* \base_reg register that contains the base of the kernel-stacks area
|
||||||
|
* \size_reg register that contains the size of one kernel stack
|
||||||
|
*/
|
||||||
|
.macro _init_kernel_sp base_reg, size_reg, buf_reg
|
||||||
|
|
||||||
|
/* get kernel name of processor */
|
||||||
|
_get_processor_id sp
|
||||||
|
|
||||||
|
/* calculate top of the kernel-stack of this processor and apply as SP */
|
||||||
|
add sp, #1
|
||||||
|
mul \size_reg, \size_reg, sp
|
||||||
|
add sp, \base_reg, \size_reg
|
||||||
|
.endm
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
** Macros regarding the mode transition **
|
||||||
|
******************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant values that the mode transition uses
|
||||||
|
*/
|
||||||
|
.macro _mt_constants
|
||||||
|
|
||||||
|
/* kernel names of exceptions that can interrupt a user */
|
||||||
|
.set rst_type, 1
|
||||||
|
.set und_type, 2
|
||||||
|
.set svc_type, 3
|
||||||
|
.set pab_type, 4
|
||||||
|
.set dab_type, 5
|
||||||
|
.set irq_type, 6
|
||||||
|
.set fiq_type, 7
|
||||||
|
|
||||||
|
.set rst_pc_adjust, 0
|
||||||
|
.set und_pc_adjust, 4
|
||||||
|
.set svc_pc_adjust, 0
|
||||||
|
.set pab_pc_adjust, 4
|
||||||
|
.set dab_pc_adjust, 8
|
||||||
|
.set irq_pc_adjust, 4
|
||||||
|
.set fiq_pc_adjust, 4
|
||||||
|
|
||||||
|
/* offsets of the member variables in a processor context */
|
||||||
|
.set r12_offset, 12 * 4
|
||||||
|
.set sp_offset, 13 * 4
|
||||||
|
.set lr_offset, 14 * 4
|
||||||
|
.set pc_offset, 15 * 4
|
||||||
|
.set psr_offset, 16 * 4
|
||||||
|
.set exception_type_offset, 17 * 4
|
||||||
|
.set contextidr_offset, 18 * 4
|
||||||
|
.set section_table_offset, 19 * 4
|
||||||
|
|
||||||
|
/* alignment constraints */
|
||||||
|
.set min_page_size_log2, 12
|
||||||
|
|
||||||
|
/* size of local variables */
|
||||||
|
.set context_ptr_size, 1 * 4
|
||||||
|
.endm
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local data structures that the mode transition uses
|
||||||
|
*/
|
||||||
|
.macro _mt_local_variables
|
||||||
|
|
||||||
|
/* space for a copy of 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:
|
||||||
|
|
||||||
|
/* space for a client context-pointer per processor */
|
||||||
|
.p2align 2
|
||||||
|
.global _mt_client_context_ptr
|
||||||
|
_mt_client_context_ptr:
|
||||||
|
.rept PROCESSORS
|
||||||
|
.space context_ptr_size
|
||||||
|
.endr
|
||||||
|
|
||||||
|
/* a globally mapped buffer per processor */
|
||||||
|
.p2align 2
|
||||||
|
.global _mt_buffer
|
||||||
|
_mt_buffer:
|
||||||
|
.rept PROCESSORS
|
||||||
|
.space buffer_size
|
||||||
|
.endr
|
||||||
|
.endm
|
24
base-hw/src/core/arm_v6/macros_arm.s
Normal file
24
base-hw/src/core/arm_v6/macros_arm.s
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* \brief Macros that are used by multiple assembly files
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2014-01-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the kernel name of the executing processor
|
||||||
|
*
|
||||||
|
* \param target_reg register that shall receive the processor name
|
||||||
|
*/
|
||||||
|
.macro _get_processor_id target_reg
|
||||||
|
|
||||||
|
/* no multiprocessing supported for ARMv6 */
|
||||||
|
mov \target_reg, #0
|
||||||
|
.endm
|
@ -11,6 +11,24 @@
|
|||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.include "macros.s"
|
||||||
|
|
||||||
|
|
||||||
|
/***************
|
||||||
|
** Constants **
|
||||||
|
***************/
|
||||||
|
|
||||||
|
/* size of local variables */
|
||||||
|
.set buffer_size, 1 * 4
|
||||||
|
|
||||||
|
/* common constants */
|
||||||
|
_mt_constants
|
||||||
|
|
||||||
|
|
||||||
|
/************
|
||||||
|
** Macros **
|
||||||
|
************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidate all entries of the branch prediction cache
|
* Invalidate all entries of the branch prediction cache
|
||||||
*
|
*
|
||||||
@ -22,7 +40,7 @@
|
|||||||
*/
|
*/
|
||||||
.macro _flush_branch_predictor
|
.macro _flush_branch_predictor
|
||||||
mcr p15, 0, sp, c7, c5, 6
|
mcr p15, 0, sp, c7, c5, 6
|
||||||
/* swi 0xf00000 */
|
/*swi 0xf00000 */
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,13 +65,13 @@
|
|||||||
|
|
||||||
/* load kernel cidr */
|
/* load kernel cidr */
|
||||||
adr sp, _mt_master_context_begin
|
adr sp, _mt_master_context_begin
|
||||||
ldr sp, [sp, #18*4]
|
ldr sp, [sp, #contextidr_offset]
|
||||||
mcr p15, 0, sp, c13, c0, 1
|
mcr p15, 0, sp, c13, c0, 1
|
||||||
_flush_branch_predictor
|
_flush_branch_predictor
|
||||||
|
|
||||||
/* load kernel section table */
|
/* load kernel section table */
|
||||||
adr sp, _mt_master_context_begin
|
adr sp, _mt_master_context_begin
|
||||||
ldr sp, [sp, #19*4]
|
ldr sp, [sp, #section_table_offset]
|
||||||
mcr p15, 0, sp, c2, c0, 0
|
mcr p15, 0, sp, c2, c0, 0
|
||||||
_flush_branch_predictor
|
_flush_branch_predictor
|
||||||
|
|
||||||
@ -72,22 +90,22 @@
|
|||||||
stmia sp, {r0-r12}^
|
stmia sp, {r0-r12}^
|
||||||
|
|
||||||
/* save user lr and sp */
|
/* save user lr and sp */
|
||||||
add r0, sp, #13*4
|
add r0, sp, #sp_offset
|
||||||
stmia r0, {sp,lr}^
|
stmia r0, {sp,lr}^
|
||||||
|
|
||||||
/* adjust and save user pc */
|
/* adjust and save user pc */
|
||||||
.if \pc_adjust != 0
|
.if \pc_adjust != 0
|
||||||
sub lr, lr, #\pc_adjust
|
sub lr, lr, #\pc_adjust
|
||||||
.endif
|
.endif
|
||||||
str lr, [sp, #15*4]
|
str lr, [sp, #pc_offset]
|
||||||
|
|
||||||
/* save user psr */
|
/* save user psr */
|
||||||
mrs r0, spsr
|
mrs r0, spsr
|
||||||
str r0, [sp, #16*4]
|
str r0, [sp, #psr_offset]
|
||||||
|
|
||||||
/* save type of exception that interrupted the user */
|
/* save type of exception that interrupted the user */
|
||||||
mov r0, #\exception_type
|
mov r0, #\exception_type
|
||||||
str r0, [sp, #17*4]
|
str r0, [sp, #exception_type_offset]
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Switch to supervisor mode
|
* Switch to supervisor mode
|
||||||
@ -102,133 +120,123 @@
|
|||||||
adr r0, _mt_master_context_begin
|
adr r0, _mt_master_context_begin
|
||||||
|
|
||||||
/* load kernel context */
|
/* load kernel context */
|
||||||
add r0, r0, #13*4
|
add r0, r0, #sp_offset
|
||||||
ldmia r0, {sp, lr, pc}
|
ldm r0, {sp, lr, pc}
|
||||||
|
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
** Linked into the text section **
|
||||||
|
**********************************/
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The mode transition PIC switches between a kernel context and a user
|
* Page aligned base of mode transition code.
|
||||||
* context and thereby between their address spaces. Due to the latter
|
*
|
||||||
|
* This position independent code 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.
|
* 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
|
* To enable such switching, the kernel context must be stored within this
|
||||||
* region, thus one should map it solely accessable for privileged modes.
|
* region, thus one should map it solely accessable for privileged modes.
|
||||||
*/
|
*/
|
||||||
.p2align 12
|
.p2align min_page_size_log2
|
||||||
.global _mt_begin
|
.global _mt_begin
|
||||||
_mt_begin:
|
_mt_begin:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On user exceptions the CPU has to jump to one of the following
|
* On user exceptions the CPU has to jump to one of the following
|
||||||
* 7 entry vectors to switch to a kernel context.
|
* seven entry vectors to switch to a kernel context.
|
||||||
*/
|
*/
|
||||||
.global _mt_kernel_entry_pic
|
.global _mt_kernel_entry_pic
|
||||||
_mt_kernel_entry_pic:
|
_mt_kernel_entry_pic:
|
||||||
|
|
||||||
b _rst_entry /* 0x00: reset */
|
b _rst_entry /* 0x00: reset */
|
||||||
b _und_entry /* 0x04: undefined instruction */
|
b _und_entry /* 0x04: undefined instruction */
|
||||||
b _swi_entry /* 0x08: software interrupt */
|
b _swi_entry /* 0x08: software interrupt */
|
||||||
b _pab_entry /* 0x0c: prefetch abort */
|
b _pab_entry /* 0x0c: prefetch abort */
|
||||||
b _dab_entry /* 0x10: data abort */
|
b _dab_entry /* 0x10: data abort */
|
||||||
nop /* 0x14: reserved */
|
nop /* 0x14: reserved */
|
||||||
b _irq_entry /* 0x18: interrupt request */
|
b _irq_entry /* 0x18: interrupt request */
|
||||||
b _fiq_entry /* 0x1c: fast interrupt request */
|
b _fiq_entry /* 0x1c: fast interrupt request */
|
||||||
|
|
||||||
/* PICs that switch from an user exception to the kernel */
|
/* PICs that switch from a user exception to the kernel */
|
||||||
_rst_entry: _user_to_kernel_pic 1, 0
|
_rst_entry: _user_to_kernel_pic rst_type, rst_pc_adjust
|
||||||
_und_entry: _user_to_kernel_pic 2, 4
|
_und_entry: _user_to_kernel_pic und_type, und_pc_adjust
|
||||||
_swi_entry:
|
_swi_entry:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME fast SWI routines pollute the SVC SP but we have
|
* FIXME fast SWI routines pollute the SVC SP but we have
|
||||||
* to call them especially in SVC mode
|
* to call them especially in SVC mode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* check if SWI requests a fast service routine */
|
/* check if SWI requests a fast service routine */
|
||||||
/* ldr sp, [r14, #-0x4]
|
/*ldr sp, [r14, #-0x4]*/
|
||||||
and sp, sp, #0xffffff
|
/*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
|
/* fast "instruction barrier" service routine */
|
||||||
_dab_entry: _user_to_kernel_pic 5, 8
|
/*cmp sp, #0xf00000*/
|
||||||
_irq_entry: _user_to_kernel_pic 6, 4
|
/*bne _slow_swi_entry*/
|
||||||
_fiq_entry: _user_to_kernel_pic 7, 4
|
/*movs pc, r14*/
|
||||||
|
|
||||||
/* kernel must jump to this point to switch to a user context */
|
/* slow high level service routine */
|
||||||
.p2align 2
|
_slow_swi_entry: _user_to_kernel_pic svc_type, svc_pc_adjust
|
||||||
.global _mt_user_entry_pic
|
|
||||||
_mt_user_entry_pic:
|
|
||||||
|
|
||||||
/* get user context pointer */
|
_pab_entry: _user_to_kernel_pic pab_type, pab_pc_adjust
|
||||||
ldr lr, _mt_client_context_ptr
|
_dab_entry: _user_to_kernel_pic dab_type, dab_pc_adjust
|
||||||
|
_irq_entry: _user_to_kernel_pic irq_type, irq_pc_adjust
|
||||||
|
_fiq_entry: _user_to_kernel_pic fiq_type, fiq_pc_adjust
|
||||||
|
|
||||||
/* buffer user pc */
|
/* kernel must jump to this point to switch to a user context */
|
||||||
ldr r0, [lr, #15*4]
|
.p2align 2
|
||||||
adr r1, _mt_buffer
|
.global _mt_user_entry_pic
|
||||||
str r0, [r1]
|
_mt_user_entry_pic:
|
||||||
|
|
||||||
/* buffer user psr */
|
/* get user context pointer */
|
||||||
ldr r0, [lr, #16*4]
|
ldr lr, _mt_client_context_ptr
|
||||||
msr spsr, r0
|
|
||||||
|
|
||||||
/* load user r0 ... r12 */
|
/* buffer user pc */
|
||||||
ldmia lr, {r0-r12}
|
ldr r0, [lr, #pc_offset]
|
||||||
|
adr r1, _mt_buffer
|
||||||
|
str r0, [r1]
|
||||||
|
|
||||||
/* load user sp and lr */
|
/* buffer user psr */
|
||||||
add sp, lr, #13*4
|
ldr r0, [lr, #psr_offset]
|
||||||
ldmia sp, {sp,lr}^
|
msr spsr, r0
|
||||||
|
|
||||||
/* get user cidr and section table */
|
/* load user r0 ... r12 */
|
||||||
ldr sp, [lr, #18*4]
|
ldm lr, {r0-r12}
|
||||||
ldr lr, [lr, #19*4]
|
|
||||||
|
|
||||||
/********************************************************
|
/* load user sp and lr */
|
||||||
** From now on, until we leave kernel mode, we must **
|
add sp, lr, #sp_offset
|
||||||
** avoid access to memory that is not mapped globally **
|
ldm sp, {sp,lr}^
|
||||||
********************************************************/
|
|
||||||
|
|
||||||
/* apply user contextidr and section table */
|
/* get user cidr and section table */
|
||||||
mcr p15, 0, sp, c13, c0, 1
|
ldr sp, [lr, #contextidr_offset]
|
||||||
mcr p15, 0, lr, c2, c0, 0
|
ldr lr, [lr, #section_table_offset]
|
||||||
_flush_branch_predictor
|
|
||||||
|
|
||||||
/* load user pc (implies application of the user psr) */
|
/********************************************************
|
||||||
adr lr, _mt_buffer
|
** From now on, until we leave kernel mode, we must **
|
||||||
ldmia lr, {pc}^
|
** avoid access to memory that is not mapped globally **
|
||||||
|
********************************************************/
|
||||||
|
|
||||||
/* leave some space for the kernel context */
|
/* apply user contextidr and section table */
|
||||||
.p2align 2
|
mcr p15, 0, sp, c13, c0, 1
|
||||||
.global _mt_master_context_begin
|
mcr p15, 0, lr, c2, c0, 0
|
||||||
_mt_master_context_begin: .space 32*4
|
_flush_branch_predictor
|
||||||
.global _mt_master_context_end
|
|
||||||
_mt_master_context_end:
|
|
||||||
|
|
||||||
/* pointer to the context backup space */
|
/* load user pc (implies application of the user psr) */
|
||||||
.p2align 2
|
adr lr, _mt_buffer
|
||||||
.global _mt_client_context_ptr
|
ldm lr, {pc}^
|
||||||
_mt_client_context_ptr: .long 0
|
|
||||||
|
|
||||||
/* a local word-sized buffer */
|
_mt_local_variables
|
||||||
.p2align 2
|
|
||||||
.global _mt_buffer
|
|
||||||
_mt_buffer: .long 0
|
|
||||||
|
|
||||||
.p2align 2
|
.p2align 2
|
||||||
.global _mt_end
|
.global _mt_end
|
||||||
_mt_end:
|
_mt_end:
|
||||||
|
|
||||||
/* FIXME this exists only because _vm_mon_entry pollutes kernel.cc */
|
/* FIXME exists only because _vm_mon_entry pollutes generic kernel code */
|
||||||
.global _mt_vm_entry_pic
|
.global _mt_vm_entry_pic
|
||||||
_mt_vm_entry_pic:
|
_mt_vm_entry_pic:
|
||||||
1: b 1b
|
1: b 1b
|
||||||
|
27
base-hw/src/core/arm_v7/macros_arm.s
Normal file
27
base-hw/src/core/arm_v7/macros_arm.s
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* \brief Macros that are used by multiple assembly files
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2014-01-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the kernel name of the executing processor
|
||||||
|
*
|
||||||
|
* \param target_reg register that shall receive the processor name
|
||||||
|
*/
|
||||||
|
.macro _get_processor_id target_reg
|
||||||
|
|
||||||
|
/* read the multiprocessor affinity register */
|
||||||
|
mrc p15, 0, \target_reg, c0, c0, 5
|
||||||
|
|
||||||
|
/* get the affinity-0 bitfield from the read register value */
|
||||||
|
and \target_reg, \target_reg, #0xff
|
||||||
|
.endm
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Transition between kernel/userland, and secure/non-secure world
|
* \brief Transition between kernel/userland, and secure/non-secure world
|
||||||
* \author Martin stein
|
* \author Martin Stein
|
||||||
* \author Stefan Kalkowski
|
* \author Stefan Kalkowski
|
||||||
* \date 2011-11-15
|
* \date 2011-11-15
|
||||||
*/
|
*/
|
||||||
@ -12,155 +12,204 @@
|
|||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.include "macros.s"
|
||||||
|
|
||||||
|
|
||||||
|
/***************
|
||||||
|
** Constants **
|
||||||
|
***************/
|
||||||
|
|
||||||
|
/* hardware names of processor modes */
|
||||||
|
.set usr_mode, 16
|
||||||
|
.set fiq_mode, 17
|
||||||
|
.set irq_mode, 18
|
||||||
|
.set svc_mode, 19
|
||||||
|
.set abt_mode, 23
|
||||||
|
.set und_mode, 27
|
||||||
|
|
||||||
|
/* size of local variables */
|
||||||
|
.set buffer_size, 2 * 4
|
||||||
|
|
||||||
|
/* common constants */
|
||||||
|
_mt_constants
|
||||||
|
|
||||||
|
|
||||||
|
/************
|
||||||
|
** Macros **
|
||||||
|
************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switch from an interrupted user context to a kernel context
|
* Determine the base of the client context of the executing processor
|
||||||
*
|
*
|
||||||
* \param exception_type immediate exception type ID
|
* \param target_reg register that shall receive the base pointer
|
||||||
* \param pc_adjust immediate value that gets subtracted from the
|
* \param buf_reg register that can be polluted by the macro
|
||||||
* user PC before it gets saved
|
*/
|
||||||
|
.macro _get_client_context_ptr target_reg, buf_reg
|
||||||
|
|
||||||
|
/* get kernel name of processor */
|
||||||
|
_get_processor_id \buf_reg
|
||||||
|
|
||||||
|
/* multiply processor name with pointer size to get offset of pointer */
|
||||||
|
mov \target_reg, #context_ptr_size
|
||||||
|
mul \buf_reg, \buf_reg, \target_reg
|
||||||
|
|
||||||
|
/* get base of the pointer array */
|
||||||
|
adr \target_reg, _mt_client_context_ptr
|
||||||
|
|
||||||
|
/* add offset and base to get processor-local pointer */
|
||||||
|
add \target_reg, \target_reg, \buf_reg
|
||||||
|
ldr \target_reg, [\target_reg]
|
||||||
|
.endm
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the base of the globally mapped buffer of the executing processor
|
||||||
|
*
|
||||||
|
* \param target_reg register that shall receive the base pointer
|
||||||
|
* \param buf_reg register that can be polluted by the macro
|
||||||
|
*/
|
||||||
|
.macro _get_buffer_ptr target_reg, buf_reg
|
||||||
|
|
||||||
|
/* get kernel name of processor */
|
||||||
|
_get_processor_id \buf_reg
|
||||||
|
|
||||||
|
/* multiply processor name with buffer size to get offset of buffer */
|
||||||
|
mov \target_reg, #buffer_size
|
||||||
|
mul \buf_reg, \buf_reg, \target_reg
|
||||||
|
|
||||||
|
/* get base of the buffer array */
|
||||||
|
adr \target_reg, _mt_buffer
|
||||||
|
|
||||||
|
/* add offset and base to get processor-local buffer */
|
||||||
|
add \target_reg, \target_reg, \buf_reg
|
||||||
|
.endm
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose a value for the translation-table-base register 0 and apply it
|
||||||
|
*
|
||||||
|
* \param section_table_reg register that contains targeted section-table base
|
||||||
|
*/
|
||||||
|
.macro _init_ttbr0 section_table_reg
|
||||||
|
|
||||||
|
/* IRGN bitfield is set to 1 to compose the TTBR0 value */
|
||||||
|
orr \section_table_reg, \section_table_reg, #0b1000000
|
||||||
|
|
||||||
|
/* write translation-table-base register 0 */
|
||||||
|
mcr p15, 0, \section_table_reg, c2, c0, 0
|
||||||
|
|
||||||
|
/* instruction and data synchronization barrier */
|
||||||
|
isb
|
||||||
|
dsb
|
||||||
|
.endm
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a value to the CONTEXTIDR register
|
||||||
|
*
|
||||||
|
* \param contexidr_reg register that contains the new CONTEXTIDR value
|
||||||
|
*/
|
||||||
|
.macro _init_contextidr contextidr_reg
|
||||||
|
|
||||||
|
/* write CONTEXTIDR register */
|
||||||
|
mcr p15, 0, \contextidr_reg, c13, c0, 1
|
||||||
|
|
||||||
|
/* finish all previous instructions */
|
||||||
|
isb
|
||||||
|
.endm
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save an interrupted user context and switch to the kernel context
|
||||||
|
*
|
||||||
|
* \param exception_type kernel name of exception type
|
||||||
|
* \param pc_adjust value that gets subtracted from saved user PC
|
||||||
*/
|
*/
|
||||||
.macro _user_to_kernel_pic exception_type, pc_adjust
|
.macro _user_to_kernel_pic exception_type, pc_adjust
|
||||||
|
|
||||||
/*
|
/*************************************************************************
|
||||||
* We expect that privileged modes are never interrupted by an
|
** Still in user protection domain, thus avoid access to kernel memory **
|
||||||
* exception. Thus we can assume that we always come from
|
*************************************************************************/
|
||||||
* user mode at this point.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* when not in FIQ mode disable FIQs */
|
/* disable fast interrupts when not in fast-interrupt mode */
|
||||||
.if \exception_type != 6
|
.if \exception_type != fiq_type
|
||||||
cpsid f
|
cpsid f
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
/************************************************
|
/*
|
||||||
** We're still in the user protection domain, **
|
* The sp in svc mode still contains the base of the globally mapped
|
||||||
** so we must avoid access to kernel memory **
|
* buffer of this processor. Hence go to svc mode and buffer user r0 and
|
||||||
************************************************/
|
* user r1 to globally mapped memory to be able to pollute r0 and r1.
|
||||||
|
*/
|
||||||
|
.if \exception_type != rst_type && \exception_type != svc_type
|
||||||
|
cps #svc_mode
|
||||||
|
.endif
|
||||||
|
stm sp, {r0, r1}^
|
||||||
|
|
||||||
/* load kernel cidr */
|
/* make buffer pointer available to all modes */
|
||||||
adr sp, _mt_master_context_begin
|
mov r0, sp
|
||||||
ldr sp, [sp, #18*4]
|
|
||||||
mcr p15, 0, sp, c13, c0, 1
|
|
||||||
isb
|
|
||||||
|
|
||||||
/* load kernel section table */
|
/* switch back to previous privileged mode */
|
||||||
|
.if \exception_type == und_type
|
||||||
|
cps #und_mode
|
||||||
|
.endif
|
||||||
|
.if \exception_type == pab_type
|
||||||
|
cps #abt_mode
|
||||||
|
.endif
|
||||||
|
.if \exception_type == dab_type
|
||||||
|
cps #abt_mode
|
||||||
|
.endif
|
||||||
|
.if \exception_type == irq_type
|
||||||
|
cps #irq_mode
|
||||||
|
.endif
|
||||||
|
.if \exception_type == fiq_type
|
||||||
|
cps #fiq_mode
|
||||||
|
.endif
|
||||||
|
|
||||||
|
/* load kernel contextidr and base of the kernel section-table */
|
||||||
adr sp, _mt_master_context_begin
|
adr sp, _mt_master_context_begin
|
||||||
ldr sp, [sp, #19*4]
|
add sp, #contextidr_offset
|
||||||
orr sp, sp, #0b1000000 /* set TTBR0 flags */
|
ldm sp, {r1, sp}
|
||||||
mcr p15, 0, sp, c2, c0, 0
|
|
||||||
isb
|
/* switch to kernel protection-domain */
|
||||||
dsb
|
_init_contextidr r1
|
||||||
|
_init_ttbr0 sp
|
||||||
|
|
||||||
/*******************************************
|
/*******************************************
|
||||||
** Now it's save to access kernel memory **
|
** Now it's save to access kernel memory **
|
||||||
*******************************************/
|
*******************************************/
|
||||||
|
|
||||||
/* get user context pointer */
|
/* get user context-pointer */
|
||||||
ldr sp, _mt_client_context_ptr
|
_get_client_context_ptr sp, r1
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 */
|
/* adjust and save user pc */
|
||||||
.if \pc_adjust != 0
|
.if \pc_adjust != 0
|
||||||
sub lr, lr, #\pc_adjust
|
sub lr, lr, #\pc_adjust
|
||||||
.endif
|
.endif
|
||||||
str lr, [sp, #15*4]
|
str lr, [sp, #pc_offset]
|
||||||
|
|
||||||
/* save user psr */
|
/* move buffer pointer to lr to enable us to save user r0 - r12 via stm */
|
||||||
|
mov lr, r0
|
||||||
|
|
||||||
|
/* restore user r0 and user r1 */
|
||||||
|
ldm lr, {r0, r1}
|
||||||
|
|
||||||
|
/* save user r0 - r12 */
|
||||||
|
stm sp, {r0-r12}^
|
||||||
|
|
||||||
|
/* save user sp and user lr */
|
||||||
|
add r0, sp, #sp_offset
|
||||||
|
stm r0, {sp, lr}^
|
||||||
|
|
||||||
|
/* get user psr and type of exception that interrupted the user */
|
||||||
mrs r0, spsr
|
mrs r0, spsr
|
||||||
str r0, [sp, #16*4]
|
mov r1, #\exception_type
|
||||||
|
|
||||||
/* save type of exception that interrupted the user */
|
b _common_user_to_kernel_pic
|
||||||
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 /* _user_to_kernel_pic */
|
.endm /* _user_to_kernel_pic */
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Switch from kernel context to a user context
|
|
||||||
*/
|
|
||||||
.macro _kernel_to_user_pic
|
|
||||||
|
|
||||||
/* get user context pointer */
|
|
||||||
ldr lr, _mt_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 contextidr and section table */
|
|
||||||
ldr sp, [lr, #18*4]
|
|
||||||
ldr lr, [lr, #19*4]
|
|
||||||
orr lr, lr, #0b1000000 /* set TTBR0 flags */
|
|
||||||
|
|
||||||
/********************************************************
|
|
||||||
** From now on, until we leave kernel mode, we must **
|
|
||||||
** avoid access to memory that is not mapped globally **
|
|
||||||
********************************************************/
|
|
||||||
|
|
||||||
/* apply user contextidr and section table */
|
|
||||||
mcr p15, 0, sp, c13, c0, 1
|
|
||||||
mcr p15, 0, lr, c2, c0, 0
|
|
||||||
isb
|
|
||||||
dsb
|
|
||||||
|
|
||||||
/* load user pc (implies application of the user psr) */
|
|
||||||
adr lr, _mt_buffer
|
|
||||||
ldmia lr, {pc}^
|
|
||||||
|
|
||||||
.endm /* _kernel_to_user_pic */
|
|
||||||
|
|
||||||
|
|
||||||
.macro _fiq_check_prior_mode
|
|
||||||
mrs r8, spsr /* load fiq-spsr */
|
|
||||||
and r8, #31
|
|
||||||
cmp r8, #16 /* check whether we come from user-mode */
|
|
||||||
beq 1f
|
|
||||||
mrs r8, spsr /* enable fiq-ignore bit */
|
|
||||||
orr r8, #64
|
|
||||||
msr spsr, r8
|
|
||||||
subs pc, lr, #4 /* resume previous exception */
|
|
||||||
1:
|
|
||||||
.endm /* _fiq_check_prior_mode */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save sp, lr and spsr register banks of specified exception mode
|
* Save sp, lr and spsr register banks of specified exception mode
|
||||||
*/
|
*/
|
||||||
@ -179,7 +228,7 @@
|
|||||||
* vm's PC before it gets saved
|
* vm's PC before it gets saved
|
||||||
*/
|
*/
|
||||||
.macro _vm_to_kernel exception_type, pc_adjust
|
.macro _vm_to_kernel exception_type, pc_adjust
|
||||||
ldr sp, _mt_client_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 */
|
stmia sp, {r0-lr}^ /* save user regs r0-r12,sp,lr */
|
||||||
add r0, sp, #15*4
|
add r0, sp, #15*4
|
||||||
.if \pc_adjust != 0 /* adjust pc if necessary */
|
.if \pc_adjust != 0 /* adjust pc if necessary */
|
||||||
@ -202,10 +251,7 @@
|
|||||||
_save_bank 17 /* save fiq banks */
|
_save_bank 17 /* save fiq banks */
|
||||||
stmia r0!, {r8-r12} /* save fiq r8-r12 */
|
stmia r0!, {r8-r12} /* save fiq r8-r12 */
|
||||||
stmia r0!, {r3-r6} /* save MMU registers */
|
stmia r0!, {r3-r6} /* save MMU registers */
|
||||||
cps #19 /* switch to supervisor mode */
|
b _common_client_to_kernel_pic
|
||||||
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 */
|
.endm /* _vm_to_kernel */
|
||||||
|
|
||||||
|
|
||||||
@ -243,67 +289,175 @@
|
|||||||
.endm /* _kernel_to_vm */
|
.endm /* _kernel_to_vm */
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
** Linked into the text section **
|
||||||
|
**********************************/
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The mode transition PIC switches between a kernel context and a user
|
* Page aligned base of mode transition code.
|
||||||
* context and thereby between their address spaces. Due to the latter
|
*
|
||||||
|
* This position independent code 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.
|
* 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
|
* To enable such switching, the kernel context must be stored within this
|
||||||
* region, thus one should map it solely accessable for privileged modes.
|
* region, thus one should map it solely accessable for privileged modes.
|
||||||
*/
|
*/
|
||||||
.p2align 12 /* page-aligned */
|
.p2align min_page_size_log2
|
||||||
.global _mt_begin
|
.global _mt_begin
|
||||||
_mt_begin:
|
_mt_begin:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On user exceptions the CPU has to jump to one of the following
|
* On user exceptions the CPU has to jump to one of the following
|
||||||
* 7 entry vectors to switch to a kernel context.
|
* seven entry vectors to switch to a kernel context.
|
||||||
*/
|
*/
|
||||||
.global _mt_kernel_entry_pic
|
.global _mt_kernel_entry_pic
|
||||||
_mt_kernel_entry_pic:
|
_mt_kernel_entry_pic:
|
||||||
|
|
||||||
b _rst_entry /* 0x00: reset */
|
/***********************
|
||||||
b _und_entry /* 0x04: undefined instruction */
|
** Exception entries **
|
||||||
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 */
|
b _rst_entry /* 0x00: reset */
|
||||||
_rst_entry: _user_to_kernel_pic 1, 0
|
b _und_entry /* 0x04: undefined instruction */
|
||||||
_und_entry: _user_to_kernel_pic 2, 4
|
b _svc_entry /* 0x08: supervisor call */
|
||||||
_svc_entry: _user_to_kernel_pic 3, 0
|
b _pab_entry /* 0x0c: prefetch abort */
|
||||||
_pab_entry: _user_to_kernel_pic 4, 4
|
b _dab_entry /* 0x10: data abort */
|
||||||
_dab_entry: _user_to_kernel_pic 5, 8
|
nop /* 0x14: reserved */
|
||||||
_irq_entry: _user_to_kernel_pic 6, 4
|
b _irq_entry /* 0x18: interrupt request */
|
||||||
|
|
||||||
/* kernel must jump to this point to switch to a user context */
|
/******************************************************
|
||||||
.p2align 2
|
** Entry for fast interrupt requests at offset 0x1c **
|
||||||
.global _mt_user_entry_pic
|
******************************************************/
|
||||||
_mt_user_entry_pic:
|
|
||||||
_kernel_to_user_pic
|
|
||||||
|
|
||||||
/* leave some space for the kernel context */
|
/* load the saved PSR of the the previous mode */
|
||||||
.p2align 2
|
mrs r8, spsr
|
||||||
.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 */
|
/* get the M bitfield from the read PSR value */
|
||||||
.p2align 2
|
and r9, r8, #0b11111
|
||||||
.global _mt_client_context_ptr
|
|
||||||
_mt_client_context_ptr: .long 0
|
|
||||||
|
|
||||||
/* a local word-sized buffer */
|
/* skip following instructions if previous mode was user mode */
|
||||||
.p2align 2
|
cmp r9, #usr_mode
|
||||||
.global _mt_buffer
|
beq 1f
|
||||||
_mt_buffer: .long 0
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we reach this point, the previous mode was not the user
|
||||||
|
* mode, meaning an exception entry has been preempted by this
|
||||||
|
* fast interrupt before it could disable fast interrupts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* disable fast interrupts in PSR value of previous mode */
|
||||||
|
orr r8, #0b1000000
|
||||||
|
|
||||||
|
/* apply PSR of previous mode */
|
||||||
|
msr spsr, r8
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resume excecution of previous exception entry leaving the fast
|
||||||
|
* interrupt unhandled till fast interrupts get enabled again.
|
||||||
|
*/
|
||||||
|
subs pc, lr, #4
|
||||||
|
|
||||||
|
/* switch to kernel to handle the fast interrupt */
|
||||||
|
1:
|
||||||
|
_user_to_kernel_pic fiq_type, fiq_pc_adjust
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
** Code that switches from a non-FIQ exception to the kernel **
|
||||||
|
***************************************************************/
|
||||||
|
|
||||||
|
_rst_entry: _user_to_kernel_pic rst_type, rst_pc_adjust
|
||||||
|
_und_entry: _user_to_kernel_pic und_type, und_pc_adjust
|
||||||
|
_svc_entry: _user_to_kernel_pic svc_type, svc_pc_adjust
|
||||||
|
_pab_entry: _user_to_kernel_pic pab_type, pab_pc_adjust
|
||||||
|
_dab_entry: _user_to_kernel_pic dab_type, dab_pc_adjust
|
||||||
|
_irq_entry: _user_to_kernel_pic irq_type, irq_pc_adjust
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
** Kernel-entry code that is common for all user exceptions **
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
_common_user_to_kernel_pic:
|
||||||
|
|
||||||
|
/* save user psr and type of exception that interrupted the user */
|
||||||
|
add sp, sp, #psr_offset
|
||||||
|
stm sp, {r0, r1}
|
||||||
|
|
||||||
|
/*********************************************************
|
||||||
|
** Kernel-entry code that is common for all exceptions **
|
||||||
|
*********************************************************/
|
||||||
|
|
||||||
|
_common_client_to_kernel_pic:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Switch to supervisor mode to circumvent incorrect behavior of
|
||||||
|
* kernel high-level code in fast interrupt mode and to ensure that
|
||||||
|
* we're in svc mode at kernel exit. The latter is because kernel
|
||||||
|
* exit stores a buffer pointer into its banked sp that is also
|
||||||
|
* needed by the subsequent kernel entry.
|
||||||
|
*/
|
||||||
|
cps #svc_mode
|
||||||
|
|
||||||
|
/* get base of the kernel-stacks area and the kernel-stack size */
|
||||||
|
adr r0, _mt_master_context_begin
|
||||||
|
add r1, r0, #r12_offset
|
||||||
|
ldm r1, {r2, r3}
|
||||||
|
|
||||||
|
/* determine top of the kernel stack of this processor and apply it as SP */
|
||||||
|
_init_kernel_sp r3, r2
|
||||||
|
|
||||||
|
/* apply kernel lr and kernel pc */
|
||||||
|
add r1, r0, #lr_offset
|
||||||
|
ldm r1, {lr, pc}
|
||||||
|
|
||||||
|
_mt_local_variables
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
** Code that switches from a kernel context to a user context **
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
.p2align 2
|
||||||
|
.global _mt_user_entry_pic
|
||||||
|
_mt_user_entry_pic:
|
||||||
|
|
||||||
|
/* get user context and globally mapped buffer of this processor */
|
||||||
|
_get_client_context_ptr lr, r0
|
||||||
|
_get_buffer_ptr sp, r0
|
||||||
|
|
||||||
|
/* buffer user pc and base of user section-table globally mapped */
|
||||||
|
ldr r0, [lr, #pc_offset]
|
||||||
|
ldr r1, [lr, #section_table_offset]
|
||||||
|
stm sp, {r0, r1}
|
||||||
|
|
||||||
|
/* buffer user psr in spsr */
|
||||||
|
ldr r0, [lr, #psr_offset]
|
||||||
|
msr spsr, r0
|
||||||
|
|
||||||
|
/* setup banked user sp and banked user lr */
|
||||||
|
add r0, lr, #sp_offset
|
||||||
|
ldm r0, {sp, lr}^
|
||||||
|
|
||||||
|
/* setup user r0 to r12 */
|
||||||
|
ldm lr, {r0-r12}^
|
||||||
|
|
||||||
|
/* load user contextidr */
|
||||||
|
ldr lr, [lr, #contextidr_offset]
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
** From now on, until we leave kernel mode, we must **
|
||||||
|
** avoid access to memory that is not mapped globally **
|
||||||
|
********************************************************/
|
||||||
|
|
||||||
|
/* switch to user protection-domain */
|
||||||
|
_init_contextidr lr
|
||||||
|
ldr lr, [sp, #4]
|
||||||
|
_init_ttbr0 lr
|
||||||
|
|
||||||
|
/* apply user pc which implies application of spsr as user psr */
|
||||||
|
ldm sp, {pc}^
|
||||||
|
|
||||||
|
/* end of the mode transition code */
|
||||||
.global _mt_end
|
.global _mt_end
|
||||||
_mt_end:
|
_mt_end:
|
||||||
|
|
||||||
@ -314,22 +468,22 @@
|
|||||||
.p2align 4
|
.p2align 4
|
||||||
.global _mon_kernel_entry
|
.global _mon_kernel_entry
|
||||||
_mon_kernel_entry:
|
_mon_kernel_entry:
|
||||||
b _mon_rst_entry /* reset */
|
b _mon_rst_entry /* reset */
|
||||||
b _mon_und_entry /* undefined instruction */
|
b _mon_und_entry /* undefined instruction */
|
||||||
b _mon_svc_entry /* supervisor call */
|
b _mon_svc_entry /* supervisor call */
|
||||||
b _mon_pab_entry /* prefetch abort */
|
b _mon_pab_entry /* prefetch abort */
|
||||||
b _mon_dab_entry /* data abort */
|
b _mon_dab_entry /* data abort */
|
||||||
nop /* reserved */
|
nop /* reserved */
|
||||||
b _mon_irq_entry /* interrupt request */
|
b _mon_irq_entry /* interrupt request */
|
||||||
_vm_to_kernel 7, 4 /* fast interrupt request */
|
_vm_to_kernel fiq_type, 4 /* fast interrupt request */
|
||||||
|
|
||||||
/* PICs that switch from a vm exception to the kernel */
|
/* PICs that switch from a vm exception to the kernel */
|
||||||
_mon_rst_entry: _vm_to_kernel 1, 0
|
_mon_rst_entry: _vm_to_kernel rst_type, 0
|
||||||
_mon_und_entry: _vm_to_kernel 2, 4
|
_mon_und_entry: _vm_to_kernel und_type, 4
|
||||||
_mon_svc_entry: _vm_to_kernel 3, 0
|
_mon_svc_entry: _vm_to_kernel svc_type, 0
|
||||||
_mon_pab_entry: _vm_to_kernel 4, 4
|
_mon_pab_entry: _vm_to_kernel pab_type, 4
|
||||||
_mon_dab_entry: _vm_to_kernel 5, 8
|
_mon_dab_entry: _vm_to_kernel dab_type, 8
|
||||||
_mon_irq_entry: _vm_to_kernel 6, 4
|
_mon_irq_entry: _vm_to_kernel irq_type, 4
|
||||||
|
|
||||||
/* kernel must jump to this point to switch to a vm */
|
/* kernel must jump to this point to switch to a vm */
|
||||||
.p2align 2
|
.p2align 2
|
||||||
|
40
base-hw/src/core/arndale/board.h
Normal file
40
base-hw/src/core/arndale/board.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* \brief Board driver for core
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2012-04-23
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2013 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BOARD_H_
|
||||||
|
#define _BOARD_H_
|
||||||
|
|
||||||
|
/* core includes */
|
||||||
|
#include <drivers/board_base.h>
|
||||||
|
|
||||||
|
namespace Genode
|
||||||
|
{
|
||||||
|
class Board : public Board_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static void prepare_kernel() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell secondary processors where to start execution from
|
||||||
|
*
|
||||||
|
* \param ip initial instruction pointer of secondary processors
|
||||||
|
*/
|
||||||
|
static void secondary_processors_ip(void * const ip)
|
||||||
|
{
|
||||||
|
*(void * volatile *)IRAM_BASE = ip;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _BOARD_H_ */
|
42
base-hw/src/core/arndale/cpu.h
Normal file
42
base-hw/src/core/arndale/cpu.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* \brief CPU driver for core
|
||||||
|
* \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 _ARNDALE__CPU_H_
|
||||||
|
#define _ARNDALE__CPU_H_
|
||||||
|
|
||||||
|
/* core includes */
|
||||||
|
#include <cpu/cortex_a15.h>
|
||||||
|
|
||||||
|
namespace Genode
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* CPU driver for core
|
||||||
|
*/
|
||||||
|
class Cpu : public Cortex_a15::Cpu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the executing processor
|
||||||
|
*/
|
||||||
|
static unsigned id() { return Mpidr::Aff_0::get(Mpidr::read()); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the primary processor
|
||||||
|
*/
|
||||||
|
static unsigned primary_id() { return Board::PRIMARY_MPIDR_AFF_0; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _ARNDALE__CPU_H_ */
|
||||||
|
|
@ -12,6 +12,7 @@ REQUIRES += platform_arndale
|
|||||||
INC_DIR += $(REP_DIR)/src/core/arndale
|
INC_DIR += $(REP_DIR)/src/core/arndale
|
||||||
INC_DIR += $(REP_DIR)/src/core/exynos5
|
INC_DIR += $(REP_DIR)/src/core/exynos5
|
||||||
INC_DIR += $(REP_DIR)/src/core/arm
|
INC_DIR += $(REP_DIR)/src/core/arm
|
||||||
|
INC_DIR += $(REP_DIR)/src/core/arm_v7
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += platform_services.cc \
|
SRC_CC += platform_services.cc \
|
||||||
|
56
base-hw/src/core/arndale/timer.h
Normal file
56
base-hw/src/core/arndale/timer.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* \brief Timer for 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 _ARNDALE__TIMER_H_
|
||||||
|
#define _ARNDALE__TIMER_H_
|
||||||
|
|
||||||
|
/* core includes */
|
||||||
|
#include <board.h>
|
||||||
|
#include <timer/exynos_mct.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Kernel timer
|
||||||
|
*/
|
||||||
|
class Timer : public Exynos_mct::Timer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of timer interrupt of a specific processor
|
||||||
|
*
|
||||||
|
* \param processor_id kernel name of targeted processor
|
||||||
|
*/
|
||||||
|
static unsigned interrupt_id(unsigned const processor_id)
|
||||||
|
{
|
||||||
|
switch (processor_id) {
|
||||||
|
case 0:
|
||||||
|
return Genode::Board::MCT_IRQ_L0;
|
||||||
|
case 1:
|
||||||
|
return Genode::Board::MCT_IRQ_L1;
|
||||||
|
default:
|
||||||
|
PERR("unknown processor");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Timer() : Exynos_mct::Timer(Genode::Board::MCT_MMIO_BASE,
|
||||||
|
Genode::Board::MCT_CLOCK) { }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _ARNDALE__TIMER_H_ */
|
@ -24,6 +24,8 @@ namespace Genode
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
static void prepare_kernel() { }
|
static void prepare_kernel() { }
|
||||||
|
|
||||||
|
static void secondary_processors_ip(void * const ip) { }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,24 @@ namespace Arm
|
|||||||
DATA_ACCESS_ALIGNM = 4,
|
DATA_ACCESS_ALIGNM = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiprocessor affinity register
|
||||||
|
*/
|
||||||
|
struct Mpidr : Register<32>
|
||||||
|
{
|
||||||
|
struct Aff_0 : Bitfield<0, 8> { };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read register value
|
||||||
|
*/
|
||||||
|
static access_t read()
|
||||||
|
{
|
||||||
|
access_t v;
|
||||||
|
asm volatile ("mrc p15, 0, %[v], c0, c0, 5" : [v] "=r" (v) ::);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache type register
|
* Cache type register
|
||||||
*/
|
*/
|
||||||
@ -574,10 +592,13 @@ namespace Arm
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush all instruction caches
|
* Invalidate all entries of all instruction caches
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline)) static void flush_instr_caches() {
|
__attribute__((always_inline))
|
||||||
asm volatile ("mcr p15, 0, %[rd], c7, c5, 0" :: [rd]"r"(0) : ); }
|
static void invalidate_instruction_caches()
|
||||||
|
{
|
||||||
|
asm volatile ("mcr p15, 0, %[rd], c7, c5, 0" :: [rd]"r"(0) : );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush all data caches
|
* Flush all data caches
|
||||||
@ -590,7 +611,7 @@ namespace Arm
|
|||||||
static void flush_caches()
|
static void flush_caches()
|
||||||
{
|
{
|
||||||
flush_data_caches();
|
flush_data_caches();
|
||||||
flush_instr_caches();
|
invalidate_instruction_caches();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -174,12 +174,57 @@ namespace Arm_v6
|
|||||||
* Ensure that TLB insertions get applied
|
* Ensure that TLB insertions get applied
|
||||||
*/
|
*/
|
||||||
static void tlb_insertions() { flush_tlb(); }
|
static void tlb_insertions() { flush_tlb(); }
|
||||||
|
|
||||||
|
static void start_secondary_processors(void * const ip)
|
||||||
|
{
|
||||||
|
if (PROCESSORS > 1) { PERR("multiprocessing not implemented"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidate all predictions about the future control-flow
|
||||||
|
*/
|
||||||
|
static void invalidate_control_flow_predictions()
|
||||||
|
{
|
||||||
|
/* FIXME invalidation of branch prediction not implemented */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish all previous data transfers
|
||||||
|
*/
|
||||||
|
static void data_synchronization_barrier()
|
||||||
|
{
|
||||||
|
/* FIXME data synchronization barrier not implemented */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for the next interrupt as cheap as possible
|
||||||
|
*/
|
||||||
|
static void wait_for_interrupt()
|
||||||
|
{
|
||||||
|
/* FIXME cheap way of waiting is not implemented */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the primary processor
|
||||||
|
*/
|
||||||
|
static unsigned primary_id() { return 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the executing processor
|
||||||
|
*/
|
||||||
|
static unsigned id() { return primary_id(); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Arm::Cpu::flush_data_caches() {
|
/**************
|
||||||
asm volatile ("mcr p15, 0, %[rd], c7, c14, 0" :: [rd]"r"(0) : ); }
|
** Arm::Cpu **
|
||||||
|
**************/
|
||||||
|
|
||||||
|
void Arm::Cpu::flush_data_caches()
|
||||||
|
{
|
||||||
|
asm volatile ("mcr p15, 0, %[rd], c7, c14, 0" :: [rd]"r"(0) : );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* _CPU__ARM_V6_H_ */
|
#endif /* _CPU__ARM_V6_H_ */
|
||||||
|
@ -222,6 +222,38 @@ namespace Arm_v7
|
|||||||
Nsacr::Cpnsae11::bits(1);
|
Nsacr::Cpnsae11::bits(1);
|
||||||
asm volatile ("mcr p15, 0, %[rd], c1, c1, 2" : : [rd] "r" (rd));
|
asm volatile ("mcr p15, 0, %[rd], c1, c1, 2" : : [rd] "r" (rd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidate all predictions about the future control-flow
|
||||||
|
*/
|
||||||
|
static void invalidate_control_flow_predictions()
|
||||||
|
{
|
||||||
|
asm volatile ("mcr p15, 0, r0, c7, c5, 6");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish all previous data transfers
|
||||||
|
*/
|
||||||
|
static void data_synchronization_barrier() { asm volatile ("dsb"); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable secondary processors that loop on wait-for-event
|
||||||
|
*
|
||||||
|
* \param ip initial instruction pointer for secondary processors
|
||||||
|
*/
|
||||||
|
static void start_secondary_processors(void * const ip)
|
||||||
|
{
|
||||||
|
if (PROCESSORS > 1) {
|
||||||
|
Genode::Board::secondary_processors_ip(ip);
|
||||||
|
data_synchronization_barrier();
|
||||||
|
asm volatile ("sev\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for the next interrupt as cheap as possible
|
||||||
|
*/
|
||||||
|
static void wait_for_interrupt() { asm volatile ("wfi"); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ REQUIRES = platform_imx31
|
|||||||
# add include paths
|
# add include paths
|
||||||
INC_DIR += $(REP_DIR)/src/core/imx31
|
INC_DIR += $(REP_DIR)/src/core/imx31
|
||||||
INC_DIR += $(REP_DIR)/src/core/arm
|
INC_DIR += $(REP_DIR)/src/core/arm
|
||||||
|
INC_DIR += $(REP_DIR)/src/core/arm_v6
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += platform_services.cc \
|
SRC_CC += platform_services.cc \
|
||||||
|
@ -23,7 +23,13 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum { IRQ = Genode::Board::EPIT_1_IRQ };
|
/**
|
||||||
|
* Return kernel name of timer interrupt
|
||||||
|
*/
|
||||||
|
static unsigned interrupt_id(unsigned)
|
||||||
|
{
|
||||||
|
return Genode::Board::EPIT_1_IRQ;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -96,6 +96,11 @@ namespace Imx53
|
|||||||
aips_1()->prepare_kernel();
|
aips_1()->prepare_kernel();
|
||||||
aips_2()->prepare_kernel();
|
aips_2()->prepare_kernel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell secondary processors where to start execution from
|
||||||
|
*/
|
||||||
|
static void secondary_processors_ip(void *) { }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,20 @@ namespace Genode
|
|||||||
/**
|
/**
|
||||||
* CPU driver for core
|
* CPU driver for core
|
||||||
*/
|
*/
|
||||||
class Cpu : public Cortex_a8::Cpu { };
|
class Cpu : public Cortex_a8::Cpu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the primary processor
|
||||||
|
*/
|
||||||
|
static unsigned primary_id() { return 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the executing processor
|
||||||
|
*/
|
||||||
|
static unsigned id() { return primary_id(); }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _IMX53__CPU_H_ */
|
#endif /* _IMX53__CPU_H_ */
|
||||||
|
@ -127,11 +127,16 @@ namespace Imx53
|
|||||||
|
|
||||||
write<Priomask::Mask>(0x1f);
|
write<Priomask::Mask>(0x1f);
|
||||||
write<Intctrl>(Intctrl::Enable::bits(1) |
|
write<Intctrl>(Intctrl::Enable::bits(1) |
|
||||||
Intctrl::Nsen::bits(1) |
|
Intctrl::Nsen::bits(1) |
|
||||||
Intctrl::Nsen_mask::bits(1));
|
Intctrl::Nsen_mask::bits(1));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize processor local interface of the controller
|
||||||
|
*/
|
||||||
|
void init_processor_local() { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receive a pending request number 'i'
|
* Receive a pending request number 'i'
|
||||||
*/
|
*/
|
||||||
@ -176,12 +181,15 @@ namespace Imx53
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unmask interrupt 'i'
|
* Unmask interrupt
|
||||||
|
*
|
||||||
|
* \param interrupt_id kernel name of targeted interrupt
|
||||||
*/
|
*/
|
||||||
void unmask(unsigned const i)
|
void unmask(unsigned const interrupt_id, unsigned)
|
||||||
{
|
{
|
||||||
if (i <= MAX_INTERRUPT_ID)
|
if (interrupt_id <= MAX_INTERRUPT_ID) {
|
||||||
write<Enset::Set_enable>(1, i);
|
write<Enset::Set_enable>(1, interrupt_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,6 +11,7 @@ REQUIRES += platform_imx53
|
|||||||
# add include paths
|
# add include paths
|
||||||
INC_DIR += $(REP_DIR)/src/core/imx53
|
INC_DIR += $(REP_DIR)/src/core/imx53
|
||||||
INC_DIR += $(REP_DIR)/src/core/arm
|
INC_DIR += $(REP_DIR)/src/core/arm
|
||||||
|
INC_DIR += $(REP_DIR)/src/core/arm_v7
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += platform_services.cc \
|
SRC_CC += platform_services.cc \
|
||||||
|
@ -27,7 +27,13 @@ namespace Imx53
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum { IRQ = Board::EPIT_1_IRQ };
|
/**
|
||||||
|
* Return kernel name of timer interrupt
|
||||||
|
*/
|
||||||
|
static unsigned interrupt_id(unsigned)
|
||||||
|
{
|
||||||
|
return Board::EPIT_1_IRQ;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -22,8 +22,13 @@
|
|||||||
extern int _mon_kernel_entry;
|
extern int _mon_kernel_entry;
|
||||||
|
|
||||||
|
|
||||||
void Kernel::trustzone_initialization(Pic *pic)
|
void Kernel::init_trustzone(Pic * pic)
|
||||||
{
|
{
|
||||||
|
/* check for compatibility */
|
||||||
|
if (PROCESSORS > 1) {
|
||||||
|
PERR("trustzone not supported with multiprocessing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
/* set exception vector entry */
|
/* set exception vector entry */
|
||||||
Genode::Cpu::mon_exception_entry_at((Genode::addr_t)&_mon_kernel_entry);
|
Genode::Cpu::mon_exception_entry_at((Genode::addr_t)&_mon_kernel_entry);
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ namespace Kernel {
|
|||||||
class Pic;
|
class Pic;
|
||||||
|
|
||||||
|
|
||||||
void trustzone_initialization(Pic *pic);
|
void init_trustzone(Pic * pic);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _CORE__INCLUDE__TRUSTZONE_H_ */
|
#endif /* _CORE__INCLUDE__TRUSTZONE_H_ */
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
/* core includes */
|
/* core includes */
|
||||||
#include <kernel/irq.h>
|
#include <kernel/irq.h>
|
||||||
#include <pic.h>
|
#include <pic.h>
|
||||||
|
#include <cpu.h>
|
||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
@ -21,4 +22,4 @@ namespace Kernel { Pic * pic(); }
|
|||||||
|
|
||||||
void Irq::_disable() const { pic()->mask(_id()); }
|
void Irq::_disable() const { pic()->mask(_id()); }
|
||||||
|
|
||||||
void Irq::_enable() const { pic()->unmask(_id()); }
|
void Irq::_enable() const { pic()->unmask(_id(), Genode::Cpu::id()); }
|
||||||
|
@ -40,8 +40,8 @@
|
|||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
extern Genode::Native_thread_id _main_thread_id;
|
extern Genode::Native_thread_id _main_thread_id;
|
||||||
extern int _kernel_stack_high;
|
|
||||||
extern "C" void CORE_MAIN();
|
extern "C" void CORE_MAIN();
|
||||||
|
extern void * _start_secondary_processors;
|
||||||
|
|
||||||
Genode::Native_utcb * _main_thread_utcb;
|
Genode::Native_utcb * _main_thread_utcb;
|
||||||
|
|
||||||
@ -62,11 +62,6 @@ namespace Kernel
|
|||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Idle thread entry
|
|
||||||
*/
|
|
||||||
static void idle_main() { while (1) ; }
|
|
||||||
|
|
||||||
Pd_ids * pd_ids() { return unmanaged_singleton<Pd_ids>(); }
|
Pd_ids * pd_ids() { return unmanaged_singleton<Pd_ids>(); }
|
||||||
Thread_ids * thread_ids() { return unmanaged_singleton<Thread_ids>(); }
|
Thread_ids * thread_ids() { return unmanaged_singleton<Thread_ids>(); }
|
||||||
Signal_context_ids * signal_context_ids() { return unmanaged_singleton<Signal_context_ids>(); }
|
Signal_context_ids * signal_context_ids() { return unmanaged_singleton<Signal_context_ids>(); }
|
||||||
@ -78,14 +73,21 @@ namespace Kernel
|
|||||||
Signal_receiver_pool * signal_receiver_pool() { return unmanaged_singleton<Signal_receiver_pool>(); }
|
Signal_receiver_pool * signal_receiver_pool() { return unmanaged_singleton<Signal_receiver_pool>(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access to static kernel timer
|
* Return singleton kernel-timer
|
||||||
*/
|
*/
|
||||||
static Timer * timer() { static Timer _object; return &_object; }
|
Timer * timer()
|
||||||
|
|
||||||
|
|
||||||
void reset_lap_time()
|
|
||||||
{
|
{
|
||||||
timer()->start_one_shot(timer()->ms_to_tics(USER_LAP_TIME_MS));
|
static Timer _object;
|
||||||
|
return &_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a new scheduling lap
|
||||||
|
*/
|
||||||
|
void reset_lap_time(unsigned const processor_id)
|
||||||
|
{
|
||||||
|
unsigned const tics = timer()->ms_to_tics(USER_LAP_TIME_MS);
|
||||||
|
timer()->start_one_shot(tics, processor_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -124,28 +126,6 @@ namespace Kernel
|
|||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Access to static CPU scheduler
|
|
||||||
*/
|
|
||||||
Cpu_scheduler * cpu_scheduler()
|
|
||||||
{
|
|
||||||
/* create idle thread */
|
|
||||||
static char idle_stack[DEFAULT_STACK_SIZE]
|
|
||||||
__attribute__((aligned(Cpu::DATA_ACCESS_ALIGNM)));
|
|
||||||
static Thread idle(Priority::MAX, "idle");
|
|
||||||
static bool init = 0;
|
|
||||||
if (!init) {
|
|
||||||
enum { STACK_SIZE = sizeof(idle_stack)/sizeof(idle_stack[0]) };
|
|
||||||
idle.ip = (addr_t)&idle_main;;
|
|
||||||
idle.sp = (addr_t)&idle_stack[STACK_SIZE];;
|
|
||||||
idle.init(0, core_id(), 0, 0);
|
|
||||||
init = 1;
|
|
||||||
}
|
|
||||||
/* create CPU scheduler with a permanent idle thread */
|
|
||||||
static Cpu_scheduler cpu_sched(&idle);
|
|
||||||
return &cpu_sched;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get attributes of the mode transition region in every PD
|
* Get attributes of the mode transition region in every PD
|
||||||
*/
|
*/
|
||||||
@ -162,64 +142,136 @@ namespace Kernel
|
|||||||
unsigned pd_alignm_log2() { return Tlb::ALIGNM_LOG2; }
|
unsigned pd_alignm_log2() { return Tlb::ALIGNM_LOG2; }
|
||||||
size_t vm_size() { return sizeof(Vm); }
|
size_t vm_size() { return sizeof(Vm); }
|
||||||
|
|
||||||
|
enum { STACK_SIZE = 64 * 1024 };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle an interrupt request
|
* Return lock that guards all kernel data against concurrent access
|
||||||
*/
|
*/
|
||||||
void handle_interrupt()
|
Lock & data_lock()
|
||||||
|
{
|
||||||
|
static Lock s;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_t core_tlb_base;
|
||||||
|
unsigned core_pd_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle interrupt request
|
||||||
|
*
|
||||||
|
* \param processor kernel object of targeted processor
|
||||||
|
* \param processor_id kernel name of targeted processor
|
||||||
|
*/
|
||||||
|
void handle_interrupt(Processor * const processor,
|
||||||
|
unsigned const processor_id)
|
||||||
{
|
{
|
||||||
/* determine handling for specific interrupt */
|
/* determine handling for specific interrupt */
|
||||||
unsigned irq_id;
|
unsigned irq_id;
|
||||||
if (pic()->take_request(irq_id))
|
if (pic()->take_request(irq_id))
|
||||||
{
|
{
|
||||||
switch (irq_id) {
|
/* check wether the interrupt is a scheduling timeout */
|
||||||
|
if (timer()->interrupt_id(processor_id) == irq_id)
|
||||||
case Timer::IRQ: {
|
{
|
||||||
|
/* handle scheduling timeout */
|
||||||
cpu_scheduler()->yield();
|
processor->scheduler()->yield();
|
||||||
timer()->clear_interrupt();
|
timer()->clear_interrupt(processor_id);
|
||||||
reset_lap_time();
|
reset_lap_time(processor_id);
|
||||||
break; }
|
} else {
|
||||||
|
|
||||||
default: {
|
|
||||||
|
|
||||||
|
/* try to inform the user interrupt-handler */
|
||||||
Irq::occurred(irq_id);
|
Irq::occurred(irq_id);
|
||||||
break; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* disengage interrupt controller from IRQ */
|
/* end interrupt request at controller */
|
||||||
pic()->finish_request();
|
pic()->finish_request();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare the first call of the kernel main-routine
|
* Enable kernel-entry assembly to get an exclusive stack at every processor
|
||||||
*/
|
*/
|
||||||
extern "C" void setup_kernel()
|
char kernel_stack[PROCESSORS][Kernel::STACK_SIZE] __attribute__((aligned()));
|
||||||
|
unsigned kernel_stack_size = Kernel::STACK_SIZE;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup kernel enviroment before activating secondary processors
|
||||||
|
*/
|
||||||
|
extern "C" void init_kernel_uniprocessor()
|
||||||
{
|
{
|
||||||
|
/************************************************************************
|
||||||
|
** As atomic operations are broken in physical mode on some platforms **
|
||||||
|
** we must avoid the use of 'cmpxchg' by now (includes not using any **
|
||||||
|
** local static objects. **
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
/* calculate in advance as needed later when data writes aren't allowed */
|
||||||
|
core_tlb_base = core()->tlb()->base();
|
||||||
|
core_pd_id = core_id();
|
||||||
|
|
||||||
|
/* initialize all processor objects */
|
||||||
|
multiprocessor();
|
||||||
|
|
||||||
|
/* go multiprocessor mode */
|
||||||
|
Cpu::start_secondary_processors(&_start_secondary_processors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup kernel enviroment after activating secondary processors
|
||||||
|
*/
|
||||||
|
extern "C" void init_kernel_multiprocessor()
|
||||||
|
{
|
||||||
|
/***********************************************************************
|
||||||
|
** As updates on a cached kernel lock might not be visible to **
|
||||||
|
** processors that have not enabled caches, we can't synchronize the **
|
||||||
|
** activation of MMU and caches. Hence we must avoid write access to **
|
||||||
|
** kernel data by now. **
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
/* synchronize data view of all processors */
|
||||||
|
Cpu::flush_data_caches();
|
||||||
|
Cpu::invalidate_instruction_caches();
|
||||||
|
Cpu::invalidate_control_flow_predictions();
|
||||||
|
Cpu::data_synchronization_barrier();
|
||||||
|
|
||||||
/* initialize processor in physical mode */
|
/* initialize processor in physical mode */
|
||||||
Cpu::init_phys_kernel();
|
Cpu::init_phys_kernel();
|
||||||
|
|
||||||
/* enable kernel timer */
|
|
||||||
pic()->unmask(Timer::IRQ);
|
|
||||||
|
|
||||||
/* TrustZone initialization code */
|
|
||||||
trustzone_initialization(pic());
|
|
||||||
|
|
||||||
/* enable performance counter */
|
|
||||||
perf_counter()->enable();
|
|
||||||
|
|
||||||
/* switch to core address space */
|
/* switch to core address space */
|
||||||
Cpu::init_virt_kernel(core()->tlb()->base(), core_id());
|
Cpu::init_virt_kernel(core_tlb_base, core_pd_id);
|
||||||
|
|
||||||
|
/************************************
|
||||||
|
** Now it's safe to use 'cmpxchg' **
|
||||||
|
************************************/
|
||||||
|
|
||||||
|
Lock::Guard guard(data_lock());
|
||||||
|
|
||||||
|
/*******************************************
|
||||||
|
** Now it's save to write to kernel data **
|
||||||
|
*******************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* From this point on, it is safe to use 'cmpxchg', i.e., to create
|
* TrustZone initialization code
|
||||||
* singleton objects via the static-local object pattern. See
|
*
|
||||||
* the comment in 'src/base/singleton.h'.
|
* FIXME This is a plattform specific feature
|
||||||
*/
|
*/
|
||||||
|
init_trustzone(pic());
|
||||||
|
|
||||||
/* create the core main thread */
|
/*
|
||||||
|
* Enable performance counter
|
||||||
|
*
|
||||||
|
* FIXME This is an optional processor specific feature
|
||||||
|
*/
|
||||||
|
perf_counter()->enable();
|
||||||
|
|
||||||
|
/* initialize interrupt controller */
|
||||||
|
pic()->init_processor_local();
|
||||||
|
unsigned const processor_id = Cpu::id();
|
||||||
|
pic()->unmask(Timer::interrupt_id(processor_id), processor_id);
|
||||||
|
|
||||||
|
/* as primary processor create the core main thread */
|
||||||
|
if (Cpu::primary_id() == processor_id)
|
||||||
{
|
{
|
||||||
/* get stack memory that fullfills the constraints for core stacks */
|
/* get stack memory that fullfills the constraints for core stacks */
|
||||||
enum {
|
enum {
|
||||||
@ -242,11 +294,12 @@ extern "C" void setup_kernel()
|
|||||||
_main_thread_utcb->start_info()->init(t.id(), Genode::Native_capability());
|
_main_thread_utcb->start_info()->init(t.id(), Genode::Native_capability());
|
||||||
t.ip = (addr_t)CORE_MAIN;;
|
t.ip = (addr_t)CORE_MAIN;;
|
||||||
t.sp = (addr_t)s + STACK_SIZE;
|
t.sp = (addr_t)s + STACK_SIZE;
|
||||||
t.init(0, core_id(), &utcb, 1);
|
t.init(multiprocessor()->select(processor_id), core_id(), &utcb, 1);
|
||||||
|
|
||||||
|
/* kernel initialization finished */
|
||||||
|
init_platform();
|
||||||
}
|
}
|
||||||
/* kernel initialization finished */
|
reset_lap_time(processor_id);
|
||||||
init_platform();
|
|
||||||
reset_lap_time();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -255,27 +308,32 @@ extern "C" void setup_kernel()
|
|||||||
*/
|
*/
|
||||||
extern "C" void kernel()
|
extern "C" void kernel()
|
||||||
{
|
{
|
||||||
cpu_scheduler()->head()->handle_exception();
|
data_lock().lock();
|
||||||
cpu_scheduler()->head()->proceed();
|
unsigned const processor_id = Cpu::id();
|
||||||
|
Processor * const processor = multiprocessor()->select(processor_id);
|
||||||
|
Processor_scheduler * const scheduler = processor->scheduler();
|
||||||
|
scheduler->head()->handle_exception(processor_id);
|
||||||
|
scheduler->head()->proceed(processor_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Kernel::Mode_transition_control * Kernel::mtc()
|
Kernel::Mode_transition_control * Kernel::mtc()
|
||||||
{
|
{
|
||||||
/* compose CPU context for kernel entry */
|
/* create singleton processor context for kernel */
|
||||||
struct Kernel_context : Cpu::Context
|
Cpu_context * const cpu_context = unmanaged_singleton<Cpu_context>();
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Kernel_context()
|
|
||||||
{
|
|
||||||
ip = (addr_t)kernel;
|
|
||||||
sp = (addr_t)&_kernel_stack_high;
|
|
||||||
core()->admit(this);
|
|
||||||
}
|
|
||||||
} * const k = unmanaged_singleton<Kernel_context>();
|
|
||||||
|
|
||||||
/* initialize mode transition page */
|
/* initialize mode transition page */
|
||||||
return unmanaged_singleton<Mode_transition_control>(k);
|
return unmanaged_singleton<Mode_transition_control>(cpu_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Kernel::Execution_context::~Execution_context() { }
|
||||||
|
|
||||||
|
|
||||||
|
Kernel::Cpu_context::Cpu_context()
|
||||||
|
{
|
||||||
|
_init(STACK_SIZE);
|
||||||
|
sp = (addr_t)kernel_stack;
|
||||||
|
ip = (addr_t)kernel;
|
||||||
|
core()->admit(this);
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,12 @@
|
|||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
class Processor;
|
||||||
|
|
||||||
unsigned core_id();
|
unsigned core_id();
|
||||||
|
|
||||||
void handle_interrupt();
|
void handle_interrupt(Processor * const processor,
|
||||||
|
unsigned const processor_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _KERNEL__KERNEL_H_ */
|
#endif /* _KERNEL__KERNEL_H_ */
|
||||||
|
24
base-hw/src/core/kernel/multiprocessor.cc
Normal file
24
base-hw/src/core/kernel/multiprocessor.cc
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* \brief Representation of a common instruction processor
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2014-01-14
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* core includes */
|
||||||
|
#include <kernel/multiprocessor.h>
|
||||||
|
|
||||||
|
using namespace Kernel;
|
||||||
|
|
||||||
|
|
||||||
|
Multiprocessor * Kernel::multiprocessor()
|
||||||
|
{
|
||||||
|
static Multiprocessor s;
|
||||||
|
return &s;
|
||||||
|
}
|
148
base-hw/src/core/kernel/multiprocessor.h
Normal file
148
base-hw/src/core/kernel/multiprocessor.h
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* \brief Provide a processor object for every available processor
|
||||||
|
* \author Martin Stein
|
||||||
|
* \date 2014-01-14
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 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 _KERNEL__MULTIPROCESSOR_H_
|
||||||
|
#define _KERNEL__MULTIPROCESSOR_H_
|
||||||
|
|
||||||
|
/* base includes */
|
||||||
|
#include <unmanaged_singleton.h>
|
||||||
|
|
||||||
|
/* core includes */
|
||||||
|
#include <kernel/thread.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
typedef Cpu_scheduler Processor_scheduler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread that consumes processor time if no other thread is available
|
||||||
|
*/
|
||||||
|
class Idle_thread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of a single common instruction processor
|
||||||
|
*/
|
||||||
|
class Processor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a processor object for every provided processor
|
||||||
|
*/
|
||||||
|
class Multiprocessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return multiprocessor singleton
|
||||||
|
*/
|
||||||
|
Multiprocessor * multiprocessor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the core protection-domain
|
||||||
|
*/
|
||||||
|
unsigned core_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Kernel::Idle_thread : public Thread
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STACK_SIZE = 4 * 1024,
|
||||||
|
STACK_ALIGNM = Cpu::DATA_ACCESS_ALIGNM,
|
||||||
|
};
|
||||||
|
|
||||||
|
char _stack[STACK_SIZE] __attribute__((aligned(STACK_ALIGNM)));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main function of all idle threads
|
||||||
|
*/
|
||||||
|
static void _main() { while (1) { Cpu::wait_for_interrupt(); } }
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* \param processor kernel object of targeted processor
|
||||||
|
*/
|
||||||
|
Idle_thread(Processor * const processor)
|
||||||
|
:
|
||||||
|
Thread(Priority::MAX, "idle")
|
||||||
|
{
|
||||||
|
ip = (addr_t)&_main;
|
||||||
|
sp = (addr_t)&_stack[STACK_SIZE];
|
||||||
|
init(processor, core_id(), 0, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Kernel::Processor
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Idle_thread _idle;
|
||||||
|
Processor_scheduler _scheduler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Processor() : _idle(this), _scheduler(&_idle) { }
|
||||||
|
|
||||||
|
|
||||||
|
/***************
|
||||||
|
** Accessors **
|
||||||
|
***************/
|
||||||
|
|
||||||
|
Processor_scheduler * scheduler() { return &_scheduler; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Kernel::Multiprocessor
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
char _data[PROCESSORS][sizeof(Processor)];
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the objects of one of the available processors
|
||||||
|
*
|
||||||
|
* \param id kernel name of the targeted processor
|
||||||
|
*/
|
||||||
|
Multiprocessor()
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < PROCESSORS; i++) {
|
||||||
|
new (_data[i]) Processor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the object of a specific processor
|
||||||
|
*
|
||||||
|
* \param id kernel name of the targeted processor
|
||||||
|
*/
|
||||||
|
Processor * select(unsigned const id) const
|
||||||
|
{
|
||||||
|
return id < PROCESSORS ? (Processor *)_data[id] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the object of the primary processor
|
||||||
|
*/
|
||||||
|
Processor * primary() const
|
||||||
|
{
|
||||||
|
return (Processor *)_data[Cpu::primary_id()];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _KERNEL__MULTIPROCESSOR_H_ */
|
@ -14,6 +14,9 @@
|
|||||||
#ifndef _KERNEL__PD_H_
|
#ifndef _KERNEL__PD_H_
|
||||||
#define _KERNEL__PD_H_
|
#define _KERNEL__PD_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <cpu/atomic.h>
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <kernel/configuration.h>
|
#include <kernel/configuration.h>
|
||||||
#include <kernel/object.h>
|
#include <kernel/object.h>
|
||||||
@ -30,6 +33,49 @@ extern Genode::addr_t _mt_client_context_ptr;
|
|||||||
extern Genode::addr_t _mt_master_context_begin;
|
extern Genode::addr_t _mt_master_context_begin;
|
||||||
extern Genode::addr_t _mt_master_context_end;
|
extern Genode::addr_t _mt_master_context_end;
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Lock that enables synchronization inside the kernel
|
||||||
|
*/
|
||||||
|
class Lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Kernel::Lock
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
int volatile _locked;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish all previously started memory transactions
|
||||||
|
*/
|
||||||
|
void _memory_barrier() { asm volatile ("" : : : "memory"); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Lock() : _locked(0) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request the lock
|
||||||
|
*/
|
||||||
|
void lock() { while (!Genode::cmpxchg(&_locked, 0, 1)); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the lock
|
||||||
|
*/
|
||||||
|
void unlock()
|
||||||
|
{
|
||||||
|
_memory_barrier();
|
||||||
|
_locked = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide guard semantic for this type of lock
|
||||||
|
*/
|
||||||
|
typedef Genode::Lock_guard<Kernel::Lock> Guard;
|
||||||
|
};
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -59,6 +105,8 @@ namespace Kernel
|
|||||||
|
|
||||||
Pd_ids * pd_ids();
|
Pd_ids * pd_ids();
|
||||||
Pd_pool * pd_pool();
|
Pd_pool * pd_pool();
|
||||||
|
|
||||||
|
Lock & data_lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
class Kernel::Mode_transition_control
|
class Kernel::Mode_transition_control
|
||||||
@ -73,6 +121,31 @@ class Kernel::Mode_transition_control
|
|||||||
|
|
||||||
addr_t const _virt_user_entry;
|
addr_t const _virt_user_entry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Continue execution of client context
|
||||||
|
*
|
||||||
|
* \param context targeted client processor-context
|
||||||
|
* \param processor_id kernel name of targeted processor
|
||||||
|
* \param entry_raw raw pointer to assembly entry-code
|
||||||
|
*/
|
||||||
|
void _continue_client(void * const context, unsigned const processor_id,
|
||||||
|
addr_t const entry_raw)
|
||||||
|
{
|
||||||
|
/* override client-context pointer of the executing processor */
|
||||||
|
addr_t const context_ptr_base = (addr_t)&_mt_client_context_ptr;
|
||||||
|
size_t const context_ptr_offset = processor_id * sizeof(context);
|
||||||
|
addr_t const context_ptr = context_ptr_base + context_ptr_offset;
|
||||||
|
*(void * *)context_ptr = context;
|
||||||
|
|
||||||
|
/* unlock kernel data */
|
||||||
|
data_lock().unlock();
|
||||||
|
|
||||||
|
/* call assembly code that applies the virtual-machine context */
|
||||||
|
typedef void (* Entry)();
|
||||||
|
Entry __attribute__((noreturn)) const entry = (Entry)entry_raw;
|
||||||
|
entry();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -126,21 +199,27 @@ class Kernel::Mode_transition_control
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Continue user-mode execution with CPU context 'c'
|
* Continue execution of userland context
|
||||||
|
*
|
||||||
|
* \param context targeted userland context
|
||||||
|
* \param processor_id kernel name of targeted processor
|
||||||
*/
|
*/
|
||||||
void continue_user(Cpu::Context * const c)
|
void continue_user(Cpu::Context * const context,
|
||||||
|
unsigned const processor_id)
|
||||||
{
|
{
|
||||||
_mt_client_context_ptr = (addr_t)c;
|
_continue_client(context, processor_id, _virt_user_entry);
|
||||||
((void(*)(void))_virt_user_entry)();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Continue VM execution with CPU state 's'
|
* Continue execution of virtual machine
|
||||||
|
*
|
||||||
|
* \param context targeted virtual-machine context
|
||||||
|
* \param processor_id kernel name of targeted processor
|
||||||
*/
|
*/
|
||||||
void continue_vm(Cpu_state_modes * s)
|
void continue_vm(Cpu_state_modes * const context,
|
||||||
|
unsigned const processor_id)
|
||||||
{
|
{
|
||||||
_mt_client_context_ptr = (addr_t)s;
|
_continue_client(context, processor_id, _mt_vm_entry_pic);
|
||||||
((void(*)(void))&_mt_vm_entry_pic)();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,11 +58,6 @@ namespace Kernel
|
|||||||
class Execution_context;
|
class Execution_context;
|
||||||
|
|
||||||
typedef Scheduler<Execution_context> Cpu_scheduler;
|
typedef Scheduler<Execution_context> Cpu_scheduler;
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the systems CPU scheduler
|
|
||||||
*/
|
|
||||||
Cpu_scheduler * cpu_scheduler();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -304,13 +299,17 @@ class Kernel::Execution_context : public Cpu_scheduler::Item
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle an exception that occured during execution
|
* Handle an exception that occured during execution
|
||||||
|
*
|
||||||
|
* \param processor_id kernel name of targeted processor
|
||||||
*/
|
*/
|
||||||
virtual void handle_exception() = 0;
|
virtual void handle_exception(unsigned const processor_id) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Continue execution
|
* Continue execution
|
||||||
|
*
|
||||||
|
* \param processor_id kernel name of targeted processor
|
||||||
*/
|
*/
|
||||||
virtual void proceed() = 0;
|
virtual void proceed(unsigned const processor_id) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -322,10 +321,7 @@ class Kernel::Execution_context : public Cpu_scheduler::Item
|
|||||||
/**
|
/**
|
||||||
* Destructor
|
* Destructor
|
||||||
*/
|
*/
|
||||||
virtual ~Execution_context()
|
virtual ~Execution_context();
|
||||||
{
|
|
||||||
if (list()) { cpu_scheduler()->remove(this); }
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _KERNEL__SCHEDULER_H_ */
|
#endif /* _KERNEL__SCHEDULER_H_ */
|
||||||
|
@ -21,7 +21,9 @@
|
|||||||
#include <kernel/kernel.h>
|
#include <kernel/kernel.h>
|
||||||
#include <kernel/thread.h>
|
#include <kernel/thread.h>
|
||||||
#include <kernel/vm.h>
|
#include <kernel/vm.h>
|
||||||
|
#include <kernel/irq.h>
|
||||||
#include <platform_pd.h>
|
#include <platform_pd.h>
|
||||||
|
#include <pic.h>
|
||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
@ -31,12 +33,12 @@ unsigned Thread::pd_id() const { return _pd ? _pd->id() : 0; }
|
|||||||
|
|
||||||
bool Thread::_core() const { return pd_id() == core_id(); }
|
bool Thread::_core() const { return pd_id() == core_id(); }
|
||||||
|
|
||||||
|
namespace Kernel { void reset_lap_time(unsigned const processor_id); }
|
||||||
|
|
||||||
void Thread::_signal_context_kill_pending()
|
void Thread::_signal_context_kill_pending()
|
||||||
{
|
{
|
||||||
assert(_state == SCHEDULED);
|
assert(_state == SCHEDULED);
|
||||||
_state = AWAITS_SIGNAL_CONTEXT_KILL;
|
_unschedule(AWAITS_SIGNAL_CONTEXT_KILL);
|
||||||
cpu_scheduler()->remove(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -58,8 +60,7 @@ void Thread::_signal_context_kill_failed()
|
|||||||
|
|
||||||
void Thread::_await_signal(Signal_receiver * const receiver)
|
void Thread::_await_signal(Signal_receiver * const receiver)
|
||||||
{
|
{
|
||||||
cpu_scheduler()->remove(this);
|
_unschedule(AWAITS_SIGNAL);
|
||||||
_state = AWAITS_SIGNAL;
|
|
||||||
_signal_receiver = receiver;
|
_signal_receiver = receiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,8 +91,7 @@ void Thread::_await_ipc()
|
|||||||
{
|
{
|
||||||
switch (_state) {
|
switch (_state) {
|
||||||
case SCHEDULED:
|
case SCHEDULED:
|
||||||
cpu_scheduler()->remove(this);
|
_unschedule(AWAITS_IPC);
|
||||||
_state = AWAITS_IPC;
|
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
PERR("wrong thread state to await IPC");
|
PERR("wrong thread state to await IPC");
|
||||||
@ -159,18 +159,25 @@ int Thread::_resume()
|
|||||||
void Thread::_pause()
|
void Thread::_pause()
|
||||||
{
|
{
|
||||||
assert(_state == AWAITS_RESUME || _state == SCHEDULED);
|
assert(_state == AWAITS_RESUME || _state == SCHEDULED);
|
||||||
cpu_scheduler()->remove(this);
|
_unschedule(AWAITS_RESUME);
|
||||||
_state = AWAITS_RESUME;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_schedule()
|
void Thread::_schedule()
|
||||||
{
|
{
|
||||||
cpu_scheduler()->insert(this);
|
if (_state == SCHEDULED) { return; }
|
||||||
|
_processor->scheduler()->insert(this);
|
||||||
_state = SCHEDULED;
|
_state = SCHEDULED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread::_unschedule(State const s)
|
||||||
|
{
|
||||||
|
if (_state == SCHEDULED) { _processor->scheduler()->remove(this); }
|
||||||
|
_state = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Thread::Thread(unsigned const priority, char const * const label)
|
Thread::Thread(unsigned const priority, char const * const label)
|
||||||
:
|
:
|
||||||
Execution_context(priority),
|
Execution_context(priority),
|
||||||
@ -184,17 +191,17 @@ Thread::Thread(unsigned const priority, char const * const label)
|
|||||||
cpu_exception = RESET;
|
cpu_exception = RESET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Thread::~Thread() { if (Execution_context::list()) { _unschedule(STOPPED); } }
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Thread::init(unsigned const cpu_id, unsigned const pd_id_arg,
|
Thread::init(Processor * const processor, unsigned const pd_id_arg,
|
||||||
Native_utcb * const utcb_phys, bool const start)
|
Native_utcb * const utcb_phys, bool const start)
|
||||||
{
|
{
|
||||||
assert(_state == AWAITS_START)
|
assert(_state == AWAITS_START)
|
||||||
|
|
||||||
/* FIXME: support SMP */
|
|
||||||
if (cpu_id) { PERR("multicore processing not supported"); }
|
|
||||||
|
|
||||||
/* store thread parameters */
|
/* store thread parameters */
|
||||||
|
_processor = processor;
|
||||||
_utcb_phys = utcb_phys;
|
_utcb_phys = utcb_phys;
|
||||||
|
|
||||||
/* join protection domain */
|
/* join protection domain */
|
||||||
@ -213,18 +220,14 @@ Thread::init(unsigned const cpu_id, unsigned const pd_id_arg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_stop()
|
void Thread::_stop() { _unschedule(STOPPED); }
|
||||||
{
|
|
||||||
if (_state == SCHEDULED) { cpu_scheduler()->remove(this); }
|
|
||||||
_state = STOPPED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Thread::handle_exception()
|
void Thread::handle_exception(unsigned const processor_id)
|
||||||
{
|
{
|
||||||
switch (cpu_exception) {
|
switch (cpu_exception) {
|
||||||
case SUPERVISOR_CALL:
|
case SUPERVISOR_CALL:
|
||||||
_call();
|
_call(processor_id);
|
||||||
return;
|
return;
|
||||||
case PREFETCH_ABORT:
|
case PREFETCH_ABORT:
|
||||||
_mmu_exception();
|
_mmu_exception();
|
||||||
@ -233,17 +236,17 @@ void Thread::handle_exception()
|
|||||||
_mmu_exception();
|
_mmu_exception();
|
||||||
return;
|
return;
|
||||||
case INTERRUPT_REQUEST:
|
case INTERRUPT_REQUEST:
|
||||||
handle_interrupt();
|
handle_interrupt(_processor, processor_id);
|
||||||
return;
|
return;
|
||||||
case FAST_INTERRUPT_REQUEST:
|
case FAST_INTERRUPT_REQUEST:
|
||||||
handle_interrupt();
|
handle_interrupt(_processor, processor_id);
|
||||||
return;
|
return;
|
||||||
case RESET:
|
case RESET:
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
PERR("unknown exception");
|
PERR("unknown exception");
|
||||||
_stop();
|
_stop();
|
||||||
reset_lap_time();
|
reset_lap_time(processor_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,9 +258,9 @@ void Thread::_receive_yielded_cpu()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::proceed()
|
void Thread::proceed(unsigned const processor_id)
|
||||||
{
|
{
|
||||||
mtc()->continue_user(static_cast<Cpu::Context *>(this));
|
mtc()->continue_user(this, processor_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -366,8 +369,14 @@ void Thread::_call_start_thread()
|
|||||||
user_arg_0(0);
|
user_arg_0(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* start thread */
|
/*
|
||||||
t->init(cpu_id, pd_id, utcb, 1);
|
* Start thread
|
||||||
|
*
|
||||||
|
* FIXME: The affinity of a thread is ignored by now.
|
||||||
|
* Instead we always assign the primary processor.
|
||||||
|
*/
|
||||||
|
if (cpu_id) { PERR("multiprocessing not supported"); }
|
||||||
|
t->init(multiprocessor()->primary(), pd_id, utcb, 1);
|
||||||
user_arg_0((Call_ret)t->_pd->tlb());
|
user_arg_0((Call_ret)t->_pd->tlb());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,7 +446,7 @@ void Thread::_call_yield_thread()
|
|||||||
{
|
{
|
||||||
Thread * const t = Thread::pool()->object(user_arg_1());
|
Thread * const t = Thread::pool()->object(user_arg_1());
|
||||||
if (t) { t->_receive_yielded_cpu(); }
|
if (t) { t->_receive_yielded_cpu(); }
|
||||||
cpu_scheduler()->yield();
|
_processor->scheduler()->yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -614,14 +623,8 @@ void Thread::_print_activity_table()
|
|||||||
|
|
||||||
void Thread::_print_activity(bool const printing_thread)
|
void Thread::_print_activity(bool const printing_thread)
|
||||||
{
|
{
|
||||||
static Thread * idle = dynamic_cast<Thread *>(cpu_scheduler()->idle());
|
|
||||||
Genode::printf("\033[33m[%u] %s", pd_id(), pd_label());
|
Genode::printf("\033[33m[%u] %s", pd_id(), pd_label());
|
||||||
Genode::printf(" (%u) %s:\033[0m", id(), label());
|
Genode::printf(" (%u) %s:\033[0m", id(), label());
|
||||||
if (id() == idle->id()) {
|
|
||||||
Genode::printf("\033[32m run\033[0m");
|
|
||||||
_print_common_activity();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (_state) {
|
switch (_state) {
|
||||||
case AWAITS_START: {
|
case AWAITS_START: {
|
||||||
Genode::printf("\033[32m init\033[0m");
|
Genode::printf("\033[32m init\033[0m");
|
||||||
@ -935,7 +938,7 @@ int Thread::_write_reg(addr_t const id, addr_t const value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_call()
|
void Thread::_call(unsigned const processor_id)
|
||||||
{
|
{
|
||||||
switch (user_arg_0()) {
|
switch (user_arg_0()) {
|
||||||
case Call_id::NEW_THREAD: _call_new_thread(); return;
|
case Call_id::NEW_THREAD: _call_new_thread(); return;
|
||||||
@ -969,6 +972,6 @@ void Thread::_call()
|
|||||||
default:
|
default:
|
||||||
PERR("unknown kernel call");
|
PERR("unknown kernel call");
|
||||||
_stop();
|
_stop();
|
||||||
reset_lap_time();
|
reset_lap_time(processor_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,6 @@ namespace Kernel
|
|||||||
typedef Genode::Cpu Cpu;
|
typedef Genode::Cpu Cpu;
|
||||||
typedef Genode::Native_utcb Native_utcb;
|
typedef Genode::Native_utcb Native_utcb;
|
||||||
|
|
||||||
void reset_lap_time();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kernel backend for userland execution-contexts
|
* Kernel backend for userland execution-contexts
|
||||||
*/
|
*/
|
||||||
@ -40,10 +38,38 @@ namespace Kernel
|
|||||||
class Thread_ids : public Id_allocator<MAX_THREADS> { };
|
class Thread_ids : public Id_allocator<MAX_THREADS> { };
|
||||||
typedef Object_pool<Thread> Thread_pool;
|
typedef Object_pool<Thread> Thread_pool;
|
||||||
|
|
||||||
|
class Processor;
|
||||||
|
|
||||||
Thread_ids * thread_ids();
|
Thread_ids * thread_ids();
|
||||||
Thread_pool * thread_pool();
|
Thread_pool * thread_pool();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processor context of the kernel
|
||||||
|
*/
|
||||||
|
class Cpu_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Kernel::Cpu_context : Cpu::Context
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook for environment specific initializations
|
||||||
|
*
|
||||||
|
* \param stack_size size of kernel stack
|
||||||
|
*/
|
||||||
|
void _init(size_t const stack_size);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Cpu_context();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class Kernel::Thread
|
class Kernel::Thread
|
||||||
:
|
:
|
||||||
public Cpu::User_context,
|
public Cpu::User_context,
|
||||||
@ -76,6 +102,7 @@ class Kernel::Thread
|
|||||||
Native_utcb * _utcb_phys;
|
Native_utcb * _utcb_phys;
|
||||||
Signal_receiver * _signal_receiver;
|
Signal_receiver * _signal_receiver;
|
||||||
char const * const _label;
|
char const * const _label;
|
||||||
|
Processor * _processor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notice that another thread yielded the CPU to this thread
|
* Notice that another thread yielded the CPU to this thread
|
||||||
@ -114,6 +141,11 @@ class Kernel::Thread
|
|||||||
*/
|
*/
|
||||||
void _schedule();
|
void _schedule();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pause execution rawly
|
||||||
|
*/
|
||||||
|
void _unschedule(State const s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pause execution
|
* Pause execution
|
||||||
*/
|
*/
|
||||||
@ -139,9 +171,11 @@ class Kernel::Thread
|
|||||||
void _mmu_exception();
|
void _mmu_exception();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle kernel-call request of this thread
|
* Handle kernel-call request of the thread
|
||||||
|
*
|
||||||
|
* \param processor_id kernel name of the trapped processor
|
||||||
*/
|
*/
|
||||||
void _call();
|
void _call(unsigned const processor_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a thread register
|
* Read a thread register
|
||||||
@ -268,15 +302,20 @@ class Kernel::Thread
|
|||||||
*/
|
*/
|
||||||
Thread(unsigned const priority, char const * const label);
|
Thread(unsigned const priority, char const * const label);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
|
~Thread();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare thread to get scheduled the first time
|
* Prepare thread to get scheduled the first time
|
||||||
*
|
*
|
||||||
* \param cpu_id kernel name of targeted processor
|
* \param processor kernel object of targeted processor
|
||||||
* \param pd_id kernel name of target protection domain
|
* \param pd_id kernel name of target protection domain
|
||||||
* \param utcb core local pointer to userland thread-context
|
* \param utcb core local pointer to userland thread-context
|
||||||
* \param start wether to start executing the thread
|
* \param start wether to start executing the thread
|
||||||
*/
|
*/
|
||||||
void init(unsigned const cpu_id, unsigned const pd_id,
|
void init(Processor * const processor, unsigned const pd_id,
|
||||||
Native_utcb * const utcb, bool const start);
|
Native_utcb * const utcb, bool const start);
|
||||||
|
|
||||||
|
|
||||||
@ -284,8 +323,8 @@ class Kernel::Thread
|
|||||||
** Execution_context **
|
** Execution_context **
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
void handle_exception();
|
void handle_exception(unsigned const processor_id);
|
||||||
void proceed();
|
void proceed(unsigned const processor_id);
|
||||||
|
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <kernel/scheduler.h>
|
#include <kernel/scheduler.h>
|
||||||
#include <kernel/kernel.h>
|
#include <kernel/kernel.h>
|
||||||
#include <kernel/pd.h>
|
#include <kernel/pd.h>
|
||||||
|
#include <kernel/multiprocessor.h>
|
||||||
#include <kernel/signal_receiver.h>
|
#include <kernel/signal_receiver.h>
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
|
|
||||||
@ -48,6 +49,7 @@ class Kernel::Vm : public Object<Vm, MAX_VMS, Vm_ids, vm_ids, vm_pool>,
|
|||||||
Genode::addr_t dfar;
|
Genode::addr_t dfar;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Processor * const _processor;
|
||||||
Vm_state * const _state;
|
Vm_state * const _state;
|
||||||
Signal_context * const _context;
|
Signal_context * const _context;
|
||||||
|
|
||||||
@ -63,6 +65,7 @@ class Kernel::Vm : public Object<Vm, MAX_VMS, Vm_ids, vm_ids, vm_pool>,
|
|||||||
Signal_context * const context)
|
Signal_context * const context)
|
||||||
:
|
:
|
||||||
Execution_context(Priority::MIN),
|
Execution_context(Priority::MIN),
|
||||||
|
_processor(multiprocessor()->primary()),
|
||||||
_state((Vm_state * const)state), _context(context)
|
_state((Vm_state * const)state), _context(context)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@ -71,31 +74,34 @@ class Kernel::Vm : public Object<Vm, MAX_VMS, Vm_ids, vm_ids, vm_pool>,
|
|||||||
** Vm_session **
|
** Vm_session **
|
||||||
****************/
|
****************/
|
||||||
|
|
||||||
void run() { cpu_scheduler()->insert(this); }
|
void run() { _processor->scheduler()->insert(this); }
|
||||||
|
|
||||||
void pause() { cpu_scheduler()->remove(this); }
|
void pause() { _processor->scheduler()->remove(this); }
|
||||||
|
|
||||||
|
|
||||||
/***********************
|
/***********************
|
||||||
** Execution_context **
|
** Execution_context **
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
void handle_exception()
|
void handle_exception(unsigned const processor_id)
|
||||||
{
|
{
|
||||||
switch(_state->cpu_exception) {
|
switch(_state->cpu_exception) {
|
||||||
case Genode::Cpu_state::INTERRUPT_REQUEST:
|
case Genode::Cpu_state::INTERRUPT_REQUEST:
|
||||||
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
||||||
handle_interrupt();
|
handle_interrupt(_processor, processor_id);
|
||||||
return;
|
return;
|
||||||
case Genode::Cpu_state::DATA_ABORT:
|
case Genode::Cpu_state::DATA_ABORT:
|
||||||
_state->dfar = Genode::Cpu::Dfar::read();
|
_state->dfar = Genode::Cpu::Dfar::read();
|
||||||
default:
|
default:
|
||||||
cpu_scheduler()->remove(this);
|
_processor->scheduler()->remove(this);
|
||||||
_context->submit(1);
|
_context->submit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void proceed() { mtc()->continue_vm(_state); }
|
void proceed(unsigned const processor_id)
|
||||||
|
{
|
||||||
|
mtc()->continue_vm(_state, processor_id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _KERNEL__VM_H_ */
|
#endif /* _KERNEL__VM_H_ */
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _EXYNOS5__CPU_H_
|
#ifndef _ODROID_XU__CPU_H_
|
||||||
#define _EXYNOS5__CPU_H_
|
#define _ODROID_XU__CPU_H_
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <cpu/cortex_a15.h>
|
#include <cpu/cortex_a15.h>
|
||||||
@ -22,8 +22,21 @@ namespace Genode
|
|||||||
/**
|
/**
|
||||||
* CPU driver for core
|
* CPU driver for core
|
||||||
*/
|
*/
|
||||||
class Cpu : public Cortex_a15::Cpu { };
|
class Cpu : public Cortex_a15::Cpu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the executing processor
|
||||||
|
*/
|
||||||
|
static unsigned id() { return 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the primary processor
|
||||||
|
*/
|
||||||
|
static unsigned primary_id() { return primary_id(); }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _EXYNOS5__CPU_H_ */
|
#endif /* _ODROID_XU__CPU_H_ */
|
||||||
|
|
@ -11,6 +11,7 @@ REQUIRES += platform_odroid_xu
|
|||||||
INC_DIR += $(REP_DIR)/src/core/odroid_xu
|
INC_DIR += $(REP_DIR)/src/core/odroid_xu
|
||||||
INC_DIR += $(REP_DIR)/src/core/exynos5
|
INC_DIR += $(REP_DIR)/src/core/exynos5
|
||||||
INC_DIR += $(REP_DIR)/src/core/arm
|
INC_DIR += $(REP_DIR)/src/core/arm
|
||||||
|
INC_DIR += $(REP_DIR)/src/core/arm_v7
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += platform_services.cc \
|
SRC_CC += platform_services.cc \
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _EXYNOS5__TIMER_H_
|
#ifndef _ODROID_XU__TIMER_H_
|
||||||
#define _EXYNOS5__TIMER_H_
|
#define _ODROID_XU__TIMER_H_
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <board.h>
|
#include <board.h>
|
||||||
@ -27,7 +27,15 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum { IRQ = Genode::Board::MCT_IRQ_L0 };
|
/**
|
||||||
|
* Return kernel name of timer interrupt of a specific processor
|
||||||
|
*
|
||||||
|
* \param processor_id kernel name of targeted processor
|
||||||
|
*/
|
||||||
|
static unsigned interrupt_id(unsigned)
|
||||||
|
{
|
||||||
|
return Genode::Board::MCT_IRQ_L0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -37,4 +45,4 @@ namespace Kernel
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _EXYNOS5__TIMER_H_ */
|
#endif /* _ODROID_XU__TIMER_H_ */
|
@ -22,7 +22,20 @@ namespace Genode
|
|||||||
/**
|
/**
|
||||||
* CPU driver for core
|
* CPU driver for core
|
||||||
*/
|
*/
|
||||||
class Cpu : public Cortex_a9::Cpu { };
|
class Cpu : public Cortex_a9::Cpu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the primary processor
|
||||||
|
*/
|
||||||
|
static unsigned primary_id() { return 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the executing processor
|
||||||
|
*/
|
||||||
|
static unsigned id() { return primary_id(); }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _PANDA__CPU_H_ */
|
#endif /* _PANDA__CPU_H_ */
|
||||||
|
@ -11,6 +11,7 @@ REQUIRES += platform_panda
|
|||||||
# add include paths
|
# add include paths
|
||||||
INC_DIR += $(REP_DIR)/src/core/panda
|
INC_DIR += $(REP_DIR)/src/core/panda
|
||||||
INC_DIR += $(REP_DIR)/src/core/arm
|
INC_DIR += $(REP_DIR)/src/core/arm
|
||||||
|
INC_DIR += $(REP_DIR)/src/core/arm_v7
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += platform_services.cc \
|
SRC_CC += platform_services.cc \
|
||||||
|
@ -22,7 +22,20 @@ namespace Genode
|
|||||||
/**
|
/**
|
||||||
* CPU driver for core
|
* CPU driver for core
|
||||||
*/
|
*/
|
||||||
class Cpu : public Cortex_a9::Cpu { };
|
class Cpu : public Cortex_a9::Cpu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the primary processor
|
||||||
|
*/
|
||||||
|
static unsigned primary_id() { return 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the executing processor
|
||||||
|
*/
|
||||||
|
static unsigned id() { return primary_id(); }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _PBXA9__CPU_H_ */
|
#endif /* _PBXA9__CPU_H_ */
|
||||||
|
@ -11,6 +11,7 @@ REQUIRES += platform_pbxa9
|
|||||||
# add include paths
|
# add include paths
|
||||||
INC_DIR += $(REP_DIR)/src/core/pbxa9
|
INC_DIR += $(REP_DIR)/src/core/pbxa9
|
||||||
INC_DIR += $(REP_DIR)/src/core/arm
|
INC_DIR += $(REP_DIR)/src/core/arm
|
||||||
|
INC_DIR += $(REP_DIR)/src/core/arm_v7
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += platform_services.cc \
|
SRC_CC += platform_services.cc \
|
||||||
|
@ -26,301 +26,318 @@ namespace Arm_gic
|
|||||||
*
|
*
|
||||||
* ARM generic interrupt controller, Architecture version 2.0
|
* ARM generic interrupt controller, Architecture version 2.0
|
||||||
*/
|
*/
|
||||||
class Pic
|
class Pic;
|
||||||
{
|
}
|
||||||
public:
|
|
||||||
|
|
||||||
enum { MAX_INTERRUPT_ID = 1023 };
|
class Arm_gic::Pic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
protected:
|
enum { MAX_INTERRUPT_ID = 1023 };
|
||||||
|
|
||||||
enum {
|
protected:
|
||||||
MIN_SPI = 32,
|
|
||||||
SPURIOUS_ID = 1023,
|
enum {
|
||||||
|
MIN_SPI = 32,
|
||||||
|
SPURIOUS_ID = 1023,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Distributor interface
|
||||||
|
*/
|
||||||
|
struct Distr : public Mmio
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Distr(addr_t const base) : Mmio(base) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control register
|
||||||
|
*/
|
||||||
|
struct Ctlr : Register<0x000, 32>
|
||||||
|
{
|
||||||
|
struct Enable : Bitfield<0,1> { };
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Distributor interface
|
* Controller type register
|
||||||
*/
|
*/
|
||||||
struct Distr : public Mmio
|
struct Typer : Register<0x004, 32>
|
||||||
{
|
{
|
||||||
/**
|
struct It_lines_number : Bitfield<0,5> { };
|
||||||
* Constructor
|
struct Cpu_number : Bitfield<5,3> { };
|
||||||
*/
|
};
|
||||||
Distr(addr_t const base) : Mmio(base) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Control register
|
|
||||||
*/
|
|
||||||
struct Ctlr : Register<0x000, 32>
|
|
||||||
{
|
|
||||||
struct Enable : Bitfield<0,1> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controller type register
|
|
||||||
*/
|
|
||||||
struct Typer : Register<0x004, 32>
|
|
||||||
{
|
|
||||||
struct It_lines_number : Bitfield<0,5> { };
|
|
||||||
struct Cpu_number : Bitfield<5,3> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interrupt group register
|
|
||||||
*/
|
|
||||||
struct Igroupr :
|
|
||||||
Register_array<0x80, 32, MAX_INTERRUPT_ID + 1, 1>
|
|
||||||
{
|
|
||||||
struct Group_status : Bitfield<0, 1> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interrupt set enable registers
|
|
||||||
*/
|
|
||||||
struct Isenabler :
|
|
||||||
Register_array<0x100, 32, MAX_INTERRUPT_ID + 1, 1, true>
|
|
||||||
{
|
|
||||||
struct Set_enable : Bitfield<0, 1> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interrupt clear enable registers
|
|
||||||
*/
|
|
||||||
struct Icenabler :
|
|
||||||
Register_array<0x180, 32, MAX_INTERRUPT_ID + 1, 1, true>
|
|
||||||
{
|
|
||||||
struct Clear_enable : Bitfield<0, 1> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interrupt priority level registers
|
|
||||||
*/
|
|
||||||
struct Ipriorityr :
|
|
||||||
Register_array<0x400, 32, MAX_INTERRUPT_ID + 1, 8>
|
|
||||||
{
|
|
||||||
enum { GET_MIN = 0xff };
|
|
||||||
|
|
||||||
struct Priority : Bitfield<0, 8> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interrupt processor target registers
|
|
||||||
*/
|
|
||||||
struct Itargetsr :
|
|
||||||
Register_array<0x800, 32, MAX_INTERRUPT_ID + 1, 8>
|
|
||||||
{
|
|
||||||
enum { ALL = 0xff };
|
|
||||||
|
|
||||||
struct Cpu_targets : Bitfield<0, 8> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interrupt configuration registers
|
|
||||||
*/
|
|
||||||
struct Icfgr :
|
|
||||||
Register_array<0xc00, 32, MAX_INTERRUPT_ID + 1, 2>
|
|
||||||
{
|
|
||||||
struct Edge_triggered : Bitfield<1, 1> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minimum supported interrupt priority
|
|
||||||
*/
|
|
||||||
Ipriorityr::access_t min_priority()
|
|
||||||
{
|
|
||||||
write<Ipriorityr::Priority>(Ipriorityr::GET_MIN, 0);
|
|
||||||
return read<Ipriorityr::Priority>(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum supported interrupt priority
|
|
||||||
*/
|
|
||||||
Ipriorityr::access_t max_priority() { return 0; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ID of the maximum supported interrupt
|
|
||||||
*/
|
|
||||||
Typer::access_t max_interrupt()
|
|
||||||
{
|
|
||||||
enum { LINE_WIDTH_LOG2 = 5 };
|
|
||||||
Typer::access_t lnr = read<Typer::It_lines_number>();
|
|
||||||
return ((lnr + 1) << LINE_WIDTH_LOG2) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
} _distr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CPU interface
|
* Interrupt group register
|
||||||
*/
|
*/
|
||||||
struct Cpu : public Mmio
|
struct Igroupr :
|
||||||
|
Register_array<0x80, 32, MAX_INTERRUPT_ID + 1, 1>
|
||||||
{
|
{
|
||||||
/**
|
struct Group_status : Bitfield<0, 1> { };
|
||||||
* Constructor
|
};
|
||||||
*/
|
|
||||||
Cpu(addr_t const base) : Mmio(base) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Control register
|
|
||||||
*/
|
|
||||||
struct Ctlr : Register<0x00, 32>
|
|
||||||
{
|
|
||||||
/* Without security extension */
|
|
||||||
struct Enable : Bitfield<0,1> { };
|
|
||||||
|
|
||||||
/* In a secure world */
|
|
||||||
struct Enable_grp0 : Bitfield<0,1> { };
|
|
||||||
struct Enable_grp1 : Bitfield<1,1> { };
|
|
||||||
struct Fiq_en : Bitfield<3,1> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Priority mask register
|
|
||||||
*/
|
|
||||||
struct Pmr : Register<0x04, 32>
|
|
||||||
{
|
|
||||||
struct Priority : Bitfield<0,8> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binary point register
|
|
||||||
*/
|
|
||||||
struct Bpr : Register<0x08, 32>
|
|
||||||
{
|
|
||||||
enum { NO_PREEMPTION = 7 };
|
|
||||||
|
|
||||||
struct Binary_point : Bitfield<0,3> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interrupt acknowledge register
|
|
||||||
*/
|
|
||||||
struct Iar : Register<0x0c, 32, true>
|
|
||||||
{
|
|
||||||
struct Irq_id : Bitfield<0,10> { };
|
|
||||||
struct Cpu_id : Bitfield<10,3> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* End of interrupt register
|
|
||||||
*/
|
|
||||||
struct Eoir : Register<0x10, 32, true>
|
|
||||||
{
|
|
||||||
struct Irq_id : Bitfield<0,10> { };
|
|
||||||
struct Cpu_id : Bitfield<10,3> { };
|
|
||||||
};
|
|
||||||
} _cpu;
|
|
||||||
|
|
||||||
unsigned const _max_interrupt;
|
|
||||||
unsigned _last_request;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wether the security extension is used or not
|
* Interrupt set enable registers
|
||||||
*/
|
*/
|
||||||
inline static bool _use_security_ext();
|
struct Isenabler :
|
||||||
|
Register_array<0x100, 32, MAX_INTERRUPT_ID + 1, 1, true>
|
||||||
public:
|
{
|
||||||
|
struct Set_enable : Bitfield<0, 1> { };
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor, all interrupts get masked
|
* Interrupt clear enable registers
|
||||||
*/
|
*/
|
||||||
Pic(addr_t const distr_base, addr_t const cpu_base) :
|
struct Icenabler :
|
||||||
_distr(distr_base), _cpu(cpu_base),
|
Register_array<0x180, 32, MAX_INTERRUPT_ID + 1, 1, true>
|
||||||
_max_interrupt(_distr.max_interrupt()),
|
|
||||||
_last_request(SPURIOUS_ID)
|
|
||||||
{
|
{
|
||||||
/* with security extension any board has its own init */
|
struct Clear_enable : Bitfield<0, 1> { };
|
||||||
if (_use_security_ext()) return;
|
};
|
||||||
|
|
||||||
/* disable device */
|
/**
|
||||||
_distr.write<Distr::Ctlr::Enable>(0);
|
* Interrupt priority level registers
|
||||||
|
*/
|
||||||
|
struct Ipriorityr :
|
||||||
|
Register_array<0x400, 32, MAX_INTERRUPT_ID + 1, 8>
|
||||||
|
{
|
||||||
|
enum { GET_MIN = 0xff };
|
||||||
|
|
||||||
/* supported priority range */
|
struct Priority : Bitfield<0, 8> { };
|
||||||
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++)
|
* Interrupt processor target registers
|
||||||
{
|
*/
|
||||||
_distr.write<Distr::Icfgr::Edge_triggered>(0, i);
|
struct Itargetsr :
|
||||||
_distr.write<Distr::Ipriorityr::Priority>(max_prio, i);
|
Register_array<0x800, 32, MAX_INTERRUPT_ID + 1, 8>
|
||||||
_distr.write<Distr::Itargetsr::Cpu_targets>(
|
{
|
||||||
Distr::Itargetsr::ALL, i);
|
enum { ALL = 0xff };
|
||||||
}
|
|
||||||
|
|
||||||
/* disable the priority filter */
|
struct Cpu_targets : Bitfield<0, 8> { };
|
||||||
_cpu.write<Cpu::Pmr::Priority>(min_prio);
|
};
|
||||||
|
|
||||||
/* disable preemption of interrupt handling by interrupts */
|
/**
|
||||||
_cpu.write<Cpu::Bpr::Binary_point>(Cpu::Bpr::NO_PREEMPTION);
|
* Interrupt configuration registers
|
||||||
|
*/
|
||||||
|
struct Icfgr :
|
||||||
|
Register_array<0xc00, 32, MAX_INTERRUPT_ID + 1, 2>
|
||||||
|
{
|
||||||
|
struct Edge_triggered : Bitfield<1, 1> { };
|
||||||
|
};
|
||||||
|
|
||||||
/* enable device */
|
/**
|
||||||
_distr.write<Distr::Ctlr::Enable>(1);
|
* Minimum supported interrupt priority
|
||||||
_cpu.write<Cpu::Ctlr::Enable>(1);
|
*/
|
||||||
|
Ipriorityr::access_t min_priority()
|
||||||
|
{
|
||||||
|
write<Ipriorityr::Priority>(Ipriorityr::GET_MIN, 0);
|
||||||
|
return read<Ipriorityr::Priority>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the ID of the last interrupt request
|
* Maximum supported interrupt priority
|
||||||
*
|
|
||||||
* \return True if the request with ID 'i' is treated as accepted
|
|
||||||
* by the CPU and awaits an subsequently 'finish_request'
|
|
||||||
* call. Otherwise this returns false and the value of 'i'
|
|
||||||
* remains useless.
|
|
||||||
*/
|
*/
|
||||||
bool take_request(unsigned & i)
|
Ipriorityr::access_t max_priority() { return 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the maximum supported interrupt
|
||||||
|
*/
|
||||||
|
Typer::access_t max_interrupt()
|
||||||
{
|
{
|
||||||
_last_request = _cpu.read<Cpu::Iar::Irq_id>();
|
enum { LINE_WIDTH_LOG2 = 5 };
|
||||||
i = _last_request;
|
Typer::access_t lnr = read<Typer::It_lines_number>();
|
||||||
return valid(i);
|
return ((lnr + 1) << LINE_WIDTH_LOG2) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} _distr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CPU interface
|
||||||
|
*/
|
||||||
|
struct Cpu : public Mmio
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Complete the last request that was taken via 'take_request'
|
* Constructor
|
||||||
*/
|
*/
|
||||||
void finish_request()
|
Cpu(addr_t const base) : Mmio(base) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control register
|
||||||
|
*/
|
||||||
|
struct Ctlr : Register<0x00, 32>
|
||||||
{
|
{
|
||||||
if (!valid(_last_request)) return;
|
/* Without security extension */
|
||||||
_cpu.write<Cpu::Eoir>(Cpu::Eoir::Irq_id::bits(_last_request) |
|
struct Enable : Bitfield<0,1> { };
|
||||||
Cpu::Eoir::Cpu_id::bits(0) );
|
|
||||||
_last_request = SPURIOUS_ID;
|
/* In a secure world */
|
||||||
}
|
struct Enable_grp0 : Bitfield<0,1> { };
|
||||||
|
struct Enable_grp1 : Bitfield<1,1> { };
|
||||||
|
struct Fiq_en : Bitfield<3,1> { };
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if 'i' is a valid interrupt request ID at the device
|
* Priority mask register
|
||||||
*/
|
*/
|
||||||
bool valid(unsigned const i) const { return i <= _max_interrupt; }
|
struct Pmr : Register<0x04, 32>
|
||||||
|
|
||||||
/**
|
|
||||||
* Unmask all interrupts
|
|
||||||
*/
|
|
||||||
void unmask()
|
|
||||||
{
|
{
|
||||||
for (unsigned i=0; i <= _max_interrupt; i++)
|
struct Priority : Bitfield<0,8> { };
|
||||||
_distr.write<Distr::Isenabler::Set_enable>(1, i);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unmask interrupt 'i'
|
* Binary point register
|
||||||
*/
|
*/
|
||||||
void unmask(unsigned const i) {
|
struct Bpr : Register<0x08, 32>
|
||||||
_distr.write<Distr::Isenabler::Set_enable>(1, i); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mask all interrupts
|
|
||||||
*/
|
|
||||||
void mask()
|
|
||||||
{
|
{
|
||||||
for (unsigned i=0; i <= _max_interrupt; i++)
|
enum { NO_PREEMPTION = 7 };
|
||||||
_distr.write<Distr::Icenabler::Clear_enable>(1, i);
|
|
||||||
}
|
struct Binary_point : Bitfield<0,3> { };
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mask interrupt 'i'
|
* Interrupt acknowledge register
|
||||||
*/
|
*/
|
||||||
void mask(unsigned const i) {
|
struct Iar : Register<0x0c, 32, true>
|
||||||
_distr.write<Distr::Icenabler::Clear_enable>(1, i); }
|
{
|
||||||
};
|
struct Irq_id : Bitfield<0,10> { };
|
||||||
}
|
struct Cpu_id : Bitfield<10,3> { };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End of interrupt register
|
||||||
|
*/
|
||||||
|
struct Eoir : Register<0x10, 32, true>
|
||||||
|
{
|
||||||
|
struct Irq_id : Bitfield<0,10> { };
|
||||||
|
struct Cpu_id : Bitfield<10,3> { };
|
||||||
|
};
|
||||||
|
} _cpu;
|
||||||
|
|
||||||
|
unsigned const _max_interrupt;
|
||||||
|
unsigned _last_request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wether the security extension is used or not
|
||||||
|
*/
|
||||||
|
inline static bool _use_security_ext();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Pic(addr_t const distr_base, addr_t const cpu_base)
|
||||||
|
:
|
||||||
|
_distr(distr_base), _cpu(cpu_base),
|
||||||
|
_max_interrupt(_distr.max_interrupt()),
|
||||||
|
_last_request(SPURIOUS_ID)
|
||||||
|
{
|
||||||
|
/* with security extension any board has its own init */
|
||||||
|
if (_use_security_ext()) return;
|
||||||
|
|
||||||
|
/* disable device */
|
||||||
|
_distr.write<Distr::Ctlr::Enable>(0);
|
||||||
|
|
||||||
|
/* configure every shared peripheral interrupt */
|
||||||
|
for (unsigned i=MIN_SPI; i <= _max_interrupt; i++)
|
||||||
|
{
|
||||||
|
_distr.write<Distr::Icfgr::Edge_triggered>(0, i);
|
||||||
|
_distr.write<Distr::Ipriorityr::Priority>(_distr.max_priority(), i);
|
||||||
|
}
|
||||||
|
/* enable device */
|
||||||
|
_distr.write<Distr::Ctlr::Enable>(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize processor local interface of the controller
|
||||||
|
*/
|
||||||
|
void init_processor_local()
|
||||||
|
{
|
||||||
|
/* disable the priority filter */
|
||||||
|
_cpu.write<Cpu::Pmr::Priority>(_distr.min_priority());
|
||||||
|
|
||||||
|
/* disable preemption of interrupt handling by interrupts */
|
||||||
|
_cpu.write<Cpu::Bpr::Binary_point>(Cpu::Bpr::NO_PREEMPTION);
|
||||||
|
|
||||||
|
/* enable device */
|
||||||
|
_cpu.write<Cpu::Ctlr::Enable>(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the ID of the last interrupt request
|
||||||
|
*
|
||||||
|
* \return True if the request with ID 'i' is treated as accepted
|
||||||
|
* by the CPU and awaits an subsequently 'finish_request'
|
||||||
|
* call. Otherwise this returns false and the value of 'i'
|
||||||
|
* remains useless.
|
||||||
|
*/
|
||||||
|
bool take_request(unsigned & i)
|
||||||
|
{
|
||||||
|
_last_request = _cpu.read<Cpu::Iar::Irq_id>();
|
||||||
|
i = _last_request;
|
||||||
|
return valid(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complete the last request that was taken via 'take_request'
|
||||||
|
*/
|
||||||
|
void finish_request()
|
||||||
|
{
|
||||||
|
if (!valid(_last_request)) return;
|
||||||
|
_cpu.write<Cpu::Eoir>(Cpu::Eoir::Irq_id::bits(_last_request) |
|
||||||
|
Cpu::Eoir::Cpu_id::bits(0) );
|
||||||
|
_last_request = SPURIOUS_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if 'i' is a valid interrupt request ID at the device
|
||||||
|
*/
|
||||||
|
bool valid(unsigned const i) const { return i <= _max_interrupt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unmask all interrupts
|
||||||
|
*/
|
||||||
|
void unmask()
|
||||||
|
{
|
||||||
|
for (unsigned i=0; i <= _max_interrupt; i++) {
|
||||||
|
_distr.write<Distr::Isenabler::Set_enable>(1, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unmask interrupt and assign it to a specific processor
|
||||||
|
*
|
||||||
|
* \param interrupt_id kernel name of targeted interrupt
|
||||||
|
* \param processor_id kernel name of targeted processor
|
||||||
|
*/
|
||||||
|
void unmask(unsigned const interrupt_id, unsigned const processor_id)
|
||||||
|
{
|
||||||
|
unsigned const targets = 1 << processor_id;
|
||||||
|
_distr.write<Distr::Itargetsr::Cpu_targets>(targets, interrupt_id);
|
||||||
|
_distr.write<Distr::Isenabler::Set_enable>(1, interrupt_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mask all interrupts
|
||||||
|
*/
|
||||||
|
void mask()
|
||||||
|
{
|
||||||
|
for (unsigned i=0; i <= _max_interrupt; i++) {
|
||||||
|
_distr.write<Distr::Icenabler::Clear_enable>(1, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mask specific interrupt
|
||||||
|
*
|
||||||
|
* \param interrupt_id kernel name of targeted interrupt
|
||||||
|
*/
|
||||||
|
void mask(unsigned const interrupt_id)
|
||||||
|
{
|
||||||
|
_distr.write<Distr::Icenabler::Clear_enable>(1, interrupt_id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _PIC__ARM_GIC_H_ */
|
#endif /* _PIC__ARM_GIC_H_ */
|
||||||
|
|
||||||
|
@ -142,6 +142,11 @@ namespace Imx31
|
|||||||
write<Nipriority>(Nipriority::ALL_LOWEST, i);
|
write<Nipriority>(Nipriority::ALL_LOWEST, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize processor local interface of the controller
|
||||||
|
*/
|
||||||
|
void init_processor_local() { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receive a pending request number 'i'
|
* Receive a pending request number 'i'
|
||||||
*/
|
*/
|
||||||
@ -182,10 +187,16 @@ namespace Imx31
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unmask interrupt 'i'
|
* Unmask interrupt
|
||||||
|
*
|
||||||
|
* \param interrupt_id kernel name of targeted interrupt
|
||||||
*/
|
*/
|
||||||
void unmask(unsigned const i) {
|
void unmask(unsigned const interrupt_id, unsigned)
|
||||||
if (i <= MAX_INTERRUPT_ID) write<Intennum>(i); }
|
{
|
||||||
|
if (interrupt_id <= MAX_INTERRUPT_ID) {
|
||||||
|
write<Intennum>(interrupt_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mask interrupt 'i'
|
* Mask interrupt 'i'
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* \brief Board driver for core
|
|
||||||
* \author Norman Feske
|
|
||||||
* \date 2013-04-05
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2013 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU General Public License version 2.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _RPI__BOARD_H_
|
|
||||||
#define _RPI__BOARD_H_
|
|
||||||
|
|
||||||
/* Genode includes */
|
|
||||||
#include <drivers/board_base.h>
|
|
||||||
|
|
||||||
namespace Genode { struct Board; }
|
|
||||||
|
|
||||||
struct Genode::Board : Genode::Board_base { static void prepare_kernel() { } };
|
|
||||||
|
|
||||||
#endif /* _RPI__BOARD_H_ */
|
|
@ -58,6 +58,8 @@ namespace Kernel
|
|||||||
|
|
||||||
Pic() : Genode::Mmio(Genode::Board::IRQ_CONTROLLER_BASE) { mask(); }
|
Pic() : Genode::Mmio(Genode::Board::IRQ_CONTROLLER_BASE) { mask(); }
|
||||||
|
|
||||||
|
void init_processor_local() { }
|
||||||
|
|
||||||
bool take_request(unsigned &irq)
|
bool take_request(unsigned &irq)
|
||||||
{
|
{
|
||||||
/* read basic IRQ status mask */
|
/* read basic IRQ status mask */
|
||||||
@ -96,7 +98,7 @@ namespace Kernel
|
|||||||
write<Irq_disable_gpu_2>(~0);
|
write<Irq_disable_gpu_2>(~0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unmask(unsigned const i)
|
void unmask(unsigned const i, unsigned)
|
||||||
{
|
{
|
||||||
if (i < 8)
|
if (i < 8)
|
||||||
write<Irq_enable_basic>(1 << i);
|
write<Irq_enable_basic>(1 << i);
|
||||||
|
@ -10,6 +10,7 @@ REQUIRES = platform_rpi
|
|||||||
# add include paths
|
# add include paths
|
||||||
INC_DIR += $(REP_DIR)/src/core/rpi
|
INC_DIR += $(REP_DIR)/src/core/rpi
|
||||||
INC_DIR += $(REP_DIR)/src/core/arm
|
INC_DIR += $(REP_DIR)/src/core/arm
|
||||||
|
INC_DIR += $(REP_DIR)/src/core/arm_v6
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += platform_services.cc \
|
SRC_CC += platform_services.cc \
|
||||||
|
@ -47,9 +47,12 @@ class Kernel::Timer : public Genode::Mmio
|
|||||||
|
|
||||||
Timer() : Mmio(Board_base::SYSTEM_TIMER_MMIO_BASE) { }
|
Timer() : Mmio(Board_base::SYSTEM_TIMER_MMIO_BASE) { }
|
||||||
|
|
||||||
enum { IRQ = Board_base::SYSTEM_TIMER_IRQ };
|
static unsigned interrupt_id(unsigned)
|
||||||
|
{
|
||||||
|
return Board_base::SYSTEM_TIMER_IRQ;
|
||||||
|
}
|
||||||
|
|
||||||
inline void start_one_shot(uint32_t const tics)
|
inline void start_one_shot(uint32_t const tics, unsigned)
|
||||||
{
|
{
|
||||||
write<Clo>(0);
|
write<Clo>(0);
|
||||||
write<Cmp>(read<Clo>() + tics);
|
write<Cmp>(read<Clo>() + tics);
|
||||||
@ -61,7 +64,7 @@ class Kernel::Timer : public Genode::Mmio
|
|||||||
return (Board_base::SYSTEM_TIMER_CLOCK / 1000) * ms;
|
return (Board_base::SYSTEM_TIMER_CLOCK / 1000) * ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_interrupt()
|
void clear_interrupt(unsigned)
|
||||||
{
|
{
|
||||||
write<Cs::Status>(1);
|
write<Cs::Status>(1);
|
||||||
read<Cs>();
|
read<Cs>();
|
||||||
|
@ -52,6 +52,7 @@ SRC_CC += console.cc \
|
|||||||
kernel/vm.cc \
|
kernel/vm.cc \
|
||||||
kernel/signal_receiver.cc \
|
kernel/signal_receiver.cc \
|
||||||
kernel/irq.cc \
|
kernel/irq.cc \
|
||||||
|
kernel/multiprocessor.cc \
|
||||||
rm_session_support.cc \
|
rm_session_support.cc \
|
||||||
trustzone.cc \
|
trustzone.cc \
|
||||||
pager.cc \
|
pager.cc \
|
||||||
|
@ -51,9 +51,9 @@ namespace Cortex_a9
|
|||||||
struct Event : Bitfield<0,1> { }; /* if counter hit zero */
|
struct Event : Bitfield<0,1> { }; /* if counter hit zero */
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
void _clear_interrupt() { write<Interrupt_status::Event>(1); }
|
||||||
|
|
||||||
enum { IRQ = Cortex_a9::Cpu::PRIVATE_TIMER_IRQ };
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor, clears the interrupt output
|
* Constructor, clears the interrupt output
|
||||||
@ -61,16 +61,26 @@ namespace Cortex_a9
|
|||||||
Timer() : Mmio(Cortex_a9::Cpu::PRIVATE_TIMER_MMIO_BASE)
|
Timer() : Mmio(Cortex_a9::Cpu::PRIVATE_TIMER_MMIO_BASE)
|
||||||
{
|
{
|
||||||
write<Control::Timer_enable>(0);
|
write<Control::Timer_enable>(0);
|
||||||
clear_interrupt();
|
_clear_interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start one-shot run with an IRQ delay of 'tics'
|
* Return kernel name of timer interrupt
|
||||||
*/
|
*/
|
||||||
inline void start_one_shot(uint32_t const tics)
|
static unsigned interrupt_id(unsigned)
|
||||||
|
{
|
||||||
|
return Cortex_a9::Cpu::PRIVATE_TIMER_IRQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start single timeout run
|
||||||
|
*
|
||||||
|
* \param tics delay of timer interrupt
|
||||||
|
*/
|
||||||
|
inline void start_one_shot(unsigned const tics, unsigned)
|
||||||
{
|
{
|
||||||
/* reset timer */
|
/* reset timer */
|
||||||
clear_interrupt();
|
_clear_interrupt();
|
||||||
Control::access_t control = 0;
|
Control::access_t control = 0;
|
||||||
Control::Irq_enable::set(control, 1);
|
Control::Irq_enable::set(control, 1);
|
||||||
write<Control>(control);
|
write<Control>(control);
|
||||||
@ -91,10 +101,7 @@ namespace Cortex_a9
|
|||||||
/**
|
/**
|
||||||
* Clear interrupt output line
|
* Clear interrupt output line
|
||||||
*/
|
*/
|
||||||
void clear_interrupt()
|
void clear_interrupt(unsigned) { _clear_interrupt(); }
|
||||||
{
|
|
||||||
write<Interrupt_status::Event>(1);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,81 +26,149 @@ namespace Exynos_mct
|
|||||||
*/
|
*/
|
||||||
class Timer : public Mmio
|
class Timer : public Mmio
|
||||||
{
|
{
|
||||||
enum {
|
private:
|
||||||
PRESCALER = 1,
|
|
||||||
DIV_MUX = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
enum {
|
||||||
* MCT configuration
|
PRESCALER = 1,
|
||||||
*/
|
DIV_MUX = 0,
|
||||||
struct Mct_cfg : Register<0x0, 32>
|
};
|
||||||
{
|
|
||||||
struct Prescaler : Bitfield<0, 8> { };
|
|
||||||
struct Div_mux : Bitfield<8, 3> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local timer 0 free running counter buffer
|
* MCT configuration
|
||||||
*/
|
*/
|
||||||
struct L0_frcntb : Register<0x310, 32> { };
|
struct Mct_cfg : Register<0x0, 32>
|
||||||
|
{
|
||||||
|
struct Prescaler : Bitfield<0, 8> { };
|
||||||
|
struct Div_mux : Bitfield<8, 3> { };
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Local timer 0 configuration
|
|
||||||
*/
|
|
||||||
struct L0_tcon : Register<0x320, 32>
|
|
||||||
{
|
|
||||||
struct Frc_start : Bitfield<3, 1> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/*******************
|
||||||
* Local timer 0 expired status
|
** Local timer 0 **
|
||||||
*/
|
*******************/
|
||||||
struct L0_int_cstat : Register<0x330, 32, true>
|
|
||||||
{
|
|
||||||
struct Frcnt : Bitfield<1, 1> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local timer 0 interrupt enable
|
* Free running counter buffer
|
||||||
*/
|
*/
|
||||||
struct L0_int_enb : Register<0x334, 32>
|
struct L0_frcntb : Register<0x310, 32> { };
|
||||||
{
|
|
||||||
struct Frceie : Bitfield<1, 1> { };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local timer 0 write status
|
* Configuration
|
||||||
*/
|
*/
|
||||||
struct L0_wstat : Register<0x340, 32, true>
|
struct L0_tcon : Register<0x320, 32>
|
||||||
{
|
{
|
||||||
struct Frcntb : Bitfield<2, 1> { };
|
struct Frc_start : Bitfield<3, 1> { };
|
||||||
struct Tcon : Bitfield<3, 1> { };
|
};
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write to reg that replies via ack bit and clear ack bit
|
* Expired status
|
||||||
*/
|
*/
|
||||||
template <typename DEST, typename ACK>
|
struct L0_int_cstat : Register<0x330, 32, true>
|
||||||
void _acked_write(typename DEST::Register_base::access_t const v)
|
{
|
||||||
{
|
struct Frcnt : Bitfield<1, 1> { };
|
||||||
typedef typename DEST::Register_base Dest;
|
};
|
||||||
typedef typename ACK::Bitfield_base Ack;
|
|
||||||
write<Dest>(v);
|
|
||||||
while (!read<Ack>());
|
|
||||||
write<Ack>(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long const _tics_per_ms;
|
/**
|
||||||
|
* Interrupt enable
|
||||||
|
*/
|
||||||
|
struct L0_int_enb : Register<0x334, 32>
|
||||||
|
{
|
||||||
|
struct Frceie : Bitfield<1, 1> { };
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start and stop counting
|
* Write status
|
||||||
*/
|
*/
|
||||||
void _run(bool const run)
|
struct L0_wstat : Register<0x340, 32, true>
|
||||||
{
|
{
|
||||||
_acked_write<L0_tcon, L0_wstat::Tcon>
|
struct Frcntb : Bitfield<2, 1> { };
|
||||||
(L0_tcon::Frc_start::bits(run));
|
struct Tcon : Bitfield<3, 1> { };
|
||||||
}
|
};
|
||||||
|
|
||||||
|
struct L0_frcnto : Register<0x314, 32> { };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start and stop counting
|
||||||
|
*/
|
||||||
|
void _run_0(bool const run)
|
||||||
|
{
|
||||||
|
_acked_write<L0_tcon, L0_wstat::Tcon>
|
||||||
|
(L0_tcon::Frc_start::bits(run));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************
|
||||||
|
** Local timer 1 **
|
||||||
|
*******************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free running counter buffer
|
||||||
|
*/
|
||||||
|
struct L1_frcntb : Register<0x410, 32> { };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration
|
||||||
|
*/
|
||||||
|
struct L1_tcon : Register<0x420, 32>
|
||||||
|
{
|
||||||
|
struct Frc_start : Bitfield<3, 1> { };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expired status
|
||||||
|
*/
|
||||||
|
struct L1_int_cstat : Register<0x430, 32, true>
|
||||||
|
{
|
||||||
|
struct Frcnt : Bitfield<1, 1> { };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interrupt enable
|
||||||
|
*/
|
||||||
|
struct L1_int_enb : Register<0x434, 32>
|
||||||
|
{
|
||||||
|
struct Frceie : Bitfield<1, 1> { };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write status
|
||||||
|
*/
|
||||||
|
struct L1_wstat : Register<0x440, 32, true>
|
||||||
|
{
|
||||||
|
struct Frcntb : Bitfield<2, 1> { };
|
||||||
|
struct Tcon : Bitfield<3, 1> { };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct L1_frcnto : Register<0x414, 32> { };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start and stop counting
|
||||||
|
*/
|
||||||
|
void _run_1(bool const run)
|
||||||
|
{
|
||||||
|
_acked_write<L1_tcon, L1_wstat::Tcon>
|
||||||
|
(L1_tcon::Frc_start::bits(run));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************
|
||||||
|
** Helper methods **
|
||||||
|
********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write to reg that replies via ack bit and clear ack bit
|
||||||
|
*/
|
||||||
|
template <typename DEST, typename ACK>
|
||||||
|
void _acked_write(typename DEST::Register_base::access_t const v)
|
||||||
|
{
|
||||||
|
typedef typename DEST::Register_base Dest;
|
||||||
|
typedef typename ACK::Bitfield_base Ack;
|
||||||
|
write<Dest>(v);
|
||||||
|
while (!read<Ack>());
|
||||||
|
write<Ack>(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long const _tics_per_ms;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -115,16 +183,33 @@ namespace Exynos_mct
|
|||||||
Mct_cfg::Div_mux::set(mct_cfg, DIV_MUX);
|
Mct_cfg::Div_mux::set(mct_cfg, DIV_MUX);
|
||||||
write<Mct_cfg>(mct_cfg);
|
write<Mct_cfg>(mct_cfg);
|
||||||
write<L0_int_enb>(L0_int_enb::Frceie::bits(1));
|
write<L0_int_enb>(L0_int_enb::Frceie::bits(1));
|
||||||
|
write<L1_int_enb>(L1_int_enb::Frceie::bits(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start one-shot run with an IRQ delay of 'tics'
|
* Start single timeout run
|
||||||
|
*
|
||||||
|
* \param tics delay of timer interrupt
|
||||||
|
* \param processor_id kernel name of processor of targeted timer
|
||||||
*/
|
*/
|
||||||
inline void start_one_shot(unsigned const tics)
|
inline void start_one_shot(unsigned const tics,
|
||||||
|
unsigned const processor_id)
|
||||||
{
|
{
|
||||||
_run(0);
|
switch (processor_id) {
|
||||||
_acked_write<L0_frcntb, L0_wstat::Frcntb>(tics);
|
case 0:
|
||||||
_run(1);
|
_run_0(0);
|
||||||
|
_acked_write<L0_frcntb, L0_wstat::Frcntb>(tics);
|
||||||
|
_run_0(1);
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
_run_1(0);
|
||||||
|
_acked_write<L1_frcntb, L1_wstat::Frcntb>(tics);
|
||||||
|
_run_1(1);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
while (1) { }
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,7 +223,45 @@ namespace Exynos_mct
|
|||||||
/**
|
/**
|
||||||
* Clear interrupt output line
|
* Clear interrupt output line
|
||||||
*/
|
*/
|
||||||
void clear_interrupt() { write<L0_int_cstat::Frcnt>(1); }
|
void clear_interrupt(unsigned const processor_id)
|
||||||
|
{
|
||||||
|
switch (processor_id) {
|
||||||
|
case 0:
|
||||||
|
write<L0_int_cstat::Frcnt>(1);
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
write<L1_int_cstat::Frcnt>(1);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned value(unsigned const processor_id)
|
||||||
|
{
|
||||||
|
switch (processor_id) {
|
||||||
|
case 0:
|
||||||
|
return read<L0_frcnto>();
|
||||||
|
case 1:
|
||||||
|
return read<L1_frcnto>();
|
||||||
|
default:
|
||||||
|
while (1) { }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned irq_state(unsigned const processor_id)
|
||||||
|
{
|
||||||
|
switch (processor_id) {
|
||||||
|
case 0:
|
||||||
|
return read<L0_int_cstat::Frcnt>();
|
||||||
|
case 1:
|
||||||
|
return read<L1_int_cstat::Frcnt>();
|
||||||
|
default:
|
||||||
|
while (1) { }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,10 +67,6 @@ namespace Arm
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 to domain 0. They are not
|
|
||||||
* shareable and have zero-filled memory region attributes.
|
|
||||||
*/
|
*/
|
||||||
class Page_table
|
class Page_table
|
||||||
{
|
{
|
||||||
@ -371,12 +367,6 @@ namespace Arm
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 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
|
class Section_table
|
||||||
{
|
{
|
||||||
|
@ -13,4 +13,4 @@
|
|||||||
|
|
||||||
#include <trustzone.h>
|
#include <trustzone.h>
|
||||||
|
|
||||||
void Kernel::trustzone_initialization(Pic *pic) { }
|
void Kernel::init_trustzone(Pic * pic) { }
|
||||||
|
@ -22,7 +22,20 @@ namespace Genode
|
|||||||
/**
|
/**
|
||||||
* CPU driver for core
|
* CPU driver for core
|
||||||
*/
|
*/
|
||||||
class Cpu : public Cortex_a9::Cpu { };
|
class Cpu : public Cortex_a9::Cpu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the primary processor
|
||||||
|
*/
|
||||||
|
static unsigned primary_id() { return 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return kernel name of the executing processor
|
||||||
|
*/
|
||||||
|
static unsigned id() { return primary_id(); }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _VEA9X4__CPU_H_ */
|
#endif /* _VEA9X4__CPU_H_ */
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
# add include paths
|
# add include paths
|
||||||
INC_DIR += $(REP_DIR)/src/core/vea9x4
|
INC_DIR += $(REP_DIR)/src/core/vea9x4
|
||||||
INC_DIR += $(REP_DIR)/src/core/arm
|
INC_DIR += $(REP_DIR)/src/core/arm
|
||||||
|
INC_DIR += $(REP_DIR)/src/core/arm_v7
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += platform_services.cc \
|
SRC_CC += platform_services.cc \
|
||||||
|
@ -20,8 +20,13 @@
|
|||||||
extern int _mon_kernel_entry;
|
extern int _mon_kernel_entry;
|
||||||
|
|
||||||
|
|
||||||
void Kernel::trustzone_initialization(Pic *pic)
|
void Kernel::init_trustzone(Pic * pic)
|
||||||
{
|
{
|
||||||
|
/* check for compatibility */
|
||||||
|
if (PROCESSORS > 1) {
|
||||||
|
PERR("trustzone not supported with multiprocessing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
/* set exception vector entry */
|
/* set exception vector entry */
|
||||||
Genode::Cpu::mon_exception_entry_at((Genode::addr_t)&_mon_kernel_entry);
|
Genode::Cpu::mon_exception_entry_at((Genode::addr_t)&_mon_kernel_entry);
|
||||||
|
|
||||||
|
@ -114,23 +114,10 @@ namespace Genode
|
|||||||
|
|
||||||
/* disable timer */
|
/* disable timer */
|
||||||
write<Cr::En>(0);
|
write<Cr::En>(0);
|
||||||
clear_interrupt();
|
clear_interrupt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
void _start_one_shot(unsigned const tics)
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Epit_base(addr_t base) : 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 */
|
/* stop timer */
|
||||||
_reset();
|
_reset();
|
||||||
@ -144,6 +131,23 @@ namespace Genode
|
|||||||
write<Cr::En>(1);
|
write<Cr::En>(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
Epit_base(addr_t base) : Mmio(base) { _reset(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start single timeout run
|
||||||
|
*
|
||||||
|
* \param tics delay of timer interrupt
|
||||||
|
*/
|
||||||
|
void start_one_shot(unsigned const tics, unsigned)
|
||||||
|
{
|
||||||
|
_start_one_shot(tics);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop the timer from a one-shot run
|
* Stop the timer from a one-shot run
|
||||||
*
|
*
|
||||||
@ -161,7 +165,7 @@ namespace Genode
|
|||||||
/**
|
/**
|
||||||
* Clear interrupt output line
|
* Clear interrupt output line
|
||||||
*/
|
*/
|
||||||
void clear_interrupt() { write<Sr::Ocif>(1); }
|
void clear_interrupt(unsigned) { write<Sr::Ocif>(1); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translate milliseconds to a native timer value
|
* Translate milliseconds to a native timer value
|
||||||
|
@ -55,6 +55,7 @@ namespace Genode
|
|||||||
MCT_MMIO_SIZE = 0x1000,
|
MCT_MMIO_SIZE = 0x1000,
|
||||||
MCT_CLOCK = 24000000,
|
MCT_CLOCK = 24000000,
|
||||||
MCT_IRQ_L0 = 152,
|
MCT_IRQ_L0 = 152,
|
||||||
|
MCT_IRQ_L1 = 153,
|
||||||
|
|
||||||
/* USB */
|
/* USB */
|
||||||
USB_HOST20_IRQ = 103,
|
USB_HOST20_IRQ = 103,
|
||||||
@ -74,6 +75,12 @@ namespace Genode
|
|||||||
|
|
||||||
/* wether board provides security extension */
|
/* wether board provides security extension */
|
||||||
SECURITY_EXTENSION = 1,
|
SECURITY_EXTENSION = 1,
|
||||||
|
|
||||||
|
/* IRAM */
|
||||||
|
IRAM_BASE = 0x02020000,
|
||||||
|
|
||||||
|
/* hardware name of the primary processor */
|
||||||
|
PRIMARY_MPIDR_AFF_0 = 0,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,7 @@ namespace Genode
|
|||||||
/**
|
/**
|
||||||
* Count down 'value', raise IRQ output, wrap counter and continue
|
* Count down 'value', raise IRQ output, wrap counter and continue
|
||||||
*/
|
*/
|
||||||
void run_and_wrap(unsigned long value) {
|
void run_and_wrap(unsigned long value) { _start_one_shot(value); }
|
||||||
start_one_shot(value); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum timeout value
|
* Maximum timeout value
|
||||||
|
Loading…
Reference in New Issue
Block a user