Lowlevel

Lowlevel => Lowlevel-Coding => Thema gestartet von: WhiteDragon am 05. October 2005, 11:15

Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: WhiteDragon am 05. October 2005, 11:15
Hallo zusammen,

also mit meinem OS bin ich nun soweit, dass ich gerne Applikationen ausführen würde. Nun habe ich in der GDT/LDT schon die Segmente für Code, Daten und Stack vorbereitet und möchte gerne in das Programm hinein springen.

Hierfür bin ich mir nicht sicher, wie ein entsprechender JMP-Befehl auszusehen hat. Descriptor-Nummer und Offset habe ich, Stack- und Datendescriptor kann ich natürlich vorher schon laden. Aber wie springe ich nun genau in die Application, damit der Code-Descriptor auch verwendet wird?

Oder gibt es eine schönere Möglichkeit, alle Daten auf den Stack zu packen und mit einem RET FAR oder etwas ähnlichem hinein zu springen? Bei einem Wiederaufsetzen auf ein schon begonnenes Programm (soll schließlich eine Multitasking-Umgebung werden) wäre natürlich auch interessant, wie ich auch die Standardregister auf ihren Ursprungswert kriege. Vielleicht wäre ein IRET dafür besser geeignet, aber ich bin leider noch etwas unerfahren in dieser Hinsicht...

Wäre schön, wenn ihr mir sagen könntet, was ein guter Weg ist oder wie ihr selbst es realisiert habt.

Gruß und vielen Dank im Voraus!
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: Legend am 05. October 2005, 12:33
Ich benutze ein IRET zum zurückspringen. Muss nur das Stacklayout vorm IRET stimmen. Registerwerte werden aus den Registern direkt übernommen.

Was das Wiederaufnehmen angeht, würde ich mal nach Software Task Switching gucken oder, wenn du willst, Hardware Task Switching.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: SSJ7Gohan am 05. October 2005, 12:56
Du brauchst nicht für jede Anwendung Segmente in der GDT/LDT, zumindest wenn du ein flaches Speichermodell benutzt.
Meine GDT sieht so aus:
1. Null Descriptor
2. Kernel Code
3. Kernel Daten
4. User Code
5. User Daten
6. TSS

Die Programme werden so geladen:
1. Eine struct die Informationen über einen Prozess enthällt wird erstellt und in eine linked list geschrieben.
2. In den neuen Prozess werden (bei mir entweder von einem JIT-Compiler, oder von einem sonstigen Programmloader) die Code/Daten/BSS Segmente gemappt. (die z.B. aus einer ELF File ausgelesen werden)
3. Dann wird eine Sturktur für eine Thread erstellt und in eine linked list geschrieben. Sie enthällt einen Stack für den Thread, der dann so aussieht, wie wenn gerade ein interrupt ausgelöst wurde, und danach alle anderen wichtigen Register gepusht wurden.

