Autor Thema: Adressraum für Kernel und Prozesse  (Gelesen 25364 mal)

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #20 am: 09. November 2010, 15:16 »
Mal was anderes, wird CR3 eigentlich jedes Mal neugeladen? Weil das wäre schon nen guter Grund kein Hardware-Multitasking zu nutzen (wenn man Threads unterstützt).

Außerdem macht das deinen Scheduler dann davon abhängig, weil du ja die TSS dann organisieren musst (du musst die dann ja im Scheduler "verlinken") und nicht mehr einfach deine Thread-Diskriptoren.

Also ich denke du musst dann schon noch an anderen Stellen anderen Code verwenden wo du dir das ohne Hardware-Multitasking sparen könntest.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #21 am: 09. November 2010, 15:33 »
Mal was anderes, wird CR3 eigentlich jedes Mal neugeladen? Weil das wäre schon nen guter Grund kein Hardware-Multitasking zu nutzen (wenn man Threads unterstützt).
Gute Frage, nächste. ;) Keine Ahnung, ehrlichgesagt. Wobei das ja sowieso keine Rolle mehr spielt, wenn der Kernel sein eigenes PD braucht, dann muss man ja auf jeden Fall wechseln.

Zitat
Außerdem macht das deinen Scheduler dann davon abhängig, weil du ja die TSS dann organisieren musst (du musst die dann ja im Scheduler "verlinken") und nicht mehr einfach deine Thread-Diskriptoren.
Hm, dieses Zeug ist mir suspekt genug (aka Protected Mode macht dem taljeth auch nach fünf Jahren noch Angst ;)), dass ich diesen Teil dann wohl doch wieder in Software basteln würde und den Inhalt des TSS durch Paging austauschen oder so.

Aber ich bin mir nicht sicher, dass der Scheduler davon was wissen muss. Gehört das nicht alles mit in den Dispatcher wie das Sichern der Register selber auch?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #22 am: 09. November 2010, 17:19 »
Hallo,


Hm, weißt du zufällig, was Hardware-MT so langsam macht? Eventuell gerade, dass der TLB jedesmal geflusht wird? Irgendwas muss ja mehr gemacht werden, damit es langsamer wird. Weiß zufällig jemand Bescheid?
Einer der Nachteile beim HW-Task-Wechsel auf x86 ist das alle Segment-Register neu geladen werden, das bedeutet 6 Descriptor-Zugriffe (und die können schon recht teuer werden wenn ein Segment noch nicht als accessed markiert ist o.ä.) und diese Descriptoren werden dann noch auf Gültigkeit geprüft (das heißt ist Executable für CS oder Readable and Writeable für SS und dazu noch diese DPL/CPL-Sachen). Ich denke gerade weil man sich (in einem Flat-Memory-OS) das Neuladen der Segmentregister spart ist auf x86 SW-Multitasking schneller. Es stimmt natürlich auch das AMD und Intel hier seit 20 Jahren keinerlei Optimierungsmöglichkeiten mehr genutzt haben, bei mir werde ich ja immerhin 16 Segmentregister (per SW) laden müssen und da will ich mit Hintergrund-Pipelining (weil der Kernel-Code diese Segmente ja gar nicht benutzt müssen die Schattenregister mit den decodierten Descriptoren auch nicht sofort zur Verfügung stehen so das die CPU in der Zeit weitere Befehle ausführen kann) einiges rausholen.
Das zwangsweise Neuladen von CR3 tut sein übriges, wobei es doch da jetzt dieses Global-Flag gibt (oder wie das heißt).

Wir reden hier eh über x86 und teilweise x86-spezifische Probleme. Interrupthandling ist nie portabel.
Die Stubs sind nie portabel (die sind immer CPU-abhängig und daher wohl auch immer in Assembler geschrieben) aber die eigentlichen (in einer Hochsprache geschriebenen) Interrupthandler sollten portabel sein (vorausgesetzt die zugehörige HW-Komponente ist identisch).


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #23 am: 09. November 2010, 17:27 »
Bei einem Ringwechsel kommt man nicht drum herum, die Segmentregister neu zu laden. Man kann sich höchstens fs und gs sparen (oder wenn man TLS haben will, nur noch eins davon).

