Autor Thema: Multitasking in meinem OS einbauen.  (Gelesen 25119 mal)

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #40 am: 06. December 2005, 18:10 »
Ja, ich mein ja nur. Weiss, das sind blöde Beispiele.
@legend Danke für dein Tut !!

bitmaster

  • Troll
  • Beiträge: 1 138
    • Profil anzeigen
    • OS-64 = 64 Bit Operating System
Gespeichert
« Antwort #41 am: 06. December 2005, 22:39 »
Juhu, ich habe jetzt Hardwaremultitasking in meinem OS integriert. Es funktioniert so weit auch alles. Nur habe ich zwei Probleme. Erst zum kleineren Problem. Ich habe den Timer noch Standardmäßig laufen. Das heißt der wird soweit ich weiss jetzt 18,2 mal pro Sekunde aufgrufen. Das ist natürlich zu wenig. Meine Frage ist, wie und auf was soll ich den Timer stellen? Jetzt das größerere Problem. Unter allen PCs von mir und Bochs, VMware läuft alles wunderbar. Nur unter Microsoft Virtual PC erhalte ich eine Meldung: Interner Fehler auf virtuellen Computer. Dann wird neu gestartet. Weiss einer von euch vielleicht woran das liegen könnte? Ich werde morgen meinen Code durch jmp $ durchgehen und weiss dann vielleicht mehr. Aber vielleicht kennt einer von euch den Fehler ja schon. Also vieles dank.

Danke!!!
In the Future everyone will need OS-64!!!

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #42 am: 07. December 2005, 14:04 »
Schau mal im PM Tut von der FH Zwickau. Dort wird das umstellen gezeigt. Ich empfehle dir den Timer etwa 100 Mal in der Sekunde (100 Hertz)laufen zu lassen.

Gruss
Noooooooos

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #43 am: 07. December 2005, 17:28 »
Aber mal ne Frage. Wie startet man bei Software-MT am besten einen neuen Task ????

SSJ7Gohan

  • Beiträge: 398
    • Profil anzeigen
Gespeichert
« Antwort #44 am: 07. December 2005, 18:00 »
#define KERNEL_STACK_SIZE 4096

typedef struct {
unsigned long *stack_base;
unsigned long *stack_ptr;
} Task;

Task *createTask(void *entry) {
// speicher für den stack anfordern
char *stack = malloc(KERNEL_STACK_SIZE);

if(stack == NULL)
return NULL;

// stack-pointer berechnen (stack wächst von oben nach unten)
unsigned long *sp = (unsgined long *)(stack + KERNEL_STACK_SIZE);

// alle register auf den stack pushen, die dein taskswitch code erfordert
// ss (wird vom iret gepopt)
*(sp--) = 0x10;

// esp (wird vom iret gepopt)
// in diesem beispiel muss der task selbst seinen esp auf einen gültigen wert setzen
*(sp--) = 0;

// eflags (wird vom iret gepopt)
// ich weiß nicht aus dem kopf, was für eflags richtig sind
*(sp--) = 0;

// cs (wird vom iret gepopt)
*(sp--) = 0x8;

// eip (wird vom iret gepopt)
*(sp--) = (unsigned long)entry;

// eax, ebx, ecx, edx, ebp, esi, edi
*(sp--) = 0;
*(sp--) = 0;
*(sp--) = 0;
*(sp--) = 0;
*(sp--) = 0;
*(sp--) = 0;
*(sp--) = 0;

// ds, es, fs, gs
*(stack--) = 0x10;
*(stack--) = 0x10;
*(stack--) = 0x10;
*(stack--) = 0x10;

Task *task = malloc(sizeof (Task));

if(task == NULL)
return NULL;

task.stack_base = stack;
task.stack_ptr = sp;

return task;
}


task.stack_base muss immer im TSS als Ring0 ESP eingetragen werden, wenn man den Task wechselt. Um den Task zu wechseln im Timer Interrupt, müssen alle register gepushed werden, der ESP in task.stack_ptr gesichert werden, der neue task muss ausgewählt werden, new_task.stack_base ins TSS eingetragen werden, new_task.stack_ptr muss in ESP eingetragen werden, alle register müssen gepopt werden, und dann muss iret ausgeführt werden.

