Autor Thema: Taskswitch  (Gelesen 10487 mal)

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« am: 14. February 2013, 01:02 »
Hi,
kann mir vielleicht jemand erklären, wie genau der Taskswitch funktioniert?

Das hier ist ja der Code aus dem Tutorial:
push %esp
call handle_interrupt
mov %eax, %esp
Danach kommt ein iret und es wird mit den richtigen Registern und dem richtigen Stack an die Adresse gesprungen, die ganz oben auf dem Stack liegt, oder? Das sollte doch .eip in der Struktur des Tasks sein... Aber .eip ist doch nicht am Anfang der Struktur, oder habe ich was falsch verstanden?

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 15. February 2013, 16:54 »
Hilft es dir, wenn ich dir sage, dass der Stack nach unten wächst? Jedes pop geht also in der struct einen Eintrag weiter nach hinten, nicht nach vorne.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 16. February 2013, 00:34 »
Nicht wirklich, weil .eip doch auch nicht am Ende der Struktur ist, sondern irgendwo in der Mitte. Warum sollte iret zu .eip springen?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 16. February 2013, 01:17 »
Hilft dir vielleicht diese Erklärung?
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 16. February 2013, 01:26 »
Ja, das hilft. Ich glaube, ich hab's verstanden.
Vielen Dank, Jidder!

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 16. February 2013, 13:15 »
Ich hab's scheinbar immer noch nicht verstanden. Es wird bei mir weder task_a() noch task_b() aufgerufen.
Hier mal mein Code:

main.c
void task_a(){
print_char('a', -1, 0xF);
while(1);
}

void task_b(){
print_char('b', -1, 0xF);
while(1);
}

int main(){
install_start();
CreateTask(task_a);
CreateTask(task_b);
__asm__ __volatile__ ("int $0x20");
while(1);
return 0;
}

multitasking.c
/** GLOBAL VARIABLES **/
struct struct_Task Tasks[MAX_TASK_NUM+1];
int task_number = 0;
int currentPID = 1;

/** GLOBAL FUNCTIONS **/
void InitMultitasking();
unsigned int multitasking_scheduler(unsigned int stack);
void CreateTask(void* start_addr);

void InitMultitasking(){
IRQ_install_handler(0, SwitchTask);
}

unsigned int multitasking_scheduler(unsigned int stack){
Tasks[currentPID].stack = stack;
while(!Tasks[currentPID].status == 1){
currentPID++;
if(currentPID > MAX_TASK_NUM) currentPID = 1;
}
print(itoa((unsigned int)Tasks[currentPID].stack), 80, 0xF); // 0x1FFF74
return Tasks[currentPID].stack;
}

void CreateTask(void* start_addr){
unsigned int* stack;
__asm__ __volatile__ ("cli");
stack = (void*)(pmm_malloc()+1024);
*stack-- = 0x202;
*stack-- = 0x8;
*stack-- = (unsigned int)start_addr;

*stack-- = 0x0;
*stack-- = 0x0;
*stack-- = 0x0;
*stack-- = 0x0;
*stack-- = 0x0;
*stack-- = 0x0;
*stack-- = 0x0;
*stack-- = 0x0;

*stack-- = 0x10;
*stack-- = 0x10;
*stack-- = 0x10;
*stack-- = 0x10;

Tasks[task_number+1].status = 1;
Tasks[task_number+1].stack = (unsigned int) stack;
Tasks[task_number+1].PID = task_number+1;

task_number++;
__asm__ __volatile__ ("sti");
}

multitasking.asm
[BITS 32]
[GLOBAL SwitchTask]
[EXTERN multitasking_scheduler]

SwitchTask:
push esp
call multitasking_scheduler
mov esp, eax

ret

In diesem und
in diesem Tutorial ist der Assembler Code zwar anders, aber so wie ich das verstanden habe, wird das alles um meinen Code von meiner ISR erledigt.

Ich hab das mal debugged: Es taucht nirgends etwas mit task_a oder task_b auf. Deshalb meine Frage: Was fehlt in meinem Code, was dafür sorgt, dass nicht zurück gesprungen wird, sondern in den Task.