Bei den Interrupthandlern hast du natürlich recht, das war schlampig formuliert.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #24 am: 09. November 2010, 22:18 »
Hallo,


Bei einem Ringwechsel kommt man nicht drum herum, die Segmentregister neu zu laden.
Sicher? im TSS sind die doch nur ein mal drin, vom SS mal abgesehen, und CS kommt von Interrupt-Gate. Wenn man für die Daten nur Ring3 braucht dann sollte IMHO auch der Ring 0 Code damit zurecht kommen, kleinerer aktueller Ring geht immer dachte ich eigentlich.
Oder irre ich mich da total?  (der x86-PM kann schon ziemlich verwirrend sein :roll: )
Dieses Problem müsste doch dann auch bei Call-Gates existieren, da könnte man dann ja nie einen FAR-Pointer an Code mit kleinerem Ring übergeben.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #25 am: 10. November 2010, 08:30 »
Zitat von: erik
Wenn man für die Daten nur Ring3 braucht dann sollte IMHO auch der Ring 0 Code damit zurecht kommen, kleinerer aktueller Ring geht immer dachte ich eigentlich.
Und welche Fälle fallen dir ein wo du ne Funktion vom UserMode aus aufrufst die dann nur mit den Daten aus dem UserMode läuft (ich hoffe dir fällt auf wie sinnlos das ist)?
Denn sobald du auf KernelMode Daten zugreifen willst geht das ja nicht, weil die ja genau gegen sowas geschützt sind und du dann nen KernelMode Datensegment brauchst.

Zitat von: erik
Dieses Problem müsste doch dann auch bei Call-Gates existieren, da könnte man dann ja nie einen FAR-Pointer an Code mit kleinerem Ring übergeben.
Doch, entweder du benutzt kein Paging dann sollte es eh gehen (wozu sind da die Ringe überhaupt da?) und wenn du Paging benutzt dann geht es um das kleine aber feine Flag was zw User- und KernelMode entscheidet und da ein User dir immer ein Segment mitgibt was auf UserMode-Daten zeigt, funktioniert das eben.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #26 am: 10. November 2010, 10:41 »
Hallo,


Und welche Fälle fallen dir ein wo du ne Funktion vom UserMode aus aufrufst die dann nur mit den Daten aus dem UserMode läuft (ich hoffe dir fällt auf wie sinnlos das ist)?
Es geht hier doch um die 4G-Segmente in einem Flat-Memory-System (das Ring-0-Code niemals nur mit Ring-3-Daten arbeitet ist mir völlig klar, dann würde ja Ring-3-Code reichen). Die 2 typischen Data-Segmente (einmal für Ring 0 und einmal für Ring 3) zeigen doch auf den selben virtuellen Speicher (eben die vollen 4GB) was bedeutet das der User-Mode-Code theoretisch auch volle 4GB ansprechen kann, nur das besagte Flag in dem Page-Descriptoren dient da noch als Schutz. Nur allein dieses Flag verhindert das Ring-3-Code in den Kernel-Bereich rein kann. Als zusätzliche Sicherheit könnte man noch das Limit in den Ring-3-Descriptoren auf 3GB beschränken aber dann muss man wirklich wechseln.

Ich hab extra noch mal hier nachgelesen und ich bin schon der Meinung das man bei einem Syscall nicht DS und ES wechseln muss (nur CS und SS werden von der CPU automatisch gewechselt) weil der Kernel im Ring 0 ja trotzdem mit DS und ES (DPL=3 und RPL=3) die gesamten 4GB virtuellen Adressraum ansprechen kann. Selbst beim Paging gibt es keine Probleme weil das von Dir erwähnte Flag ja wimre gegen CPL (und die ist 0 im Kernel weil CS ja automatisch gewechselt wird) geprüft wird.
Es kann natürlich sein das ich mich total irre, meine x86-Kenntnisse sind etwas eingerostet, aber ich bin schon der Meinung das Ring-0-Code auch über ein Ring-3-Segment mit dem Speicher ganz normal arbeiten kann.

