Lowlevel
Lowlevel => OS-Design => Thema gestartet von: nooooooooos am 22. December 2005, 12:56
-
Hallo
Wie realisiert ihr die Kommunikation unter verschiedenen Modulen? Bei mir laufen alle Module in Ring3. Wie kann ich jetzt eine bestimmte Funktion oder ein bestimtes Modul aufrufen ???? Macht ihr das mit Interrupts? Oder geht das auch mit Gates usw...
Gruss Noooooooos
-
Hallo,
Vor der Sache stehe ich auch grade. Warscheinlich arbeite ich basierend auf einem Nachrichtensystem. Sprich der Kernel verwaltet einen großen Briefkasten und jeder Task kann in den Briefe reinwerfen und welche für sich rausholen und dann verarbeiten. Auf dieser Struktur kann man dann auch einfach Streams und Co implementieren.
Gruß,
Joachim
-
Ich hatte mir überlegt, alles über Shared Memory und Signale sowie RPC zu machen. RPC und Signale werden benutzt, um einfache Nachrichten zu versenden, über Shared Memory werden Daten übertragen.
-
Ist RPC ein Hardwareteil im Computer, etwas von der CPU oder einfach eine Technik ??
Wie würde man einen solchen Breifkasten realisieren ???
-
hi,
RPC (Remote Procedure Call) ist eine technik und wird so nicht von der CPU unterstützt. Es bedeutet imho, dass man eine Funktion innerhalb eines anderen Addressraums ausführt und dabei Parameter übergeben kann und auch ein/mehrere Rückgabewerte bekommt.
Ein Briefkasten könnte der Kernel einfach so implementieren: Jeder Prozess der eine Nachricht/Brief senden will führt einen syscall aus und übergibt zB in den Registern die parameter oder vllt auch nur einen pointer auf einen zu kopierenden speicherblock. Der kernel speichert dann die parameter/den speicherblock in zB dem zum Prozess gehörenden std::vector<letter*>. Will der andere Prozess an die briefe/nachrichten kommen führt er auch einen syscall aus und bekommt die parameter in den registern geliefert oder in einen Puffer kopiert.
Hoffe das hilft :!:
-
Und also SYSCALL benutzt ihr Interrupts? Oder wäre da ein Deskriptor in der GDT besser/schneller ?
@bluecode: Ja, das hilft. Danke
Gruss
Noooooooos
-
nun den, nun den; ich hab auch ein modularisiertes Kernelprinzip und hab auch schon ein Interface ausgearbeitet: (kruze Einführung)
Alle Kernel module werden mit PL=0 in alle Virtuellen Adressräume eingelinkt. (0-32 MB)
Am Anfang der 32 MB steht [m]ein "Kernel NT Emulator".
Um eine Funktion aufzurufen ruft der User ein API macro auf, welches zu dem Kernel NT Emulator über ein Call Gate springt.
Dabei push das API macro noch den ESP und die Adresse der Funktion.
der ESP wird als letztes gepusht, und im gall cate geb ich 1 stackframe zu kopieren an.
dan change ich den stack im Kernel NT Emulator und springe zur angegebenen Adresse.
Und wenn ein Kernel modul das API macro aufruft, springt das Macro direkt zur funktion, ohne umschweife des Kernel NT Emulators.
Mehr info auf Anfrage.
Übrigens heißt Kernel NT Emulator Kernel Nested Task Emulator for Paging and Extensions.
Vieles davon ist auch meiner Doku zu entnehmen.
lg,
Toaster
-
Was bedeutet pl=0? Was soll denn der NT Kernel Emulator bewirken ???
Gruss Noooooooos
-
PL = Privilege Level;
Also in welcher Privilegsstufe der Code ausgeführt wird.
Dazu gibts 2 Faktoren: Segmentierung + Paging
Der Kernel NT Emulator bewirkt einen Privilegewechsel UND einen Stack wechsel, den sonst niemand schafft, da dass so gut wie nur mit call gate geht,
-
Naja, meine Module werden von einem JIT Compiler kompiliert und wie alle Java/Bytecode Anwendungen in Ring0 ausgeführt. Ring3 Programme werden nur aus Kompitibilitätsgründen unterstützt. Wenn ein Ring3 Programm ein Ring0 Modul aufrufen will, macht es einen SYSCALL/SYSENTER/INT (je nachdem, was auf dem System unterstützt wird) in den Kernel, der dann die Parameter, die in den Registern übergeben werden, pushed, und dann den kompilierten Bytecode aufruft. Threads (egal welche Privilegstufe) können wie in meinen letzten Posts beschrieben kommunizieren.
-
Ah, danke. Jetzt hab ich eine Ahnung, wie ich das machen werden.
Gruss
Noooooooooos
-
Naja, meine Module werden von einem JIT Compiler kompiliert und wie alle Java/Bytecode Anwendungen in Ring0 ausgeführt. Ring3 Programme werden nur aus Kompitibilitätsgründen unterstützt.
Ist das nicht verdammt unsicher? Wenn in deinem Compiler ein Bug drinn ist, könnte man damit ordentliche Ausfälle provozieren...
-
Naja, meine Module werden von einem JIT Compiler kompiliert und wie alle Java/Bytecode Anwendungen in Ring0 ausgeführt. Ring3 Programme werden nur aus Kompitibilitätsgründen unterstützt.
Ist das nicht verdammt unsicher? Wenn in deinem Compiler ein Bug drinn ist, könnte man damit ordentliche Ausfälle provozieren...
Wenn in deinen Routinen zum Shared Memory ein Bug drin ist kann ich bei dir evtl. Daten von anderen Prozessen, wenn in deinen Kernel Routinen ein Buffer Overflow drin ist kann ich Code auf Ring 0 ausführen, usw.
Von der Sicht aus ist es nicht unsicherer als andere Konzepte.
-
Ich habe bisher noch kein SharedMemory. ;) Aber die Unsicherheit der anderen Mittel "rechtfertigt" nicht die Unsicherheit des eigenen Mittels, oder? Ist so ein Compiler nicht irre aufwendig?
-
Sofern der Compiler richtig funktioniert, ist das System 100%ig sicher. Es könnten nur im Kernel oder Compiler Fehler auftreten, der Kernel und Compiler Code ist aber immernoch überschaubarer und leichter zu debuggen, als tausende native Treiber. Ausserdem habe ich den Vorteil, dass die Treiber selber das System nicht zum Absturtz bringen können, nur der falsch kompilierte Code könnte das System abstürtzen lassen, ich muss also nur einen verhälltnissmässig leichten/kleinen Codeteil im Compiler ändern.
-
nur nochmal ne kurze Zwischenfrage:
Wird euer Javacode beim Laden eines Treibers in maschinencode kompiliert oder wird er als java bytecode ausgeführt :?: Inwieweit stehen dem Java code I/O Funktionen zur Verfügung :?:
-
Er wird vor dem Ausführen kompiliert.
Der Compiler ist noch nicht fertig, daher gibt es noch keine genaue Spezifikation über den Zugriff auf I/O Funktionen. Generell ist das eh vom Compiler unabhängig, und ich denke, ich werde es etwa so implementieren:
(Das habe ich mir grad mal ausgedacht und das ist sicher nur eine Möglichkeit.)
class X86_IO {
public native short inb(int port);
public native void outb(int port, short value);
// speicherzugriff könnte so aussehen:
public native byte[] access(String identifier);
// spezielle speicherbereiche allokieren
public native byte[] allocDMA(int size);
};
-
Ich habe bisher noch kein SharedMemory. ;) Aber die Unsicherheit der anderen Mittel "rechtfertigt" nicht die Unsicherheit des eigenen Mittels, oder? Ist so ein Compiler nicht irre aufwendig?
Interessant wird so eine Überlegung erst wenn man sagt: "Angenommen da ist ein Bug, gibt es noch etwas anderes was eine grössere Katastrophe verhindert." In diesem Falle bei allen Fragestellungen (Compiler, Shared Memory, Buffer overflow) nichts. Wenn es eine andere Möglichkeit dann jedoch gibt die dann noch etwas Schutz hat, dann kann man darüber mal nachdenken.
Einfach mal ein "Toll, wenn da ein Bug ist ..." in den Raum zu werfen bringt nicht viel.
So ein Compiler ist schon etwas aufwendiger - dafür kann man sich jedoch andere sehr aufwendige Dinge durchaus sparen, wie z.B. getrennte Addressräume einzurichten und dann wieder eine Kommunikation zwischen diesen zu ermöglichen.
Und wie SSJ7Gohan schon gesagt hat, damit erspart man sich eine gigantische Menge an Bugs in anderen Teilen des Gesamtsystems ...
-
Stimmt. Obwohl ich warscheinlich bei der wohl doch eher konventionellen Methode bleiben werde.
Sind die nachcompilierten Anwendungen von der Performance dann mit echtem Maschinencode gleich auf oder gibt es dort immernoch Nachteile?
-
Er wird vor dem Ausführen kompiliert.
Ich bin mir noch nicht ganz sicher wie dus meinst: Java Bytecode -> Maschinencode oder Java Quellcode -> Java Bytecode oder Java Quellcode -> Maschinencode?
Irgendwie find ich den Ansatz mit Java ziemlich cool und gewagt.
Danke für Antworten.
-
Ich bin mir nicht sicher, aber ist es nicht so?:
Java Quellcode -> Java Bytecode -> Maschinencode
Den ersten Schritt macht der "Compiler", den zweiten Schritt die "Virtual Machine"...
-
Java Quellcode --> kompilieren mit javac ---> Java Bytecode ---> just-in-time kompilieren mit unserem Compiler ---> Maschienencode
Je nach Compiler und Optimierungen kann der Javacode fast C++ Geschwindigkeit erreichen.
-
Doch, so wie joachim_neu es beschrieben hat stimmt es.
Das Ergebnis des JIT-Schrittes kann genauso gut sein, kommt auf die Anzahl der durchgeführten Optimierungen an. Jede Optimierung kostet Zeit, das ist ein Problem. Deswegen lohnt es sich nicht Code der nur einmal durchlaufen zu kompilieren.
Theoretisch hat ein JIT Compiler mehr Möglichkeiten zu optimieren.
Sun's VM ist bei Sachen die nur in der VM ablaufen eigentlich gleich schnell, ganz besonders bei mathematischen Berechnungen wie ich es mal in Benchmarks gesehen hatte. Ein grosses Problem wie ich mal gemerkt habe ist das geringe Tempo von JNI in Sun's VM. Und das man die erstmal starten muss. Aber das beheben wir ja! :)