Hier noch das, was beim Debuggen raus gekommen ist:
=> 0x1000e8 <main+47>:  int    $0x20
(gdb)
0x00101111 in IRQ0 ()
1: x/i $pc
=> 0x101111 <IRQ0+1>:   push   $0x0
(gdb)
0x00101113 in IRQ0 ()
1: x/i $pc
=> 0x101113 <IRQ0+3>:   push   $0x20
(gdb)
0x00101115 in IRQ0 ()
1: x/i $pc
=> 0x101115 <IRQ0+5>:   jmp    0x101180 <IRQ_common_stub>
(gdb)
0x00101180 in IRQ_common_stub ()
1: x/i $pc
=> 0x101180 <IRQ_common_stub>:  pusha
(gdb)
0x00101181 in IRQ_common_stub ()
1: x/i $pc
=> 0x101181 <IRQ_common_stub+1>:        push   %ds
(gdb)
0x00101182 in IRQ_common_stub ()
1: x/i $pc
=> 0x101182 <IRQ_common_stub+2>:        push   %es
(gdb)
0x00101183 in IRQ_common_stub ()
1: x/i $pc
=> 0x101183 <IRQ_common_stub+3>:        push   %fs
(gdb)
0x00101185 in IRQ_common_stub ()
1: x/i $pc
=> 0x101185 <IRQ_common_stub+5>:        push   %gs
(gdb)
0x00101187 in IRQ_common_stub ()
1: x/i $pc
=> 0x101187 <IRQ_common_stub+7>:        mov    $0x10,%ax
(gdb)
0x0010118b in IRQ_common_stub ()
1: x/i $pc
=> 0x10118b <IRQ_common_stub+11>:       mov    %eax,%ds
(gdb)
0x0010118d in IRQ_common_stub ()
1: x/i $pc
=> 0x10118d <IRQ_common_stub+13>:       mov    %eax,%es
(gdb)
0x0010118f in IRQ_common_stub ()
1: x/i $pc
=> 0x10118f <IRQ_common_stub+15>:       mov    %eax,%fs
(gdb)
0x00101191 in IRQ_common_stub ()
1: x/i $pc
=> 0x101191 <IRQ_common_stub+17>:       mov    %eax,%gs
(gdb)
0x00101193 in IRQ_common_stub ()
1: x/i $pc
=> 0x101193 <IRQ_common_stub+19>:       mov    %esp,%eax
(gdb)
0x00101195 in IRQ_common_stub ()
1: x/i $pc
=> 0x101195 <IRQ_common_stub+21>:       push   %eax
(gdb)0x00101196 in IRQ_common_stub ()
1: x/i $pc
=> 0x101196 <IRQ_common_stub+22>:       mov    $0x1007ca,%eax
(gdb)
0x0010119b in IRQ_common_stub ()
1: x/i $pc
=> 0x10119b <IRQ_common_stub+27>:       call   *%eax
(gdb)
0x001007ca in IRQ_handler ()
1: x/i $pc
=> 0x1007ca <IRQ_handler>:      push   %esi
(gdb)
0x001007cb in IRQ_handler ()
1: x/i $pc
=> 0x1007cb <IRQ_handler+1>:    push   %ebx
(gdb)
0x001007cc in IRQ_handler ()
1: x/i $pc
=> 0x1007cc <IRQ_handler+2>:    sub    $0x4,%esp
(gdb)
0x001007cf in IRQ_handler ()
1: x/i $pc
=> 0x1007cf <IRQ_handler+5>:    mov    0x10(%esp),%ebx
(gdb)
0x001007d3 in IRQ_handler ()
1: x/i $pc
=> 0x1007d3 <IRQ_handler+9>:    mov    0x30(%ebx),%eax
(gdb)
0x001007d6 in IRQ_handler ()
1: x/i $pc
=> 0x1007d6 <IRQ_handler+12>:   mov    0x1241c0(,%eax,4),%esi
(gdb)
0x001007dd in IRQ_handler ()
1: x/i $pc
=> 0x1007dd <IRQ_handler+19>:   test   %esi,%esi
(gdb)
0x001007df in IRQ_handler ()
1: x/i $pc
=> 0x1007df <IRQ_handler+21>:   je     0x1007ea <IRQ_handler+32>
(gdb)
0x001007e1 in IRQ_handler ()
1: x/i $pc
=> 0x1007e1 <IRQ_handler+23>:   sub    $0xc,%esp
(gdb)
0x001007e4 in IRQ_handler ()
1: x/i $pc
=> 0x1007e4 <IRQ_handler+26>:   push   %ebx
(gdb)
0x001007e5 in IRQ_handler ()
1: x/i $pc
=> 0x1007e5 <IRQ_handler+27>:   call   *%esi
(gdb)