Das mit dem Call-Gate ist folgender Gedanke: wenn Ring-3-Code per Call-Gate eine Ring-0-Funktion aufruft (welche dann auch wirklich mit Ring 0 läuft) und dieser einen FAR-Pointer (Selector mit RPL=3 und im Descriptor ist DPL=3) mitgibt so kann doch der Ring-0-Code problemlos mit diesem Pointer auf Speicher zugreifen. Wenn das nicht ginge könnte der Ring-0-Code ja niemals mit den Nutzdaten des Ring-3-Codes arbeiten oder er müsste jedes mal den Selector modifizieren (wegen dem RPL) und auch noch den Decriptor in der GDT/LDT ändern (wegen dem DPL) und das wäre IMHO völlig unpraktikabel.

Ich befürchte ich hab da irgendwo einen Denkfehler, nur wo?
(ich bin doch ziemlich froh mich bei meinen Segmentierungsplänen gegen x86 entschieden zu haben, der ganze CPL/RPL/DPL-Kram macht einen noch ganz verrückt)


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #27 am: 10. November 2010, 10:50 »
Ich denke, du hast in beiden Fällen recht.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #28 am: 10. November 2010, 11:02 »
Hallo,


Ich denke, du hast in beiden Fällen recht.
Ich fürchte das ich Deinen Optimismus nicht teilen kann, irgendeinen Grund muss es doch geben das alle x86-OSe 4 Descriptoren in die GDT packen obwohl doch theoretisch (wenn meine Erklärungen stimmen würden) auch 2 reichen täten.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #29 am: 10. November 2010, 11:42 »
Ich glaube, ss muss im Kernel Ring 0 bleiben, aber sicher bin ich mir nicht. Und auch sonst wären es immer noch drei, weil das Codesegment auf jeden Fall bleiben muss.

Ich hab mal testweise im Interrupt-Stub von tyndur das Laden der Ring-0-Deskriptoren für ds und es rausgeworfen und es hat ohne irgendwelche Auffälligkeiten zur Shell gebootet.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #30 am: 10. November 2010, 13:16 »
Zitat von: erik
Als zusätzliche Sicherheit könnte man noch das Limit in den Ring-3-Descriptoren auf 3GB beschränken aber dann muss man wirklich wechseln.
Es ging ja damals darum, dass sich Segmente nicht durchgesetzt haben und auf anderen Architekturen gab es halt sowas nicht. Deswegen nimmt man heute nur noch das FlatMemoryModel und regelt die Sicherheit über die Flags in den Paging Tabellen.

Zitat von: taljeth
Ich hab mal testweise im Interrupt-Stub von tyndur das Laden der Ring-0-Deskriptoren für ds und es rausgeworfen und es hat ohne irgendwelche Auffälligkeiten zur Shell gebootet.
Ich habe mal das selbe bei mir gemacht und funktioniert auch.

Jetzt bin ich aber auch baff. Denn wenn man sich das sparen kann, wäre das schon nicht schlecht.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #31 am: 10. November 2010, 13:17 »
Kann man sich nicht sparen. Ring 3 Code kann die Segment Register mit 0 laden und dann knallts im Kernel.

Edit: Man braucht außerdem einen Ring 0 Datendeskriptor, weil RPL und DPL von SS (bzw. dem Deskriptor) dem CPL entsprechen müssen.
« Letzte Änderung: 10. November 2010, 13:28 von PorkChicken »
Dieser Text wird unter jedem Beitrag angezeigt.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #32 am: 10. November 2010, 13:24 »
Sehr guter Einwand!

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #33 am: 10. November 2010, 14:02 »
Hallo,


Kann man sich nicht sparen. Ring 3 Code kann die Segment Register mit 0 laden und dann knallts im Kernel.
Und? Dann gibt es im Kernel ne Exception und die biegt DS, ES, FS und GS wieder gerade und als Straffe für den Prozess (der diese Schandtat begangen hat) wird dieser gekillt, fertig. Dafür kann man sich das Neuladen von 4 Segmentregistern im Interrupt-Stub sparen, in einem Flat-Memory-OS sind die doch eh immer gleich und da sollte man diesen Performance-Vorteil ruhig mitnehmen. Oder sieht da jemand irgendwelche ernsten Gefahren?