bitmaster

  • Troll
  • Beiträge: 1 138
    • Profil anzeigen
    • OS-64 = 64 Bit Operating System
Gespeichert
« Antwort #45 am: 07. December 2005, 19:17 »
Also irgendwie verstehe ich das nicht. Der Fehler in Microsoft Virtual PC tritt auf, wenn er den IRQ0 läd. Aber nur wenn es sich dabei um einen Task-Gate in der IDT handelt. Nutze ich einen Interrupt-Gate funktioniert das wunderbar. Aber damit Multitasking funktioniert (Hardware) muss ich ja ein Task-Gate benutzen. Aber das finde ich komisch. Alle anderen Emulatoren und meine PCs laufen damit. Nutzt ihr Task-Gates(s) in eurem OS? Und funktioniert dieses unter Microsoft Virtual PC? Hier mal den Eintrag in der IDT:

;IRQ0 = Timer
dw 0000h                ;always zero
dw task1_tss_selector   ;Task State Segment Selektor
db 00h                  ;always zero
db 10000101b            ;type
dw 0000h                ;always zero


Das ist doch richtig oder? Schließlich funktioniert es ja überall, nur nicht unter MS-VPC. Könnt ihr mir helfen? Wisst ihr warum?

Danke!!!
In the Future everyone will need OS-64!!!

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #46 am: 08. December 2005, 08:47 »
Also muss man bei SM einen Task so starten ???
-In die Task-Tabelle den neuen Platz vom Stack eintragen
-Auf diesen Stack CS:IP und die Flagsspeichern
-Und nacher noch die Startwerte für die Register dort speichern.
-Und sobald der neue Task das erstemal vom Timer drankommt, werden die Register zurückgeladen und der Task das ausgeführt

Ist das richtig so ????? Ginge es auch einfacher ????

SSJ7Gohan

  • Beiträge: 398
    • Profil anzeigen
Gespeichert
« Antwort #47 am: 08. December 2005, 13:26 »
Ja, das ist richtig so. Bei Userlevel Tasks musst du noch darauf achten, das du die Segmentregister richtig setzt, da sind ein paar Bits anders als beim Kernellevel, steht aber im PM Tutorial.

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #48 am: 08. December 2005, 13:28 »
Also das gilt nur für Ring3 Tasks??? Oder ???

Danke!!!


Gruss
Noooooooos

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #49 am: 08. December 2005, 16:15 »
Also um einen neuen Task zu laden, muss ich zu aller erst CS:IP und die Flags des neuen Tasks auf dessen neuen Stack legen. Aber in welche Reihenfolge geschiet das ????

-EFLAGs (Double Word)
-CS (Word)
-EIP (Double Word)

Stimmt diese Reihenfolge so, oder nicht ?????

Gruss
Nooooooos

SSJ7Gohan

  • Beiträge: 398
    • Profil anzeigen
Gespeichert
« Antwort #50 am: 08. December 2005, 16:34 »
Zuerst SS, dann ESP, EFLAGS, CS und EIP. Sowie ich oben beschrieben hatte. Auch wenn CS und die anderen Segmentregister nur ein Word sind, sind wie du warscheinlich weißt alle Stackelemente 4 Bytes (also ein DWORD) groß. Der Beispielcode von mir oben müsste eigentlich funzen, ich habe ihn aber nicht getestet.^^

Osbios

  • Beiträge: 247
    • Profil anzeigen
Gespeichert
« Antwort #51 am: 08. December 2005, 19:00 »
Zitat von: SSJ7Gohan
Zuerst SS, dann ESP, EFLAGS, CS und EIP. Sowie ich oben beschrieben hatte. Auch wenn CS und die anderen Segmentregister nur ein Word sind, sind wie du warscheinlich weißt alle Stackelemente 4 Bytes (also ein DWORD) groß. Der Beispielcode von mir oben müsste eigentlich funzen, ich habe ihn aber nicht getestet.^^