Breakpoint 1, 0x001011b0 in SwitchTask ()
1: x/i $pc
=> 0x1011b0 <SwitchTask>:       push   %esp
(gdb)
0x001011b1 in SwitchTask ()
1: x/i $pc
=> 0x1011b1 <SwitchTask+1>:     call   0x100cb4 <multitasking_scheduler>
(gdb)
0x00100cb4 in multitasking_scheduler ()
1: x/i $pc
=> 0x100cb4 <multitasking_scheduler>:   push   %ebx
(gdb)
0x00100cb5 in multitasking_scheduler ()
1: x/i $pc
=> 0x100cb5 <multitasking_scheduler+1>: mov    0x1021c0,%eax
(gdb)
0x00100cba in multitasking_scheduler ()
1: x/i $pc
=> 0x100cba <multitasking_scheduler+6>: lea    (%eax,%eax,2),%edx
(gdb)
0x00100cbd in multitasking_scheduler ()
1: x/i $pc
=> 0x100cbd <multitasking_scheduler+9>: mov    0x8(%esp),%ecx
(gdb)
0x00100cc1 in multitasking_scheduler ()
1: x/i $pc
=> 0x100cc1 <multitasking_scheduler+13>:        mov    %ecx,0x122ac4(,%edx,4)
(gdb)
0x00100cc8 in multitasking_scheduler ()
1: x/i $pc
=> 0x100cc8 <multitasking_scheduler+20>:        mov    $0x1,%ebx
(gdb)
0x00100ccd in multitasking_scheduler ()
1: x/i $pc
=> 0x100ccd <multitasking_scheduler+25>:
    jmp    0x100cdc <multitasking_scheduler+40>
(gdb)
0x00100cdc in multitasking_scheduler ()
1: x/i $pc
=> 0x100cdc <multitasking_scheduler+40>:        lea    (%eax,%eax,2),%edx
(gdb)
0x00100cdf in multitasking_scheduler ()
1: x/i $pc
=> 0x100cdf <multitasking_scheduler+43>:        lea    0x122ac8(,%edx,4),%edx
(gdb)
0x00100ce6 in multitasking_scheduler ()
1: x/i $pc
=> 0x100ce6 <multitasking_scheduler+50>:        cmpb   $0x0,(%edx)
(gdb)
0x00100ce9 in multitasking_scheduler ()
1: x/i $pc
=> 0x100ce9 <multitasking_scheduler+53>:
    je     0x100ccf <multitasking_scheduler+27>
