Temporarily removed arch_selector.c from the build - it's currently not used

at all, and assumes a fixed and wrong number of preallocated GDT entries.

Implemented TLS: there is one GDT entry per CPU. If a context switch happens,
the FS register of the new thread is set to the matching GDT, and the GDT is
changed so that it points to the current thread's TLS storage area.
This area currently resides unsafely at the bottom of the user stack - for
some reason I could not figure out, it doesn't even work correctly most of
the time (it segfaults when accessing a slot via FS). I've added a ToDo item
explaining the situation - hopefully I have more ideas when I slept a bit more...

The GDT is now no longer static in arch_cpu.c and has been renamed from gdt to
gGDT. It's now also referenced in arch_thread.c, and it would make sense for
arch_selector.c to use it as well (instead of another local copy).
arch_cpu_init2() now uses the set_tss_descriptor() inline function and the
TSS_BASE_SEGMENT macro to set up the TSS section. It now also sets up the
TLS segment descriptors (as TSS, one entry per CPU).

Since I removed desc_table from the headers (the GDT is now a (segment_descriptor *)),
I added it locally to arch_int.c.
i386_enter_uspace() now don't set the FS register to 0x23 anymore, since it's
now already set correctly at the end of arch_thread_context_switch().

Some clean-ups.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2366 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2003-01-06 08:25:01 +00:00
parent 722bf47f67
commit 19321ae5a8
7 changed files with 113 additions and 84 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ KernelStaticLibrary libx86 :
<$(SOURCE_GRIST)>arch_elf.c
<$(SOURCE_GRIST)>arch_faults.c
<$(SOURCE_GRIST)>arch_int.c
<$(SOURCE_GRIST)>arch_selector.c
# <$(SOURCE_GRIST)>arch_selector.c
<$(SOURCE_GRIST)>arch_smp.c
<$(SOURCE_GRIST)>arch_thread.c
<$(SOURCE_GRIST)>arch_timer.c
+22 -20
View File
@@ -11,6 +11,7 @@
#include <smp.h>
#include <arch/x86/selector.h>
#include <Errors.h>
#include <TLS.h>
#include <kerrors.h>
#include <stage2.h>
@@ -21,7 +22,7 @@
static struct tss **tss;
static int *tss_loaded;
static unsigned int *gdt = 0;
segment_descriptor *gGDT = NULL;
int
@@ -44,16 +45,19 @@ arch_cpu_init(kernel_args *ka)
int
arch_cpu_init2(kernel_args *ka)
{
region_id rid;
struct tss_descriptor *tss_d;
unsigned int i;
// account for the segment descriptors
gdt = (unsigned int *)ka->arch_args.vir_gdt;
vm_create_anonymous_region(vm_get_kernel_aspace_id(), "gdt", (void **)&gdt,
gGDT = (segment_descriptor *)ka->arch_args.vir_gdt;
vm_create_anonymous_region(vm_get_kernel_aspace_id(), "gdt", (void **)&gGDT,
REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL);
i386_selector_init(gdt); // pass the new gdt
// currently taken out of the build, because it's not yet used (and assumes
// (a fixed number of used GDT entries)
//i386_selector_init(gGDT); // pass the new gdt
// setup task-state segments
tss = malloc(sizeof(struct tss *) * ka->num_cpus);
if (tss == NULL) {
@@ -69,7 +73,9 @@ arch_cpu_init2(kernel_args *ka)
memset(tss_loaded, 0, sizeof(int) * ka->num_cpus);
for (i = 0; i < ka->num_cpus; i++) {
struct segment_descriptor *tss_d;
char tss_name[16];
region_id rid;
sprintf(tss_name, "tss%d", i);
rid = vm_create_anonymous_region(vm_get_kernel_aspace_id(), tss_name, (void **)&tss[i],
@@ -79,25 +85,21 @@ arch_cpu_init2(kernel_args *ka)
return ENOMEM;
}
// initialize TSS
memset(tss[i], 0, sizeof(struct tss));
tss[i]->ss0 = KERNEL_DATA_SEG;
// add TSS descriptor for this new TSS
tss_d = (struct tss_descriptor *)&gdt[10 + i*2];
tss_d->limit_00_15 = sizeof(struct tss) & 0xffff;
tss_d->limit_19_16 = 0; // not this long
tss_d->base_00_15 = (addr)tss[i] & 0xffff;
tss_d->base_23_16 = ((addr)tss[i] >> 16) & 0xff;
tss_d->base_31_24 = (addr)tss[i] >> 24;
tss_d->type = 0x9;
tss_d->zero = 0;
tss_d->dpl = 0;
tss_d->present = 1;
tss_d->avail = 0;
tss_d->zero1 = 0;
tss_d->zero2 = 1;
tss_d->granularity = 1;
set_tss_descriptor(&gGDT[TSS_BASE_SEGMENT + i], (addr)tss[i], sizeof(struct tss));
}
// setup TLS descriptors (one for every CPU)
for (i = 0; i < ka->num_cpus; i++) {
set_segment_descriptor(&gGDT[TLS_BASE_SEGMENT + i], 0, TLS_MAX_KEYS * sizeof(void *),
DT_DATA_WRITEABLE, DPL_USER);
}
return 0;
}
+40 -33
View File
@@ -24,6 +24,7 @@
#include <arch/x86/interrupts.h>
#include <arch/x86/faults.h>
#include <arch/x86/descriptors.h>
#include <stage2.h>
@@ -31,15 +32,18 @@
#define MAX_ARGS 16
typedef struct {
uint32 a, b;
} desc_table;
static desc_table *idt = NULL;
static void
interrupt_ack(int n)
{
if(n >= 0x20 && n < 0x30) {
if (n >= 0x20 && n < 0x30) {
// 8239 controlled interrupt
if(n > 0x27)
if (n > 0x27)
out8(0x20, 0xa0); // EOI to pic 2
out8(0x20, 0x20); // EOI to pic 1
}
@@ -47,7 +51,7 @@ interrupt_ack(int n)
static void
_set_gate(desc_table *gate_addr, unsigned int addr, int type, int dpl)
set_gate(desc_table *gate_addr, unsigned int addr, int type, int dpl)
{
unsigned int gate1; // first byte of gate desc
unsigned int gate2; // second byte of gate desc
@@ -60,6 +64,29 @@ _set_gate(desc_table *gate_addr, unsigned int addr, int type, int dpl)
}
static void
set_intr_gate(int n, void *addr)
{
set_gate(&idt[n], (unsigned int)addr, 14, DPL_KERNEL);
}
/* XXX - currently unused and static...
static void
set_trap_gate(int n, void *addr)
{
set_gate(&idt[n], (unsigned int)addr, 15, DPL_KERNEL);
}
*/
static void
set_system_gate(int n, void *addr)
{
set_gate(&idt[n], (unsigned int)addr, 15, DPL_USER);
}
void
arch_int_enable_io_interrupt(int irq)
{
@@ -89,29 +116,6 @@ arch_int_disable_io_interrupt(int irq)
}
static void
set_intr_gate(int n, void *addr)
{
_set_gate(&idt[n], (unsigned int)addr, 14, 0);
}
/* XXX - currently unused and static...
static void
set_trap_gate(int n, void *addr)
{
_set_gate(&idt[n], (unsigned int)addr, 15, 0);
}
*/
static void
set_system_gate(int n, void *addr)
{
_set_gate(&idt[n], (unsigned int)addr, 15, 3);
}
void
arch_int_enable_interrupts(void)
{
@@ -136,8 +140,7 @@ arch_int_restore_interrupts(int oldstate)
{
int flags = oldstate ? 0x200 : 0;
asm (
"pushfl;\n"
asm("pushfl;\n"
"popl %1;\n"
"andl $0xfffffdff,%1;\n"
"orl %0,%1;\n"
@@ -174,14 +177,16 @@ i386_handle_trap(struct iframe frame)
// if(frame.vector != 0x20)
// dprintf("i386_handle_trap: vector 0x%x, ip 0x%x, cpu %d\n", frame.vector, frame.eip, smp_get_current_cpu());
switch(frame.vector) {
case 8:
switch (frame.vector) {
case 8: // double fault
ret = i386_double_fault(frame.error_code);
break;
case 13:
case 13: // general protection fault
ret = i386_general_protection_fault(frame.error_code);
break;
case 14: {
case 14: // page fault
{
unsigned int cr2;
addr newip;
@@ -207,7 +212,8 @@ i386_handle_trap(struct iframe frame)
}
break;
}
case 99: {
case 99: // syscall
{
uint64 retcode;
unsigned int args[MAX_ARGS];
int rc;
@@ -279,6 +285,7 @@ i386_handle_trap(struct iframe frame)
int
arch_int_init(kernel_args *ka)
{
// set the global idt variable
idt = (desc_table *)ka->arch_args.vir_idt;
// setup the interrupt controller
+2 -2
View File
@@ -145,8 +145,8 @@ FUNCTION(i386_stack_switch):
pushl %ss
cmpl $KERNEL_DATA_SEG,(%esp)
je kernel_stack2
popl %eax
jmp switch
popl %eax
jmp switch
kernel_stack2:
popl 4(%eax)
movl %esp,(%eax)
+12 -13
View File
@@ -23,13 +23,13 @@
#include <string.h>
#include <stdio.h>
static int num_cpus = 1;
static unsigned int *apic = NULL;
static unsigned int cpu_apic_id[SMP_MAX_CPUS] = { 0, 0};
static unsigned int cpu_os_id[SMP_MAX_CPUS] = { 0, 0};
static unsigned int cpu_apic_version[SMP_MAX_CPUS] = { 0, 0};
static unsigned int *ioapic = NULL;
static unsigned int apic_timer_tics_per_sec = 0;
static uint32 *apic = NULL;
static uint32 cpu_apic_id[SMP_MAX_CPUS] = { 0, 0};
static uint32 cpu_os_id[SMP_MAX_CPUS] = { 0, 0};
static uint32 cpu_apic_version[SMP_MAX_CPUS] = { 0, 0};
static uint32 *ioapic = NULL;
static uint32 apic_timer_tics_per_sec = 0;
static int32
@@ -58,6 +58,7 @@ i386_spurious_interrupt(void *data)
// spurious interrupt
// dprintf("spurious interrupt on cpu %d\n", arch_smp_get_current_cpu());
arch_smp_ack_interrupt();
return B_HANDLED_INTERRUPT;
}
@@ -68,6 +69,7 @@ i386_smp_error_interrupt(void *data)
// smp error interrupt
// dprintf("smp error interrupt on cpu %d\n", arch_smp_get_current_cpu());
arch_smp_ack_interrupt();
return B_HANDLED_INTERRUPT;
}
@@ -91,11 +93,10 @@ arch_smp_init(kernel_args *ka)
{
dprintf("arch_smp_init: entry\n");
if(ka->num_cpus > 1) {
if (ka->num_cpus > 1) {
// setup some globals
num_cpus = ka->num_cpus;
apic = ka->arch_args.apic;
ioapic = ka->arch_args.ioapic;
apic = (uint32 *)ka->arch_args.apic;
ioapic = (uint32 *)ka->arch_args.ioapic;
memcpy(cpu_apic_id, ka->arch_args.cpu_apic_id, sizeof(ka->arch_args.cpu_apic_id));
memcpy(cpu_os_id, ka->arch_args.cpu_os_id, sizeof(ka->arch_args.cpu_os_id));
memcpy(cpu_apic_version, ka->arch_args.cpu_apic_version, sizeof(ka->arch_args.cpu_apic_version));
@@ -111,8 +112,6 @@ arch_smp_init(kernel_args *ka)
install_interrupt_handler(0xfd, &i386_ici_interrupt, NULL);
install_interrupt_handler(0xfe, &i386_smp_error_interrupt, NULL);
install_interrupt_handler(0xff, &i386_spurious_interrupt, NULL);
} else {
num_cpus = 1;
}
return 0;
}
+32 -10
View File
@@ -18,7 +18,7 @@
// from arch_interrupts.S
extern void i386_stack_init( struct farcall *interrupt_stack_offset );
extern void i386_stack_init(struct farcall *interrupt_stack_offset);
void
@@ -37,6 +37,13 @@ i386_pop_iframe(struct thread *thread)
}
static void
i386_set_fs_register(uint32 segment)
{
asm("movl %0,%%fs" :: "r" (segment));
}
int
arch_team_init_team_struct(struct team *p, bool kernel)
{
@@ -52,7 +59,7 @@ arch_thread_init_thread_struct(struct thread *t)
// let the asm function know the offset to the interrupt stack within struct thread
// I know no better ( = static) way to tell the asm function the offset
i386_stack_init( &((struct thread*)0)->arch_info.interrupt_stack );
i386_stack_init(&((struct thread *)0)->arch_info.interrupt_stack);
return 0;
}
@@ -89,7 +96,7 @@ arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(void),
// *kstack_top = 0x00; // interrupts still disabled after the switch
// simulate initial popad
for(i=0; i<8; i++) {
for (i = 0; i < 8; i++) {
kstack_top--;
*kstack_top = 0;
}
@@ -123,7 +130,7 @@ arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
t_to->arch_info.current_stack.ss, t_to->arch_info.current_stack.esp);
#endif
#if 0
for(i=0; i<11; i++)
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);
@@ -134,19 +141,19 @@ arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
}
#endif
if(t_from->team->_aspace_id >= 0 && t_to->team->_aspace_id >= 0) {
if (t_from->team->_aspace_id >= 0 && t_to->team->_aspace_id >= 0) {
// they are both uspace threads
if(t_from->team->_aspace_id == t_to->team->_aspace_id) {
if (t_from->team->_aspace_id == t_to->team->_aspace_id) {
// dont change the pgdir, same address space
new_pgdir = NULL;
} else {
// switching to a new address space
new_pgdir = vm_translation_map_get_pgdir(&t_to->team->aspace->translation_map);
}
} else if(t_from->team->_aspace_id < 0 && t_to->team->_aspace_id < 0) {
} else if (t_from->team->_aspace_id < 0 && t_to->team->_aspace_id < 0) {
// they must both be kspace threads
new_pgdir = NULL;
} else if(t_to->team->_aspace_id < 0) {
} else if (t_to->team->_aspace_id < 0) {
// the one we're switching to is kspace
new_pgdir = vm_translation_map_get_pgdir(&t_to->team->kaspace->translation_map);
} else {
@@ -162,11 +169,26 @@ arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
}
#endif
if((new_pgdir % PAGE_SIZE) != 0)
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);
}
}
@@ -184,7 +206,7 @@ arch_thread_dump_info(void *info)
void
arch_thread_enter_uspace(addr entry, void *args, addr ustack_top)
{
dprintf("arch_thread_entry_uspace: entry 0x%lx, args %p, ustack_top 0x%lx\n",
dprintf("arch_thread_enter_uspace: entry 0x%lx, args %p, ustack_top 0x%lx\n",
entry, args, ustack_top);
// make sure the fpu is in a good state
+4 -5
View File
@@ -144,7 +144,7 @@ FUNCTION(i386_fxsave_swap):
/* void i386_context_switch(struct arch_thread *old_state, struct arch_thread *new_state, addr new_pgdir); */
FUNCTION(i386_context_switch):
pusha /* pushes 8 words onto the stack */
movl 36(%esp),%eax /* save current_stack */
movl 36(%esp),%eax /* save old_state->current_stack */
movl %esp,(%eax)
pushl %ss
popl %edx
@@ -152,9 +152,9 @@ FUNCTION(i386_context_switch):
movl 44(%esp),%eax /* get possible new pgdir */
orl %eax,%eax /* is it null? */
je skip_pgdir_swap
movl %eax,%cr3
movl %eax,%cr3
skip_pgdir_swap:
movl 40(%esp),%eax /* get new current_stack */
movl 40(%esp),%eax /* get new new_state->current_stack */
lss (%eax),%esp
popa
ret
@@ -185,7 +185,7 @@ FUNCTION(i386_enter_uspace):
movw $0x23,%cx
movw %cx,%ds
movw %cx,%es
movw %cx,%fs
//movw %cx,%fs // fs points to the TLS storage (CPU dependent segment)
movw %cx,%gs
// copy exit stub to stack
@@ -198,7 +198,6 @@ _copy_more:
cmp $i386_uspace_exit_stub, %esi
jg _copy_more
// push the args onto the user stack
movl %edx,-4(%ebx) // args
movl %ebx,-8(%ebx) // fake return address to copied exit stub