Autor Thema: Logisim CPU  (Gelesen 160006 mal)

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #200 am: 14. May 2013, 20:06 »
Ich interpretiere deinen Mechanismus mit den "Permission-Registern" als Versuch bestimmte Funktionen als privilegiert zu markieren. Und du willst, dass nur diese privilegierten Funktionen Operationen an dem Mapping zwischen virtuellen und physischen Adressen ausführen dürfen. Dadurch soll gewährleistet werden, dass kein Programm Änderungen an dem Mapping vornehmen kann, um den Kernel bzw. andere Programme unzulässig zu beeinflussen. Ist das richtig?

Das reicht nämlich nicht. Du brauchst definitiv eine konkrete Trennung zwischen User-Mode und Kernel-Mode mit einem definierten Übergang. Ein Problem ist folgendes: Einzelne Funktionen als privilegiert zu markieren reicht nicht, weil es funktionale Abhängigkeiten zwischen den Kernelbestandteilen gibt. Eine privilegierte Funktion, die die Page Tables ändert, ist ja kein Selbstzweck, sondern wird von vielen anderen Funktionen, z.B. aus der Speicherverwaltung (sowas wie malloc und free, ganze Seiten anfordern/freigeben für Treiber, ...), Prozessverwaltung (z.B. Erstellung eines neuen Adressraums), oder Interprozesskommunikation (Shared Memory) aufgerufen. Und natürlich ruft vermutlich jeder Bestandteil im Kernel malloc/free auf, also irgendwann landet jeder mal in einer privilegierten Funktion. Das Problem ist, dass eine privilegierte Funktion nicht feststellen kann, zu welchem dieser Zwecke sie verwendet wird. Sie kann ohne definierten Übergang zwischen User-Space und Kernel-Space auch nicht feststellen, ob sie gerade von einem Programm aufgerufen wird. Ein Programm könnte den System-Zustand (Registerinhalte und Stack) so hindrehen, dass es aussieht, als ob die Funktion aus dem Kernel aufgerufen wird, obwohl das nicht der Fall ist. Das kannst du nur verhindern, indem du dafür sorgst, dass jeder Aufruf vom User-Space in den Kernel durch eine "Schleuse" (Interrupt/Syscall) geht.

Ein weiteres Problem ist, dass du mit dem Mechanismus nur Code schützt. Daten sind entweder ungeschützt, unzugänglich für nicht privilegierte Funktionen oder nicht gemappt. Wenn sie nicht gemappt sind, müssen sie erst von einer privilegierten Funktion gemappt werden, was ebenfalls die eben beschriebenen mit sich bringt, und darüberhinaus langsam ist. Das verkompliziert die Kernel-Entwicklung erheblich.
« Letzte Änderung: 14. May 2013, 20:08 von Jidder »
Dieser Text wird unter jedem Beitrag angezeigt.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #201 am: 14. May 2013, 23:52 »
Hallo,

Zitat
Der Übergang von User- in Kernel-Mode sollte nur durch bestimmte Befehle (Interrupts, Syscall) möglich sein, sonst kannst du dir die Unterscheidung gleich sparen. Außerdem sollten bestimmte Befehle im User-Mode verboten sein.
Naja ich hab bei mir kein software-interrupts eingebaut, mit interrupts in den kernel-Mode zu kommen wird daher eher schwierig :D Und wieso sollten Befehle verboten sein ?
Ob du Syscalls nun über Interrupts, Call Gates, spezielle Syscall-Befehle oder Longjmp machst, ist an sich total egal. Wichtig ist, wie Jidder schrieb, dass dieser Durchgang die einzige Möglichkeit ist, um in den Kernel-Mode zu kommen - dann kannst du alle Berechtigungen nämlich an dieser Stelle prüfen.

Warum du bestimmte Befehle im User-Mode sperren solltest? Weil sie dein Betriebssystem gefährden können. So Dinge wie HLT (hält die CPU bis zum nächsten Interrupt an) oder CLI/STI (spiele am Interrupt-Flag rum) sind da ganz wunderbare Kandidaten.

