168 lines
3.9 KiB
ArmAsm
168 lines
3.9 KiB
ArmAsm
@ vim:ft=arm
|
|
|
|
/*
|
|
* The interrupt management code for the syscall handler depends on both the
|
|
* type of interrupt controller and the source of the syscall interrupt, so we
|
|
* provide a way to extend this code with assembly macros.
|
|
* vic_syscall_start needs to mask and clear the syscall interrupt such that
|
|
* another syscall cannot occur when IRQs are re-enabled. vic_syscall_finish
|
|
* must unmask the syscall interrupt. Both are run with IRQs disabled.
|
|
*/
|
|
|
|
#include <rt/mpu.h>
|
|
|
|
#include <vic.S>
|
|
|
|
#include "mode.h"
|
|
|
|
.macro mpuconfigure
|
|
#if RT_MPU_ENABLE
|
|
ldr r1, =rt_mpu_config
|
|
ldr r1, [r1]
|
|
movs r2, RT_MPU_TASK_REGION_START_ID
|
|
adds r5, r2, RT_MPU_NUM_TASK_REGIONS
|
|
|
|
.Lmpusetloop\@:
|
|
// Set the region number register.
|
|
mcr p15, 0, r2, c6, c2, 0
|
|
|
|
// Load the region configuration and advance to the next one.
|
|
ldmia r1!, {r3, r4}
|
|
|
|
// Set the base address register.
|
|
mcr p15, 0, r3, c6, c1, 0
|
|
|
|
// Set the size and enable register.
|
|
uxtb r3, r4
|
|
mcr p15, 0, r3, c6, c1, 2
|
|
|
|
// Set the access control register.
|
|
lsrs r3, r4, 16
|
|
mcr p15, 0, r3, c6, c1, 4
|
|
|
|
add r2, 1
|
|
cmp r2, r5
|
|
blt .Lmpusetloop\@
|
|
dsb
|
|
#endif
|
|
.endm
|
|
|
|
#ifdef __thumb__
|
|
.thumb
|
|
#else
|
|
.arm
|
|
// arm mode doesn't have cbz, so make our own.
|
|
.macro cbz reg, label
|
|
cmp \reg, 0
|
|
beq \label
|
|
.endm
|
|
#endif
|
|
|
|
.syntax unified
|
|
.section .text.rt_syscall_handler,"ax",%progbits
|
|
.global rt_syscall_handler
|
|
.type rt_syscall_handler, %function
|
|
#ifdef RT_VIC_IRQ_ALIGN
|
|
.balign RT_VIC_IRQ_ALIGN
|
|
#endif
|
|
rt_syscall_handler:
|
|
sub lr, 4
|
|
|
|
// Some VIC implementations use a separate SVC handler.
|
|
.ifndef rt_syscall_handler_svc
|
|
.global rt_syscall_handler_svc
|
|
.type rt_syscall_handler_svc, %function
|
|
rt_syscall_handler_svc:
|
|
.endif
|
|
// Push lr (task pc) and spsr (task cpsr) to the system/user stack.
|
|
srsdb sp!, MODE_SYS
|
|
cps MODE_SYS
|
|
// Save the task's volatile registers.
|
|
push {r0-r3, r12, lr}
|
|
vic_syscall_start
|
|
|
|
cpsie i, MODE_SVC
|
|
bl rt_syscall_run
|
|
cps MODE_SYS
|
|
|
|
// If there's no new context to switch to, return early.
|
|
cbz r0, .Lreturn
|
|
|
|
/* Ordinarily a clrex is necessary here, but rt_syscall_run uses strex,
|
|
* which also clears the exclusive monitor. */
|
|
|
|
#ifdef __ARM_FP
|
|
// Check if the task has a floating-point context.
|
|
mrc p15, 0, r1, cr1, cr0, 2
|
|
tst r1, 0xf00000 // CPACR_10_FULL_ACCESS | CPACR_11_FULL_ACCESS
|
|
beq .Lskip_fp_save
|
|
vpush {d0-d15}
|
|
vmrs r2, fpexc
|
|
vmrs r3, fpscr
|
|
push {r2, r3}
|
|
.Lskip_fp_save:
|
|
push {r1, r4-r11} // cpacr, callee-saved registers
|
|
#else // !defined(__ARM_FP)
|
|
push {r4-r11}
|
|
#endif // __ARM_FP
|
|
|
|
// Store the stack pointer with the saved context.
|
|
ldr r2, =rt_context_prev
|
|
ldr r2, [r2]
|
|
str sp, [r2]
|
|
|
|
mpuconfigure
|
|
|
|
// Switch to the new task stack returned by rt_syscall_run.
|
|
mov sp, r0
|
|
|
|
#ifdef __ARM_FP
|
|
pop {r1, r4-r11}
|
|
mcr p15, 0, r1, cr1, cr0, 2
|
|
tst r1, 0xf00000
|
|
beq .Lskip_fp_restore
|
|
pop {r2, r3}
|
|
vmsr fpexc, r2
|
|
vmsr fpscr, r3
|
|
vpop {d0-d15}
|
|
.Lskip_fp_restore:
|
|
#else // !defined(__ARM_FP)
|
|
pop {r4-r11}
|
|
#endif // __ARM_FP
|
|
|
|
.Lreturn:
|
|
/* Disable interrupts again before unmasking the syscall interrupt at the
|
|
* VIC; otherwise, repeated syscalls could grow the task stack
|
|
* indefinitely. */
|
|
cpsid i
|
|
vic_syscall_finish
|
|
|
|
// Restore the task's volatile registers.
|
|
pop {r0-r3, r12, lr}
|
|
// Restore the task's pc and cpsr (this re-enables interrupts).
|
|
rfeia sp!
|
|
|
|
.size rt_syscall_handler, .-rt_syscall_handler
|
|
|
|
|
|
.section .text.rt_start,"ax",%progbits
|
|
.global rt_start
|
|
.type rt_start, %function
|
|
rt_start:
|
|
bl rt_start_context
|
|
cps MODE_SYS
|
|
mpuconfigure
|
|
mov sp, r0
|
|
|
|
#ifdef __ARM_FP
|
|
pop {r1, r4-r11}
|
|
mcr p15, 0, r1, cr1, cr0, 2
|
|
#else // !defined(__ARM_FP)
|
|
pop {r4-r11}
|
|
#endif // __ARM_FP
|
|
|
|
pop {r0-r3, r12, lr}
|
|
rfeia sp!
|
|
|
|
.size rt_start, .-rt_start
|