(gdb)
0x00100ceb in multitasking_scheduler ()
1: x/i $pc
=> 0x100ceb <multitasking_scheduler+55>:        mov    %eax,0x1021c0
(gdb)
0x00100cf0 in multitasking_scheduler ()
1: x/i $pc
=> 0x100cf0 <multitasking_scheduler+60>:        lea    (%eax,%eax,2),%eax
(gdb)
0x00100cf3 in multitasking_scheduler ()
1: x/i $pc
=> 0x100cf3 <multitasking_scheduler+63>:        mov    0x122ac4(,%eax,4),%eax
(gdb)
0x00100cfa in multitasking_scheduler ()
1: x/i $pc
=> 0x100cfa <multitasking_scheduler+70>:        pop    %ebx
(gdb)
0x00100cfb in multitasking_scheduler ()
1: x/i $pc
=> 0x100cfb <multitasking_scheduler+71>:        ret
(gdb)
0x001011b6 in SwitchTask ()
1: x/i $pc
=> 0x1011b6 <SwitchTask+6>:     mov    %eax,%esp
(gdb)
0x001011b8 in SwitchTask ()
1: x/i $pc
=> 0x1011b8 <SwitchTask+8>:     ret
(gdb)
0x001007e7 in IRQ_handler ()
1: x/i $pc
=> 0x1007e7 <IRQ_handler+29>:   add    $0x10,%esp
(gdb)
0x001007ea in IRQ_handler ()
1: x/i $pc
=> 0x1007ea <IRQ_handler+32>:   cmpl   $0x27,0x30(%ebx)
(gdb)
0x001007ee in IRQ_handler ()
1: x/i $pc
=> 0x1007ee <IRQ_handler+36>:   jbe    0x100802 <IRQ_handler+56>
(gdb)
0x00100802 in IRQ_handler ()
1: x/i $pc
=> 0x100802 <IRQ_handler+56>:   sub    $0x8,%esp
(gdb)
0x00100805 in IRQ_handler ()
1: x/i $pc
=> 0x100805 <IRQ_handler+59>:   push   $0x20
(gdb)
0x00100807 in IRQ_handler ()
1: x/i $pc
=> 0x100807 <IRQ_handler+61>:   push   $0x20
(gdb)
0x00100809 in IRQ_handler ()
1: x/i $pc
=> 0x100809 <IRQ_handler+63>:   call   0x100fac <outb>
(gdb)
0x00100fac in outb ()
1: x/i $pc
=> 0x100fac <outb>:     push   %ebp
(gdb)
0x00100fad in outb ()
1: x/i $pc
=> 0x100fad <outb+1>:   mov    %esp,%ebp
(gdb)
0x00100faf in outb ()
1: x/i $pc
=> 0x100faf <outb+3>:   mov    0x8(%ebp),%dx
(gdb)
0x00100fb3 in outb ()
1: x/i $pc
=> 0x100fb3 <outb+7>:   mov    0xc(%ebp),%al
(gdb)
0x00100fb6 in outb ()
1: x/i $pc
=> 0x100fb6 <outb+10>:  out    %al,(%dx)
(gdb)
0x00100fb7 in outb ()
1: x/i $pc
=> 0x100fb7 <outb+11>:  mov    %ebp,%esp
(gdb)
0x00100fb9 in outb ()
1: x/i $pc
=> 0x100fb9 <outb+13>:  pop    %ebp
(gdb)
0x00100fba in outb ()
1: x/i $pc
=> 0x100fba <outb+14>:  ret
(gdb)
0x0010080e in IRQ_handler ()
1: x/i $pc
=> 0x10080e <IRQ_handler+68>:   add    $0x14,%esp
(gdb)
0x00100811 in IRQ_handler ()
1: x/i $pc
=> 0x100811 <IRQ_handler+71>:   pop    %ebx
(gdb)
0x00100812 in IRQ_handler ()
1: x/i $pc
=> 0x100812 <IRQ_handler+72>:   pop    %esi
(gdb)
0x00100813 in IRQ_handler ()
1: x/i $pc
=> 0x100813 <IRQ_handler+73>:   ret
(gdb)
0x0010119d in IRQ_common_stub ()
1: x/i $pc
=> 0x10119d <IRQ_common_stub+29>:       pop    %eax
(gdb)
0x0010119e in IRQ_common_stub ()
1: x/i $pc
=> 0x10119e <IRQ_common_stub+30>:       pop    %gs
(gdb)
0x0010119f in IRQ_common_stub ()
1: x/i $pc
=> 0x10119f <IRQ_common_stub+32>:       pop    %fs
(gdb)
0x001011a2 in IRQ_common_stub ()
1: x/i $pc
=> 0x1011a2 <IRQ_common_stub+34>:       pop    %es
(gdb)
0x001011a3 in IRQ_common_stub ()
1: x/i $pc
=> 0x1011a3 <IRQ_common_stub+35>:       pop    %ds
(gdb)
0x001011a4 in IRQ_common_stub ()
1: x/i $pc
=> 0x1011a4 <IRQ_common_stub+36>:       popa
(gdb)
0x001011a5 in IRQ_common_stub ()
1: x/i $pc
=> 0x1011a5 <IRQ_common_stub+37>:       add    $0x8,%esp
(gdb)
0x001011a8 in IRQ_common_stub ()
1: x/i $pc
=> 0x1011a8 <IRQ_common_stub+40>:       iret
(gdb)
0x001000ea in main ()
1: x/i $pc
=> 0x1000ea <main+49>:  add    $0x10,%esp
(gdb)
0x001000ed in main ()
1: x/i $pc
=> 0x1000ed <main+52>:  jmp    0x1000ed <main+52>
(gdb)
0x001000ed in main ()
1: x/i $pc
=> 0x1000ed <main+52>:  jmp    0x1000ed <main+52>
(gdb)
0x001000ed in main ()
1: x/i $pc
=> 0x1000ed <main+52>:  jmp    0x1000ed <main+52>
(gdb)
0x001000ed in main ()
1: x/i $pc
=> 0x1000ed <main+52>:  jmp    0x1000ed <main+52>
(gdb)
0x001000ed in main ()
1: x/i $pc
=> 0x1000ed <main+52>:  jmp    0x1000ed <main+52>
(gdb)
0x001000ed in main ()
1: x/i $pc
=> 0x1000ed <main+52>:  jmp    0x1000ed <main+52>
(gdb)

