Du traust also dem Treiber zu, dass er nicht DMA auf "irgendwelchen" Speicher in die Hardware schreibt, traust ihm dann aber wieder nicht zu, dass er sich Speicher holen darf, den er braucht?
Naja, wenn du so ran gehst, dann brauchst du für einen Treiber gar keine Sicherheit! Wozu kontrollieren auf welche Ports der Treiber zugreifen darf?
Ich will, soweit es geht, ein wenig Sicherheit auch vor Treibern. Das ich mich nicht vor falschen DMA Adressen schützen kann, ist leider schade, aber damit muss ich leben.
Da ist der alte ISA DMA Kontroller natürlich besser zu kontrollieren. Denn den könntest du noch abstrahieren und selbst kontrollieren und die Treiber müssten dann alle DMA Anforderungen an dich (als z.B. Server) machen.
Damit weißt du also, welcher Teil des physischen Speichers wo im virtuellen Speicher eines jeden Prozesses gemappt ist.
Mein Problem hier ist, meinst du damit auch, dass ich wissen müsste in welchem Prozess die Page 0x1000 ist? Denn das könnte ich zwar rausbekommen, aber nur ziemlich umständlich indem ich von jedem Prozess die PTs einblenden müssten (in den Kernel) und die PTs dann nach der Page durchsuchen müsste. Bis das alles fertig ist, kann die Page schonwieder in einem ganz anderem Prozess sein (zwecks Swapping).
Teile des physischen Adressraums sind nicht mit Speicher unterlegt, sondern mit Konfigurationsregistern der Hardware, meist jenseits des realen RAM-Ausbaus (z.B. jenseits der 2GB). Dort muss ein Treiber also unter Umständen physischen Adressraum in seinen eigenen virtuellen Adressraum mappen, der kein RAM ist.
Was du meinst ist linearer Adressraum und virtueller Adressraum! Physischer Speicher (wie der Name schon sagt) ist wirklich vorhandener RAM!
Und wenn du auf einem 32bit System 4GB RAM hast, dann belegt auch MMIO physischen RAM, was halt weniger schön, aber unvermeidbar ist.
Wo die Adressen im virtuellen Adressraum landen, ist egal. Welche Adressen im physischen Adressraum benutzt werden, hängt konkret von der Hardware ab (Konfigurationsregister sind fest) und ist nur teilweise programmierbar (Zieladresse des DMA ist es).
Da liegst du falsch. Denn die MMIO Adressen von PCI Geräten kann man sehr wohl selber bestimmen oder wie meinst du funktioniert das!? Eigentlich macht das BIOS diese Verwaltung, aber wenn es das nicht macht, müsstest du es selber machen und genau das ist momentan bei mir nicht möglich (da ich noch nichts habe, um bestimmte Pages im PMM als benutzt zu markieren).
Wie gesagt, Teile des physischen Adressraums, den du benötigst, sind nicht mit RAM unterlegt.
Wie oben geschrieben, stimmt das leider nicht immer.
Wenn der Treiber physisch 4 MB RAM unterhalb der 16 MB fordert (weil es halt ein popeliger ISA-SCSI-Controller ist), dann wird das wahrscheinlich nicht gehen. Wenn du aber gerne physisch 4 MB RAM als Block irgendwo möchtest, dann geht das wahrscheinlich schon. Ist der RAM voll, dann geht das eben nicht. Wie auch?
Deswegen macht es z.B. Linux auch so, dass so lange wie freier Speicher >16MB vorhanden ist, wird dieser genommen und somit kann der Speicher <16MB für ISA Treiber genutzt werden. Bei meinem Bsp darf das also nicht passieren.
Mir geht es auch nicht darum das der RAM voll ist, sondern das er fragmentiert ist!
Außerdem sollte der Treiber für die Kommunikation mit dem Gerät den Speicher direkt beantragen, oder zumindest einen kleinen Block (z.B. 64 KB). Damit garantierst du auch bei voller Speicherauslastung, dass du die Hardware ansteuern kannst.
Ich habe mir das für ISA Geräte so vorgestellt, das sie immer "nur" 64KB Speicher bekommen (davon wird es 8-10 Blöcke geben) und mit diesem Block dann auch auskommen müssen.
Aber die Idee kann ich auch auf andere Treiber übertragen. Problematisch wären dann aber Systeme mit wenig RAM (im Moment soll mein OS auch mit 8MB klar kommen), wo man nicht einfach mal sagenkann , ich benutze jetzt immer 4MB um die Daten von HDD in den Speicher zu bekommen und kopiere die Daten dann in SharedMem.
Was man machen könnte, ist je nach Speicherausstattung einen Cache bei der Initialisierung anzulegen.
Was nicht ausreicht, da der physische Adressraum halt 4GB groß ist und du dort (z.B. ab 3GB) den Framebuffer der Grafikkarte oder die PCI-Konfigurationsregister findest. Die musst du auch verwalten!
Im Moment gehe ich noch davon aus, dass das BIOS diese Arbeit für mich schon gemacht hat, aber ich werde mir wohl nochmal was einfallen lassen müssen wie ich es mache, wenn das nicht der Fall ist. Wobei hier dann auch die Frage aufkommt, wie bekomme ich raus, dass das BIOS die Arbeit schon gemacht hat?
Was hat dein Treiber davon, wenn er sich jede einzelne Page, die er für die Kommunikation mit der Hardware braucht, einzeln anfordern muss? Außerdem garantierst du ja nicht, dass die Pages zusammenhängend sind.
Der Treiber fordert ja nicht jede Page einzeln an, sondern er muss für jede Page einzeln nachgucken welche physische Adresse dahinter steckt und das genau wegen dem Grund, dass die Pages nicht zusammenhängend sein müssen (es bei der Initialisierung aber höchst wahrscheinlich sein werden).
Erklär du mal dem HDD-Controller, dass er die ersten 4 KB nach 0x3400 0000, die zweiten 4 KB nach 0x3800 0000 und die dritten 4 KB nach 0x3400 8000 schreiben soll. Das heißt, du programmierst die Hardware dreimal, um 12KB von der Festplatte zu lesen.
Im schlimmsten Fall, ja
![Wink ;)](https://forum.lowlevel.eu/Smileys/classic/wink.gif)
Aber bevor es soweit kommt, würde ich halt sagen, der Treiber guckt wieviel RAM das System gesamt hat und legt sich danach einen Cache an (für DMA) und damit ist das Problem dann auch gegessen. Obwohl es gerade bei der HDD nicht die Welt sein sollte, für jede Page eine neue Anfrage zu machen, da ersten die Datei sowieso fragmentiert sein könnte (dann musst du das eh machen) und die Festplatte so "langsam" liest das sich an der absoluten Zeit nicht viel ändern wird.
Implementier lieber zwei Funktionen:
*getPhysMem( int size, ptr physAddr )
-> gib mir "size" Bytes ab physisch "physAddr" zurück
=> malloc() mit gegebener Adresse für deinen PMM
*getPhysMem( int size, ptr *physAddr )
-> gib mir "size" Bytes Speicher und schreibe in "physAddr" die physische Adresse rein
=> malloc() mit Rückgabe der verwendeten physischen Adresse
Also beide Funktionen haben schonmal das Problem (was aber auch nur meiner Sichtweise entspricht) das sie mit "Bytes" arbeiten, aber die Größe eigentlich auf 4KB Blöcke beschränkt ist.
Dann habe ich bei der ersten Funktion noch das Problem, versuche das mal bei einem PMM der mit nem Stack arbeitet!
Die 2. Funktion ist da schon eher was für mich, aber siehe weiter unten.
Wenn du willst, kannst du noch einen Alignment-Parameter mit einbinden, wenn du z.B. Hardware hast, die ein Alignment >4K braucht.
Gibt es sowas (also wo die Adresse wo das Gerät hinschreiben soll ein Alignment >4K brauch)? Das wäre ein echtes Problem
![Sad :(](https://forum.lowlevel.eu/Smileys/classic/sad.gif)
Was du dir sparst:
- Prozesse müssen die PageTables nicht selbst parsen können (Portabilität, vgl. taljeth)
- Prozesse haben keine Möglichkeit, das Mapping zwischen virt. und phys. Adressraum rauszukriegen (Sicherheit)
- nur ein Syscall pro Treiber und Adressraumblock
Was die Portabilität betrifft, siehe meine Antwort darauf und auch muss es der Treiber nicht selbst könne (siehe selbe Antwort).
Mir hat noch keiner eine wirkliche Antwort gegeben wo das Sicherheitsproblem wäre, wenn der Treiber die PTs parsen könnte.
Beim Parsen der PTs hätte ich auch nur einen Syscall.