From 1b895c8371ef970ea2e556d3e122c1eac871ff70 Mon Sep 17 00:00:00 2001 From: David Karoly Date: Tue, 22 Feb 2022 18:17:03 +0100 Subject: [PATCH] kernel/arm: implement syscall handler Change-Id: I75f2fb7808f55a460835276ca66cce8a26e8403d Reviewed-on: https://review.haiku-os.org/c/haiku/+/4980 Tested-by: Commit checker robot Reviewed-by: X512 Reviewed-by: Fredrik Holmqvist --- src/system/kernel/arch/arm/arch_exceptions.S | 30 ++++++++++++++-- src/system/kernel/arch/arm/arch_int.cpp | 36 +++++++++++++++++++- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/system/kernel/arch/arm/arch_exceptions.S b/src/system/kernel/arch/arm/arch_exceptions.S index 42ff0bb533..a7a792dc3e 100644 --- a/src/system/kernel/arch/arm/arch_exceptions.S +++ b/src/system/kernel/arch/arm/arch_exceptions.S @@ -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) diff --git a/src/system/kernel/arch/arm/arch_int.cpp b/src/system/kernel/arch/arm/arch_int.cpp index 00be3be99a..1fde42b741 100644 --- a/src/system/kernel/arch/arm/arch_int.cpp +++ b/src/system/kernel/arch/arm/arch_int.cpp @@ -21,7 +21,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -30,6 +32,7 @@ #include #include #include +#include #include #include @@ -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(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; }