Danke schon mal. :)

Martin Erhardt

  • Beiträge: 165
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 16. February 2013, 13:33 »
CreateTask kommt mir zunächst komisch vor.
"*(void*)((unsigned int)(stack)--)"ist eigentlich(,falls das gleich "*stack--" ist), immer die address vom stack minus ein byte.
dh du schreibst immer an die gleiche stelle  0x0.
Wieso verwendest du dazu keine schöne Struktur, dann müsste man sich hier gar nicht mit pointerarithmetik auseinandersetzen
Und wieso verbietest du während deserstellen des Tasks Interrupts
void CreateTask(void* start_addr){
   unsigned int* stack;
   __asm__ __volatile__ ("cli");
   stack = (void*)(pmm_malloc()+1024);
   *stack-- = 0x202;
   *stack-- = 0x8;
   *stack-- = (unsigned int)start_addr;
   
   *stack-- = 0x0;
   *stack-- = 0x0;
   *stack-- = 0x0;
   *stack-- = 0x0;
   *stack-- = 0x0;
   *stack-- = 0x0;
   *stack-- = 0x0;
   *stack-- = 0x0;
   
   *stack-- = 0x10;
   *stack-- = 0x10;
   *stack-- = 0x10;
   *stack-- = 0x10;
   
   Tasks[task_number+1].status = 1;
   Tasks[task_number+1].stack = (unsigned int) stack;
   Tasks[task_number+1].PID = task_number+1;
   
   task_number++;
   __asm__ __volatile__ ("sti");
}
Wieso legst du eigtl einen leeren Cpu status auf den Userstack?
« Letzte Änderung: 16. February 2013, 13:44 von Martin Erhardt »

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 16. February 2013, 13:46 »
Ich hab mich bei meinem Code sehr stark an dieses Tutorial gehalten. Was kann es denn für Probleme geben, die auftreten, wenn ich Interrupts verbiete? Ich habe es beim Debuggen überprüft, beim stack wird nicht immer an dieselbe Adresse geschrieben. Ich werd's aber trotzdem umschreiben. Woran kann's denn noch liegen?

Martin Erhardt

  • Beiträge: 165
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 16. February 2013, 13:50 »
Ich hab mich bei meinem Code sehr stark an dieses Tutorial gehalten. Was kann es denn für Probleme geben, die auftreten, wenn ich Interrupts verbiete? Ich habe es beim Debuggen überprüft, beim stack wird nicht immer an dieselbe Adresse geschrieben. Ich werd's aber trotzdem umschreiben. Woran kann's denn noch liegen?
Eig gar keine ^^ soviel ich weiß, ich wollte nur wissen wieso du das machst.
« Letzte Änderung: 16. February 2013, 13:53 von Martin Erhardt »

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 16. February 2013, 13:58 »
Hm... Ich hab mir mal die Stackadresse ausgeben lassen.
multitasking_scheduler() gibt 0x1FFF74 zurück. Weiß jemand, ob das so stimmen kann?