Dein Ansatz ist nicht tauglich, um das Problem zu lösen.

Gruß,
Svenska

Dimension

  • Beiträge: 155
    • Profil anzeigen
Gespeichert
« Antwort #202 am: 15. May 2013, 10:53 »
Ich glaube er will bestimmte Prozedureinsprungspunkte markieren, so dass diese bei Aufruf in einen privilegierten Modus wechseln und mit privilegierten Rechten ausgeführt werden. Vor dem RET muss die privilegierte Funktion den privilegierten Modus beenden, da die Markierungen nur in eine Richtung funktionieren.

Diese Markierungen und das "privileged mode Flag" sind wiederum nur schreibbar, wenn der privilegierte Modus aktiv ist, so auch beim Systemstart.

Aber so richtig verstanden habe ich es wohl auch nicht.

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #203 am: 25. May 2013, 18:20 »
Naja meine idee ist glaub wirklich nicht so gut wie ich anfangs dachte...Meine CPU wechselt jetzt einfach bei einem interrupt in den Kernel-Mode , auserdem bau ich dazu noch ein software-interrupt ein. Nun spezielle Befehle die nur im Kernelmode benutzt werden dürfen werd ich glaub nicht einbauen. Die größten Probleme macht mir noch der Systemstart..das Panging muss ja da deaktiviert sein da die Tabellen noch nicht beschrieben sind oder ?

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #204 am: 26. May 2013, 00:48 »
Die größten Probleme macht mir noch der Systemstart..das Panging muss ja da deaktiviert sein da die Tabellen noch nicht beschrieben sind oder ?
Das Stichwort dabei nennt sich "Reset-Logik". Deine MMU kann nach einem Reset durchaus aktiv sein, wenn sie nach einem Reset automatisch ein 1:1-Mapping herstellt. Streng genommen muss das auch nicht für den ganzen Speicher gelten, sondern z.B. nur für die erste Page.

Was genau unterscheidet deinen Kernel-Mode vom User-Mode?

Gruß,
Svenska

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #205 am: 26. May 2013, 16:49 »
Zitat
Was genau unterscheidet deinen Kernel-Mode vom User-Mode?
Nun im Kernel-Mode darf man auf die MMU tabellen und den interrupt-controler zugreifen.

Zitat
Das Stichwort dabei nennt sich "Reset-Logik". Deine MMU kann nach einem Reset durchaus aktiv sein, wenn sie nach einem Reset automatisch ein 1:1-Mapping herstellt. Streng genommen muss das auch nicht für den ganzen Speicher gelten, sondern z.B. nur für die erste Page.
Mhh cool, hab schon ne idee wie ich das umsetzten könnte XD.

Auserdem ist mir noch was beim Paging aufgefallen was ich nicht ganz verstehe...
Nun normalerweiße ist das ja so:
Der jeweilige Eintrag im Page Direcory dient als Basis-adresse für die Page-table. Und aus dem jeweiligen Eintrag der Page table und dem Offset wird dann die Physikalische Adresse.


Wiso macht man das dann nicht so:
Das aus dem Jeweiligen eintrag Der Page-Directory und der Page-Table zusammen mit dem Offset die physikalische adresse wird.



streetrunner

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #206 am: 26. May 2013, 20:44 »
Ziel einer MMU ist es aus einer virtuellen eine reale Speicheradresse zu machen. Das heißt u.U. das zwei unterschiedliche Adressen auf die selbe reale Adresse gemappt werden. Spielen wir dieses Beispiel einmal durch:

