Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: bitmaster am 03. December 2005, 19:23
-
Also ich habe demnächst vor, in meinem OS Multitasking einzubauen. Da gibt es je Kooperatives und präemptives. Kooperatives schließe ich schon mal aus, weil es unsicher ist und vieles nicht kann. Also werde ich präemptives Multitasking benutzen. Aber da gibt es so weit ich weis auch wieder zwei unterschiede. Einer nennt sich Softwaremultitasking und der andere Hardwaremultitasking. Ich glaube die Namen heißen so, weil ich beim Softwaremultitasking die ganzen Register selber (also meine Software) sichern muss. Beim Hardwaremultitasking wird dies automatisch gemacht. Also jetzt würde ich von euch gerne wissen was ihr mir empfehlen würden und warum. Welche Vor-/ oder Nachteile hat jeweils das andere gegenüber dem anderen. Aus Joachim Neumanns Tutorial werde ich ehrlich gesagt nicht so schlau. Also was würdet ihr mir empfehlen. Ich wäre auch dankbar für Links, Tutorials, Downloads etc.
Bitmaster
-
Meiner Meinung nach ist Software Multitasking in allen Anwendungsbereichen besser als Hardwaretasking.
Vorteile:
-> Es ist schneller (Der Taskwechsel selber ist 3mal so schnell wie beim Hardwaretasking)
-> Man hat eine größere Kontrolle über den Taskswitch, man kann bestimmen, welche Register gespeichert werden usw. (Es ist z.B. unsinnig ss, es, ds, fs und gs zu speichern, wenn sie in einem flachen Speichermodell eh alle die selben Werte haben.)
-> Man kann es leichter erweitern. Speichern der FPU Register usw. lässt sich leicht einbauen.
-> Es ist leichter einzubauen. Man muss nicht an den TSS und Descriptor rumwerkeln, man braucht zwar immernoch ein TSS, das muss man aber nur einmal initialisieren und dann beim jedem Taskswitch den ESP im TSS ändern, das wars aber schon. Über dieses TSS kann man z.B. auch die IO Permission Bitmap nutzen, um einzelne Ports zu sperren usw.
-> Es ist portabler (x86-64 unterstützt z.B. kein Hardwaretasking mehr, andere Prozessoren enthalten es überhaupt nicht.)
-
-> Man hat eine größere Kontrolle über den Taskswitch, man kann bestimmen, welche Register gespeichert werden usw. (Es ist z.B. unsinnig ss, es, ds, fs und gs zu speichern, wenn sie in einem flachen Speichermodell eh alle die selben Werte haben.)
und ein prozess lädt dann ds mit 0 und freut sich wie die anderen prozesse abstürzen? die segmentregister sollte man schon speichern, oder zumindest bei jedem taskwechsel wieder auf einen gültigen wert setzen. dann kann man sie aber auch gleich sichern und neu laden ...
-> Man kann es leichter erweitern. Speichern der FPU Register usw. lässt sich leicht einbauen.
das speichern der fpu, sse, mmx, etc register ist beim software- und hardwaretaskswitching gleich, wenn ich mich nicht irre.
das killerargument ist aber die geschwindigkeit. software multitasking soll schneller sein. ob das stimmt weiss ich nicht und ich habe auch nie konkrete messergebnisse gesehen, aber plausibel klingts.
-
Ja, man muss natürlich die Segmentregister wieder auf einen gültigen Wert setzen, aber warum auf den Speicher zugreifen, wenns auch schneller geht? Man muss ausserdem beachten, dass die Segmentregister in Ring0 anders sind usw. Trotzdem kann man mit Softwaretasking mehr beeinflussen, was man sicher und was nicht, man könnte etwa die Debugregister speichern usw.
-
und ein prozess lädt dann ds mit 0 und freut sich wie die anderen prozesse abstürzen? die segmentregister sollte man schon speichern, oder zumindest bei jedem taskwechsel wieder auf einen gültigen wert setzen. dann kann man sie aber auch gleich sichern und neu laden ...
Wenn man ein Flatmodel benutzt sind die Register immer gleich! Egal welcher Task gerade läuft. Und um mögliche Veränderungen eines Tasks nicht mit in einen anderen zu übernehmen (z. B. gs=0) kann man sie, wie du ja selber sagst, jedesmal auf den Standardwert setzen.
-> Man kann es leichter erweitern. Speichern der FPU Register usw. lässt sich leicht einbauen.
das speichern der fpu, sse, mmx, etc register ist beim software- und hardwaretaskswitching gleich, wenn ich mich nicht irre.
Stimmt! Wenn man es wie vorgesehen über IRQs macht ist das kein Unterschied.
das killerargument ist aber die geschwindigkeit. software multitasking soll schneller sein. ob das stimmt weiss ich nicht und ich habe auch nie konkrete messergebnisse gesehen, aber plausibel klingts.
Da muss ich auch nicht ganz unrecht geben, jedoch hat es seine Gründe weshalb HT im Longmode nicht mehr unterstützt wird. Eine meiner Vermutungen ist die größere Freiheit für die Programmierer bei ST weshalb HT fast nicht genutzt wird.
PS: Kann mal jemand gute Beispiele für ein schnelleres ST posten? Also was für Optimierungen durch ST alle möglich sind.
-
Grundsätzlich ist (ich selbst habs noch nicht getestet) ein einfach Softwaretasking der Art:
pusha
mov [taskstack], esp
call scheduler
mov esp, [taskstack]
popa
iret
schon schneller als Hardwaretasking.
Man kann es aber noch optimieren, indem man nur benötigte Register pusht. Von pusha wird auch ESP und SS gepusht, was man aber nicht braucht, da es schon vom Interruptgate gesichert wird usw.
-
Also ihr meint das ich Softwaremultitasking benutzen soll. Gibt es keinen nachteil gegenüber dem Hardwaremultitasking? Weis man welches Windows/Linux benutzt? Also gut dann werde ich warscheinlich Softwaremultitasking benutzen. Kennt ihr noch Dokumente, Referenzen, Tutorials etc. wo so etwas - eventuell sogar mit Code - erklärt wird?
Danke!!!
-
Linux und Windows nutzen beide Softwaremultitasking.
Legend hat mal ein Tutorial geschrieben, benutz mal die Suchfunktion^^
-
Legend hat mal ein Tutorial geschrieben, benutz mal die Suchfunktion^^
Meinst du das hier? http://legendos.codingworld.net/tutorials/software_task_switching.html Es funktioniert leider nicht.
-
Linux und Windows nutzen beide Softwaremultitasking.
Ich dachte unter Softwaretasking könnte man z.B. keinen VM86-Mode verwenden. Aber Win kann trotzdem 16Bit-Anwendungen ausführen... Irgendwas ist da nicht korrekt.
-
Mit dem VM86 Mode hab ich mich noch nicht beschäftigt, aber soweit ich weiß muss man da nur EFLAGS ändern, was ja auch mit IRET möglich ist.
-
Wie geht das denn, mit dem einzelnen TSS? Was wird da neugeladen?
Gruss
Noooooooooos
-
Man läd beim Starten des Kernels mit LTR einmalig das TSS. Danach trägt man vor jedem Taskswitch Ring0 ESP (und evt. Ring0 SS, wenn SS in verschiedenen Tasks anders ist, die meisten nutzen aber einen flachen Addressraum, daher ist das normalerweise nicht notwendig) in das TSS ein. Neugeladen wird da garnichts. Das TSS wird nur benötigt, damit bei einem Interrupt der Ring0 ESP richtig gesetzt wird.
-
Also bei was für einem Interrupt. Timer ??? Fehler ???? Oder ein Intrerupt mittels "int" vom Programm aus ??? Muss dieses TSS irgendwie verlinkt mit anderen Deskriptoren usw. sein ???
Gruss
Nooooooooos
-
Legend hat mal ein Tutorial geschrieben, benutz mal die Suchfunktion^^
Meinst du das hier? http://legendos.codingworld.net/tutorials/software_task_switching.html Es funktioniert leider nicht.
Ja, meine Seite zieht bald um. Der Vertrag für den Rootserver ist nun vorbei, die meisten anderen hatten keine Lust mehr, da sie es nicht hinbekommen hatten zusammenzuarbeiten.
Ich nehme mal an das AMD Hardware TS aus dem Long Mode genommen hat da es nun mal auch in Software ging und man sich theoretisch Prozessorfunktionen sparen kann. Jetzt müsste eine CPU auch nur den Long Mode unterstützen, diese könnte dann ein paar Transistoren sparen. ;)
-
Bei jeder Art von Interrupt (wenn in der IDT ein Interrupt Gate eingetragen ist) wird folgendes gemacht:
-> Switch zu Ring0
-> Der Ring0 ESP wird aus dem TSS gelesen und der Ring3 ESP wird auf den neuen Stack gepushet
-> Ring0 SS wird aus dem TSS gelesen und der Ring3 SS wird auf den Stack gepushed
-> CS:EIP wird auf den Stack gepushet
Daher braucht man auch bei Softwaretasking ein TSS, man muss es aber nicht neuladen, es reicht, Ring0 ESP und SS zu ändern, wärend man das TSS geladen lässt. Die anderen Felder des TSS sind egal, man muss nur ein TSS erstellen, einen Descriptor dafür in die GDT eintragen und es dann mit LTR laden.
-
Ich nehme mal an das AMD Hardware TS aus dem Long Mode genommen hat da es nun mal auch in Software ging und man sich theoretisch Prozessorfunktionen sparen kann. Jetzt müsste eine CPU auch nur den Long Mode unterstützen, diese könnte dann ein paar Transistoren sparen. ;)
Sparen? Du vergisst den Abwärtskompatibilitätswahn von x86. ;)
-
Deswegen habe ich theoretisch gesagt.
-
Dann wird bei iret das ganze umgekehrt gemacht oder ?????
Oder? , das TSS wird dazu verwendet, um den Stack vom Task auch im höher privilegiertem Timer zu sichern ????? Korrigiert mich !!!!
Aber wäre es nicht sinnvoller/schneller gar kein "ltr" Befehl kein TSS .... zu benutzen. Denn man könnte ja einfach anfangs Timer den Stack vom Task nocheimal in "sp" laden und dann die Register sichern. Warum macht man das nicht ??????
Gruss
Noooooooooooos
-
Bevor du irgend etwas laden kannst muss ich schon die Rücksprungaddresse gesichert werden.
-
@Legend: Hast du zufälligerweise noch irgendwo auf deiner Festplatte (oder sons wo) dein Tutorial, was du mir schicken könntest?
Das wäre sehr nett.
-
Ja, auf meiner Platte ist das noch. Das wären schon zwei die das wollen, wenn ich dann eure Email-Addressen haben könnte? *g*
-
Ja, auf meiner Platte ist das noch. Das wären schon zwei die das wollen, wenn ich dann eure Email-Addressen haben könnte? *g*
privat@osm-page.de
danke!!!
-
doru91@bluewin.ch
-
Bevor du irgend etwas laden kannst muss ich schon die Rücksprungaddresse gesichert werden.
Wie meinst du das jetzt ????
Ginge es rein theoretisch Software-Multitasking ohne TSS zu realisieren ???? Dann wäre das System ja noch schneller ?????
-
Die Rücksprungaddresse, sprich z.B. EIP vom Prozess der unterbrochen wurde (und noch ein paar Dinge mehr) werden von der CPU gesichert bevor dein Code im ISR zum Zuge kommt. Und diese werden auf dem Stack von dem Ziel-ISR gesichert, weil der Stack wohl vom Betriebssystem verwaltet wird.
Du kannst Software Task Switching ohne TSS machen, solange du keine sog. Ring Transisitions hast, also Sprünge von Ring zu Ring (z.B. von Ring 3 durch einen ISR der in Ring 0 behandelt wird). Das bedeutet jedoch das dann dein ganzes System im Ring 0 laufen müsste.
-
Ah, jetzt ist alles klar. Danke vielmals!!!!!
-
Schade das ich nichts bekommen habe. Aber ich werde es mit Hardwaremultitasking machen, indem ich das ptl vom IRQ0 ändere.
-
Ich habe auch noch gar nichts verschickt. In der Uni hab ich das Dokument irgendwie nicht rumliegen.
-
Also ich würde dir Software MT empfehlen: Einfacher, schneller und du hast die voller Kontrolle über alles was abläuft.
Gruss
Noooooooos
-
Also ich würde dir Software MT empfehlen: Einfacher, schneller und du hast die voller Kontrolle über alles was abläuft.
Gruss
Noooooooos
Wie kommst du darauf das es einfacher ist? Hardwaremultitasking ist auch nicht sonderlich schwer (nachdem ich es verstanden habe). Ich brauche ja nur einen TSS-Deskriptor anzuspringen. Wieso unter Software MT volle Kontrolle? Das hat man doch unter Hardware MT auch. Ob Softwaremultitasking wirklich schneller ist, ist auch eine Frage. Und selbst wenn es schneller ist, wird es wohl so gering sein das man es gar nicht merkt.
PS: Wo steht eigentlich das Windows und Linux Software MT verwenden?
-
Auf die PS-Frage habe ich mal ein bisel gesucht und einen sehr interessanten Artikel gefunden: http://neworder.box.sk/newsread.php?newsid=10562
Dort wird auch über fast alle hier gestellten Fragen geschrieben.
Sehr lesenswert!!!
-
Ich habe das Gefühl, wenn die Hälfte von der CPU erledigt wird, kann man selbst einfach nicht mitmischen. Denn bei Hardware-MT werden viele Sachen gesichert, die man gar nicht braucht.
Angenommen die TSS-Variante braucht 30 Takte mehr dann ist das bei einem Timer von 100 Herz (etwa nötig für MT) 3 000 Takte pro Sekunde, pro Minute 180 000. Und das ist dann nicht mehr wenig. (finde ich :) )
-
Denn bei Hardware-MT werden viele Sachen gesichert, die man gar nicht braucht.
Was denn zum Beispiel?
-
Vieleicht kann es sein, dass man manche Register nicht braucht, oder dass das OS nur die Ringe 0 und 3 braucht ????
-
@Legend: Danke für das Tutorial. Aber ich werde Hardwaremultitasking in meinem OS benutzen.
Danke!!!
-
Angenommen die TSS-Variante braucht 30 Takte mehr dann ist das bei einem Timer von 100 Herz (etwa nötig für MT) 3 000 Takte pro Sekunde, pro Minute 180 000. Und das ist dann nicht mehr wenig. (finde ich :) )
Naja, bei einer 3 GHz CPU haste 180.000.000.000 Takte pro Minute.
-
Angenommen die TSS-Variante braucht 30 Takte mehr dann ist das bei einem Timer von 100 Herz (etwa nötig für MT) 3 000 Takte pro Sekunde, pro Minute 180 000. Und das ist dann nicht mehr wenig. (finde ich :) )
Naja, bei einer 3 GHz CPU haste 180.000.000.000 Takte pro Minute.
Hä? Wie kommst du denn darauf?
-
Hab ich auch herausgefunden. Aber in dieser Zeit kann man immerhin sehr viel machen. Aber es kann sein, dass das OS auf einem älteren PC läuft... Oder vieleicht sogar mal auf nem GameBoy oder iPod ??...???
-
Hä? Wie kommst du denn darauf?
Nur zum Vergleich wie viel es von der Gesammtleitung eines "aktuellen" Prozessors beansprucht. Daher kann man sich seine gedanken machen wie sehr es sich lohnt da zu optimieren. Nicht dass ich jetzt was gegen Optimierung hätte. :wink:
Hab ich auch herausgefunden. Aber in dieser Zeit kann man immerhin sehr viel machen. Aber es kann sein, dass das OS auf einem älteren PC läuft... Oder vieleicht sogar mal auf nem GameBoy oder iPod ??...???
GameBoy oder iPod mit x86 Technik?
-
Ja, ich mein ja nur. Weiss, das sind blöde Beispiele.
@legend Danke für dein Tut !!
-
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!!!
-
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
-
Aber mal ne Frage. Wie startet man bei Software-MT am besten einen neuen Task ????
-
#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.
-
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!!!
-
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 ????
-
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.
-
Also das gilt nur für Ring3 Tasks??? Oder ???
Danke!!!
Gruss
Noooooooos
-
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
-
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.^^
-
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.
-
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.
-
@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.
-
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 ?
-
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.
-
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
-
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
-
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.
-
Aha
Danke vielmals !!!!
-
Also, dann muss ich in meiner Tabelle eigentlich nur den Task des Programmes des Kernels speichern ????
-
Hm? Ich versteh den Satz nicht^^
-
In der Tabelle, die ich fürs Multitasking brauche muss ich also nicht den Stack des Tasks selbst (der Stack für Daten usw.) eintragen, sondern den Stack des Tasks des Kernels (der, der benuzt wird, wenn ein Interrupt auftritt..).
-
Ja, genau.
-
Dann ist alles klar.
Danke!!!!
Nooooooooooos
-
Das erstellen eines Tasks funzt halt immer noch nicht. Ich progge in Assembler und wäre froh, wennn mir einer ein Code-Beispiel geben würde. Ich poste hier mal meinen Code. Was ist daran falsch ????
Stackpointer:
heip:
dd 0
hcs:
dd 0x8
heflags:
dd 0x3202
hesp:
dd 0x70000
hss:
dd 0x10
Die Adresse die das Label Stackpointer beinhaltet steht in meiner Task-Tabelle. EIP wird während der Laufzeit mit der Adresse eines Tasks geladen. Der Fehler tritt dann auf, wenn nach dem iret des Timers versucht wird, eben diese Daten zu laden. Bochs meldet: "Can_push(): esp < N" und dass eine 12. Exeption aufgetreten ist.
Gruss Nooooooooos
-
Hm, in Assembler müsste das so aussehen:
task_ss equ 0x10
task_esp equ 0x70000
task_eflags equ 0x3202
task_cs equ 0x8
task_eax equ 0
task_ebx equ 0
task_ecx equ 0
task_edx equ 0
task_esi equ 0
task_edi equ 0
task_ebp equ 0
; 1024 elemente großen stack erstellen
[section .bss]
resd 1024
task_stackbase:
[section .text]
; erstellt einen neuen task
; erwartet den eip in eax
; und gibt den sp des kernelstacks in eax zurück
create_new_task:
; später solltest du den speicher für den stack dynamisch allokieren
mov [task_stackbase - 4], task_ss
mov [task_stackbase - 8], task_esp
mov [task_stackbase - 12], task_eflags
mov [task_stackbase - 16], task_cs
mov [task_stackbase - 20], eax
mov [task_stackbase - 24], task_eax
mov [task_stackbase - 28], task_ebx
mov [task_stackbase - 32], task_ecx
mov [task_stackbase - 36], task_edx
mov [task_stackbase - 40], task_esi
mov [task_stackbase - 44], task_edi
mov [task_stackbase - 48], task_ebp
mov eax, task_stackbase - 48
ret
task_switch_isr:
push eax
push ebx
push ecx
push edx
push esi
push edi
push ebp
; scheduler aufrufen und nächsten task bestimmen
; dann esp switchen
; eoi senden
mov al, 0x20
out 0x20, al
pop ebp
pop edi
pop esi
pop edx
pop ecx
pop ebx
pop eax
iret
btw, bei ring0 tasks wird kein SS und ESP auf den stack gepusht (und vom iret auch nicht gepopt), wenn ein interrupt eintritt. Wenn der Ring nicht gewechselt wird, ändert sich der ESP auch nicht beim Interrupt.