Martin Erhardt

  • Beiträge: 165
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 16. February 2013, 14:09 »
sry die Stelle mit *stack-- ist schon richtig ich (Noob!) hab nicht gewusst das bei -- nicht nur ein dekrementierter wert zurückgegeben wird sondern auch dem Operand ein dekrementierter Wert zugewiesen wird. und weil stack vom typ uint ist stimmt auch die Pointerarithmetik.
« Letzte Änderung: 16. February 2013, 14:14 von Martin Erhardt »

Martin Erhardt

  • Beiträge: 165
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 16. February 2013, 14:16 »
Ich versteh den Code aber immer noch nicht nach dem Aufruf von multitasking_scheduler verschiebst du den aktuellen wert von esp nach eax und die addresse die die Funktion zurückgegeben hat geht verloren. vllt wolltest du mov eax esp
« Letzte Änderung: 16. February 2013, 14:17 von Martin Erhardt »

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 16. February 2013, 14:18 »
Kein Problem.
Ich verschiebe nicht den Wert von esp nach eax, sondern genau andersrum. :)

Ich hab ne andere Syntax als hier.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 16. February 2013, 15:30 »
Ich hab meinen Code jetzt mal geändert so sieht er jetzt aus:
void CreateTask(void* start_addr){
__asm__ __volatile__ ("cli");
struct cpu_state* task_state = pmm_malloc();
task_state->eax = 0;
task_state->ebx = 0;
task_state->ecx = 0;
task_state->edx = 0;
task_state->esi = 0;
task_state->edi = 0;
task_state->ebp = 0;
task_state->eip = (unsigned int) start_addr;
task_state->cs  = 0x08;
task_state->eflags = 0x202;

Tasks[task_number+1].status = 1;
Tasks[task_number+1].stack = (unsigned int) task_state;
Tasks[task_number+1].PID = task_number+1;

task_number++;
__asm__ __volatile__ ("sti");
}
Das hat aber leider nichts geändert.

Martin Erhardt

  • Beiträge: 165
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 16. February 2013, 15:40 »
Ich hab meinen Code jetzt mal geändert so sieht er jetzt aus:
void CreateTask(void* start_addr){
__asm__ __volatile__ ("cli");
struct cpu_state* task_state = pmm_malloc();
task_state->eax = 0;
task_state->ebx = 0;
task_state->ecx = 0;
task_state->edx = 0;
task_state->esi = 0;
task_state->edi = 0;
task_state->ebp = 0;
task_state->eip = (unsigned int) start_addr;
task_state->cs  = 0x08;
task_state->eflags = 0x202;

Tasks[task_number+1].status = 1;
Tasks[task_number+1].stack = (unsigned int) task_state;
Tasks[task_number+1].PID = task_number+1;

task_number++;
__asm__ __volatile__ ("sti");
}
Das hat aber leider nichts geändert.
Nö aber es ist ne schönere Lösung(finde ich zumindest :))

Ich zumindest kann jezt nichts wirklich finden vllt wird nach dem interrupt der cpu Zustand nicht richtig hergestellt mit pop %eax
pop %ebx
pop ...
oder wie auch immer das in Intel Syntax aussieht. oder deine Tasks wollen iwann returnen aber das geht nicht so wie das bei mir mal war: http://forum.lowlevel.eu/index.php?topic=3153.msg36532#msg36532
« Letzte Änderung: 16. February 2013, 15:47 von Martin Erhardt »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 16. February 2013, 16:23 »
Ein Problem ist auf jeden Fall, wie du den IRQ-Handler einrichtest. Das passt nicht zu dem Stack.

Der Interrupthandler muss auf IRET enden, nicht RET. Wenn SwitchTask der komplette Interrupthandler ist, dann fehlt das IRET. Wenn hingegen IRQ_install_handler SwitchTask so einträgt, dass er indirekt von einem Interrupthandler aufgerufen wird, dann passt die struct cpu_state nicht dazu. Ich glaube alle Tutorials im Wiki (inkl. unseres empfohlenen Tutorials) wechseln die Tasks in den Interrupt-Stubs, nicht indirekt über eine zusätzliche Methode. Ein Vorteil davon ist, dass die struct cpu_state dann einfacher ist.