Das Programmwechseln sieht nun so aus:
1. Der Timer Interrupt wird aufgerufen.
2. Alle wichtigen Register werden gepushed (EAX, EBX, ECX, EDX, ESI, EDI, EBP, sowie die Segmentregister, wobei man das evt. sich sparen könnte, da sie Segmentregister sich ja nicht verändern. (EFLAGS, der Userlevel ESP, CS und EIP werden durch den Aufruf des Interrupts gepushed)
3. Der aktuelle Stack wird in die thread-struct geschrieben
4. Der scheduler sucht einen Thread, das alls nächstes ausgeführt wird.
5. Eventuell wird ein neues Pagedirectory geladen
6. Der neue Stack wird aus der thread-struct des neuen Threads gelesen.
7. Es werden alle wichtigen Register gepoppt.
8. IRET wird ausgeführt, um in das Programm zu springen.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: joachim_neu am 05. October 2005, 14:50
Also ich halte TSS für am besten, da du damit wirklich alle Möglichkeiten der CPU ausschöpfst, es relativ einfach zu benutzen und zu implementieren ist und du wenig selbst machen musst. (Sichern der Umgebung, ...)
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: Jidder am 05. October 2005, 14:56
Zitat von: SSJ7Gohan
2. Alle wichtigen Register werden gepushed (EAX, EBX, ECX, EDX, ESI, EDI, EBP, sowie die Segmentregister, wobei man das evt. sich sparen könnte, da sie Segmentregister sich ja nicht verändern. (EFLAGS, der Userlevel ESP, CS und EIP werden durch den Aufruf des Interrupts gepushed)

die segmentregister solltest du auch mit sichern und wiederherstellen, da ein "böses" programm diese doch ändern könnte (zumindest könnte es iirc den null deskriptor laden), und wenn dann ein anderes programm dann auf den speicher zugreift, würde dieses andere programm abstürzen.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: SSJ7Gohan am 05. October 2005, 15:20
Naja, man kann statt dem Sichern der Register auch

mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

für den kernelspace und das gleiche mit 0x20 für den userspace machen, wenn man ein gewöhnliches GDT Layout hat. Das spart dann einige Speicherzugriffe und ein paar Bytes auf dem Stack
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: Legend am 05. October 2005, 18:54
Ich fand ein PUSHA und POPA einfacher als die TSS zu benutzen ...
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: WhiteDragon am 05. October 2005, 20:27
Dank euch allen - die Entscheidung ist zwar noch nicht gefallen (muss mich mit allem mal eine Weile auseinander setzen), aber ihr habt mir schon mal Denkanstöße gegeben.

Danke!
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: joachim_neu am 06. October 2005, 17:01
Zitat von: Legend
Ich fand ein PUSHA und POPA einfacher als die TSS zu benutzen ...


Mit Softwaretasking kannst du aber nicht alle Möglichkeiten des Prozessors ausnutzen. (Soweit ich mich erinnere; z.B. dieser RM-Fake-Mode (Name is mir grade entronnen) ist meines Wissens nach an ein TSS gekoppelt)
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: Legend am 06. October 2005, 18:43
Jep, das stimmt, der v86 Modus arbeitet wohl auch mit der TSS. Leider.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: maumo am 09. October 2005, 09:09
ich würde jetzt auch lieber TSS nutzen, aber nicht so wie J!N in seinem tut, sondern einfach den TimerInterrupt als TaskGate setzten und dann einfach Backlink ändern -> viel viel leichter
ausserdem haste dann nicht tausende Stacks...
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: joachim_neu am 09. October 2005, 11:35
Zitat von: maumo
[...] sondern einfach den TimerInterrupt als TaskGate setzten und dann einfach Backlink ändern -> viel viel leichter
ausserdem haste dann nicht tausende Stacks...


Ja, dieser Weg geht auch. Allerdings finde ich ihn von der Theorie her etwas komplizierter, deswegen habe ich den anderen genommen.
"Tausend" Stacks haste mit der Methode auch, jede Applikation braucht ihren eigenen Stack...
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: Legend am 09. October 2005, 13:23
Backlink war auch so ne Sache die mich abgeschreckt hat ...
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: SSJ7Gohan am 09. October 2005, 14:41
Naja, die um angeblich 300% geringe Taskwechsel-Dauer ist meiner Meinung schon ein Grund, Software Taskswitching zu benutzen. Welche PM Funktionen kann man denn mit Software Taskswitching nicht nutzen?
Mit TSS brauchst du genauso viele Stacks, wie mit Software Taskswitching, jede Anwendung braucht mindestens einen Kernelstack und in 99.9% der Fälle wohl auch einen Userlevel Stack. Falls du Ring1 und Ring2 benutzt, brauchst du sogar noch 2 Stacks mehr.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: n3Ro am 09. October 2005, 14:49
Beim Software-Taskswitching ist es schwieriger für einzelne Tasks IO-Ports zu sperren / freizugeben, da der Mechanismus dafür auf dem TSS aufbaut. Und kleiner Tipp nebenbei: man braucht nicht immer pro Task einen Kernelstack, sondern kann auch pro CPU einen Kernelstack benutzen, das hängt ganz am Kerneldesign.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: Jidder am 09. October 2005, 15:24
Zitat von: SSJ7Gohan
Naja, die um angeblich 300% geringe Taskwechsel-Dauer ist meiner Meinung schon ein Grund, Software Taskswitching zu benutzen.

gibt es eigentlich dafür irgendwelche tests oder benchmarks oder so?
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: Legend am 09. October 2005, 15:33
Zitat von: n3Ro
Beim Software-Taskswitching ist es schwieriger für einzelne Tasks IO-Ports zu sperren / freizugeben, da der Mechanismus dafür auf dem TSS aufbaut. Und kleiner Tipp nebenbei: man braucht nicht immer pro Task einen Kernelstack, sondern kann auch pro CPU einen Kernelstack benutzen, das hängt ganz am Kerneldesign.

Stimmt, die Bitmap dafür ist in TSS. Jedoch soll die TSS sowieso pagingsensitiv sein, weswegen man es bei geschickter Positionierung hinbekommt die Bitmap gleich mit dem Wechseln von CR3 auszutauschen ...
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: joachim_neu am 09. October 2005, 17:41
Zitat von: SSJ7Gohan
Naja, die um angeblich 300% geringe Taskwechsel-Dauer ist meiner Meinung schon ein Grund, Software Taskswitching zu benutzen. Welche PM Funktionen kann man denn mit Software Taskswitching nicht nutzen?


Das heißt, dass Hardwaretasking 3 mal so lange dauert, wie Softwaretasking. Wie man das misst ist mir eigendlich schleierhaft, ich frage mich auch, wieso es länger dauert, wenn die CPU auf Hardwareebene was macht, als wenn sie Befehle abarbeitet. Erklärbar währe das damit, dass man mit TSS eben weit mehr Möglichkeiten hat, wie zum Beispiel die Sache mit dem Portbitmap oder v86-Mode.
Und dafür, dass ich mit TSS eben die CPU weit mehr ausreizen kann, nehme ich gerne in Kauf, dass es angeblich 3 mal so lange dauert.

Zitat von: Legend

Backlink war auch so ne Sache die mich abgeschreckt hat ...


Backlinks braucht man standartmäßig garnicht, jedenfalls habe ich die meines Wissens nach nicht aktiv irgendwo einbezogen. Scheint alles automatisch zu gehen... (oder ich war so müde, dass ichs in trance gemacht hab, weil ich MT mit TSS nähmlich in den osterferien um 3 uhr in der nacht eingebaut hab ;))
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: Legend am 09. October 2005, 19:47
Wohl soll das Wechseln von der TSS dann wohl drei mal so lange dauern als ein PUSHA, ein MOV um CR3 auszutauschen und noch ein POPA.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: maumo am 11. October 2005, 22:03
vorher musste ja in den kernelspace kommen, einen neuen task wählen und zurückspringen...
das sind dann auch mal n paar mov *s, eax, ...
bei hardware mt macht das die CPU für dich
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: Legend am 11. October 2005, 22:10
Nen neuen Task (also Scheduling) wählt die CPU für dich nicht aus ...
Das sind ein paar schnelle Movs gegen eine doch etwas komplexere Operation ... gute Frage.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: n3Ro am 11. October 2005, 22:12
Um die neue Task zu wählen wird doch dein Scheduler aufgerufen, und der liegt ganz bestimmt nicht im Userspace ;-)
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: bluecode am 17. October 2005, 20:12
hi,