Angenommen die Adressen 0xFFF00xxx und 0xFFFFFxxx sollen auf die selbe Adresse gemappt werden.
Damit müssten sowohl der Eintrag 768 (die unteren 10Bit von F00) als auch der Eintrag 1023 (die unteren 10Bit von FFF) in der Page-Table den selben Wert enthalten. Leider ist es aber so dass man nur 10Bit hat um die insgesammt 1024 Einträge zu adressieren. Wenn nun aber 2 Einträge den selben Wert enthalten bleibt zwangsläufig ein Wert auf der Strecke, für den kein Platz in der Page-Table mehr ist. Daraus resultiert dann nicht addressierbarer Speicher, da die passenden (Teil)-Addressen einfach nicht in der Page-Table vorhanden sind. Gleiches gilt natürlich auch für das Page-Directory. Dabei ist es egal, wo jetzt Werte fehlen, der verschwendete Speicherplatz ist von der selben Größenordnung und beträgt (richtig gerechnet vorrausgesetzt) pro nicht vorhandenem Wert 4MB.

Hoffe mal ich hab da nichts übersehen, dann wäre das wahrscheinlich hinfällig.


Tante Edit sagte mir gerade dass das teilweise kompletter Unsinn ist was ich da oben geschrieben habe. Aber ich steh zu meinen Fehlern. :-D

Daher auf ein neues:
Wenn ein OS einen Neuen Task startet, dann legt es üblicherweise neue Paging-Tabllen an, damit der Task über den kompletten Adressraum verfügen kann, ohne irgendwem ins Handwerk zu pfuschen. Sinn dieser Tabellen ist nun neben der Adressumwandlung der MMU mitzuteilen, ob der betreffende Task überhaubt an diese Speicheradressen schreiben darf. Desweiteren fehlen manchmal Einträge, da diese entweder nicht in den Adressraum des Tasks gehören oder nicht im Speicher vorhanden sind (Swapping). Dies kann nun nur für eine einzige Page der Fall sein. Bei deiner Lösung müsste man dafür aber wieder einen kompletten Eintrag in deinen Tabellen löschen, womit sich direkt 4MB Speicher verabschieden.

Hoffe diesmal, das mir nicht im Nachhinein einfällt, dass das auch Unsinn ist....

Gruß,
Streetrunner
« Letzte Änderung: 26. May 2013, 21:52 von streetrunner »

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #207 am: 27. May 2013, 00:54 »
Hallo,

also laut Wikipedia wird das so gemacht.
Der PD-Eintrag ergibt direkt die oberen 10 Bits der linearen Adresse, der PT-Eintrag die folgenden 10 Bits, der Offset sind dann die verbleibenden 12 Bits.

Gruß,
Svenska

streetrunner

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #208 am: 27. May 2013, 11:34 »
Wie die lineare Adresse zustande kommt habe ich auch verstanden. Sieht man sich aber das Beispiel auf Wikipedia an (ich denke mal, Svenska meint das erste Schaubild), so erkennt man das dort nur eine große Tabelle existiert. Diese hat 2^n Einträge, auf Tufelix Bsp. angewandt ergeben sich damit 2^20 Einträge. Tufelix hat aber nur 2 x 2^10 = 2^11 Einträge. Irgendwo muss es also einen Haken geben, und dieser liegt darin dass in einem PT-Eintrag immer der selbe Wert steht, unabhängig vom PD-Eintrag. So steht z.B. im PT-Eintrag 127 immer der Wert 0x3FF, unabhängig davon welchen Eintrag ich im PD selektiert habe (vorausgesetzt natürlich ich habe auch wieder den Eintrag 127 im PT selektiert). Dies könnte aber unerwünscht sein, da eventuell der Wunsch aufkommen könnte, bei unterschiedlichen PD-Einträgen unterschiedliche PT-Werte im PT-Eintrag 127 zu haben.

