kernel/arm: implement syscall handler
Change-Id: I75f2fb7808f55a460835276ca66cce8a26e8403d Reviewed-on: https://review.haiku-os.org/c/haiku/+/4980 Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org> Reviewed-by: X512 <danger_mail@list.ru> Reviewed-by: Fredrik Holmqvist <fredrik.holmqvist@gmail.com>
This commit is contained in:
parent
a40b421ac7
commit
1b895c8371
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012, Haiku Inc. All rights reserved.
|
||||
* Copyright 2012-2022, Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@ -52,6 +52,30 @@
|
||||
ldmia sp, {sp, lr, pc}^ /* Restore lr and exit */
|
||||
.endm
|
||||
|
||||
/* The following two macros are adapted from the two macros above, taken from FreeBSD. */
|
||||
|
||||
.macro PUSHFRAMEINSWI
|
||||
str lr, [sp, #-4]! /* Push the return address */
|
||||
sub sp, sp, #(4*17) /* Adjust the stack pointer */
|
||||
stmia sp, {r0-r12} /* Store the general purpose registers */
|
||||
add r0, sp, #(4*13) /* Adjust the stack pointer */
|
||||
stmia r0, {r13-r14}^ /* Store the user mode sp and lr registers */
|
||||
mrs r0, spsr /* Store the SPSR */
|
||||
str r0, [sp, #-4]!
|
||||
mov r0, #0 /* Fill in svc mode sp and lr with zeroes */
|
||||
str r0, [sp, #(4*16)]
|
||||
str r0, [sp, #(4*17)]
|
||||
.endm
|
||||
|
||||
.macro PULLFRAMEINSWIANDEXIT
|
||||
ldr r0, [sp], #4 /* Get SPSR from stack */
|
||||
msr spsr, r0
|
||||
ldmia sp, {r0-r14}^ /* Restore user mode registers */
|
||||
add sp, sp, #(4*17) /* Adjust the stack pointer */
|
||||
ldr lr, [sp], #4 /* Pull the return address */
|
||||
movs pc, lr /* Return to user mode */
|
||||
.endm
|
||||
|
||||
.text
|
||||
|
||||
.globl _vectors_start
|
||||
@ -137,12 +161,12 @@ FUNCTION_END(arm_undefined)
|
||||
|
||||
|
||||
FUNCTION(arm_syscall):
|
||||
PUSHFRAMEINSVC
|
||||
PUSHFRAMEINSWI
|
||||
|
||||
mov r0, sp
|
||||
bl arch_arm_syscall
|
||||
|
||||
PULLFRAMEFROMSVCANDEXIT
|
||||
PULLFRAMEINSWIANDEXIT
|
||||
FUNCTION_END(arm_syscall)
|
||||
|
||||
|
||||
|
@ -21,7 +21,9 @@
|
||||
#include <device_manager.h>
|
||||
#include <kscheduler.h>
|
||||
#include <interrupt_controller.h>
|
||||
#include <ksyscalls.h>
|
||||
#include <smp.h>
|
||||
#include <syscall_numbers.h>
|
||||
#include <thread.h>
|
||||
#include <timer.h>
|
||||
#include <util/AutoLock.h>
|
||||
@ -30,6 +32,7 @@
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_priv.h>
|
||||
#include <vm/VMAddressSpace.h>
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
|
||||
#include <drivers/bus/FDT.h>
|
||||
@ -236,8 +239,39 @@ arch_arm_undefined(struct iframe *iframe)
|
||||
extern "C" void
|
||||
arch_arm_syscall(struct iframe *iframe)
|
||||
{
|
||||
#ifdef TRACE_ARCH_INT
|
||||
print_iframe("Software interrupt", iframe);
|
||||
IFrameScope scope(iframe); // push/pop iframe
|
||||
#endif
|
||||
|
||||
uint32_t syscall = *(uint32_t *)(iframe->pc-4) & 0x00ffffff;
|
||||
TRACE(("syscall number: %d\n", syscall));
|
||||
|
||||
uint32_t args[20];
|
||||
if (syscall < kSyscallCount) {
|
||||
TRACE(("syscall(%s,%d)\n",
|
||||
kExtendedSyscallInfos[syscall].name,
|
||||
kExtendedSyscallInfos[syscall].parameter_count));
|
||||
|
||||
int argSize = kSyscallInfos[syscall].parameter_size;
|
||||
memcpy(args, &iframe->r0, std::min<int>(argSize, 4 * sizeof(uint32)));
|
||||
if (argSize > 4 * sizeof(uint32)) {
|
||||
status_t res = user_memcpy(&args[4], (void *)iframe->usr_sp,
|
||||
(argSize - 4 * sizeof(uint32)));
|
||||
if (res < B_OK) {
|
||||
dprintf("can't read syscall arguments on user stack\n");
|
||||
iframe->r0 = res;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enable_interrupts();
|
||||
|
||||
uint64 returnValue = 0;
|
||||
syscall_dispatcher(syscall, (void*)args, &returnValue);
|
||||
|
||||
TRACE(("returning %" B_PRId64 "\n", returnValue));
|
||||
iframe->r0 = returnValue;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user