kernel/arm: implement entering userspace

Change-Id: Icf3945db979a8f4444856fc7157649f48b297c29
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5037
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Reviewed-by: Fredrik Holmqvist <fredrik.holmqvist@gmail.com>
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
David Karoly 2022-02-28 13:35:08 +01:00 committed by waddlesplash
parent 6acf0b3e21
commit 6804f6c764
7 changed files with 136 additions and 13 deletions

View File

@ -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 */

View File

@ -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 <commpage_defs.h> 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 */

View File

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

View File

@ -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 <arch/arm/arch_cpu.h>
#include <arch/arm/arch_cpu_defs.h>
#include <asm_defs.h>
#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)

View File

@ -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 <smp.h>
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;
}

View File

@ -18,6 +18,7 @@
#include <arch_cpu.h>
#include <arch/thread.h>
#include <boot/stage2.h>
#include <commpage.h>
#include <kernel.h>
#include <thread.h>
#include <tls.h>
@ -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;
}

View File

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