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:
David Karoly 2022-02-22 18:17:03 +01:00 committed by Fredrik Holmqvist
parent a40b421ac7
commit 1b895c8371
2 changed files with 62 additions and 4 deletions

View File

@ -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)

View File

@ -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;
}