Danke für den Link, das Tutorial hat mir sehr geholfen^^.
Ich habe es jetzt geschaft das Multitasking einzubauen, jedoch funktioniert irgentwie der Ring 0 -> Ring 3 Change nicht, oder umgekehrt. Wenn ich Prozesse im Ring 0 laufen laufen lasse funktioniert aber alles.
Bochs liefert mir den Fehlercode:
fetch_raw_descriptor: LDTR.valid=0
Der Fehler wird offensichtlich beim 1. Taskswitch ausgelöst, beim Switch vom Idle zum "test" Prozess
Hier ist mein Code:
Diese Prozeduren handlen die Prozesse und wählen den nächsten Task aus:
#include "memory.h"
#include "process.h"
extern void updateGDT();
tTSS kernelTSS;
tProcess *parentProcess;
tProcess *currentProcess;
unsigned long currentStack;
unsigned char enableSchedule;
tProcess *createProcess( unsigned char *id, void *entry ) {
tProcess *process = allocateSystemMemory( sizeof( tProcess ) );
memset( process, 0, sizeof( tProcess ) );
strcpy( process->processID, id );
memset( process->processKernelStack, 0, 256 );
memset( process->processUserStack, 0, 256 );
unsigned long *stack = process->processKernelStack + 256;
*(--stack) = 0x20; // User stack selector
*(--stack) = 0;(unsigned long)process->processUserStack + 256; // User ESP
*(--stack) = 0x200; // EFLAGS
*(--stack) = 0x18; // User code selector
*(--stack) = (unsigned long)entry; // EIP
*(--stack) = 0; // EDX
*(--stack) = 0; // ECX
*(--stack) = 0; // EBX
*(--stack) = 0; // EAX
*(--stack) = 0; // (User) ESP - get's discarded while popping
*(--stack) = 0; // EBP
*(--stack) = 0; // EDI
*(--stack) = 0; // ESI
*(--stack) = 0x20; // DS
*(--stack) = 0x20; // ES
*(--stack) = 0x20; // FS
*(--stack) = 0x20; // GS
process->processStack = stack;
process->next = 0;
return process;
}
void testProcess() {
while( 1 );
}
void initScheduler() {
// create idle process
parentProcess = allocateSystemMemory( sizeof( tProcess ) );
memset( parentProcess, 0, sizeof( tProcess ) );
strcpy( parentProcess->processID, "system/idle" );
parentProcess->processStack = parentProcess->processKernelStack + 256; //stack;
// create test process
tProcess *proc = createProcess( "application/test", testProcess );
parentProcess->next = proc;
// setup tss for ring change
memset( &kernelTSS, 0, sizeof( tTSS ) );
kernelTSS.esp_ring0 = (unsigned long)parentProcess->processKernelStack + 256;
kernelTSS.cs = 0x18;
kernelTSS.ds = 0x20;
kernelTSS.es = 0x20;
kernelTSS.fs = 0x20;
kernelTSS.gs = 0x20;
kernelTSS.ss_ring0 = 0x10;
updateGDT();
currentProcess = parentProcess;
enableSchedule = 1;
}
void schedule() {
if( enableSchedule == 1 ) {
//if( currentProcess == 0 ){
// currentProcess = parentProcess;
//}else{
currentProcess->processStack = (unsigned long*)currentStack;
//}
if( currentProcess->next == 0 ) {
currentProcess = parentProcess;
}else{
currentProcess = currentProcess->next;
}
printk( "Task %s\n", currentProcess->processID );
currentStack = (unsigned long)currentProcess->processStack;
kernelTSS.esp_ring0 = (unsigned int)currentProcess->processKernelStack + 256;
}
}
Die Prozess Struktur sieht so aus:
256 Einträge pro Stack ist zwar schon etwas wenig, sollte aber für Testzwecke reichen^^
struct tProcess {
unsigned char processID[32];
unsigned long *processDirectory;
tMemory processMemory;
unsigned long processKernelStack[256];
unsigned long processUserStack[256];
unsigned long *processStack;
struct tProcess *next;
};
Das hier ist mein Scheduler:
[global _isr_32]
[extern _schedule]
[extern _currentStack]
_isr_32:
cld
pushad
push ds
push es
push fs
push gs
;change the task
;save old esp
mov [_currentStack], esp
call _schedule
mov esp, [_currentStack]
mov al, 0x20
out 0x20, al
pop gs
pop fs
pop es
pop ds
popad
iret
Meine GDT baue ich so auf:
[bits 32]
[section .text]
[global _updateGDT]
[extern _kernelTSS]
DESC_4K_GRAN EQU 128
DESC_BIG EQU 64
DESC_32BIT EQU 8
DESC_TSS EQU 1
DESC_PRESENT EQU 128
DESC_DPL3 EQU 64+32
DESC_DPL0 EQU 0
DESC_SEGMENT EQU 16
DESC_CODE EQU 8
DESC_DATA EQU 0
DESC_DATA_EXPAND_DOWN EQU 4
DESC_CODE_READ_EXEC EQU 2
DESC_DATA_READ_WRITE EQU 2
DESC_ACCESSED EQU 1
_updateGDT:
; fill in tss value
push eax
lgdt [GDT_DESC]
mov eax, _kernelTSS
mov [DESC_KERNEL_TSS+2], al
mov [DESC_KERNEL_TSS+3], ah
shr eax, 16
mov [DESC_KERNEL_TSS+4], al
mov eax, _kernelTSS
shr eax, 24
mov [DESC_KERNEL_TSS+7], al
mov ax, 0x28
ltr ax
pop eax
retn
GDT_START:
DESC_NULL: ;0x0
dd 0
dd 0
DESC_KERNEL_CODE: ;0x8
db 255
db 255
db 0
db 0
db 0
db DESC_PRESENT + DESC_DPL0 + DESC_SEGMENT + DESC_CODE + DESC_CODE_READ_EXEC
db DESC_4K_GRAN + DESC_BIG + 0xF
db 0
DESC_KERNEL_DATA: ;0x10
db 255
db 255
db 0
db 0
db 0
db DESC_PRESENT + DESC_DPL0 + DESC_SEGMENT + DESC_DATA + DESC_DATA_READ_WRITE
db DESC_4K_GRAN + DESC_BIG + 0xF
db 0
DESC_USER_CODE: ;0x18
db 255
db 255
db 0
db 0
db 0
db DESC_PRESENT + DESC_DPL3 + DESC_SEGMENT + DESC_CODE + DESC_CODE_READ_EXEC
db DESC_4K_GRAN + DESC_BIG + 0xF
db 0
DESC_USER_DATA: ;0x20
db 255
db 255
db 0
db 0
db 0
db DESC_PRESENT + DESC_DPL3 + DESC_SEGMENT + DESC_DATA + DESC_DATA_READ_WRITE
db DESC_4K_GRAN + DESC_BIG + 0xF
db 0
DESC_KERNEL_TSS: ;0x28
db 104
db 0
db 0
db 0
db 0
db DESC_PRESENT + DESC_DPL0 + DESC_32BIT + DESC_TSS
db DESC_BIG
db 0
GDT_END:
GDT_DESC:
dw GDT_END - GDT_START
dd GDT_START
[/code]