Gruß,
Streetrunner

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #209 am: 30. May 2013, 18:09 »
Mhh was sind eigentlich Translation Lookaside Buffer? Sind das die Seiten-tabellen ?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #210 am: 30. May 2013, 18:18 »
Das ist ein Cache für die Page Tables, damit die CPU nicht für jeden Speicherzugriff zusätzlich nochmal auf den Speicher zugreifen muss, um die Mappings auszulesen.
Dieser Text wird unter jedem Beitrag angezeigt.

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #211 am: 31. May 2013, 12:53 »
Mhh wieso baut man die Page-Tables nicht direkt in die MMU?  Wär doch praktischer :D.

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #212 am: 31. May 2013, 13:23 »
Weil vom Kernel eine beliebige Anzahl an PageDirectories (pro Prozess eine) und damit PageTables erstellt werden kann. Und damit bräuchtest du in der MMU sehr viel Speicher (genug um seeehr viele PTs zu halten, wie viele es werden kannst du ja nicht beeinflussen)

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #213 am: 01. June 2013, 17:36 »
Mhh wieso baut man die Page-Tables nicht direkt in die MMU?  Wär doch praktischer :D.
Das hat man zu Zeiten des Z80 auch gemacht. Bei 4 KB pro Page und 1 MB adressierbarem Speicher in einem 64 KB-Adressraum, ohne Flags, dafür aber mit langsamen CPUs und noch viel langsamerem Speicher kann man das machen (z.B. 74xx189).

Bei 32-Bit-x86ern müsstest du 4 MB in extrem schnellem Speicher halten (vergleiche mal, wieviel Cache in modernen CPUs drin ist und wieviel Platz (=Kosten) der auf dem Wafer wegnimmt). Außerdem müsstest du diese (bis zu) 4 MB bei jedem Taskwechsel zwischen Speicher und MMU hin- und herkopieren, was zusätzlich Speicherbandbreite kostet.

Bei 64 Bit-Adressräumen geht das überhaupt nicht mehr.

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #214 am: 03. June 2013, 16:39 »
Naja dann bau ich mal die Pages auch in den hauptspeicher ein. Auserdem leg ich die Page directory und die page table zusammen zu einer großen Tabelle damit die MMU nur ein speicherzugriff auf den hauptspeicher machen muss um eine adresse zu berechnen. Zudem bau ich so nen Translation Lookaside Buffer mit 256 wort größe in der MMU ein und dazu noch ne Daten/Befehls-Cache mit 512 wörter in der CPU ein.
Nun laut wikipedia gibts ja für die cache 2 schreib stategien -write-back und write-through. Meine frage ist etwas blöd...welche von den beiden strategien ist die bessere ?  :-D
« Letzte Änderung: 03. June 2013, 16:41 von Tufelix »

streetrunner

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #215 am: 03. June 2013, 17:22 »
Zu deiner MMU:
Ich denke mal Du versuchst folgendes: Du hast irgendwo ein Register in dem die Adresse Deiner "großen" Tabelle steht. Wenn nun ein Speicherzugriff erfolgt, braucht Deine MMU nur an "Adresse + Offset" nachsehen wohin es denn wirklich geht. In sofern funktioniert das, aber das Problem wird sein dass Du im Adressraum einen extrem großen Bereich (bei 32Bit, bei x86_64 im "Maximalausbau" dann 512GB) an zusammenhängendem Speicher reservieren musst, um dort Deine Tabelle abzulegen. Das ist in sofern unglücklich, da nun zwar jeder Prozess per Default extrem viel Speicher reservieren kann, ABER diesen vermutlich überhaubt nicht braucht (man überlege sich hier dass ein Prozess bei x86_64 allein 512GB für das Paging verschwendet, auch wenn er selbst nur 1MB wirklich braucht).

Und nun zum Cache:
Letztenendlich kommt es darauf an wie viel Aufwand Du betreiben möchtest. Geht man davon aus dass Deine CPU nur alleine arbeitet, dann ist Write-Allocation wohl die beste Wahl. Dabei wird bei einem Cache-Hit der Wert in den Cache geschrieben und mit dem sogenannten "Dirty-Bit" als "nicht mit dem Haubtspeicher übereinstimmend" markiert. Der Haubtspeicher wird dabei nicht angerührt. Bei einem Cache-Miss wird der Wert ebenfalls direkt in den Cache geschrieben, ist dieser voll muss halt irgendwas überschrieben werden (möglichst etwas was bereits im Haubtspeicher liegt). Sonst ist es wie beim Cache-Hit. Das Problem bei allen Varianten die den Zugriff auf den Haubtspeicher vermeiden ist, dass andere Geräte die auf den Haubtspeicher zugreifen (DMA, andere CPUs) eventuell mit den falschen Daten arbeiten. Das Problem mit den CPUs kann man relativ einfach umgehen, indem man einen großen (mittlerweile L3) Cache hat auf den alle CPUs zugreifen und mit dem alle CPUs ihre Daten abgleichen. Dauert zwar bei neu geschriebenen Daten (Cache-Miss) etwas länger, aber immer noch bedeutend kürzer als auf den RAM zuzugreifen. Mit DMA ist das dann etwas schwierieger, da müsstest Du Dir dann eine Lösung überlegen.