hier (englisch) (http://www.mega-tokyo.com/osfaq2/index.php/Context%20Switching) wird erklärt warum software task-switching schneller ist. Messen kann mans auch durch den Time-Stamp-Counter in der CPU, da der jeden Prozessortick zählt (Zugriff mit rdtsc)
Ich finds außerdem einfachen! Und die Permission-Bitmap kann man ja trotzdem verwenden, da man so oder so ein TSS braucht.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: n3Ro am 17. October 2005, 20:57
Zitat von: bluecode
hi,

hier (englisch) (http://www.mega-tokyo.com/osfaq2/index.php/Context%20Switching) wird erklärt warum software task-switching schneller ist. Messen kann mans auch durch den Time-Stamp-Counter in der CPU, da der jeden Prozessortick zählt (Zugriff mit rdtsc)
Ich finds außerdem einfachen! Und die Permission-Bitmap kann man ja trotzdem verwenden, da man so oder so ein TSS braucht.


Em, naja, da steht wenn man es genauer betrachtet, dass der Hardware-Anteil an der Switching Zeit sehr lange im Vergleich zum Speichern und Laden der Register ist, und da die Hardware Switches (User nach Kernelmode, CR3 reload, Kernel nach User) sowieso auch beim Software Taskswitching durchlaufen werden, ist keinesfalls gesagt, dass es schneller sein muss.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: Legend am 17. October 2005, 23:56
Nun ja, andere Sache die mir grad aufgefallen ist: Was macht ihr mit der FPU usw. mit euren scheinbar favorisierten Task Gates auf dem Timer IRQ?
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: n3Ro am 18. October 2005, 00:08
Das Handling der FPU ist bei beiden Methoden das gleiche: durch setzen des TaskSwitched-Flags im CR0 schmeißt die nächste FPU-Instruktion eine Exception, und man kann den alten Zustand wegsichern und den neuen laden ...
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: Legend am 18. October 2005, 11:33
Hmm, interessante Methode, kannte ich noch nicht. Bin nur am Überlegen ob das bei manchen Anwendungen nicht langsamer sein könnte ...
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: n3Ro am 18. October 2005, 18:54
Langsamer im Bezug auf was? Unter der Annahme, dass nicht jede Task die FPU benötigt und wenn, dann auch nicht immer, ist es immer noch schneller als bei jedem Taskwechsel den gesamten Context zu speichern und neu zu laden, welcher bei SSE immerhin schon 512 Byte groß ist! Und wenn nur eine Task die FPU benutzt hat, kann man es so regeln, das der Context nicht gespeichert und neu geladen wird, so spart man nochmal Zeit!
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: SSJ7Gohan am 18. October 2005, 21:06
Wie kann man eigentlich mit Softwaretasking die FPU Register sichern? Bei jedem Taskswitch alle Register der FPU zu sichern ist ja viel zu langsam, gibt es da bessere Alternativen?
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: joachim_neu am 18. October 2005, 22:03
Ich hab kein Taskgate auf das Timer IRQ. Bei der FPU hab ich 2 Ideen:

1. Die FPU wird beim Kernel beantragt und ab da speichert und läd der deren Ergebnisse zusätzlich aus dem TSS.
2. Der Task schickt eine Aufgabe per IPC an den Kernel oder einen FPU-Treiber, der führt sie aus und schickt das Ergebnis zurück.

Momentan favorisiere ich die 2. Idee, da sie nicht so komplex ist und nicht so weit ins System greift, dieses also so weit wie möglich abstrakt hält.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: SSJ7Gohan am 18. October 2005, 22:13
Naja, theoretisch ist das möglich, du musst aber bedenken, das alle Programme, die in C geschrieben sind und die FPU benutzen, nicht mehr richtig laufen werden, es sei denn, man schreibt einen eigenen Compiler, der beim verwenden der FPU (also des float oder double types) automatisch den FPU-Treiber aufruft. Die 2. Möglichkeit ist ja sehr viel langsammer, da wird es schneller sein, die Register immer zu sichern.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: n3Ro am 18. October 2005, 23:19
Also: der FPU/SSE Registersatz/Zustand hat NIX mit der TSS zu tun und wird KEINESFALLS automatisch gespeichert oder geladen, geschweigedenn automatisch umgeschalten. Deswegen gibt es die fsave und frstor bzw. fxsave und fxrstor Befehle, womit man das ganze per Hand speichern und laden muss, egal ob Hardware oder Software Taskswitching. Deswegen hat dieses nette TaskSwitched Flag in CR0 Einzug gehalten, und führt wie gesagt dazu, dass FPU/SSE Befehle eine Exception auslösen, wenn es gesetzt wird. Beim Hardware Taskswitching wird es nur automatisch gesetzt!!!!!Das "Beantragen" der FPU ist außerdem die Exception, die ein FPU Befehl dabei auslöst (hier haben sich die Chip Designer mal wirklich etwas sinnvolles augedacht).@j!n:  Ein FPU Treiber ist eine grandios langsame Idee, aber die Umsetzung würd ich mir doch gerne anschauen wollen, vor allem wie "unkomplex" diese sein soll.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: Legend am 19. October 2005, 14:01
Zitat von: n3Ro
Langsamer im Bezug auf was? Unter der Annahme, dass nicht jede Task die FPU benötigt und wenn, dann auch nicht immer, ist es immer noch schneller als bei jedem Taskwechsel den gesamten Context zu speichern und neu zu laden, welcher bei SSE immerhin schon 512 Byte groß ist! Und wenn nur eine Task die FPU benutzt hat, kann man es so regeln, das der Context nicht gespeichert und neu geladen wird, so spart man nochmal Zeit!

Ja, da war ich am überlegen wie viele Programme wohl die FPU brauchen würden.
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: SSJ7Gohan am 19. October 2005, 14:22
Wann wird denn eine Exception ausgelöst, wenn man einen FPU Befehl nutzt? Muss man dazu ein spezielles Bit setzen?
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: Legend am 19. October 2005, 17:37
Steht doch oben! :P
Dieses TaskSwitched-Bit oder wie das hiess! ;)
Titel: Applikationen: Aufruf und ähnliches.
Beitrag von: n3Ro am 19. October 2005, 19:50
Ganz genau steht es übrigens im System Programming Manual für IA32 von Intel in den Kapiteln über MMX und SSE ;-)