Lowlevel

Lowlevel => OS-Design => Thema gestartet von: Sannaj am 11. July 2011, 19:21

Titel: Schnellste Möglichkeit des Syscalls
Beitrag von: Sannaj am 11. July 2011, 19:21
Im Wiki werden Syscalls zumeist mithilfe eines Interrupt implementiert, seltener auch mit der sysenter/sysextit-Instruktion. Beide Methoden halte ich nicht für das wahre. Interrupts prüfen zu viel Unfug vor der Ausführung. Die sysenter/sysextit-Instruktion hingegen ist auf Intel Plattformen beschränkt und stellt zudem einige Ansprüche. Im Englische Wiki wurden noch die Möglichkeit über die Invalid Opcode Fault und über far Jump aufgeführt. Diese beiden Möglickeiten erscheinen mir schon interessanter.

Darum frage ich mal: Welche Vorteile bieten die beiden Varianten und wie lässt sich die far Jump Version einsetzten? Kennt jemand noch andere Syscall Methoden?
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: Svenska am 11. July 2011, 19:37
Hallo,

Interrupts sind wirklich nicht die schnellste Variante, dafür aber auf jedem Prozessor einsetzbar. SYSENTER/SYSEXIT sind eine wesentlich schnellere Intel-spezifische Möglichkeit; auf AMD-Prozessoren gibt es die gleichwertige Variante SYSCALL/SYSRET.

Sowohl Windows als auch Linux reservieren eine Page im Speicher, die den CPU-spezifischen Code für einen Syscall enthält; dieser Code wird dann (als far jmp) einfach angesprungen und erledigt den Moduswechsel auf dem jeweils schnellsten Weg. Ein einfacher far jmp ist kein Syscall, da nicht in den Ring 0 gewechselt wird.

Traps (Exceptions) sind Interrupts, die von der CPU ausgelöst werden. Ich behaupte mal, dass die genauso langsam sind wie normale Interrupts. Mit der Variante hat MacOS in der Übergangszeit von m68k auf PPC gearbeitet, indem bei einer Invalid Opcode Exception der m68k-Emulator für den entsprechenden Codeabschnitt angeworfen wurde. Ansonsten funktioniert das wie ein Interrupt, dessen Nummer bekannt ist.

Gruß,
Svenska
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: Sannaj am 11. July 2011, 19:54
Das blöde ist halt, das sysenter/syscall nicht das selbe ist, oder lässt sich da irgend eine Uniformierung einbauen.

Das mit der Invalid Opcode Exeption hab ich mir auch gedacht, bloß komisch, das manche Systeme wie L4 das einsetzten, wenn das keine Vorteile bietet.

Aber nochmal zu der Möglichkeit mit dem far call (jmp ist ja nur in eine Richtung, hab ich vorhin nicht bedacht), die erscheint mir irgentwie Interessant. Gibt's da nicht ne Möglichkeit far call zu nutzen?
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: Svenska am 11. July 2011, 20:14
Hallo,

Auch ein far call ändert den Modus nicht. ;-)

Windows und Linux reservieren eine Page im Adressraum jedes Prozesses, wo der prozessorspezifische Code drin ist. Bei der Initialisierung des Kernels wird diese Page dann - je nach Prozessor - mit entsprechendem Code (sysenter, syscall oder interrupt) befüllt. Das geschieht also zur Laufzeit.

Call Gates sind eine Möglichkeit, wenn du stark auf Segmentierung setzt. Wenn du ein Flat-Memory-OS schreibst, wo du keine Segmente hast, ist das aber wieder mit Overhead verbunden, bringt also nichts.

Gruß,
Svenska
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: Sannaj am 11. July 2011, 20:18
Ah danke jetzt kapier ich das. Was mich verwirrt ist, das man in Linux Assemblerprogrammen Syscalls über Interrupts handelt. Besitzt das System dann zwei Syscallmethoden?

