SELFOUR-615: arm entry point stubs

This commit is contained in:
Anna Lyons 2016-08-22 11:46:47 +10:00
parent 297ad035a6
commit ef00e98689
11 changed files with 188 additions and 199 deletions

View file

@ -23,4 +23,21 @@ static inline void arch_c_exit_hook(void) {
void c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall)
VISIBLE SECTION(".vectors.text");
void c_handle_interrupt(void)
VISIBLE SECTION(".vectors.text");
void c_handle_undefined_instruction(void)
VISIBLE SECTION(".vectors.text");
void c_handle_data_fault(void)
VISIBLE SECTION(".vectors.text");
void c_handle_instruction_fault(void)
VISIBLE SECTION(".vectors.text");
#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
void c_handle_vcpu_fault(word_t hsr)
VISIBLE SECTION(".vectors.text");
#endif /* CONFIG_ARM_HYPERVISOR_SUPPORT */
#endif /* __KERNEL_ARM_TRAPS_H */

View file

@ -21,6 +21,7 @@
#include <api/debug.h>
#if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES)
#define TRACK_KERNEL_ENTRIES 1
#ifdef CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES
/**
* Calculate the maximum number of kernel entries that can be tracked,

View file

@ -18,7 +18,8 @@
/* This C function should be the first thing called from C after entry from
* assembly. It provides a single place to do any entry work that is not
* done in assembly for various reasons */
static inline void c_entry_hook(void) {
static inline void c_entry_hook(void)
{
arch_c_entry_hook();
#if defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES) || defined(CONFIG_BENCHMARK_TRACK_UTILISATION)
ksEnter = timestamp();
@ -29,14 +30,12 @@ static inline void c_entry_hook(void) {
* the kernel (be it to assembly or returning to user space). It provides
* a place to provide any additional instrumentation or functionality
* in C before leaving the kernel */
static inline void c_exit_hook(void) {
static inline void c_exit_hook(void)
{
#ifdef CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES
benchmark_track_exit();
#endif /* CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES */
arch_c_exit_hook();
}
void c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall)
VISIBLE SECTION(".vectors.text");
#endif /* __KERNEL_TRAPS_H */

View file

@ -24,7 +24,9 @@ typedef enum {
Entry_UnknownSyscall,
Entry_UserLevelFault,
Entry_VMFault,
Entry_Syscall
Entry_Syscall,
Entry_UnimplementedDevice,
Entry_VCPUFault
} entry_type_t;
/**

View file

@ -39,13 +39,7 @@ handleInterruptEntry(void)
{
irq_t irq;
c_entry_hook();
irq = getActiveIRQ();
#if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES)
ksKernelEntry.path = Entry_Interrupt;
ksKernelEntry.word = irq;
#endif /* DEBUG */
if (irq != irqInvalid) {
handleInterrupt(irq);
@ -59,8 +53,6 @@ handleInterruptEntry(void)
schedule();
activateThread();
c_exit_hook();
return EXCEPTION_NONE;
}
@ -68,9 +60,6 @@ exception_t
handleUnknownSyscall(word_t w)
{
#ifdef CONFIG_DEBUG_BUILD
ksKernelEntry.path = Entry_UnknownSyscall;
ksKernelEntry.word = w;
if (w == SysDebugPutChar) {
kernel_putchar(getRegister(ksCurThread, capRegister));
return EXCEPTION_NONE;
@ -190,22 +179,12 @@ handleUnknownSyscall(word_t w)
exception_t
handleUserLevelFault(word_t w_a, word_t w_b)
{
c_entry_hook();
#if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES)
ksKernelEntry.path = Entry_UserLevelFault;
ksKernelEntry.word = w_a;
#endif /* DEBUG */
current_fault = fault_user_exception_new(w_a, w_b);
handleFault(ksCurThread);
schedule();
activateThread();
#ifdef CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES
benchmark_track_exit();
#endif
return EXCEPTION_NONE;
}
@ -213,11 +192,6 @@ exception_t
handleVMFaultEvent(vm_fault_type_t vm_faultType)
{
exception_t status;
c_entry_hook();
#if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES)
ksKernelEntry.path = Entry_VMFault;
ksKernelEntry.word = vm_faultType;
#endif /* DEBUG */
status = handleVMFault(ksCurThread, vm_faultType);
if (status != EXCEPTION_NONE) {
@ -227,8 +201,6 @@ handleVMFaultEvent(vm_fault_type_t vm_faultType)
schedule();
activateThread();
c_exit_hook();
return EXCEPTION_NONE;
}
@ -252,10 +224,6 @@ handleInvocation(bool_t isCall, bool_t isBlocking)
/* faulting section */
lu_ret = lookupCapAndSlot(thread, cptr);
#if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES)
ksKernelEntry.is_fastpath = false;
#endif
if (unlikely(lu_ret.status != EXCEPTION_NONE)) {
userError("Invocation of invalid cap #%lu.", cptr);
current_fault = fault_cap_fault_new(cptr, false);

View file

@ -95,30 +95,6 @@ END_FUNC(arm_vector_table)
#define HSREC_DATA_ABORT 0x24
#define HSRIL32 (1 << 25)
/* Helper to return to userland. */
.macro RET_TO_USER, cur_thread_reg
/* cur_thread_reg should contain the address of ksCurThread. */
/* Set stack pointer to point at the r0 of the user context. */
ldr sp, [\cur_thread_reg]
/* Pop user registers */
pop {r0-r12}
/* Retore the user stack pointer */
pop {lr}
msr sp_usr, lr
/* prepare the eception return lr */
ldr lr, [sp, #4]
msr elr_hyp, lr
/* prepare the user status register */
ldr lr, [sp, #8]
msr spsr_hyp, lr
/* Finally, pop our LR */
pop {lr}
/* Return to user */
eret
.endm
.macro EX_ENTRY
/* Create some scratch space */
push {lr}
@ -133,6 +109,16 @@ END_FUNC(arm_vector_table)
push {lr}
.endm
/* Prepare to enter the kernel */
.macro PUSH_STACK
/* store FaultInstruction */
str lr, [sp, #(PT_FaultInstruction - PT_SP)]
/* Stack all user registers */
push {r0-r12}
/* Load the kernel's real stack pointer */
mov sp, #(PPTR_KERNEL_STACK_TOP)
.endm
/********************************
*** Traps taken to HYP mode ***
********************************/
@ -155,95 +141,36 @@ BEGIN_FUNC(arm_hyp_trap)
beq arm_undefined_inst
/** Everything else is assumed to be a VCPU trap **/
/* Store FaultInstruction */
mrs lr, elr_hyp
str lr, [sp, #(PT_FaultInstruction - PT_SP)]
/* Stack all user registers */
push {r0-r12}
/* Load the kernel's real stack pointer */
mov sp, #(PPTR_KERNEL_STACK_TOP)
/* Call out to the user */
ldr r7, =ksCurThread
PUSH_STACK
mrc HSR(r0)
blx handleVCPUFault
/* Exception return */
RET_TO_USER r7
b c_handle_vcpu_fault
END_FUNC(arm_hyp_trap)
BEGIN_FUNC(arm_undefined_inst)
/* Store FaultInstruction */
mrs lr, elr_hyp
str lr, [sp, #(PT_FaultInstruction - PT_SP)]
/* Stack all user registers */
push {r0-r12}
/* Load the kernel's real stack pointer */
mov sp, #(PPTR_KERNEL_STACK_TOP)
/* Call out to the user */
ldr r7, =ksCurThread
mov r0, #0
mov r1, #0
blx handleUserLevelFault
/* Exception return */
RET_TO_USER r7
PUSH_STACK
b c_handle_undefined_instruction
END_FUNC(arm_undefined_inst)
BEGIN_FUNC(arm_prefetch_abort)
/* Store FaultInstruction */
mrs lr, elr_hyp
str lr, [sp, #(PT_FaultInstruction - PT_SP)]
/* Stack all user registers */
push {r0-r12}
/* Load the kernel's real stack pointer */
mov sp, #(PPTR_KERNEL_STACK_TOP)
/* Call out to the user */
ldr r7, =ksCurThread
mov r0, #seL4_InstructionFault
blx handleVMFaultEvent
/* Exception return */
RET_TO_USER r7
PUSH_STACK
b c_handle_instruction_fault
END_FUNC(arm_prefetch_abort)
BEGIN_FUNC(arm_data_abort)
/* Store FaultInstruction */
mrs lr, elr_hyp
str lr, [sp, #(PT_FaultInstruction - PT_SP)]
/* Stack all user registers */
push {r0-r12}
/* Load the kernel's real stack pointer */
mov sp, #(PPTR_KERNEL_STACK_TOP)
/* Call out to the user */
ldr r7, =ksCurThread
mov r0, #seL4_DataFault
blx handleVMFaultEvent
/* Exception return */
RET_TO_USER r7
PUSH_STACK
b c_handle_data_fault
END_FUNC(arm_data_abort)
BEGIN_FUNC(arm_syscall)
/* Store FaultInstruction */
mrs lr, elr_hyp
sub lr, lr, #4
str lr, [sp, #(PT_FaultInstruction - PT_SP)]
/* Stack all user registers */
push {r0-r12}
/* Load the kernel's real stack pointer */
mov sp, #(PPTR_KERNEL_STACK_TOP)
/* Load system call number as a c_handle_syscall argument. r0 and r1 are passed
* unmodified (cptr and msgIngo respectively).
*/
PUSH_STACK
/* r0: cptr, r1: msgInfo, r2: syscallNo */
mov r2, r7
b c_handle_syscall
END_FUNC(arm_syscall)
@ -295,20 +222,9 @@ END_FUNC(arm_hyp_syscall)
BEGIN_FUNC(arm_hyp_irq_exception)
EX_ENTRY
/* Store FaultInstruction */
mrs lr, elr_hyp
str lr, [sp, #(PT_FaultInstruction - PT_SP)]
/* Stack all user registers */
push {r0-r12}
/* Handle the exception */
ldr r7, =ksCurThread
mov sp, #(PPTR_KERNEL_STACK_TOP)
blx handleInterruptEntry
/* Return to the user */
RET_TO_USER r7
PUSH_STACK
b c_handle_interrupt
END_FUNC(arm_hyp_irq_exception)
BEGIN_FUNC(arm_hyp_reset_exception)

View file

@ -38,20 +38,6 @@ END_FUNC(arm_vector_table)
#include <arch/machine/registerset.h>
#include <mode/api/constants.h>
/* Helper to return to userland. */
.macro RET_TO_USER, cur_thread_reg
/* cur_thread_reg should contain the address of ksCurThread. */
/* Set stack pointer to point at the LR_svc of the user context. */
ldr sp, [\cur_thread_reg]
add sp, sp, #PT_LR_svc
/* Unstack user registers */
ldmdb sp, {r0-lr}^
/* Jump to user NextPC and restore user CPSR */
rfeia sp
.endm
BEGIN_FUNC(arm_undefined_inst_exception)
/* Full save/restore, documented in arm_swi_syscall */
srsia #PMODE_SUPERVISOR
@ -66,15 +52,7 @@ BEGIN_FUNC(arm_undefined_inst_exception)
sub r8, r8, #4
str r8, [sp, #(PT_FaultInstruction - PT_LR_svc)]
ldr sp, =(PPTR_KERNEL_STACK_TOP)
ldr r7, =ksCurThread
/* There's only one user-level fault on ARM, and the code is (0,0) */
mov r0, #0
mov r1, #0
blx handleUserLevelFault
RET_TO_USER r7
b c_handle_undefined_instruction
#endif
END_FUNC(arm_undefined_inst_exception)
@ -98,7 +76,7 @@ BEGIN_FUNC(arm_swi_syscall)
ldr sp, =(PPTR_KERNEL_STACK_TOP)
/* Load system call number as a c_handle_syscall argument. r0 and r1 are passed
* unmodified (cptr and msgInfo respectively).
* unmodified (cptr and msgInfo) respectively.
*/
mov r2, r7
b c_handle_syscall
@ -127,11 +105,7 @@ BEGIN_FUNC(arm_prefetch_abort_exception)
str r8, [sp, #(PT_FaultInstruction - PT_LR_svc)]
ldr sp, =(PPTR_KERNEL_STACK_TOP)
ldr r7, =ksCurThread
mov r0, #seL4_InstructionFault
blx handleVMFaultEvent
RET_TO_USER r7
b c_handle_instruction_fault
kernel_prefetch_fault:
#ifdef DEBUG
@ -175,10 +149,8 @@ BEGIN_FUNC(arm_data_abort_exception)
ldr sp, =(PPTR_KERNEL_STACK_TOP)
ldr r7, =ksCurThread
mov r0, #seL4_DataFault
blx handleVMFaultEvent
b c_handle_data_fault
RET_TO_USER r7
kernel_data_fault:
#ifdef DEBUG
@ -207,12 +179,8 @@ BEGIN_FUNC(arm_irq_exception)
sub r8, r8, #4
str r8, [sp]
str r8, [sp, #(PT_FaultInstruction - PT_LR_svc)]
ldr r7, =ksCurThread
ldr sp, =(PPTR_KERNEL_STACK_TOP)
blx handleInterruptEntry
RET_TO_USER r7
b c_handle_interrupt
END_FUNC(arm_irq_exception)
BEGIN_FUNC(arm_reset_exception)

View file

@ -10,14 +10,83 @@
#include <config.h>
#include <arch/kernel/traps.h>
#include <arch/object/vcpu.h>
#include <arch/machine/registerset.h>
#include <api/syscall.h>
#include <benchmark_track_types.h>
#include <benchmark_track.h>
#include <benchmark_utilisation.h>
/** DONT_TRANSLATE */
void NORETURN slowpath(syscall_t syscall)
void VISIBLE NORETURN
c_handle_undefined_instruction(void)
{
c_entry_hook();
#ifdef TRACK_KERNEL_ENTRIES
ksKernelEntry.path = Entry_UserLevelFault;
ksKernelEntry.word = getRegister(ksCurThread, LR_svc);
#endif
/* There's only one user-level fault on ARM, and the code is (0,0) */
handleUserLevelFault(0, 0);
restore_user_context();
UNREACHABLE();
}
/** DONT_TRANSLATE */
static inline void NORETURN
c_handle_vm_fault(vm_fault_type_t type)
{
c_entry_hook();
#ifdef TRACK_KERNEL_ENTRIES
ksKernelEntry.path = Entry_VMFault;
ksKernelEntry.word = getRegister(ksCurThread, LR_svc);
#endif
handleVMFaultEvent(type);
restore_user_context();
UNREACHABLE();
}
/** DONT_TRANSLATE */
void VISIBLE NORETURN
c_handle_data_fault(void)
{
c_handle_vm_fault(seL4_DataFault);
}
/** DONT_TRANSLATE */
void VISIBLE NORETURN
c_handle_instruction_fault(void)
{
c_handle_vm_fault(seL4_InstructionFault);
}
/** DONT_TRANSLATE */
void VISIBLE NORETURN
c_handle_interrupt(void)
{
c_entry_hook();
#ifdef TRACK_KERNEL_ENTRIES
ksKernelEntry.path = Entry_Interrupt;
ksKernelEntry.word = getActiveIRQ();
#endif
handleInterruptEntry();
restore_user_context();
}
/** DONT_TRANSLATE */
void NORETURN
slowpath(syscall_t syscall)
{
#ifdef TRACK_KERNEL_ENTIRES
ksEntry.is_fastpath = 0;
#endif /* TRACK KERNEL ENTRIES */
handleSyscall(syscall);
restore_user_context();
@ -25,11 +94,13 @@ void NORETURN slowpath(syscall_t syscall)
}
/** DONT_TRANSLATE */
void VISIBLE c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall)
void VISIBLE
c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall)
{
c_entry_hook();
#if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES)
#if TRACK_KERNEL_ENTRIES
benchmark_debug_syscall_start(cptr, msgInfo, syscall);
ksKernelEntry.is_fastpath = 1;
#endif /* DEBUG */
#ifdef CONFIG_FASTPATH
@ -43,6 +114,10 @@ void VISIBLE c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall)
#endif /* CONFIG_FASTPATH */
if (unlikely(syscall < SYSCALL_MIN || syscall > SYSCALL_MAX)) {
#ifdef TRACK_KERNEL_ENTIRES
ksKernelEntry.path = Entry_UnknownSyscall;
/* ksKernelEntry.word word is already set to syscall */
#endif /* TRACK_KERNEL_ENTRIES */
handleUnknownSyscall(syscall);
restore_user_context();
UNREACHABLE();
@ -51,3 +126,20 @@ void VISIBLE c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall)
UNREACHABLE();
}
}
#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
/** DONT_TRANSLATE */
VISIBLE NORETURN void
c_handle_vcpu_fault(word_t hsr)
{
c_entry_hook();
#ifdef TRACK_KERNEL_ENTRIES
ksKernelEntry.path = Entry_VCPUFault;
ksKernelEntry.word = hsr;
#endif
handleVCPUFault(hsr);
restore_user_context();
UNREACHABLE();
}
#endif /* CONFIG_ARM_HYPERVISOR_SUPPORT */

View file

@ -596,12 +596,10 @@ invokeVCPUSetTCB(vcpu_t *vcpu, tcb_t *tcb)
void
handleVCPUFault(word_t hsr)
{
c_entry_hook();
current_fault = fault_vcpu_fault_new(hsr);
handleFault(ksCurThread);
schedule();
activateThread();
c_exit_hook();
}
#endif

View file

@ -18,22 +18,38 @@
#include <benchmark_track.h>
#include <benchmark_utilisation.h>
void VISIBLE c_handle_interrupt(int irq, int syscall)
/** DONT_TRANSLATE */
void VISIBLE
c_handle_interrupt(int irq, int syscall)
{
/* for annoying reasons we cannot currently consider this the C entry
* point as we would like to call various functions that are considered
* as entry points from the point of view of the arm code. Therefore
* we are *not* calling c_entry_hook here */
c_entry_hook();
if (irq == int_unimpl_dev) {
handleUnimplementedDevice();
#ifdef TRACK_KERNEL_ENTRIES
ksKernelEntry.path = Entry_UnimplementedDevice;
ksKernelEntry.word = irq;
#endif
} else if (irq == int_page_fault) {
/* Error code is in Error. Pull out bit 5, which is whether it was instruction or data */
handleVMFaultEvent((ksCurThread->tcbArch.tcbContext.registers[Error] >> 4) & 1);
vm_fault_type_t type = (ksCurThread->tcbArch.tcbContext.registers[Error] >> 4u) & 1u;
#ifdef TRACK_KERNEL_ENTRIES
ksKernelEntry.path = Entry_VMFault;
ksKernelEntry.word = type;
#endif
handleVMFaultEvent(type);
} else if (irq < int_irq_min) {
#ifdef TRACK_KERNEL_ENTRIES
ksKernelEntry.path = Entry_UserLevelFault;
ksKernelEntry.word = irq;
#endif
handleUserLevelFault(irq, ksCurThread->tcbArch.tcbContext.registers[Error]);
} else if (likely(irq < int_trap_min)) {
x86KScurInterrupt = irq;
#ifdef TRACK_KERNEL_ENTRIES
ksKernelEntry.path = Entry_Interrupt;
ksKernelEntry.word = irq;
#endif
handleInterruptEntry();
} else if (irq == int_spurious) {
/* fall through to restore_user_context and do nothing */
@ -45,14 +61,16 @@ void VISIBLE c_handle_interrupt(int irq, int syscall)
ksCurThread->tcbArch.tcbContext.registers[FaultIP] -= 2;
/* trap number is MSBs of the syscall number and the LSBS of EAX */
sys_num = (irq << 24) | (syscall & 0x00ffffff);
/* in this case we are calling a function that is *not*
* an entry point */
c_entry_hook();
#ifdef TRACK_KERNEL_ENTIRES
ksKernelEntry.path = Entry_UnknownSyscall;
ksKernelEntry.word = sys_num;
#endif
handleUnknownSyscall(sys_num);
}
restore_user_context();
}
/** DONT_TRANSLATE */
void NORETURN
slowpath(syscall_t syscall)
{
@ -61,21 +79,32 @@ slowpath(syscall_t syscall)
ksCurThread->tcbArch.tcbContext.registers[NextIP] += 2;
/* check for undefined syscall */
if (unlikely(syscall < SYSCALL_MIN || syscall > SYSCALL_MAX)) {
#ifdef TRACK_KERNEL_ENTIRES
ksKernelEntry.path = Entry_UnknownSyscall;
/* ksKernelEntry.word word is already set to syscall */
#endif /* TRACK_KERNEL_ENTRIES */
handleUnknownSyscall(syscall);
} else {
#ifdef TRACK_KERNEL_ENTIRES
ksEntry.is_fastpath = 0;
#endif /* TRACK KERNEL ENTRIES */
handleSyscall(syscall);
}
restore_user_context();
UNREACHABLE();
}
void VISIBLE c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall)
/** DONT_TRANSLATE */
void VISIBLE
c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall)
{
c_entry_hook();
#if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES)
#ifdef TRACK_KERNEL_ENTRIES
benchmark_debug_syscall_start(cptr, msgInfo, syscall);
#endif /* DEBUG */
ksKernelEntry.is_fastpath = 1;
#endif /* TRACK_KERNEL_ENTRIES */
#ifdef CONFIG_FASTPATH
if (syscall == SysCall) {

View file

@ -57,7 +57,6 @@ switchFpuOwner(tcb_t *new_owner)
VISIBLE exception_t
handleUnimplementedDevice(void)
{
c_entry_hook();
/*
* If we have already given the FPU to the user, we should not reach here.
*