Falls SwitchTask tatsächlich indirekt aufgerufen wird: Du könntest zwar die Idee den Taskwechsel in einer ausgelagerten Methode durchzuführen weiterverfolgen, aber dann musst du mindestens die struct cpu_state anpassen. Unter anderem muss dann CS raus, und du musst EFLAGS in SwitchTask manuell wechseln, ebenso wie die General Purpose Register, die in der C-Konvention als Callee-Save deklariert sind. Die übrigen Register (Caller-Save inkl. Clobber-Register wie EAX) musst du im Interruptstub wechseln. Klingt kompliziert und ist es auch. Ich weiß nicht, ob das wirklich dein Plan ist, weil du nicht den kompletten Interruptcode gezeigt hast, aber wenn ja, dann rate ich davon ab. Ich empfehle, dass du dich an die Tutorials hältst, bis du weißt, was da genau passiert.

Das mit dem Interrupts deaktivieren und wieder aktivieren halte ich auch für problematisch. (Denk mal über den Fall nach, wenn beim CLI die Interrupts bereits aus irgendeinem guten Grund deaktiviert waren. Dann aktiviert STI sie wieder, obwohl das gar nicht so sein soll.) In unseren Tutorials werden die Interrupts übrigens immer so eingerichtet, dass die Interrupts für die dauer der Behandlung deaktiviert sind, und nach Rückkehr wieder aktiviert werden. Das heißt Kernel-Code läuft immer mit deaktiviertem Interrupts und User-Code mit aktiviertem Interrupts. Das vermeidet viele Probleme.
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 16. February 2013, 16:51 »
Ja, so etwas war meine Idee.
Ich habe die Struktur cpu_state auch schon geändert. Sie sieht jetzt so aus:
struct cpu_state {
    unsigned int   eax;
    unsigned int   ebx;
    unsigned int   ecx;
    unsigned int   edx;
    unsigned int   esi;
    unsigned int   edi;
    unsigned int   ebp;
 
    unsigned int   int_no;
    unsigned int   err_code;
 
    unsigned int   eip;
    unsigned int   cs;
    unsigned int   eflags;
    unsigned int   esp;
    unsigned int   ss;
};

Ich denke, ich werde es trotzdem sein lassen, vor allem, weil ich nicht genau weiß, wie ich eflags setzen muss und was das General Purpose Register ist. :D
Habe ich es richtig verstanden, dass die Interruptbehandlung zumindest für IRQ 0 so ändern muss, dass direkt SwitchTask aufgerufen wird und in SwitchTask auch das gemacht wird, was ansonsten meine Interruptbehandlung automatisch macht?

Hier ist noch meine Interruptbehandlung.

IRQ.c
#include "system.h"

/** GLOBAL VARIABLES **/
void *IRQ_routines[16] = {
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0
};

/** GLOBAL FUNCTIONS **/
void IRQ_install_handler(int irq, void (*handler)(struct cpu_state *r));
void IRQ_uninstall_handler(int irq);
void IRQ_remap();
void IRQ_handler(struct cpu_state *r);
void IRQ_install();
extern void IRQ0();
extern void IRQ1();
extern void IRQ2();
extern void IRQ3();
extern void IRQ4();
extern void IRQ5();
extern void IRQ6();
extern void IRQ7();
extern void IRQ8();
extern void IRQ9();
extern void IRQ10();
extern void IRQ11();
extern void IRQ12();
extern void IRQ13();
extern void IRQ14();
extern void IRQ15();

void IRQ_install_handler(int irq, void (*handler)(struct cpu_state *r)){
    IRQ_routines[irq] = handler;
}

void IRQ_uninstall_handler(int irq){
    IRQ_routines[irq] = 0;
}

void IRQ_remap(){
    outb(0x20, 0x11);
    outb(0xA0, 0x11);
    outb(0x21, 0x20);
    outb(0xA1, 0x28);
    outb(0x21, 0x04);
    outb(0xA1, 0x02);
    outb(0x21, 0x01);
    outb(0xA1, 0x01);
    outb(0x21, 0x0);
    outb(0xA1, 0x0);
}