Gruß Sannaj
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: kevin am 11. July 2011, 20:31
Das blöde ist halt, das sysenter/syscall nicht das selbe ist, oder lässt sich da irgend eine Uniformierung einbauen.
Für ein Protected-Mode-OS nimmst du einfach immer sysenter und für ein Long-Mode-OS immer syscall.
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: Sannaj am 11. July 2011, 20:32
und das klappt? ich dachte immer da muss man zwischen intel und amd unterscheiden.
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: kevin am 11. July 2011, 20:42
Intel kann sysenter in beiden Modi und syscall nur im LM, AMD kann syscall in beiden Modi und sysenter nur im PM. Es gibt also in jedem Modus einen Befehl, der auf beiden läuft.
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: erik.vikinger am 11. July 2011, 20:45
Hallo,


ich bin mir nicht ganz sicher aber ich denke das an die Performance von sysenter/syscall ein Call-Gate (für das man dann einen FAR CALL benötigt) nicht ran kommt, erst recht nicht in einem Flat-Memory-OS. Wer wirklich die schnellste Methode will ist auf x86 mit sysenter/syscall IMO auf jeden Fall am besten beraten. Wer maximale Kompatibilität benötigt nutzt dann eben die Methode mit der einen Page in welche der Befehl reingemappt wird der auf der gegebenen CPU am besten funktioniert.


Grüße
Erik
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: kevin am 11. July 2011, 20:56
Wenn dafür dann eine Page ausgelagert werden muss, auf die der Syscall zugreift, ist es die langsamste Methode. ;)
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: erik.vikinger am 11. July 2011, 21:12
Wenn dafür dann eine Page ausgelagert werden muss, auf die der Syscall zugreift, ist es die langsamste Methode. ;)
Ich weiß zwar nicht welche Page Du meinst aber die Spezial-Page mit dem sysenter/syscall gibt es physisch nur ein einziges mal und wird in alle Prozesse identisch eingeblendet so das es sehr unklug wäre gerade diese auszulagern. ;)
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: kevin am 11. July 2011, 21:23
Ja, das wollte ich erst schreiben, bin dann aber zum selben Schluss gekommen. Deswegen habe ich eine andere Page genommen, die ausgelagert werden muss, weil die Syscallpage drinbleibt. Nicht, dass es viel wahrscheinlicher wäre, aber zum Haarespalten gut genug. ;)
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: erik.vikinger am 11. July 2011, 21:44
aber zum Haarespalten gut genug. ;)
Guter Versuch, aber diesmal nicht. Diesmal bleibe ich standhaft! :evil:
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: Sannaj am 11. July 2011, 21:53
Nochmal zurück zum far call. Wenn ich in der GDT das Ring 3 Segment über das Ring 0 Segment lege, kann ich doch mit einem far call auf das Ring 0 Segment wechseln und mit far ret wieder zurückkehren.
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: erik.vikinger am 11. July 2011, 22:01
Hallo,


@Sannaj:
Nein, für einen richtigen x86-PM-Ringwechsel benötigt man schon etwas mehr, entweder ein Call-Gate oder einen Interrupt/Trap.
Um eine andere Berechtigung zu bekommen muss sich auch die CPL ändern und das geht nicht so ohne weiteres sonst wäre es ja eine Sicherheitslücke.


Grüße
Erik
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: kevin am 11. July 2011, 22:07
Nein, ein "normaler" Far Call geht nur innerhalb einer Privilegstufe, sonst bekommst du einen GPF. Die Ausnahmen sind Sprünge zu Call Gates und Task Gates oder direkt zu einem TSS. (Weiß grad zufällig jemand, was der Unterschied ist zwischen Task Gate und TSS? Auf den ersten Blick hab ich das im Manual nicht gefunden.)
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: Sannaj am 11. July 2011, 22:08
Und ist das mit der Call Gate schneller als sysenter?

PS: Das mit dem far call ist logisch, sonst könnt man ja den Code als Inhalt der R3-segments laden und dann mit einem far call als r0 code anspringen.
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: kevin am 11. July 2011, 22:11
Würde mir sehr wundern, wenn Call Gates schneller wären als sysenter.
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: erik.vikinger am 11. July 2011, 22:20
Hallo,

Und ist das mit der Call Gate schneller als sysenter?
Nein, ganz sicher nicht.


@taljeth:
Ich rate mal das man ein Task-Gate auch in eine beliebige LDT packen kann und ein TSS immer in der GDT sein muss außerdem kann man einem Gate eine niedrigere Priorität (höheren Ring) geben damit das Gate auch aus weniger privilegierten Ringen benutzt werden kann.


