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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user