diff --git a/headers/private/kernel/arch/thread.h b/headers/private/kernel/arch/thread.h index 225f001c9b..8f11286d11 100644 --- a/headers/private/kernel/arch/thread.h +++ b/headers/private/kernel/arch/thread.h @@ -23,7 +23,7 @@ status_t arch_thread_init_tls(struct thread *thread); void arch_thread_context_switch(struct thread *t_from, struct thread *t_to); status_t arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void)); void arch_thread_dump_info(void *info); -void arch_thread_enter_uspace(struct thread *t, addr_t entry, void *args1, void *args2); +status_t arch_thread_enter_userspace(struct thread *t, addr_t entry, void *args1, void *args2); void arch_thread_switch_kstack_and_call(struct thread *t, addr_t new_kstack, void (*func)(void *), void *arg); // ToDo: doing this this way is an ugly hack - please fix me! diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index 46fd99b4fe..ff70e45ab7 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -100,7 +100,9 @@ struct arch_thread; void __x86_setup_system_time(uint32 cv_factor); void i386_context_switch(struct arch_thread *old_state, struct arch_thread *new_state, addr_t new_pgdir); -void i386_enter_uspace(addr_t entry, void *args1, void *args2, addr_t ustack_top); +void x86_userspace_thread_exit(void); +void x86_end_userspace_thread_exit(void); +void x86_enter_userspace(addr_t entry, void *args1, void *args2, addr_t ustack_top); void i386_set_tss_and_kstack(addr_t kstack); void i386_switch_stack_and_call(addr_t stack, void (*func)(void *), void *arg); void i386_swap_pgdir(addr_t new_pgdir); diff --git a/src/system/kernel/arch/ppc/arch_thread.c b/src/system/kernel/arch/ppc/arch_thread.c index 903b1c37bf..a416a65315 100644 --- a/src/system/kernel/arch/ppc/arch_thread.c +++ b/src/system/kernel/arch/ppc/arch_thread.c @@ -206,10 +206,11 @@ arch_thread_dump_info(void *info) } -void -arch_thread_enter_uspace(struct thread *thread, addr_t entry, void *arg1, void *arg2) +status_t +arch_thread_enter_userspace(struct thread *thread, addr_t entry, void *arg1, void *arg2) { panic("arch_thread_enter_uspace(): not yet implemented\n"); + return B_ERROR; } diff --git a/src/system/kernel/arch/x86/arch_thread.c b/src/system/kernel/arch/x86/arch_thread.c index 2f115c118f..e7cead4791 100644 --- a/src/system/kernel/arch/x86/arch_thread.c +++ b/src/system/kernel/arch/x86/arch_thread.c @@ -306,18 +306,22 @@ arch_thread_dump_info(void *info) /** Sets up initial thread context and enters user space */ -void -arch_thread_enter_uspace(struct thread *t, addr_t entry, void *args1, void *args2) +status_t +arch_thread_enter_userspace(struct thread *t, addr_t entry, void *args1, void *args2) { - addr_t ustack_top = t->user_stack_base + t->user_stack_size; + addr_t stackTop = t->user_stack_base + t->user_stack_size; + uint32 codeSize = (addr_t)x86_end_userspace_thread_exit + - (addr_t)x86_userspace_thread_exit; TRACE(("arch_thread_enter_uspace: entry 0x%lx, args %p %p, ustack_top 0x%lx\n", - entry, args1, args2, ustack_top)); + entry, args1, args2, stackTop)); - // access the new stack to make sure the memory page is present - // while interrupts are disabled. - // XXX does this belong there, should caller take care of it? - *(uint32 *)(ustack_top - 8) = 0; + // copy the little stub that calls exit_thread() when the thread entry + // function returns + stackTop -= codeSize; + + if (user_memcpy((void *)stackTop, x86_userspace_thread_exit, codeSize) < B_OK) + return B_BAD_ADDRESS; disable_interrupts(); @@ -326,7 +330,10 @@ arch_thread_enter_uspace(struct thread *t, addr_t entry, void *args1, void *args // set the CPU dependent GDT entry for TLS set_tls_context(t); - i386_enter_uspace(entry, args1, args2, ustack_top - 4); + x86_enter_userspace(entry, args1, args2, stackTop); + + return B_OK; + // never gets here } diff --git a/src/system/kernel/arch/x86/arch_x86.S b/src/system/kernel/arch/x86/arch_x86.S index 695631f970..ef7741a1dd 100644 --- a/src/system/kernel/arch/x86/arch_x86.S +++ b/src/system/kernel/arch/x86/arch_x86.S @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * * Copyright 2001, Travis Geiselbrecht. All rights reserved. @@ -126,20 +126,20 @@ FUNCTION(i386_swap_pgdir): movl %eax,%cr3 ret -/* thread exit stub */ +/* thread exit stub - is copied to the userspace stack in arch_thread_enter_uspace() */ .align 4 -i386_uspace_exit_stub: +FUNCTION(x86_userspace_thread_exit): pushl %eax movl $1, %ecx - lea (%esp), %edx + lea (%esp), %edx movl $SYSCALL_EXIT_THREAD, %eax; - int $99 + int $99 .align 4 -i386_uspace_exit_stub_end: +FUNCTION(x86_end_userspace_thread_exit): -/* void i386_enter_uspace(addr entry, void *args1, void *args2, addr ustack_top); */ -FUNCTION(i386_enter_uspace): +/* void x86_enter_userspace(addr entry, void *args1, void *args2, addr stackTop); */ +FUNCTION(x86_enter_userspace): movl 4(%esp),%eax // get entry point movl 8(%esp),%edx // get arguments movl 12(%esp),%edi @@ -150,16 +150,6 @@ FUNCTION(i386_enter_uspace): //movw $0x33 + cpu_num,%fs -> fs points to the TLS storage (CPU dependent segment) movw %cx,%gs - // copy exit stub to stack - movl $i386_uspace_exit_stub_end, %esi -_copy_more: - lea -4(%esi), %esi - lea -4(%ebx), %ebx - mov (%esi), %ecx - mov %ecx, (%ebx) - cmp $i386_uspace_exit_stub, %esi - jg _copy_more - // push the args onto the user stack movl %edi,-4(%ebx) // args1 movl %edx,-8(%ebx) // args2 diff --git a/src/system/kernel/team.c b/src/system/kernel/team.c index 5ac18a2fc3..e250329fe1 100644 --- a/src/system/kernel/team.c +++ b/src/system/kernel/team.c @@ -819,10 +819,8 @@ team_create_thread_start(void *args) team->state = TEAM_STATE_NORMAL; // jump to the entry point in user space - arch_thread_enter_uspace(t, entry, uspa, NULL); - - // never gets here - return B_OK; + return arch_thread_enter_userspace(t, entry, uspa, NULL); + // only returns in case of error } diff --git a/src/system/kernel/thread.c b/src/system/kernel/thread.c index 1d7ff170ed..df948c6524 100644 --- a/src/system/kernel/thread.c +++ b/src/system/kernel/thread.c @@ -309,9 +309,10 @@ _create_user_thread_kentry(void) thread_at_kernel_exit(); // jump to the entry point in user space - arch_thread_enter_uspace(thread, (addr_t)thread->entry, thread->args1, thread->args2); + arch_thread_enter_userspace(thread, (addr_t)thread->entry, + thread->args1, thread->args2); - // never get here + // only get here if the above call fails return 0; } @@ -462,14 +463,12 @@ create_thread(const char *name, team_id teamID, thread_entry_func entry, (void **)&thread->user_stack_base, B_BASE_ADDRESS, thread->user_stack_size + TLS_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA | B_STACK_AREA); - if (thread->user_stack_area < 0) { - // great, we have a fully running thread without a stack - dprintf("create_thread: unable to create user stack!\n"); + if (thread->user_stack_area < B_OK + || arch_thread_init_tls(thread) < B_OK) { + // great, we have a fully running thread without a (usable) stack + dprintf("create_thread: unable to create proper user stack!\n"); status = thread->user_stack_area; kill_thread(thread->id); - } else { - // now that the TLS area is allocated, initialize TLS - arch_thread_init_tls(thread); } // copy the user entry over to the args field in the thread struct @@ -603,8 +602,8 @@ dump_thread_info(int argc, char **argv) } if (argc == 1) { - name = NULL; - id = thread_get_current_thread()->id; + _dump_thread_info(thread_get_current_thread()); + return 0; } else { name = argv[1]; id = strtoul(argv[1], NULL, 0);