Grüße
Erik


Und danke taljeth das Du das mit dem Haarespalten heute nicht mehr weiter verfolgst. Meine Goldwaage ist derzeit leider, äh, indisponiert. Die turnusmäßige Prüfzertifizierung muss gerade beim TÜV-Kalibrierdienst erneuert werden. Du weißt schon wegen ISO 9001 und so. Nächste Woche oder später mach ich aber gerne wieder mal bei einer richtig zünftigen Haarspalterei mit, versprochen.
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: kevin am 11. July 2011, 22:25
Naja, ein Task Gate verweist ja immer auf ein TSS, insofern hat man sich den GDT-Eintrag damit auch nicht gespart. Dass es was damit zu tun hat, höherprivilegierte Tasks aufzurufen, könnte aber sein.
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: erik.vikinger am 11. July 2011, 22:33
Naja, TSS-Descriptor benötigt man eh in der GDT aber die Gates kann man IMHO schon in die LDT packen, könnte also eine Erleichterung sein. Genau beschäftigt hab ich mich damit aber auch noch nicht, diese ganze Angelegenheit mit den Gates ist recht komplex und in meiner CPU will ich darauf konsequent verzichten (hab ja eh keine HW-Unterstützung für Tasks vorgesehen aber dafür einen richtig schnellen syscall-Befehl).
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: Svenska am 12. July 2011, 12:42
Das blöde ist halt, das sysenter/syscall nicht das selbe ist, oder lässt sich da irgend eine Uniformierung einbauen.
Für ein Protected-Mode-OS nimmst du einfach immer sysenter und für ein Long-Mode-OS immer syscall.
SYSENTER können Intel-CPUs erst ab dem Pentium II, seit wann SYSCALL existiert, weiß ich nicht. Außerdem gibt es dann ja noch so Dinge wie CPUs von VIA oder Transmeta... bei denen wäre ich mir nicht sicher, ob die das auch können.

Ah danke jetzt kapier ich das. Was mich verwirrt ist, das man in Linux Assemblerprogrammen Syscalls über Interrupts handelt. Besitzt das System dann zwei Syscallmethoden?
Ja. Wenn das Betriebssystem eine spezielle Page mit Syscall-Code hat, dann enthält der Code dort auf alten/unüblichen Prozessoren auch nur einen Interruptaufruf. Den Interrupt-Handler kann man aber auch aktiv lassen, wenn dort anderer Code ist. :-) Der offizielle Weg ist ein FAR CALL an eine bestimmte Speicheradresse (nämlich die reservierte Page).

Gruß,
Svenska
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: Sannaj am 12. July 2011, 15:10
Ok dann frag ich mal was anderes. Ist sysenter immer noch schnelle, wenn man dazu eine Funktion von der Syscall-Page aufrufen muss, als wenn man über eine Call-Gate arbeitet (dann ohne syscall-Page)
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: kevin am 12. July 2011, 15:56
Die Funktion auf der Syscall-Page ist ja nicht groß, sollte also keinen wesentlichen Unterschied zum Szenario ohne Indirektion machen.
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: Svenska am 12. July 2011, 17:00
Hallo,

um den Code in der Syscall-Page auszuführen, brauchst du einen far jump oder far call. Der ist verglichen mit dem Sysenter selbst extrem schnell. Ein Call Gate ist wesentlich langsamer (wäre es schnell, gäbe es weder Sysenter noch Syscall, weil die dann unnötig wären).

Die ganzen Verrenkungen sind schon nicht ohne Grund so, wie sie sind. ;-)

Gruß,
Svenska
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: Jidder am 12. July 2011, 17:02
Sicher, dass du nicht einen near call (absolute indirect) meinst?
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: erik.vikinger am 12. July 2011, 17:10
Hallo,


Anspringen sollte man diese Page IMHO mit einem NEAR CALL, da das User-Programm ja trotzdem nur 2 Segmente in der GDT belegt gibt es auch kein alternatives Code-Segment auf das sich ein FAR CALL beziehen könnte. Wahrscheinlich muss der CALL beim Laden des Executables reloziert werden ansonsten muss spätestens der Linker statisch wissen wo im virtuellen Adressraum diese Page liegt und genau diese Freiheit würde ich dem Kernel überlassen.

