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:
parent
94782cf761
commit
fde77afb37
@ -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);
|
||||
|
@ -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
|
||||
|
14
headers/private/kernel/arch/x86/descriptors.h
Normal file
14
headers/private/kernel/arch/x86/descriptors.h
Normal 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
|
34
headers/private/kernel/arch/x86/selector.h
Normal file
34
headers/private/kernel/arch/x86/selector.h
Normal 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
|
@ -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);
|
||||
|
@ -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];
|
||||
};
|
||||
|
@ -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
|
||||
|
86
src/kernel/core/arch/x86/arch_selector.c
Normal file
86
src/kernel/core/arch/x86/arch_selector.c
Normal 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];
|
||||
}
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user