Man braucht außerdem einen Ring 0 Datendeskriptor, weil RPL und DPL von SS (bzw. dem Deskriptor) dem CPL entsprechen müssen.
Aha, gut das wusste ich nicht.
Aber ein Argument warum man sich das Kernel-Code-Segment nicht sparen kann gibt es scheinbar noch nicht, aber es geht mir auch nicht darum in der GDT ein paar Bytes zu sparen (das bringt IMHO wahrlich nicht viel) sondern darum das ein Neuladen der Segment-Register eigentlich nicht erforderlich ist.


Es ging ja damals darum, dass sich Segmente nicht durchgesetzt haben und auf anderen Architekturen gab es halt sowas nicht.
Es ging in der Frage, auf die ich geantwortet hatte, ausdrücklich um das HW-Multitasking von x86 und nicht um irgendwelche anderen Architekturen.

Deswegen nimmt man heute nur noch das FlatMemoryModel und regelt die Sicherheit über die Flags in den Paging Tabellen.
Du vergisst da jemanden!


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #34 am: 10. November 2010, 14:03 »
Kann man sich nicht sparen. Ring 3 Code kann die Segment Register mit 0 laden und dann knallts im Kernel.
Ich wusste doch, dass da irgendwo noch ein Problem ist, aber dieses Szenario war zu einfach. ;)

Zitat
Edit: Man braucht außerdem einen Ring 0 Datendeskriptor, weil RPL und DPL von SS (bzw. dem Deskriptor) dem CPL entsprechen müssen.
Ja, das meinte ich.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #35 am: 10. November 2010, 14:54 »
Kann man sich nicht sparen. Ring 3 Code kann die Segment Register mit 0 laden und dann knallts im Kernel.
Und? Dann gibt es im Kernel ne Exception [...]
Exceptions im Kernel sind keine gute Idee.
Dieser Text wird unter jedem Beitrag angezeigt.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #36 am: 10. November 2010, 15:18 »
Hallo,


Exceptions im Kernel sind keine gute Idee.
Dem kann ich nur voll und ganz zustimmen (auch wenn FlashBurn das sicherlich anders sieht).
Trotzdem bietet x86 eben diese Möglichkeit und an dieser konkreten Stelle finde ich das auch recht sinnvoll. Man benutzt eben ein architektur-spezifisches Feature um ein architektur-spezifisches Problem zu lösen. ;)


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #37 am: 10. November 2010, 21:26 »
Zitat von: erik
Dem kann ich nur voll und ganz zustimmen (auch wenn FlashBurn das sicherlich anders sieht).
Habe ich sowas mal irgendwann gesagt  :?

Denn ich sehe es auch, Exceptions sollte man aus dem Kernel raushalten!

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #38 am: 10. November 2010, 23:42 »
Hallo,


Zitat von: erik
Dem kann ich nur voll und ganz zustimmen (auch wenn FlashBurn das sicherlich anders sieht).
Habe ich sowas mal irgendwann gesagt  :?
Aber Du bist doch so sehr für einen unterbrechbaren Kernel eingetreten und wenn Du HW-IRQs im Kernel willst dann sind Exceptions auch nicht mehr schlimm. Trotzdem sorry das ich Dich da falsch eingeschätzt hab.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #39 am: 11. November 2010, 11:00 »
Zitat von: erik
Aber Du bist doch so sehr für einen unterbrechbaren Kernel eingetreten und wenn Du HW-IRQs im Kernel willst dann sind Exceptions auch nicht mehr schlimm.
Das sind für mich 2 Paar Schuhe.

Das eine (HW-IRQs) sind einfach nur Unterbrechungen, wie sie in jedem UserApp auch vorkommen und das andere (Exceptions) sind Fehler! Letztere möchte ich nicht im Kernel behandeln, denn Exception könnte bedeuten das ich den Fehler nicht behandeln kann und das Programm muss gekillt werden, versuch das mal mit deinem Kernel ;)

Eine Exception im Kernel heißt bei mir grundsätzlich PANIC().

 

Einloggen