Gruß,
Streetrunner

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #216 am: 03. June 2013, 17:25 »
Wenn eine von beiden die bessere wäre, dann wäre nur diese bei Wikipedia erwähnt worden.

Write-Back: Manchmal sparst du einen unnötigen Speicherzugriff, wenn die Daten noch im Cache sind. Manchmal kann ein Miss beim Lesen aber auch dafür sorgen, dass zweimal auf den Speicher zugegriffen werden muss, weil erst der alte Inhalt zurückgeschrieben werden muss, bevor der neue gelesen werden kann. Das sorgt dafür, dass die Kosten für manche Zugriffe auf andere Zugriffe umverteilt werden, also manche Schreibzugriffe sind schnell, dafür aber ein folgender Lesezugriff langsam.

Write-Through: Mehrfache Schreibzugriffe auf die selbe Line sind langsamer. Dafür ist es einfacher zu umzusetzen.

Ich hoffe, dass du nicht vor hast, nur einzelne Worte zu cachen, sondern ganze Lines. Ansonsten verlierst du den Hauptvorteil des Caches: Ausnutzung von räumlicher und zeitlicher Lokalität. In Logisim würde ich übrigens tendenziell keine Caches verwenden, weil jeder Speicher gleichschnell ist, was bei einer Harvard-Architektur jeden Vorteil aufhebt, und Caches bei einer von-Neumann-Architektur ganz schnell unnötig kompliziert werden.
Dieser Text wird unter jedem Beitrag angezeigt.

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #217 am: 03. June 2013, 18:40 »
Zitat
In Logisim würde ich übrigens tendenziell keine Caches verwenden, weil jeder Speicher gleichschnell ist, was bei einer Harvard-Architektur jeden Vorteil aufhebt, und Caches bei einer von-Neumann-Architektur ganz schnell unnötig kompliziert werden.
Naja werden in der Cache die Virtuelle oder die physikalische adresse gespeichert ?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #218 am: 03. June 2013, 19:33 »
Es geht beides. Virtuelle Adresse hat den Vorteil, dass man keinen TLB-/Page-Table-Zugriff machen muss bzw. ihn parallel zum Cachezugriff ausführen kann. Physische Adresse hat den Vorteil, dass man bei einem Adressraumwechsel den Cache nicht flushen muss. Man kann für L1- und L2-Cache auch unterschiedliche Strategien fahren. Zum Beispiel kann man im L1-Cache virtuelle und im L2-Cache physische Adressen verwenden und den TLB-Zugriff parallel zum L1-Zugriff ausführen.

Mein Punkt war eher, dass ich glaube, dass Caches in Logisim einiges an zusätzlicher Logik für das Laden und Sicherstellen der Konsistenz erfordern, aber die CPU nicht wirklich beschleunigen.
Dieser Text wird unter jedem Beitrag angezeigt.

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #219 am: 03. June 2013, 22:42 »
Zitat
Mein Punkt war eher, dass ich glaube, dass Caches in Logisim einiges an zusätzlicher Logik für das Laden und Sicherstellen der Konsistenz erfordern, aber die CPU nicht wirklich beschleunigen.
Naja, dachte mir das wenn die Cache mit vituelle adressen arbeitet und dadurch weniger adressen von der MMU berechnet werden muss, die CPU schneller wird...aber stimmt eigentlich, der Geschwindigkeit-vorteil ist glaub in logisim so gering, da könnte ich eigentlich einfach mehr TLB buffer einbauen, das bringt glaub mehr  :roll:

 

Einloggen