rt/arch/arm/m/syscall-v7-v8.S

173 lines
3.6 KiB
ArmAsm

@ vim:ft=arm
/*
* This variant of the syscall handler supports armv{7,8}-m{,+nofp}.
*/
#include <rt/mpu.h>
#include "exc_return.h"
#ifdef __ARM_FP
/*
* For floating-point, save and restore lr, which contains the exception return
* value, and use the floating-point context bit of this value to decide if the
* non-volatile fp context should be saved/restored as well.
*/
#define excreturn ,lr
#define pushlr str lr, [sp, #-8]! // Push only lr but keep sp 8-byte aligned.
#define poplr ldr lr, [sp], 8
#define savefp tst lr, 0x10; it eq; vstmdbeq r1!, {s16-s31}
#define loadfp tst lr, 0x10; it eq; vldmiaeq r0!, {s16-s31}
#define return bx lr
#else
/*
* With nofp, lr can be clobbered and reloaded from an immediate because the
* exception return value for tasks is a constant.
*/
#define excreturn
#define pushlr
#define poplr
#define savefp
#define loadfp
#define return mov r0, TASK_INITIAL_EXC_RETURN; bx r0
#endif
#if RT_MPU_ENABLE
#define controltemp r2,
#define getcontrol mrs r2, control
#define setcontrol msr control, r2
.macro mpuconfigure
ldr r1, =rt_mpu_config
ldr r1, [r1]
ldr r2, =0xE000ED9C
mpuset RT_MPU_TASK_REGION_START_ID, RT_MPU_NUM_TASK_REGIONS
dsb
.endm
.macro mpuset r, n
.if \n == 0
.exitm
.endif
#if (__ARM_ARCH == 8) && (RT_MPU_NUM_TASK_REGIONS > 4)
.if (\r == RT_MPU_TASK_REGION_START_ID) || ((\r % 4) == 0)
mov r3, \r & 0xFC
str r3, [r2, -4]
.endif
#endif
.if ((\r % 4) == 0) && (\n >= 4)
ldmia r1!, {r4-r11}
stmia r2, {r4-r11}
mpuset (\r + 4), (\n - 4)
.elseif ((\r % 4) == 1) && (\n >= 3)
ldmia r1!, {r4-r9}
#if __ARM_ARCH == 8
add r3, r2, 4
stmia r3, {r4-r9}
#else
stmia r2, {r4-r9}
#endif
mpuset (\r + 3), (\n - 3)
.elseif ((\r % 4) == 2) && (\n >= 2)
ldmia r1!, {r4-r7}
#if __ARM_ARCH == 8
add r3, r2, 8
stmia r3, {r4-r7}
#else
stmia r2, {r4-r7}
#endif
mpuset (\r + 2), (\n - 2)
.else
ldmia r1!, {r4-r5}
#if __ARM_ARCH == 8
strd r4, r5, [r2, (\r % 4) * 4]
#else
strd r4, r5, [r2]
#endif
mpuset (\r + 1), (\n - 1)
.endif
.endm
#else
#define controltemp
#define getcontrol
#define setcontrol
#define mpuconfigure
#endif
#if __ARM_ARCH == 8
#define psplimtemp r3,
#define getpsplim mrs r3, psplim
#define setpsplim msr psplim, r3
#else // v7
#define psplimtemp
#define getpsplim
#define setpsplim
#endif
#define saveregs stmdb r1!, {controltemp psplimtemp r4-r11 excreturn}
#define loadregs ldmia r0!, {controltemp psplimtemp r4-r11 excreturn}
.syntax unified
.section .text.rt_syscall_handler,"ax",%progbits
.global rt_syscall_handler
.type rt_syscall_handler, %function
rt_syscall_handler:
pushlr
bl rt_syscall_run
poplr
// If there's no new context to switch to, return early.
cbz r0, .Lreturn
// Write the suspending context to its stack pointer.
mrs r1, psp
savefp
getcontrol
getpsplim
saveregs
// Store the new stack pointer with the saved context.
ldr r2, =rt_context_prev
ldr r2, [r2]
str r1, [r2]
mpuconfigure
// Load the new context returned by rt_syscall_run.
loadregs
loadfp
// Set the new stack pointer.
msr psp, r0
setcontrol
setpsplim
.Lreturn:
return
.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
mpuconfigure
loadregs
msr psp, r0
setpsplim
movs r0, 2
msr control, r0
isb
// Once we are using the process stack pointer, interrupts can be enabled.
cpsie i
pop {r0-r3, r12, lr}
ldr pc, [sp], 8
.size rt_start, .-rt_start