d7fa4cfb8b
* Add an ieee754 FPU test * Remove simple fpu test Fix #2822
168 lines
4.0 KiB
ArmAsm
168 lines
4.0 KiB
ArmAsm
/*
|
|
* \brief Transition between kernel/userland
|
|
* \author Martin Stein
|
|
* \author Stefan Kalkowski
|
|
* \date 2011-11-15
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2011-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
|
|
/*********************
|
|
** Constant values **
|
|
*********************/
|
|
|
|
.set USR_MODE, 16
|
|
.set FIQ_MODE, 17
|
|
.set IRQ_MODE, 18
|
|
.set SVC_MODE, 19
|
|
.set ABT_MODE, 23
|
|
.set UND_MODE, 27
|
|
.set SYS_MODE, 31
|
|
|
|
.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 CPU context members */
|
|
.set PC_OFFSET, 15 * 4
|
|
.set STACK_OFFSET, 17 * 4
|
|
|
|
|
|
/************
|
|
** Macros **
|
|
************/
|
|
|
|
/**
|
|
* Save an interrupted user context and switch to kernel context
|
|
*
|
|
* \param exception_type kernel name of exception type
|
|
* \param mode mode number of program status register
|
|
* \param pc_adjust value that gets subtracted from saved user PC
|
|
*/
|
|
.macro _user_to_kernel exception_type, mode, pc_adjust
|
|
|
|
cpsid f, #SVC_MODE /* disable interrupts and change to SVC mode */
|
|
stm sp, {r0-r14}^ /* the sp_svc contains the user context pointer */
|
|
add r0, sp, #PC_OFFSET
|
|
ldr sp, [sp, #STACK_OFFSET] /* restore kernel stack pointer */
|
|
cps #\mode
|
|
sub r1, lr, #\pc_adjust /* calculate user program counter */
|
|
mrs r2, spsr /* get user cpsr */
|
|
mov r3, #\exception_type
|
|
b _common_kernel_entry
|
|
|
|
.endm
|
|
|
|
|
|
.section .text.crt0
|
|
|
|
/***********************
|
|
** Exception entries **
|
|
***********************/
|
|
|
|
b _rst_entry /* 0x00: reset */
|
|
b _und_entry /* 0x04: undefined instruction */
|
|
b _svc_entry /* 0x08: supervisor call */
|
|
b _pab_entry /* 0x0c: prefetch abort */
|
|
b _dab_entry /* 0x10: data abort */
|
|
nop /* 0x14: reserved */
|
|
b _irq_entry /* 0x18: interrupt request */
|
|
|
|
/*
|
|
* Fast interrupt exception entry 0x1c.
|
|
*
|
|
* If the previous mode was not the user mode, it means a previous
|
|
* exception got interrupted by a fast interrupt.
|
|
* In that case, we disable fast interrupts and return to the
|
|
* previous exception handling routine.
|
|
*/
|
|
mrs r8, spsr
|
|
and r9, r8, #0b11111
|
|
cmp r9, #USR_MODE
|
|
cmpne r9, #SYS_MODE
|
|
beq _fiq_entry
|
|
orr r8, #0b1000000
|
|
msr spsr_cxsf, r8
|
|
subs pc, lr, #4
|
|
|
|
_rst_entry: _user_to_kernel RST_TYPE, SVC_MODE, RST_PC_ADJUST
|
|
_und_entry: _user_to_kernel UND_TYPE, UND_MODE, UND_PC_ADJUST
|
|
_svc_entry: _user_to_kernel SVC_TYPE, SVC_MODE, SVC_PC_ADJUST
|
|
_pab_entry: _user_to_kernel PAB_TYPE, ABT_MODE, PAB_PC_ADJUST
|
|
_dab_entry: _user_to_kernel DAB_TYPE, ABT_MODE, DAB_PC_ADJUST
|
|
_irq_entry: _user_to_kernel IRQ_TYPE, IRQ_MODE, IRQ_PC_ADJUST
|
|
_fiq_entry: _user_to_kernel FIQ_TYPE, FIQ_MODE, FIQ_PC_ADJUST
|
|
|
|
_common_kernel_entry:
|
|
stmia r0!, {r1-r3} /* save pc, cpsr and exception type */
|
|
clrex /* clear exclusive access needed for cmpxchg */
|
|
cps #SVC_MODE
|
|
|
|
mov r1, #1 /* clear exception state of the VFP */
|
|
lsl r1, #30
|
|
vmsr fpexc, r1
|
|
adr r1, _fpu_save
|
|
ldr r1, [r1]
|
|
blx r1
|
|
|
|
/*
|
|
* Go to kernel entry code
|
|
*/
|
|
adr lr, _kernel_entry
|
|
ldr lr, [lr]
|
|
bx lr
|
|
|
|
_kernel_entry:
|
|
.long kernel
|
|
|
|
_fpu_save:
|
|
.long vfp_save_fpu_context
|
|
|
|
|
|
.section .text
|
|
|
|
/*******************************
|
|
** idle loop for idle thread **
|
|
*******************************/
|
|
|
|
.global idle_thread_main
|
|
idle_thread_main:
|
|
wfi
|
|
b idle_thread_main
|
|
|
|
|
|
/*****************************
|
|
** kernel to userland switch **
|
|
*******************************/
|
|
|
|
.global kernel_to_user_context_switch
|
|
kernel_to_user_context_switch:
|
|
push { r0 }
|
|
mov r0, r1
|
|
bl vfp_load_fpu_context
|
|
pop { r0 }
|
|
mov sp, r0
|
|
ldr lr, [sp, #15*4]
|
|
ldr r1, [sp, #16*4]
|
|
msr spsr_cxsf, r1
|
|
ldm sp, {r0-r14}^
|
|
subs pc, lr, #0
|