void IRQ_handler(struct cpu_state *r){
    void (*handler)(struct cpu_state *r);
    handler = IRQ_routines[r->int_no - 32];
    if(handler) handler(r);
    if(r->int_no >= 40){
        outb(0xA0, 0x20);
    }
    outb(0x20, 0x20);
}

void IRQ_install(){
    IRQ_remap();
    CreateIDTGate(32, (unsigned)IRQ0, 0x08, 0x8E);
    CreateIDTGate(33, (unsigned)IRQ1, 0x08, 0x8E);
    CreateIDTGate(34, (unsigned)IRQ2, 0x08, 0x8E);
    CreateIDTGate(35, (unsigned)IRQ3, 0x08, 0x8E);
    CreateIDTGate(36, (unsigned)IRQ4, 0x08, 0x8E);
    CreateIDTGate(37, (unsigned)IRQ5, 0x08, 0x8E);
    CreateIDTGate(38, (unsigned)IRQ6, 0x08, 0x8E);
    CreateIDTGate(39, (unsigned)IRQ7, 0x08, 0x8E);
    CreateIDTGate(40, (unsigned)IRQ8, 0x08, 0x8E);
    CreateIDTGate(41, (unsigned)IRQ9, 0x08, 0x8E);
    CreateIDTGate(42, (unsigned)IRQ10, 0x08, 0x8E);
    CreateIDTGate(43, (unsigned)IRQ11, 0x08, 0x8E);
    CreateIDTGate(44, (unsigned)IRQ12, 0x08, 0x8E);
    CreateIDTGate(45, (unsigned)IRQ13, 0x08, 0x8E);
    CreateIDTGate(46, (unsigned)IRQ14, 0x08, 0x8E);
    CreateIDTGate(47, (unsigned)IRQ15, 0x08, 0x8E);
}

void fault_handler(struct cpu_state *r){
    if(r->int_no < 32){
        print(exception_messages[r->int_no], 160+44, 0x07);
kernelerror();
restart_pc();
    }
}

IRQ.asm
; ...
[EXTERN] IRQ_handler

IRQ_common_stub:
    push ebp
    push edi
    push esi
    push edx
    push ecx
    push ebx
    push eax
 
    push esp
    call IRQ_handler
    add esp, 4
 
    pop eax
    pop ebx
    pop ecx
    pop edx
    pop esi
    pop edi
    pop ebp
 
    add esp, 0x8
 
    iret

Im Moment ist bei mir halt der IRQ_handler SwitchTask, aber man sieht ja, dass das nicht funktioniert.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 16. February 2013, 17:03 »
Habe ich es richtig verstanden, dass die Interruptbehandlung zumindest für IRQ 0 so ändern muss, dass direkt SwitchTask aufgerufen wird und in SwitchTask auch das gemacht wird, was ansonsten meine Interruptbehandlung automatisch macht?

Ja. Und natürlich den Stack wechseln statt add esp, 4.

Ein mögliches Problem, dass ich mit so einer Umsetzung sehe, ist, dass die Stacks bei verschiedenen Interrupts nun unterschiedlich aussehen. Wenn jetzt zum Beispiel ein Systemaufruf wie Sleep einen Taskwechsel verursacht, muss der ja zu einem Task wechseln können, der von einem Timer-IRQ unterbrochen wurde. Und irgendwann muss wieder zurückgewechselt werden. Kann sein, dass das kein Problem ist. Ich hab da nicht länger drüber nachgedacht, als ich an diesem Absatz geschrieben habe. Und der ist deswegen unnötig lang. 8-)
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 16. February 2013, 17:51 »
Ja. Und natürlich den Stack wechseln statt add esp, 4.
Was meinst du mit Stack wechseln? Es gibt doch nur ein esp.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 16. February 2013, 17:52 »
Damit meine ich mov esp, eax. Da wird der Wert in ESP verändert. Es wird also der Stack gewechselt.
Dieser Text wird unter jedem Beitrag angezeigt.

 

Einloggen