Hi,
Nachdem ich jetzt das Multitasking in Ring 0 hinbekommen habe, wollte ich jetzt das genze nach ring 3 verschieben.
Nur leider kommen As bis zum nächsten Timerinterrupt und dann meldet qemu: fatal: trying to execute code outside RAM or ROM.(oder so ähnlich)
könnte da mal jemand drübergucken?
multitasking.c
#include <stdint.h>
#include "gdt.h"
#include "interrupt.h"
#include "cpu.h"
#include "console.h"
/* ---------- Globale Variablen ----------------------- */
static uint8_t stack_a[4096];
static uint8_t stack_b[4096];
static uint8_t user_stack_a[4096];
static uint8_t user_stack_b[4096];
static int current_task = -1;
static int num_tasks = 2;
static cpu_state* task_states[2];
/* --------- Tasks ------------- */
void task_a(void){
while(1){
setColor(0x02);
printf("A");
}
}
void task_b(void){
while(1){
setColor(0x06);
printf("B");
}
}
/* ---------- Task initalisieren ---------------------- */
cpu_state* init_task(uint8_t *stack, uint8_t *user_stack, void *entry){
cpu_state new_state = {
.eax = 0,
.ebx = 0,
.ecx = 0,
.edx = 0,
.esi = 0,
.edi = 0,
.ebp = 0,
.esp = (uint32_t) user_stack + 4096,
.eip = (uint32_t) entry,
// Ring-3 Segmentregister
.cs = 0x1b /*0x18 | 0x03*/,
.ss = 0x23 /*0x20 | 0x03*/,
// IRQs einschalten
.eflags = 0x202,
};
cpu_state *state = (void*) (stack + 4096 - sizeof(new_state));
*state = new_state;
return state;
}
/* ---------- Multitasking initalisieren -------------- */
void init_multitasking(void){
task_states[0] = init_task(stack_a, user_stack_a, task_a);
task_states[1] = init_task(stack_b, user_stack_b, task_b);
cpu_dump(task_states[0]);
cpu_dump(task_states[1]);
}
/* ---------- Scheduler ------------------------------- */
cpu_state* schedule(cpu_state *cpu){
// Alten zustand des Tasks sichern
if(current_task >= 0){
task_states[current_task] = cpu;
}
// Nächsten Task auswählen
current_task++;
current_task %= num_tasks;
// Neuen Task aktivieren
cpu = task_states[current_task];
return cpu;
}
timer_irq_handler.c
#include <stdint.h>
#include "cpu.h"
#include "gdt.h"
#include "multitasking.h"
static uint32_t tss[TSS_SIZE];
cpu_state* timer_irq_handler(cpu_state *cpu){
cpu_state *new_cpu = schedule(cpu);
tss[1] = (uint32_t) (new_cpu + 1);
send_eoi(0);
return new_cpu;
}
irq handler:
// Gemeinsamer interrupt handler
.extern common_intrpt_handler
.extern common_intrpt_handler_with_new_cpu
// IRQ - Handler
.extern timer_irq_handler
.extern keyboard_irq_handler
.macro irq_empty nr
.global int_handler\nr
int_handler\nr:
iret
.endm
.macro irq nr isr
.global int_handler\nr
int_handler\nr:
push $0
push $\nr
push $\isr
jmp common_intrpt_handler
.endm
.macro irq_with_new_cpu nr isr
.global int_handler\nr
int_handler\nr:
push $0
push $\nr
push $\isr
jmp common_intrpt_handler_with_new_cpu
.endm
irq_with_new_cpu 0x20 timer_irq_handler
irq 0x21 keyboard_irq_handler
irq_empty 0x22
irq_empty 0x23
irq_empty 0x24
irq_empty 0x25
irq_empty 0x26
irq_empty 0x27
irq_empty 0x28
irq_empty 0x29
irq_empty 0x2A
irq_empty 0x2B
irq_empty 0x2C
irq_empty 0x2D
irq_empty 0x2E
irq_empty 0x2F
//Ende - handler.S
common handler:
.global common_intrpt_handler_with_new_cpu
common_intrpt_handler_with_new_cpu:
// ISR nach eax legen
pop %ebx
push %ebp
push %edi
push %esi
push %edx
push %ecx
push %ebx
push %eax
// Kernel-Datensegmente laden
mov $0x10, %ax
mov %ax, %ds
mov %eax, %es
// ISR aufrufen
push %esp
call *%ebx
mov %eax, %esp //Neuen Stack laden
// User-Datensegmente laden
mov $0x23, %ax
mov %ax, %ds
mov %ax, %es
// Neue cpu herstellen
pop %eax
pop %ebx
pop %ecx
pop %edx
pop %esi
pop %edi
pop %ebp
// Errorcode und Interruptnummer vom Stack nehmen
add $8, %esp
iret
gdt.c
#include <stdint.h>
#include "gdt.h"
/* ---------- Globale Variablen ----------------------- */
static uint64_t gdt[GDT_ENTRIES]; //Global Deskriptor Table
static uint32_t tss[TSS_SIZE] = {0, 0, 0x10}; //Task State Segment
/* ---------- Eintrag in die GDT setzen --------------- */
void set_gdt_entry(int i, uint32_t limit, uint32_t base, uint8_t access, uint8_t flags){
gdt[i] = 0;
//untere 32-Bit
gdt[i] = (limit & 0x0ffff) | ((base & 0x0000ffff) << 16);
//obere 32-Bit
gdt[i] |=(
( (base & 0x00ff0000) >> 16 ) |
( access << 8 ) |
( flags << 16 ) |
( (limit & 0xf0000) << 4) |
( (base & 0xff000000) << 56 )
) * 0x100000000;
}
/* ---------- GDT Laden (GDTR ändern) ----------------- */
void load_gdt(void){
struct {
uint16_t size;
uint64_t *pointer;
} __attribute__((packed)) gdtp = {
.size = GDT_ENTRIES * 8 - 1,
.pointer = gdt,
};
asm volatile("lgdt %0" : : "m" (gdtp));//GDT Laden
}
/* ---------- GDT initalisieren ----------------------- */
void init_gdt(void){
//Nulldeskriptor
set_gdt_entry(0, 0, 0, 0, 0);
//Kernel - Codesegment
set_gdt_entry(1, 0xfffff, 0, //index, limit, base
GDT_CODESEG_RD | GDT_SEGMENT | GDT_RING0 | GDT_PRESENT,//Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
//Kernel - Datensegment
set_gdt_entry(2, 0xfffff, 0, //index, limit, base
GDT_DATASEG_WR | GDT_SEGMENT | GDT_RING0 | GDT_PRESENT,//Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
//Userspace - Codesegment
set_gdt_entry(3, 0xfffff, 0, //index, limit, base
GDT_CODESEG_RD | GDT_SEGMENT | GDT_RING3 | GDT_PRESENT,//Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
//Userpsace - Datensegment
set_gdt_entry(4, 0xfffff, 0, //index, limit, base
GDT_DATASEG_WR | GDT_SEGMENT | GDT_RING3 | GDT_PRESENT,//Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
//Task State Segment
set_gdt_entry(5, sizeof(tss)-1, (uint32_t) &tss, //index, limit, base
GDT_TSS | GDT_PRESENT | GDT_RING3, //Access-Byte
GDT_32_BIT | GDT_4K_GRAN); //Flags
// nach ss0 das Kernel Datensegment legen
tss[2] = 0x10;
}
/* ---------- GDT schnell initalisieren --------------- */
void init_gdt_fast(void){
gdt[0] = 0x0000000000000000;//Nulldeskriptor
gdt[1] = 0x00FC9A000000FFFF;//Kernel - Codesegment
gdt[2] = 0x00FC92000000FFFF;//Kernel - Datensegment
gdt[3] = 0x00FCFA000000FFFF;//Userspace - Codesegment
gdt[4] = 0x00FCF2000000FFFF;//Userpsace - Datensegment
// gdt[5] = 0x0000000000000000;//Task State Segment
}
/* ---------- Segmenregister neuladen ----------------- */
void reload_segment_registers(void){
asm volatile(
"ljmpl $0x08, $1f\n\t"
"1:\n\t"
"mov $0x10, %eax\n\t"
"mov %eax, %ds\n\t"
"mov %eax, %es\n\t"
"mov %eax, %fs\n\t"
"mov %eax, %gs\n\t"
"mov %eax, %ss\n\t"
);
}
/* ---------- Taskregister neuladen ------------------- */
void reload_task_registers(void){
asm volatile("ltr %%ax" : : "a" (5 << 3));
}