Die Größe ist aber egal, denn alle POP/PUSH Aktionen verändern den Stackpointer um 4 Byte. Also auch wenn man POP AL benutzt, verbraucht das 4 Byte Stack im Pmode.
db 0x55AA

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #52 am: 08. December 2005, 19:12 »
Ja dein Code funzt, ich hatte nur Probleme einen neuen Task zu starten. Um einen zu starten, kann ich nun alle Elemente auf einen neuen Stack pushen und dann warten, bis er vom Timer-Interrupt ausgeführt wird.

SSJ7Gohan

  • Beiträge: 398
    • Profil anzeigen
Gespeichert
« Antwort #53 am: 08. December 2005, 19:14 »
@Osbios
Ja, es ist schon klar, das push esp um 4 verringert, aber wenn man den Stack wie in meinem Beispiel mit C erstellt, muss man halt daran denken, das alle Elemente 4 Bytes groß sind.

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #54 am: 10. December 2005, 14:48 »
Also irgendwie funktioniert der Code um einen neuen Task zu laden immer noch nicht.
Mein Stack im Kernel ist auf 0x90000, der vom neuen Task auf 0x80000. Mein neuer Task hat ein Label "neuerTask".

mov esp,0x80000                                   ;Stack vom neuen Task laden

push ss                                   ;ss und esp auf den Stack
push esp

mov eax,0x0                                   ;Die EFLAGS mit lauter nullen laden
push eax

mov ax,0x8                                   ;Der Selektor vom Codesegment
push ax

mov DWORD eax,neuerTask                                   ;Offset vom Codeteil
push eax

xor eax,eax                                   ;Alle Register auf 0 setzen
xor ecx,ecx
xor edx,edx
xor ebx,ebx
xor ebp,ebp
xor esi,esi
xor edi,edi

pushad                                   ;Alle Register pushen, damit sie der Timer Interrupt laden kann.

mov esp,0x90000


Was ist daran falsch ?

SSJ7Gohan

  • Beiträge: 398
    • Profil anzeigen
Gespeichert
« Antwort #55 am: 10. December 2005, 15:07 »
Hm, ich würde einfach die Werte, die auf den Stack sollen in den Speicher schreiben, und nicht ESP wechseln und dann die Werte poppen. Wenn du den Kernel in C schreibst, kannst du meinen Code nehmen, sonst übersetz ihn einfach in ASM.

Ausserdem ist es warscheinlich ungültig, das Flagregister auf 0 zu setzen, guck die Belegung der Bits mal im PM Mode Tutorial nach.

Du pushst den falschen ESP auf den Stack, der ESP Wert auf dem Stack wird der ESP des Programms und nicht der Kernel-ESP des Programms.

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #56 am: 10. December 2005, 15:12 »
Zitat von: SSJ7Gohan
Du pushst den falschen ESP auf den Stack, der ESP Wert auf dem Stack wird der ESP des Programms und nicht der Kernel-ESP des Programms.


Hä ?? Muss dann der Kernel ESP (also Ring 0 Stack ???) nicht der selbe sein, wie der des Programms ????

Ich habe gemeint, die sind identisch.

Erklär mir das bitte genauer.

Danke
Noooooooos

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #57 am: 10. December 2005, 21:57 »
Wie geht jetzt das ????

Muss der Kernel-ESP eines Programms verschieden sein, mit dem normalen Stack eines Programms.  Können sie auch identisch sein ????

Gruss
Nooooooooos

SSJ7Gohan

  • Beiträge: 398
    • Profil anzeigen
Gespeichert
« Antwort #58 am: 10. December 2005, 22:03 »
Du brauchst für jedes Programm 2 Stacks (brauchst du beim Hardwaretasking übringens auch):

-> Einen Stack, der benutzt wird, wenn ein Interrupt auftritt. Wenn ein Interrupt auftitt wird der ESP und SS Wert aus dem TSS geladen. Daher muss er ja dort immer aktualisiert werden.
-> Einen Stack, den die Anwendung für ihre Daten usw. nutzt. Der wird beim Interrupt auf den neuen Stack gepusht, und vom IRET wieder runtergenommen.

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #59 am: 10. December 2005, 22:08 »
Aha

Danke vielmals !!!!

 

Einloggen