Ported my NewOS changes to OpenBeOS.
A couple of changes in various interrupt and thread functions and structures. These make it now possible to change the stack at any time without making the kernel crash. This is needed for calling VESA 3.0 VBE functions through the protected mode interface. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@422 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,16 +1,17 @@
|
||||
SubDir OBOS_TOP src kernel core arch x86 ;
|
||||
|
||||
KernelStaticLibrary libx86 :
|
||||
<$(SOURCE_GRIST)>arch_cpu.c
|
||||
<$(SOURCE_GRIST)>arch_dbg_console.c
|
||||
<$(SOURCE_GRIST)>arch_debug.c
|
||||
<$(SOURCE_GRIST)>arch_faults.c
|
||||
<$(SOURCE_GRIST)>arch_int.c
|
||||
<$(SOURCE_GRIST)>arch_smp.c
|
||||
<$(SOURCE_GRIST)>arch_thread.c
|
||||
<$(SOURCE_GRIST)>arch_timer.c
|
||||
<$(SOURCE_GRIST)>arch_vm.c
|
||||
<$(SOURCE_GRIST)>arch_vm_translation_map.c
|
||||
KernelStaticLibrary libx86 :
|
||||
<$(SOURCE_GRIST)>arch_cpu.c
|
||||
<$(SOURCE_GRIST)>arch_dbg_console.c
|
||||
<$(SOURCE_GRIST)>arch_debug.c
|
||||
<$(SOURCE_GRIST)>arch_faults.c
|
||||
<$(SOURCE_GRIST)>arch_int.c
|
||||
<$(SOURCE_GRIST)>arch_selector.c
|
||||
<$(SOURCE_GRIST)>arch_smp.c
|
||||
<$(SOURCE_GRIST)>arch_thread.c
|
||||
<$(SOURCE_GRIST)>arch_timer.c
|
||||
<$(SOURCE_GRIST)>arch_vm.c
|
||||
<$(SOURCE_GRIST)>arch_vm_translation_map.c
|
||||
<$(SOURCE_GRIST)>arch_x86.S
|
||||
<$(SOURCE_GRIST)>arch_interrupts.S
|
||||
:
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <vm.h>
|
||||
#include <debug.h>
|
||||
#include <smp.h>
|
||||
#include <arch/x86/selector.h>
|
||||
#include <Errors.h>
|
||||
#include <kerrors.h>
|
||||
|
||||
@@ -52,6 +53,8 @@ arch_cpu_init2(kernel_args *ka)
|
||||
vm_create_anonymous_region(vm_get_kernel_aspace_id(), "gdt", (void **)&gdt,
|
||||
REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL);
|
||||
|
||||
i386_selector_init( gdt ); // pass the new gdt
|
||||
|
||||
tss = kmalloc(sizeof(struct tss *) * ka->num_cpus);
|
||||
if (tss == NULL) {
|
||||
panic("arch_cpu_init2: could not allocate buffer for tss pointers\n");
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
/*
|
||||
/*
|
||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
** Copyright 2002, Michael Noisternig. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
#include <arch/x86/descriptors.h>
|
||||
|
||||
#define FUNCTION(x) .global x; .type x,@function; x
|
||||
|
||||
.text
|
||||
|
||||
#define TRAP_ERRC(name, vector) \
|
||||
@@ -10,7 +16,7 @@
|
||||
name: \
|
||||
pushl $vector; \
|
||||
jmp int_bottom
|
||||
|
||||
|
||||
#define TRAP(name, vector) \
|
||||
.globl name; \
|
||||
.align 8; \
|
||||
@@ -64,7 +70,7 @@ TRAP(trap253, 253)
|
||||
TRAP(trap254, 254)
|
||||
TRAP(trap255, 255)
|
||||
|
||||
.align 8
|
||||
.align 16
|
||||
.globl int_bottom
|
||||
int_bottom:
|
||||
pusha
|
||||
@@ -72,9 +78,14 @@ int_bottom:
|
||||
push %es
|
||||
push %fs
|
||||
push %gs
|
||||
movw $0x10,%ax
|
||||
movw %ax,%ds
|
||||
movl $KERNEL_DATA_SEG,%eax
|
||||
cld
|
||||
movl %eax,%ds
|
||||
movl %ss,%ebx
|
||||
movl %esp,%esi
|
||||
cmpl %eax,%ebx // check if we changed the stack
|
||||
jne custom_stack
|
||||
kernel_stack:
|
||||
call i386_handle_trap
|
||||
pop %gs
|
||||
pop %fs
|
||||
@@ -83,3 +94,60 @@ int_bottom:
|
||||
popa
|
||||
addl $8,%esp
|
||||
iret
|
||||
|
||||
// custom stack -> copy registers to kernel stack and switch there
|
||||
custom_stack:
|
||||
movl %dr3,%edx // get_current_thread
|
||||
movl %eax,%es
|
||||
addl _interrupt_stack_offset,%edx
|
||||
lss (%edx),%esp
|
||||
movl %ebx,%ds
|
||||
subl $84,%esp
|
||||
movl %esp,%edi
|
||||
movl $19,%ecx
|
||||
rep movsl
|
||||
movl %eax,%ds
|
||||
subl $76,%esi
|
||||
movl %esi,(%edi) // save custom stack address
|
||||
movl %ebx,4(%edi)
|
||||
call i386_handle_trap
|
||||
lss 76(%esp),%esp // reload custom stack address
|
||||
pop %gs
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
popa
|
||||
addl $8,%esp
|
||||
iret
|
||||
|
||||
_interrupt_stack_offset:
|
||||
.long 0
|
||||
|
||||
// void i386_stack_init(struct farcall *interrupt_stack_offset)
|
||||
/* setup in arch_thread.c: arch_thread_init_thread_struct() */
|
||||
FUNCTION(i386_stack_init):
|
||||
movl 4(%esp),%eax
|
||||
movl %eax,_interrupt_stack_offset
|
||||
ret
|
||||
|
||||
// void i386_stack_switch(struct farcall new_stack)
|
||||
FUNCTION(i386_stack_switch):
|
||||
movl %dr3,%eax // get_current_thread
|
||||
movl (%esp),%edx
|
||||
pushf
|
||||
popl %ecx
|
||||
addl _interrupt_stack_offset,%eax
|
||||
cli
|
||||
pushl %ss
|
||||
cmpl $KERNEL_DATA_SEG,(%esp)
|
||||
je kernel_stack2
|
||||
popl %eax
|
||||
jmp switch
|
||||
kernel_stack2:
|
||||
popl 4(%eax)
|
||||
movl %esp,(%eax)
|
||||
switch:
|
||||
lss 4(%esp),%esp
|
||||
pushl %ecx
|
||||
popf
|
||||
jmp *%edx
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
** Copyright 2002, Michael Noisternig. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
** Distributed under the terms of the MIT License as part of the OpenBeOS project.
|
||||
*/
|
||||
#include <arch/x86/arch_stage2.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <smp.h>
|
||||
#include <int.h>
|
||||
|
||||
#include <arch/x86/selector.h>
|
||||
|
||||
#define MAX_SELECTORS (GDT_LIMIT/8)
|
||||
#define ENTRIES (MAX_SELECTORS/(sizeof(uint32)*8))
|
||||
|
||||
static uint32 selector_bitmap[ENTRIES]
|
||||
= { 0x000000ff }; // first 8 selectors reserved
|
||||
|
||||
static selector_type *gdt_table;
|
||||
static struct gdt_idt_descr descr = { GDT_LIMIT - 1, NULL };
|
||||
|
||||
void i386_selector_init( void *gdt )
|
||||
{
|
||||
gdt_table = (selector_type *)gdt;
|
||||
descr.b = (unsigned int *)gdt_table;
|
||||
}
|
||||
|
||||
// creates a new selector in the gdt of given type (use SELECTOR macro)
|
||||
// IN: selector type
|
||||
// RET: selector that can be directly used for segment registers
|
||||
// 0 on error
|
||||
selector_id i386_selector_add( selector_type type )
|
||||
{
|
||||
static int spinlock;
|
||||
int state;
|
||||
uint32 mask;
|
||||
selector_id id = 0;
|
||||
unsigned i;
|
||||
|
||||
state = int_disable_interrupts();
|
||||
acquire_spinlock( &spinlock );
|
||||
|
||||
for ( i = 0; i < ENTRIES; i++ )
|
||||
if ( selector_bitmap[i] != 0xffffffff ) { // found free place in there
|
||||
id = i*sizeof(uint32)*8;
|
||||
mask = 1;
|
||||
while ( selector_bitmap[i] & mask ) {
|
||||
mask <<= 1;
|
||||
id++;
|
||||
}
|
||||
selector_bitmap[i] |= mask;
|
||||
gdt_table[id] = type;
|
||||
break;
|
||||
}
|
||||
|
||||
release_spinlock( &spinlock );
|
||||
int_restore_interrupts( state );
|
||||
|
||||
if ( id ) {
|
||||
asm("lgdt %0;"
|
||||
: : "m" (descr));
|
||||
}
|
||||
|
||||
return id*8;
|
||||
}
|
||||
|
||||
// removes a selector with given id from the gdt
|
||||
void i386_selector_remove( selector_id id )
|
||||
{
|
||||
if ( id < 8*8 || id >= MAX_SELECTORS*8 )
|
||||
return;
|
||||
|
||||
id /= 8;
|
||||
gdt_table[id] = 0;
|
||||
|
||||
atomic_and( &selector_bitmap[id/32], ~(1<<(id&31)) );
|
||||
|
||||
asm("lgdt %0;"
|
||||
: : "m" (descr));
|
||||
}
|
||||
|
||||
// returns the selector type of a given id
|
||||
selector_type i386_selector_get( selector_id id )
|
||||
{
|
||||
return gdt_table[id/8];
|
||||
}
|
||||
@@ -17,12 +17,17 @@ int arch_proc_init_proc_struct(struct proc *p, bool kernel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// from arch_interrupts.S
|
||||
extern void i386_stack_init( struct farcall *interrupt_stack_offset );
|
||||
|
||||
int arch_thread_init_thread_struct(struct thread *t)
|
||||
{
|
||||
t->arch_info.esp = NULL;
|
||||
// set up an initial state (stack & fpu)
|
||||
memset(&t->arch_info, 0, sizeof(t->arch_info));
|
||||
|
||||
// set up an initial fpu state
|
||||
memset(&t->arch_info.fpu_state[0], 0, sizeof(t->arch_info.fpu_state));
|
||||
// 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 );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -62,8 +67,9 @@ int arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(voi
|
||||
*kstack_top = 0;
|
||||
}
|
||||
|
||||
// save the esp
|
||||
t->arch_info.esp = kstack_top;
|
||||
// save the stack position
|
||||
t->arch_info.current_stack.esp = kstack_top;
|
||||
t->arch_info.current_stack.ss = (int *)KERNEL_DATA_SEG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -79,10 +85,11 @@ void arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
|
||||
#if 0
|
||||
int i;
|
||||
|
||||
dprintf("arch_thread_context_switch: cpu %d 0x%x -> 0x%x, aspace 0x%x -> 0x%x, &old_esp = 0x%p, esp = 0x%p\n",
|
||||
dprintf("arch_thread_context_switch: cpu %d 0x%x -> 0x%x, aspace 0x%x -> 0x%x, old stack = 0x%x:0x%x, stack = 0x%x:0x%x\n",
|
||||
smp_get_current_cpu(), t_from->id, t_to->id,
|
||||
t_from->proc->aspace, t_to->proc->aspace,
|
||||
&t_from->arch_info.esp, t_to->arch_info.esp);
|
||||
t_from->arch_info.current_stack.ss, t_from->arch_info.current_stack.esp,
|
||||
t_to->arch_info.current_stack.ss, t_to->arch_info.current_stack.esp);
|
||||
#endif
|
||||
#if 0
|
||||
for(i=0; i<11; i++)
|
||||
@@ -120,7 +127,7 @@ void arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
|
||||
|
||||
#if 0
|
||||
{
|
||||
int a = *(int *)(t_to->arch_info.esp - 4);
|
||||
int a = *(int *)(t_to->arch_info.current_stack.esp - 4);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -128,14 +135,15 @@ void arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
|
||||
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.esp, t_to->arch_info.esp, new_pgdir);
|
||||
i386_context_switch(&t_from->arch_info, &t_to->arch_info, new_pgdir);
|
||||
}
|
||||
|
||||
void arch_thread_dump_info(void *info)
|
||||
{
|
||||
struct arch_thread *at = (struct arch_thread *)info;
|
||||
|
||||
dprintf("\tesp: %p\n", at->esp);
|
||||
dprintf("\tesp: %p\n", at->current_stack.esp);
|
||||
dprintf("\tss: %p\n", at->current_stack.ss);
|
||||
dprintf("\tfpu_state at %p\n", at->fpu_state);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
** Copyright 2002, Michael Noisternig. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
@@ -75,13 +76,12 @@ FUNCTION(setup_system_time):
|
||||
movl %eax,cv_factor
|
||||
ret
|
||||
|
||||
/* long long system_time(); */
|
||||
/* uint64 system_time(); */
|
||||
FUNCTION(system_time):
|
||||
/* load 64-bit factor into %eax (low), %edx (high) */
|
||||
rdtsc /* time in %edx,%eax */
|
||||
|
||||
pushl %ebx
|
||||
pushl %ecx
|
||||
movl cv_factor, %ebx
|
||||
movl %edx, %ecx /* save high half */
|
||||
mull %ebx /* truncate %eax, but keep %edx */
|
||||
@@ -92,7 +92,6 @@ FUNCTION(system_time):
|
||||
subl %ebx, %ebx /* need zero to propagate carry */
|
||||
addl %ecx, %eax
|
||||
adc %ebx, %edx
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
ret
|
||||
|
||||
@@ -118,18 +117,21 @@ FUNCTION(i386_fxsave_swap):
|
||||
fxrstor (%eax)
|
||||
ret
|
||||
|
||||
/* void i386_context_switch(unsigned int **old_esp, unsigned int *new_esp, addr new_pgdir); */
|
||||
/* 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
|
||||
movl 36(%esp),%eax /* save current_stack */
|
||||
movl %esp,(%eax)
|
||||
pushl %ss
|
||||
popl %edx
|
||||
movl %edx,4(%eax)
|
||||
movl 44(%esp),%eax /* get possible new pgdir */
|
||||
cmpl $0x0,%eax /* is it null? */
|
||||
orl %eax,%eax /* is it null? */
|
||||
je skip_pgdir_swap
|
||||
movl %eax,%cr3
|
||||
movl %eax,%cr3
|
||||
skip_pgdir_swap:
|
||||
movl 40(%esp),%eax
|
||||
movl %eax,%esp
|
||||
movl 40(%esp),%eax /* get new current_stack */
|
||||
lss (%eax),%esp
|
||||
popa
|
||||
ret
|
||||
|
||||
|
||||
Reference in New Issue
Block a user