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:
notion 2002-07-24 20:59:25 +00:00
parent 94782cf761
commit fde77afb37
12 changed files with 277 additions and 57 deletions

View File

@ -7,12 +7,9 @@
/* ??? why include this as we're normally included from that file! */
#include <arch/cpu.h>
#include <arch/x86/thread_struct.h>
#include <arch/x86/descriptors.h>
#define KERNEL_CODE_SEG 0x8
#define KERNEL_DATA_SEG 0x10
#define USER_CODE_SEG 0x1b
#define USER_DATA_SEG 0x23
#define TSS 0x28
#define PAGE_SIZE 4096
#define _BIG_ENDIAN 0
@ -88,7 +85,7 @@ typedef struct pdentry {
#define nop() __asm__ ("nop"::)
void setup_system_time(unsigned int cv_factor);
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);
void i386_enter_uspace(addr entry, void *args, addr ustack_top);
void i386_set_kstack(addr kstack);
void i386_switch_stack_and_call(addr stack, void (*func)(void *), void *arg);

View File

@ -1,15 +1,26 @@
/*
/*
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
** Distributed under the terms of the NewOS License.
*/
#ifndef _NEWOS_KERNEL_BOOT_ARCH_I386_STAGE2_H
#define _NEWOS_KERNEL_BOOT_ARCH_I386_STAGE2_H
#ifndef _KERNEL_ARCH_x86_STAGE2_H
#define _KERNEL_ARCH_x86_STAGE2_H
#include <stage2_struct.h>
#define MAX_BOOT_PTABLES 4
#define _PACKED __attribute__((packed))
#define IDT_LIMIT 0x800
#define GDT_LIMIT 0x800
struct gdt_idt_descr {
unsigned short a;
unsigned int *b;
} _PACKED;
// kernel args
typedef struct {
// architecture specific

View File

@ -0,0 +1,14 @@
/*
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
** Distributed under the terms of the NewOS License.
*/
#ifndef _KERNEL_ARCH_x86_DESCRIPTORS_H
#define _KERNEL_ARCH_x86_DESCRIPTORS_H
#define KERNEL_CODE_SEG 0x8
#define KERNEL_DATA_SEG 0x10
#define USER_CODE_SEG 0x1b
#define USER_DATA_SEG 0x23
#define TSS 0x28
#endif

View File

@ -0,0 +1,34 @@
/*
** Copyright 2002, Michael Noisternig. All rights reserved.
** Distributed under the terms of the NewOS License.
*/
#ifndef _KERNEL_ARCH_x86_SELECTOR_H
#define _KERNEL_ARCH_x86_SELECTOR_H
#include <arch/x86/types.h>
typedef uint32 selector_id;
typedef uint64 selector_type;
// DATA segments are read-only
// CODE segments are execute-only
// both can be modified by using the suffixed enum versions
// legend: w = writable
// d = expand down
// r = readable
// c = conforming
enum segment_type {
DATA = 0x8, DATA_w, DATA_d, DATA_wd, CODE, CODE_r, CODE_c, CODE_rc
};
#define SELECTOR(base,limit,type,mode32) \
(((uint64)(((((uint32)base)>>16)&0xff) | (((uint32)base)&0xff000000) | ((type)<<9) | ((mode32)<<22) | (1<<15))<<32) \
| ( (limit) >= (1<<20) ? (((limit)>>12)&0xffff) | ((uint64)(((limit)>>12)&0xf0000)<<32) | ((uint64)1<<(23+32)) : ((limit)&0xffff) | ((uint64)((limit)&0xf0000)<<32) ) \
| ((((uint32)base)&0xffff)<<16))
void i386_selector_init( void *gdt );
selector_id i386_selector_add( selector_type selector );
void i386_selector_remove( selector_id id );
selector_type i386_selector_get( selector_id id );
#endif

View File

@ -39,16 +39,6 @@ void cpuid(unsigned int selector, unsigned int *data);
#define SCREEN_HEIGHT 24
#define ADDR_MASK 0xfffff000
#define _PACKED __attribute__((packed))
#define IDT_LIMIT 0x800
#define GDT_LIMIT 0x800
struct gdt_idt_descr {
unsigned short a;
unsigned int *b;
} _PACKED;
// SMP stuff
extern int smp_boot(kernel_args *ka, unsigned int kernel_entry);
extern void smp_trampoline(void);

View File

@ -2,12 +2,18 @@
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
** Distributed under the terms of the NewOS License.
*/
#ifndef _NEWOS_KERNEL_ARCH_I386_THREAD_STRUCT_H
#define _NEWOS_KERNEL_ARCH_I386_THREAD_STRUCT_H
#ifndef _KERNEL_ARCH_x86_THREAD_STRUCT_H
#define _KERNEL_ARCH_x86_THREAD_STRUCT_H
struct farcall {
unsigned int *esp;
unsigned int *ss;
};
// architecture specific thread info
struct arch_thread {
unsigned int *esp;
struct farcall current_stack;
struct farcall interrupt_stack;
// 512 byte floating point save point
uint8 fpu_state[512];
};

View File

@ -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
:

View File

@ -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");

View File

@ -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

View File

@ -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];
}

View File

@ -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);
}

View File

@ -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