diff --git a/headers/private/kernel/arch/arm/arch_thread_types.h b/headers/private/kernel/arch/arm/arch_thread_types.h index d0749137d0..593606961b 100644 --- a/headers/private/kernel/arch/arm/arch_thread_types.h +++ b/headers/private/kernel/arch/arm/arch_thread_types.h @@ -37,4 +37,15 @@ struct arch_fork_arg { char dummy; }; + +#ifdef __cplusplus +extern "C" { +#endif + +void arch_return_to_userland(struct iframe *); + +#ifdef __cplusplus +} +#endif + #endif /* KERNEL_ARCH_ARM_THREAD_TYPES_H */ diff --git a/headers/private/system/arch/arm/arch_commpage_defs.h b/headers/private/system/arch/arm/arch_commpage_defs.h index 39bf6f641d..e334652349 100644 --- a/headers/private/system/arch/arm/arch_commpage_defs.h +++ b/headers/private/system/arch/arm/arch_commpage_defs.h @@ -1,15 +1,17 @@ /* + * Copyright 2022, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * * Copyright 2007, Travis Geiselbrecht. All rights reserved. * Distributed under the terms of the MIT License. */ -#ifndef _SYSTEM_ARCH_M68K_COMMPAGE_DEFS_H -#define _SYSTEM_ARCH_M68K_COMMPAGE_DEFS_H +#ifndef _SYSTEM_ARCH_ARM_COMMPAGE_DEFS_H +#define _SYSTEM_ARCH_ARM_COMMPAGE_DEFS_H #ifndef _SYSTEM_COMMPAGE_DEFS_H # error Must not be included directly. Include instead! #endif -//#define COMMPAGE_ENTRY_M68K_SYSCALL (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 0) -//#define COMMPAGE_ENTRY_M68K_MEMCPY (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 1) +#define COMMPAGE_ENTRY_ARM_THREAD_EXIT (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 0) -#endif /* _SYSTEM_ARCH_M68K_COMMPAGE_DEFS_H */ +#endif /* _SYSTEM_ARCH_ARM_COMMPAGE_DEFS_H */ diff --git a/headers/private/system/arch/arm/arch_cpu_defs.h b/headers/private/system/arch/arm/arch_cpu_defs.h index bc07e0b32f..e34eeeec73 100644 --- a/headers/private/system/arch/arm/arch_cpu_defs.h +++ b/headers/private/system/arch/arm/arch_cpu_defs.h @@ -13,6 +13,12 @@ #define CPSR_MODE_MASK 0x1f #define CPSR_MODE_USR 0x10 +#define CPSR_MODE_SVC 0x13 +#define CPSR_MODE_SYS 0x1f + +#define CPSR_T 0x20 +#define CPSR_F 0x40 +#define CPSR_I 0x80 #define FSR_WNR 0x800 diff --git a/src/system/kernel/arch/arm/arch_asm.S b/src/system/kernel/arch/arm/arch_asm.S index ac82e80602..d253ad8dbf 100644 --- a/src/system/kernel/arch/arm/arch_asm.S +++ b/src/system/kernel/arch/arm/arch_asm.S @@ -1,4 +1,7 @@ /* + * Copyright 2022, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * * Copyright 2009, Wischert, johanneswi@gmail.com. * All rights reserved. Distributed under the terms of the MIT License. * @@ -7,10 +10,12 @@ */ #include +#include #include #include "asm_offsets.h" +#include "syscall_numbers.h" .text @@ -253,3 +258,42 @@ FUNCTION(arch_debug_call_with_fault_handler): mov r1, #1 b longjmp FUNCTION_END(arch_debug_call_with_fault_handler) + + +FUNCTION(arch_return_to_userland): + // set SPSR to user mode, IRQ enabled, FIQ disabled + mrs ip, cpsr + bic ip, ip, #(CPSR_MODE_MASK | CPSR_T | CPSR_F | CPSR_I) + orr ip, ip, #(CPSR_MODE_USR | CPSR_F) + msr spsr, ip + + // use system mode to load user mode SP and LR + ldr r4, [r0, #IFRAME_usr_sp] + ldr r5, [r0, #IFRAME_usr_lr] + mrs ip, cpsr + bic ip, ip, #(CPSR_MODE_MASK) + orr ip, ip, #(CPSR_MODE_SYS) + msr cpsr, ip + mov sp, r4 + mov lr, r5 + bic ip, ip, #(CPSR_MODE_MASK) + orr ip, ip, #(CPSR_MODE_SVC) + msr cpsr, ip + + // load user mode entry point in LR + ldr lr, [r0, #IFRAME_pc] + + // load general purpose registers + mov sp, r0 + add sp, sp, #4 + ldmfd sp!, { r0-r12 } + + // jump to user mode entry point + movs pc, lr +FUNCTION_END(arch_return_to_userland) + + +FUNCTION(arch_user_thread_exit): + svc SYSCALL_EXIT_THREAD + bx lr +FUNCTION_END(arch_user_thread_exit) diff --git a/src/system/kernel/arch/arm/arch_commpage.cpp b/src/system/kernel/arch/arm/arch_commpage.cpp index 412edd235f..8480aaacdd 100644 --- a/src/system/kernel/arch/arm/arch_commpage.cpp +++ b/src/system/kernel/arch/arm/arch_commpage.cpp @@ -1,4 +1,7 @@ /* + * Copyright 2022, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * * Copyright 2009, Johannes Wischert, johanneswi@gmail.com. * Distributed under the terms of the MIT License. */ @@ -15,14 +18,36 @@ #include +extern "C" void arch_user_thread_exit(); + + +static void +register_commpage_function(const char* functionName, int32 commpageIndex, + const char* commpageSymbolName, addr_t expectedAddress) +{ + // get address and size of function + elf_symbol_info symbolInfo; + if (elf_lookup_kernel_symbol(functionName, &symbolInfo) != B_OK) { + panic("register_commpage_function(): Failed to find " + "function \"%s\"!", functionName); + } + + ASSERT(expectedAddress == symbolInfo.address); + + // fill in the commpage table entry + addr_t position = fill_commpage_entry(commpageIndex, + (void*)symbolInfo.address, symbolInfo.size); + + // add symbol to the commpage image + image_id image = get_commpage_image(); + elf_add_memory_image_symbol(image, commpageSymbolName, position, + symbolInfo.size, B_SYMBOL_TYPE_TEXT); +} + + status_t arch_commpage_init(void) { - /* no optimized memcpy or anything yet */ - /* we don't use it for syscall yet either */ - // add syscall to the commpage image -// image_id image = get_commpage_image(); -#warning ARM:IMPLEMENTME return B_OK; } @@ -30,7 +55,10 @@ arch_commpage_init(void) status_t arch_commpage_init_post_cpus(void) { -#warning ARM:IMPLEMENTME + register_commpage_function("arch_user_thread_exit", + COMMPAGE_ENTRY_ARM_THREAD_EXIT, "commpage_thread_exit", + (addr_t)&arch_user_thread_exit); + return B_OK; } diff --git a/src/system/kernel/arch/arm/arch_thread.cpp b/src/system/kernel/arch/arm/arch_thread.cpp index 4670fc1434..2a9bece808 100644 --- a/src/system/kernel/arch/arm/arch_thread.cpp +++ b/src/system/kernel/arch/arm/arch_thread.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -198,9 +199,37 @@ arch_thread_dump_info(void *info) status_t arch_thread_enter_userspace(Thread *thread, addr_t entry, - void *arg1, void *arg2) + void *args1, void *args2) { - panic("arch_thread_enter_uspace(): not yet implemented\n"); + arm_set_tls_context(thread); + + addr_t stackTop = thread->user_stack_base + thread->user_stack_size; + + TRACE(("arch_thread_enter_userspace: entry 0x%" B_PRIxADDR ", args %p %p, " + "ustack_top 0x%" B_PRIxADDR "\n", entry, args1, args2, stackTop)); + + //stackTop = arch_randomize_stack_pointer(stackTop - sizeof(args)); + + // Copy the address of the stub that calls exit_thread() when the thread + // entry function returns to LR to act as the return address. + // The stub is inside commpage. + addr_t commPageAddress = (addr_t)thread->team->commpage_address; + + disable_interrupts(); + + // prepare the user iframe + iframe frame = {}; + frame.r0 = (uint32)args1; + frame.r1 = (uint32)args2; + frame.usr_sp = stackTop; + frame.usr_lr = ((addr_t*)commPageAddress)[COMMPAGE_ENTRY_ARM_THREAD_EXIT] + + commPageAddress; + frame.pc = entry; + + // return to userland + arch_return_to_userland(&frame); + + // normally we don't get here return B_ERROR; } diff --git a/src/system/kernel/arch/arm/asm_offsets.cpp b/src/system/kernel/arch/arm/asm_offsets.cpp index 64e85057d7..f2cd43c9c0 100644 --- a/src/system/kernel/arch/arm/asm_offsets.cpp +++ b/src/system/kernel/arch/arm/asm_offsets.cpp @@ -46,6 +46,9 @@ dummy() // struct iframe DEFINE_SIZEOF_MACRO(IFRAME, iframe); + DEFINE_OFFSET_MACRO(IFRAME, iframe, pc); + DEFINE_OFFSET_MACRO(IFRAME, iframe, usr_sp); + DEFINE_OFFSET_MACRO(IFRAME, iframe, usr_lr); // struct signal_frame_data DEFINE_SIZEOF_MACRO(SIGNAL_FRAME_DATA, signal_frame_data);