first version to support the FPU

- seems to work
- currently, we didn't support SIMD instructions
This commit is contained in:
Stefan Lankes 2011-04-20 15:16:22 +02:00
parent ea19b15781
commit 7e0179f5f7
5 changed files with 42 additions and 10 deletions

View file

@ -55,11 +55,15 @@ typedef struct i387_fxsave_struct {
long padding[56];
} i387_fxsave_t __attribute__ ((aligned (16)));
union fpu_union {
union fpu_state {
i387_fsave_t fsave;
i387_fxsave_t fxsave;
};
static inline void save_fpu_state(union fpu_state* state) {
asm volatile ("fsave %0; fwait" : "=m"((*state).fsave));
}
#ifdef __cplusplus
}
#endif

View file

@ -64,16 +64,19 @@ ALIGN 4
stublet:
; initialize stack pointer.
mov esp, default_stack_pointer
; enable cache and turn on FPU exceptions
mov eax, cr0
; enable cache
and eax, 0x9fffffff
; ...and turn on FPU exceptions
or eax, 0x20
; enable cache, disable paging and fpu emulation
and eax, 0x3ffffffb
; ...monitor coprocessor and turn on FPU exceptions
or eax, 0x22
mov cr0, eax
; clears the current pgd entry
xor eax, eax
mov cr3, eax
; disable SSE support (TODO)
mov eax, cr4
and eax, 0xfffbf9ff
mov cr4, eax
; interpret multiboot information
extern multiboot_init
push ebx

View file

@ -74,6 +74,7 @@ extern void isr30(void);
extern void isr31(void);
static void fault_handler(struct state *s);
static void fpu_handler(struct state *s);
/*
* This is a very repetitive function... it's not hard, it's
@ -158,6 +159,23 @@ void isrs_install(void)
// install the default handler
for(i=0; i<32; i++)
irq_install_handler(i, fault_handler);
// set hanlder for fpu exceptions
irq_uninstall_handler(7);
irq_install_handler(7, fpu_handler);
}
static void fpu_handler(struct state *s)
{
task_t* task = per_core(current_task);
kputs("got FPU exception\n");
asm volatile ("clts"); // clear the TS flag of cr0
if (!task->fpu_used) {
task->fpu_used = 1;
asm volatile ("finit");
} else
asm volatile ("frstor %0" :: "m"(task->fpu.fsave)); // restore fpu state
}
/** @brief Exception messages
@ -189,7 +207,7 @@ static void fault_handler(struct state *s)
{
if (s->int_no < 32) {
kputs(exception_messages[s->int_no]);
kputs(" Exception.\n");
kprintf(" Exception. (%d)\n", s->int_no);
/* Now, we signalize that we have handled the interrupt */
if (apic_is_enabled())

View file

@ -66,12 +66,14 @@ typedef struct task {
spinlock_t vma_lock;
/// List of VMAs
vma_t* vma_list;
/// Is set, when the FPU is used
uint32_t fpu_used;
/// Mail inbox
mailbox_wait_msg_t inbox;
/// Mail outbox array
mailbox_wait_msg_t* outbox[MAX_TASKS];
/// FPU state
union fpu_union fpu_state;
union fpu_state fpu;
} __attribute__((packed)) task_t;
#ifdef __cplusplus

View file

@ -48,7 +48,7 @@ DEFINE_PER_CORE(task_t*, current_task, NULL);
* A task's id will be its position in this array.
*/
static task_t task_table[MAX_TASKS] = {[0 ... MAX_TASKS-1] = {0, TASK_INVALID, ATOMIC_INIT(0), \
SPINLOCK_INIT, NULL, SPINLOCK_INIT, NULL}};
SPINLOCK_INIT, NULL, SPINLOCK_INIT, NULL, 0}};
static spinlock_irqsave_t table_lock = SPINLOCK_IRQSAVE_INIT;
/** @brief helper function for the assembly code to determine the current task
@ -67,6 +67,7 @@ int multitasking_init(void) {
memset(task_table[0].outbox, 0x00, sizeof(mailbox_wait_msg_t*)*MAX_TASKS);
per_core(current_task) = task_table+0;
per_core(current_task)->pgd = get_boot_pgd();
task_table[0].fpu_used = 0;
return 0;
}
@ -189,6 +190,7 @@ static int create_task(tid_t* id, entry_point_t ep, void* arg)
ret = create_default_frame(task_table+i, ep, arg);
task_table[i].fpu_used = 0;
task_table[i].status = TASK_READY;
break;
}
@ -250,6 +252,7 @@ int sys_fork(void)
mailbox_wait_msg_init(&task_table[i].inbox);
memset(task_table[i].outbox, 0x00, sizeof(mailbox_wait_msg_t*)*MAX_TASKS);
task_table[i].outbox[per_core(current_task)->id] = &per_core(current_task)->inbox;
task_table[i].fpu_used = 0x00;
ret = arch_fork(task_table+i);
@ -707,7 +710,9 @@ void scheduler(void)
if (per_core(current_task)->status == TASK_RUNNING)
per_core(current_task)->status = TASK_READY;
task_table[new_id].status = TASK_RUNNING;
if (per_core(current_task)->fpu_used)
save_fpu_state(&(per_core(current_task)->fpu));
per_core(current_task) = task_table+new_id;
goto get_task_out;
}