Diese spezielle Page dürfte fast keine Performance kosten. Zum einen sollte sie im Bereich des Kernel-Space liegen (nur eben auch mit Ring 3 Lesbar/Ausführbar) und als global gekennzeichnet werden damit sie bei einem TLB-Flush nicht aus dem TLB fliegt (CPUs die sysenter/syscall können können auch das). Zum anderen sollte der kurze Code (sind ja nur 2 Assemblerbefehle) direkt am Anfang stehen damit er auch immer gut ausgerichtet in eine Cacheline passt. Dieser kurze Code belegt auch nur eine einzige Cacheline und bei der häufigen Verwendung dieses Codes sollte diese Cacheline auch mindestens im L2-Cache permanent drin bleiben (da der L2-Cache üblicherweise mit physischen Adressen getaggt und indiziert ist ist diese Cachline auch für alle Prozesse nutzbar).

Den durchschnittlichen Performanceverlust durch diese Indirektion würde ich auf etwa 1 bis 4 Takte pro Benutzung schätzen.
Da die Hersteller von x86-CPUs die Segmentierung schon vor sehr vielen Jahren beerdigt haben und daher Mechanismen wie Call-Gates schon sehr lange nicht mehr optimiert wurden schätze ich den Zeitbedarf eines Call-Gates (mit allen seinen Sicherheitschecks) auf mindestens 20 Takte ein.
(alle Angaben wie immer ohne Gewähr ;) )


Grüße
Erik
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: Jidder am 12. July 2011, 17:27
Au weia. Fasse mich kurz. Telegramm teuer. Da der call indirect ist, reicht es die Adresse zur Laufzeit (Initialisierung) zu wissen.
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: erik.vikinger am 12. July 2011, 17:36
Hallo,


Da der call indirect ist
Du meinst einen Call der die Zieladresse aus einer extra Variable holt? Davon würde ich abraten da das eine weitere Indirektion ist die das ganze zusätzlich verteuert. Ein absoluter Call ist IMHO die beste Lösung und da der Executable-Loade eh Relozieren können muss (zumindest wenn man mehr als nur simpelste Executables haben will) macht das auch nichts aus.


Grüße
Erik
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: Svenska am 12. July 2011, 22:46
Sicher, dass du nicht einen near call (absolute indirect) meinst?
Meinetwegen auch einen near jump, aber die Adresse ist bekannt und konstant.
Titel: Re:Schnellste Möglichkeit des Syscalls
Beitrag von: erik.vikinger am 13. July 2011, 13:00
Hallo,


aber die Adresse ist bekannt und konstant.
Ja, zur Laufzeit auf jeden Fall.
Die Frage ist nur ab wann, also schon zur Compilezeit (dann könnte diese Adresse bereits vom Linker fest im Call-Befehl eingebaut werden) oder erst zur Ladezeit (dann muss der Executable-Loader passend Relozieren). Ich persönlich würde mich für die zweite Variante entscheiden (um dem Kernel etwas mehr Flexibilität zu geben) aber für die Performance macht das absolut keinen Unterschied.

Ein Call oder Jump dessen Zieladresse bereits der Decoder ermitteln kann (das trifft auch auf relative Sprünge zu da der Decoder ja die Adresse das Sprungs selber kennt und demzufolge auch das relative Ziel errechnen kann) kostet fast gar nichts, im Optimum kostet der wirklich 0 Takte. Call-Befehle die ihre Zieladresse erst während der Ausführung ermitteln müssen sind dagegen auf jeden Fall ziemlich teuer. Intel und AMD geben sich da zwar viel Mühe um das zu bessern, diese Calls werden auch für virtuelle Methoden benötigt, aber ganz kostenlos sind diese indirekten Sprünge auf jeden Fall nicht.

Das besondere an der hier diskutierten Situation ist natürlich das der angesprungene Code in einer speziellen extra Page liegt so das eben doch ab und an mal ein TLB-Miss oder auch ein normaler Code-Cache-Miss auftreten kann aber das dürfte wohl ziemlich selten sein.


Grüße
Erik