Removed some hard-coded values with definitions (mostly USER_x_SEG in arch_x86.S,

and TSS_BASE_SEGMENT in i386_set_tss_and_kstack() (thanks Daniel for pointing this
out)).
Added a arch_thread_init_tls() function which fills the reserved slots - the find_thread()
inline asm in OS.h is finally working.
Added some more comments, resolved the ToDo items from last time :-)
arch_thread_context_switch() now calls set_tls_context() at the correct location.
arch_thread_enter_uspace() now calls set_tls_context() as there is no context
switch in this case for the current thread after TLS has been set up, and it
now gets a pointer to the thread structure directly, and calculates the user
stack top itself, rather than the callee.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2380 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2003-01-07 09:33:30 +00:00
parent 074a16b53e
commit 2a6fbb7f88
3 changed files with 65 additions and 46 deletions

View File

@ -105,19 +105,19 @@ arch_cpu_init2(kernel_args *ka)
void
i386_set_kstack(addr kstack)
i386_set_tss_and_kstack(addr kstack)
{
int curr_cpu = smp_get_current_cpu();
int currentCPU = smp_get_current_cpu();
// dprintf("i386_set_kstack: kstack 0x%x, cpu %d\n", kstack, curr_cpu);
if (tss_loaded[curr_cpu] == 0) {
short seg = (0x28 + 8*curr_cpu);
// dprintf("i386_set_kstack: kstack 0x%x, cpu %d\n", kstack, currentCPU);
if (tss_loaded[currentCPU] == 0) {
short seg = ((TSS_BASE_SEGMENT + currentCPU) << 3) | DPL_KERNEL;
asm("movw %0, %%ax;"
"ltr %%ax;" : : "r" (seg) : "eax");
tss_loaded[curr_cpu] = 1;
tss_loaded[currentCPU] = 1;
}
tss[curr_cpu]->sp0 = kstack;
tss[currentCPU]->sp0 = kstack;
// dprintf("done\n");
}

View File

@ -15,6 +15,7 @@
#include <string.h>
#include <Errors.h>
#include <signal.h>
#include <tls.h>
// from arch_interrupts.S
@ -37,13 +38,23 @@ i386_pop_iframe(struct thread *thread)
}
static void
i386_set_fs_register(uint32 segment)
static inline void
set_fs_register(uint32 segment)
{
asm("movl %0,%%fs" :: "r" (segment));
}
static void
set_tls_context(struct thread *thread)
{
int entry = smp_get_current_cpu() + TLS_BASE_SEGMENT;
set_segment_descriptor_base(&gGDT[entry], thread->user_local_storage);
set_fs_register((entry << 3) | DPL_USER);
}
int
arch_team_init_team_struct(struct team *p, bool kernel)
{
@ -66,7 +77,7 @@ arch_thread_init_thread_struct(struct thread *t)
int
arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void))
arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void))
{
unsigned int *kstack = (unsigned int *)t->kernel_stack_base;
unsigned int kstack_size = KSTACK_SIZE;
@ -109,6 +120,28 @@ arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(void),
}
/** Initializes the user-space TLS local storage pointer in
* the thread structure, and the reserved TLS slots.
*
* Is called from _create_user_thread_kentry().
*/
void
arch_thread_init_tls(struct thread *thread)
{
uint32 *tls;
thread->user_local_storage = thread->user_stack_base + STACK_SIZE;
tls = (uint32 *)thread->user_local_storage;
tls[TLS_BASE_ADDRESS_SLOT] = thread->user_local_storage;
tls[TLS_THREAD_ID_SLOT] = thread->id;
tls[TLS_ERRNO_SLOT] = 0;
set_tls_context(thread);
}
void
arch_thread_switch_kstack_and_call(struct thread *t, addr new_kstack, void (*func)(void *), void *arg)
{
@ -120,6 +153,7 @@ void
arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
{
addr new_pgdir;
#if 0
int i;
@ -133,13 +167,12 @@ arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
for (i = 0; i < 11; i++)
dprintf("*esp[%d] (0x%x) = 0x%x\n", i, ((unsigned int *)new_at->esp + i), *((unsigned int *)new_at->esp + i));
#endif
i386_set_kstack(t_to->kernel_stack_base + KSTACK_SIZE);
i386_set_tss_and_kstack(t_to->kernel_stack_base + KSTACK_SIZE);
#if 0
{
int a = *(int *)(t_to->kernel_stack_base + KSTACK_SIZE - 4);
}
#endif
// set TLS GDT entry to the current thread - since this action is
// dependent on the current CPU, we have to do it here
if (t_to->user_local_storage != NULL)
set_tls_context(t_to);
if (t_from->team->_aspace_id >= 0 && t_to->team->_aspace_id >= 0) {
// they are both uspace threads
@ -159,36 +192,12 @@ arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
} else {
new_pgdir = vm_translation_map_get_pgdir(&t_to->team->aspace->translation_map);
}
#if 0
dprintf("new_pgdir is 0x%x\n", new_pgdir);
#endif
#if 0
{
int a = *(int *)(t_to->arch_info.current_stack.esp - 4);
}
#endif
if ((new_pgdir % PAGE_SIZE) != 0)
panic("arch_thread_context_switch: bad pgdir 0x%lx\n", new_pgdir);
i386_fsave_swap(t_from->arch_info.fpu_state, t_to->arch_info.fpu_state);
i386_context_switch(&t_from->arch_info, &t_to->arch_info, new_pgdir);
// set TLS GDT entry to the current thread - since this action is
// dependent on the current CPU, we have to do it here
{
int entry = smp_get_current_cpu() + TLS_BASE_SEGMENT;
// ToDo: the TLS storage is currently located simply at the bottom of the user stack
// perhaps we want to put it somewhere else, in a safe place?
// very strange: the user_stack_base pointer seg faults, (+ PAGE_SIZE) improves
// the situation, but the main thread still don't work correctly...
// Also have a look at the stack addresses: the main thread is located at
// 0x7ffd600, the ones of the others are at 0x0062b000 and following
set_segment_descriptor_base(&gGDT[entry], t_to->user_stack_base + PAGE_SIZE);
i386_set_fs_register((entry << 3) | DPL_USER);
}
}
@ -203,9 +212,14 @@ arch_thread_dump_info(void *info)
}
/** Sets up initial thread context and enters user space
*/
void
arch_thread_enter_uspace(addr entry, void *args, addr ustack_top)
arch_thread_enter_uspace(struct thread *t, addr entry, void *args)
{
addr ustack_top = t->user_stack_base + STACK_SIZE;
dprintf("arch_thread_enter_uspace: entry 0x%lx, args %p, ustack_top 0x%lx\n",
entry, args, ustack_top);
@ -219,7 +233,10 @@ arch_thread_enter_uspace(addr entry, void *args, addr ustack_top)
disable_interrupts();
i386_set_kstack(thread_get_current_thread()->kernel_stack_base + KSTACK_SIZE);
i386_set_tss_and_kstack(t->kernel_stack_base + KSTACK_SIZE);
// set the CPU dependent GDT entry for TLS
set_tls_context(t);
i386_enter_uspace(entry, args, ustack_top - 4);
}

View File

@ -4,6 +4,8 @@
** Distributed under the terms of the NewOS License.
*/
#include <arch/x86/descriptors.h>
#define FUNCTION(x) .global x; .type x,@function; x
.text
@ -182,10 +184,10 @@ FUNCTION(i386_enter_uspace):
movl 4(%esp),%eax // get entry point
movl 8(%esp),%edx // get arguments
movl 12(%esp),%ebx // get user stack
movw $0x23,%cx
movw $USER_DATA_SEG,%cx
movw %cx,%ds
movw %cx,%es
//movw %cx,%fs // fs points to the TLS storage (CPU dependent segment)
//movw $0x33 + cpu_num,%fs -> fs points to the TLS storage (CPU dependent segment)
movw %cx,%gs
// copy exit stub to stack
@ -203,10 +205,10 @@ _copy_more:
movl %ebx,-8(%ebx) // fake return address to copied exit stub
sub $8,%ebx
pushl $0x23 // user data segment
pushl $USER_DATA_SEG // user data segment
pushl %ebx // user stack
pushl $(1 << 9) | 2 // user flags
pushl $0x1b // user code segment
pushl $USER_CODE_SEG // user code segment
pushl %eax // user IP
iret