Lowlevel

Lowlevel => Lowlevel-Coding => Thema gestartet von: FlashBurn am 27. December 2010, 22:00

Titel: runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 27. December 2010, 22:00
Ich wollte mich mal wieder mit meinem OS beschäftigen und das Programme laden/ausführen besser implementieren, da es mir so wie ich es im Moment noch habe nicht gefällt.

Im Moment muss ich dem Kernel nen Pointer auf nen Speicherbereich, mit zugehöriger Größe, übergeben in dem Sich die auszuführenden Datei befindet.

Dieser Speicher wird dann in einen neuen Prozess gemappt und erst dann wird der Speicher geparst und das Programm-Image erstellt. Erst jetzt würden auch (wenn ich es denn schon implementiert hätte) die erforderlichen Libraries geladen werden.

Eigentlich finde ich dieses Vorgehen ganz gut, aber eine Art Programm, den Runtime-Loader, zu haben hätte auch so seine Vorteile (ich kann leichter mehrere Dateiformate unterstützen und noch andere nette Dinge leichter machen).

Aber wie funktioniert so ein Runtime-Loader eigentlich und welche Variante ist eurere Meinung nach besser und warum?
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: Svenska am 28. December 2010, 02:53
Nabend,

das Unix-Konzept geht so: der Kernel hat eine Liste mit Identifizierungsmerkmalen für ausführbare Dateien (im Zweifelsfall ist das nur ein Eintrag für ELF, aber vgl. BINFMT) und dazu passend den jeweiligen Loader.

Unter Linux ist das die /lib/ld-linux.so für ELF-Dateien, /lib/ld.so für a.out.

Der Loader zerbröselt nun das Executable und tut dann mehrere Dinge:

Er schaut bei dynamisch gelinkten Programmen in der Executable nach, welche Bibliotheken in welcher Version benötigt werden und lädt diese in den Speicher. Dann merkt er sich die in den Bibliotheken verwendeten Symbole und stopft die in eine Symboltabelle.

Er legt für jeden Bestandteil des Executables (.code, .data) den Speicherbereich an und füllt diesen bei Bedarf, anschließend baut er die Symboltabellen aus dem ersten Schritt noch so ein, dass das Programm damit was anfangen kann (ich weiß aber nicht, wie genau).

Dann führt er das Programm aus.

Unter Linux wird die Variable LD_LIBRARY_PATH (nebst anderen) vom Loader benutzt, um die Bibliotheken zu finden. Das ist hässlich, bitte tu es nicht. Außerdem kann man über Variablen und Parameter noch Debugging einschalten und Einfluss auf den Loader nehmen, während er Dinge tut (vgl. ld-linux(8)).

Ob und was du genau implementieren musst, hängt auch noch von deinem gewählten Binärformat ab (z.B. musst du Scripts an den Interpreter übergeben, das macht den Loader einfacher). Eventuell lädt der Loader das Programm auch direkt vom Datenträger (der Kernel liest nur z.B. die ersten 8K, um den Loader zu ermitteln - das ermöglicht z.B. XIP oder transparente Code-Kompression ohne, dass der Kernel das können muss).

Gruß,
Svenska
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 28. December 2010, 10:32
Ich würde halt gerne nen Runtime-Loader nutzen, weil ich damit den ganzen Kram aus dem Kernel habe und weil ich dann einfacher auch andere Dateiformate unterstützen kann.

Ein Vorteil (je nachdem wie man es sieht) ist ja das der Runtime-Loader im UserSpace läuft. Ich kann mir halt nur nicht so richtig erklären wie man das dann alles so macht.

Ich habe mir das so vorgestellt das man als erstes mal nen fork() vom Runtime-Loader macht und dann die Datei in den Speicher laden lässt.
Problem ist jetzt halt, das der Runtime-Loader ja dem Executeable-Image nicht im Weg rumliegen darf, sprich das der Runtime-Loader nicht an einer Adresse sein darf, die eigentlich das Executeable-Image nutzen will. Das war auch ein Grund warum ich das alles in den Kernel gepackt habe.

Vorallem wenn ich das richtig verstanden habe, dann hat Linux eigentlich auch nen Runtime-Loader, sprich die ld-linux.so parst die Datei und erstellt das Image?
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: Svenska am 28. December 2010, 11:46
Ich habe mir das so vorgestellt das man als erstes mal nen fork() vom Runtime-Loader macht und dann die Datei in den Speicher laden lässt.
Richtig. Sinnvollerweise lädst du die Datei nicht am Stück, sondern parst den Header und lädst die Bestandteile an verschiedene Adressen.

Problem ist jetzt halt, das der Runtime-Loader ja dem Executeable-Image nicht im Weg rumliegen darf, sprich das der Runtime-Loader nicht an einer Adresse sein darf, die eigentlich das Executeable-Image nutzen will. Das war auch ein Grund warum ich das alles in den Kernel gepackt habe.
Das Executable darf keine fixen Adressen anfordern (du könntest natürlich Segmentierung nutzen, dann geht das), sondern der Loader verrät dem Executable, an welche Adresse es geladen wurde. Gleiches kann auch für die benötigten Libraries gelten.

Windows CE hat die DLLs an fixe Adressen gelinkt (verschieden für jede DLL), d.h. jede DLL kann nur einmal im System existieren. Normales Windows und Linux erlauben DLLs/Libs mehrfach an verschiedenen Adressen im Speicher (jede Anwendung kann ihre eigene SDL.DLL/libSDL haben).

Vorallem wenn ich das richtig verstanden habe, dann hat Linux eigentlich auch nen Runtime-Loader, sprich die ld-linux.so parst die Datei und erstellt das Image?
Ja. Linux hat nicht nur einen, sondern sogar linuxtypisch mehrere (ld.so für a.out, ld-linux.so für ELF plus das binfmt_misc-Framework und den Shebang).

Gruß,
Svenska
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 28. December 2010, 11:57
Zitat von: svenska
Richtig. Sinnvollerweise lädst du die Datei nicht am Stück, sondern parst den Header und lädst die Bestandteile an verschiedene Adressen.
Da fällt mir auch wieder ein was noch ein Grund war, das alles im Kernel zu machen. Ich gehe halt davon aus, das die Datei schon komplett geladen ist und das die Segmente (wenn es eine ELF-Datei ist) schon in der Datei an 4KB ausgerichtet sind, so dass ich nichts kopieren muss, sondern einfach nur den Speicher an die richtige Stelle mappen muss.
Das sollte schneller gehen und selbst wenn ich das vom UserSpace aus machen könnte, dann hätte ich noch das Problem das ich zum ummappen jedes Mal in den Kernel müsste und damit wäre dann der Vorteil eh wieder weg.

Zumal ich es eh so sehe, dass das Laden der kompletten Datei schneller sein sollte, als wenn man (bei einem MikroKernel) sie in mehreren Stücken laden lässt.

Zitat von: svenska
Das Executable darf keine fixen Adressen anfordern (du könntest natürlich Segmentierung nutzen, dann geht das), sondern der Loader verrät dem Executable, an welche Adresse es geladen wurde. Gleiches kann auch für die benötigten Libraries gelten.
Das sehe ich anders (und der ELF-Standard auch ;) ). Eine ganz normale Executeable-ELF-Datei (kein shared-object) kann komplett fertig gelinkt sein, sprich man muss nur noch die Segmente an die entsprechenden Adressen packen und dann läuft das Programm (Libraries werden in dem Fall statisch gelinkt).
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: Svenska am 28. December 2010, 13:22
Hallo,

Da fällt mir auch wieder ein was noch ein Grund war, das alles im Kernel zu machen. Ich gehe halt davon aus, das die Datei schon komplett geladen ist und das die Segmente (wenn es eine ELF-Datei ist) schon in der Datei an 4KB ausgerichtet sind, so dass ich nichts kopieren muss, sondern einfach nur den Speicher an die richtige Stelle mappen muss.
Du kannst natürlich das Laden der Datei im Kernel machen, dann kriegt der Loader nur noch die Adresse des ELF-BLOBs, aus dem er Symboltabellen generieren muss. Damit kannst du natürlich nicht mehr .code und .data zufällig voneinander trennen (Adressraum-Randomisierung), weil sie im Block im Speicher liegen. Du kannst kein XIP (eXecute In Place) mehr machen, ohne die schon geladenen Daten wieder aus dem RAM zu entfernen und du brauchst einen vollwertigen ELF-Parser im Kernel, um Alignments erzwingen zu können.

Wenn der Loader sich um das ELF-Parsen kümmert, kannst du .code/.data dynamisch komprimieren/verschlüsseln/usw., die Datei braucht kein inhärentes Alignment haben und du kannst alle möglichen witzigen Dinge tun. Außerdem hast du dann die Freiheit, mehrere Binärformate durch ein gemeinsames Framework zu unterstützen. Die Linux-Emulation von FreeBSD funktioniert auf der Ebene, der Loader erkennt ein Linux-ELF und erstellt eine Umgebung, in der die Syscalls umnummeriert (auf die Linux-Nummern) werden. Oder du kannst eine PE-Datei durch Wine/DOSEMU schicken.

Henne-Ei-Problem: Der Kernel muss den Runtime-Loader starten können... dessen Format muss aber kein full-blown ELF sein.

Das sollte schneller gehen und selbst wenn ich das vom UserSpace aus machen könnte, dann hätte ich noch das Problem das ich zum ummappen jedes Mal in den Kernel müsste und damit wäre dann der Vorteil eh wieder weg.
Sehe ich keinen Nachteil, denn Programme laden und ausführen ist eine sehr seltene Sache (verglichen mit der Laufzeit der Anwendungen) und du musst ja nur ein Mapping pro Section machen, statt alle gleichzeitig. Die paar zusätzlichen Syscalls fallen nicht ins Gewicht, weil die Ladezeit vom Medium einen Großteil der Zeit ausmacht.

Zumal ich es eh so sehe, dass das Laden der kompletten Datei schneller sein sollte, als wenn man (bei einem MikroKernel) sie in mehreren Stücken laden lässt.
Du lädst einmal die ersten 8K als Kernel (um den korrekten Loader zu ermitteln). Ist es keine erkannte Datei (*), brauchst du den Rest nicht mehr laden. Der Loader kümmert sich um das Laden und Parsen. Er kann die Datei trotzdem am Stück laden, das schließt sich ja nicht aus.

(*) Jemand hat ein NTFS gemountet, wo Dateien standardmäßig als executable markiert sind und im "mc" auf eine Videodatei gedrückt. Dann erstmal 3 GB in den RAM laden zu müssen ist unschön.

Zitat von: svenska
Das Executable darf keine fixen Adressen anfordern (du könntest natürlich Segmentierung nutzen, dann geht das), sondern der Loader verrät dem Executable, an welche Adresse es geladen wurde. Gleiches kann auch für die benötigten Libraries gelten.
Das sehe ich anders (und der ELF-Standard auch ;) ). Eine ganz normale Executeable-ELF-Datei (kein shared-object) kann komplett fertig gelinkt sein, sprich man muss nur noch die Segmente an die entsprechenden Adressen packen und dann läuft das Programm (Libraries werden in dem Fall statisch gelinkt).
Okay, ich schwäche ab: sollte keine fixen Adressen anfordern. Was passiert denn, wenn du zwei Executables an die gleiche Adresse gelinkt hast und sie ausführen möchtest?

Entweder du kannst die Sections im Adressraum beliebig verteilen, dann kann der Loader sie dorthin schieben, wo er sie gern hätte und wo Platz ist. Oder du linkst sie an fixe Adressen und kannst nur eine Anwendung gleichzeitig (pro Segment) haben; der Loader berücksichtigt das oder verweigert den Start.

PS: Zum Zitieren kannst du den Knopf drücken, dann bleibt die Verlinkung und Formatierung erhalten.

Gruß,
Svenska
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 28. December 2010, 14:16
Zitat von: svenska
Henne-Ei-Problem: Der Kernel muss den Runtime-Loader starten können... dessen Format muss aber kein full-blown ELF sein.
Das ist ein Problem was ich mit dem Runtime-Loader habe, aber das sollte sich irgendwie lösen lassen.

Zitat von: svenska
Du lädst einmal die ersten 8K als Kernel (um den korrekten Loader zu ermitteln). Ist es keine erkannte Datei (*), brauchst du den Rest nicht mehr laden. Der Loader kümmert sich um das Laden und Parsen. Er kann die Datei trotzdem am Stück laden, das schließt sich ja nicht aus.
Richtig und guter Punkt. Ich würde dann sogar sagen, das man zuerst 8K lädt und guckt was für ein Format es ist bzw. ob es unterstützt wird und dann wird ein fork() gemacht.

Zitat von: svenska
Okay, ich schwäche ab: sollte keine fixen Adressen anfordern. Was passiert denn, wenn du zwei Executables an die gleiche Adresse gelinkt hast und sie ausführen möchtest?

Entweder du kannst die Sections im Adressraum beliebig verteilen, dann kann der Loader sie dorthin schieben, wo er sie gern hätte und wo Platz ist. Oder du linkst sie an fixe Adressen und kannst nur eine Anwendung gleichzeitig (pro Segment) haben; der Loader berücksichtigt das oder verweigert den Start.
Denk nochmal darüber nach was du hier geschrieben hast ;)

Jedes Programm hat seinen eigenen Adressraum und somit gibt es keine Probleme mit fixen Adressen. Das Problem was ich halt mit fixen Adressen sehe ist, dass das Programm gerne an eine Adresse geladen werden möchte wo der Runtime-Loader ist (und um überhaupt Programme erstellen zu können darf der Runtime-Loader auch nicht an der Standard-Start-Adresse stehen) und das geht ja dann nicht.

Zitat von: svenska
PS: Zum Zitieren kannst du den Knopf drücken, dann bleibt die Verlinkung und Formatierung erhalten.
Zu faul ;)
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: Svenska am 28. December 2010, 20:28
Zitat von: svenska
Henne-Ei-Problem: Der Kernel muss den Runtime-Loader starten können... dessen Format muss aber kein full-blown ELF sein.
Das ist ein Problem was ich mit dem Runtime-Loader habe, aber das sollte sich irgendwie lösen lassen.
Der Kernel muss in der Lage sein, ein Binärformat direkt ausführen zu können. Das kann ganz simpel sein (flat binary an fixe Adresse). Man kann im Kernel auch eine Liste statisch hinterlegen, welche Binaries damit ausgeführt werden können, dann ist der Sicherheitsaspekt nicht zu stark vernachlässigt.

Alternativ ist der Runtime Loader ein Teil des Kernels, aber das willst du sicherlich nicht. ;-)

Richtig und guter Punkt. Ich würde dann sogar sagen, das man zuerst 8K lädt und guckt was für ein Format es ist bzw. ob es unterstützt wird und dann wird ein fork() gemacht.
Der Kernel forkt sich selbst? Ich dachte, er macht ein CreateUserspaceProcess() oder Äquivalent; die 8K muss er übrigens selbst laden, um den richtigen Loader auswählen zu können.

Jedes Programm hat seinen eigenen Adressraum und somit gibt es keine Probleme mit fixen Adressen. Das Problem was ich halt mit fixen Adressen sehe ist, dass das Programm gerne an eine Adresse geladen werden möchte wo der Runtime-Loader ist (und um überhaupt Programme erstellen zu können darf der Runtime-Loader auch nicht an der Standard-Start-Adresse stehen) und das geht ja dann nicht.
Wenn ich ein paged-flat-memory-Speichermodell habe, dann gibt es die Adresse 0x1234 systemweit doch nur ein einziges Mal; wie kann dann jeder Prozess diese Adresse nutzen? Das ist doch der Sinn von flat memory? Nur Segmentierung erzeugt doch jedesmal einen neuen Adressraum? Ich hab da glaube grad ein Brett vorm Schädel, führ mal bitte genauer aus.

Gruß
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 28. December 2010, 20:47
Zitat von: svenska
Alternativ ist der Runtime Loader ein Teil des Kernels, aber das willst du sicherlich nicht.
Genau deswegen versuche ich mich mit nem Runtime-Loader anzufreunden. Damit ich das alles aus dem Kernel rausbekomme und der nur noch ne Art Blackbox ist, wo kein unbekannter Code rein kann und der auch ansonsten nicht viele Angriffspunkte biete.

Zitat von: svenska
Der Kernel forkt sich selbst? Ich dachte, er macht ein CreateUserspaceProcess() oder Äquivalent; die 8K muss er übrigens selbst laden, um den richtigen Loader auswählen zu können.
So wie ich mir das vorstelle, macht der Runtime-Loader so ziemlich alles (jetzt kommt mir gerade eine Idee :D ).

Ich bräuchte also nur nen fork() Syscall und nen createThread() Syscall. Der Runtime-Loader forkt sich selber (nachdem er überprüft hat ob die Datei die er ausführen soll in Ordnung ist) und erledigt dann die ganze Arbeit.

Somit würde es keinen exec() Syscall (oder halt createProcess()) geben, sondern das wäre nen RPC zum Runtime-Loader. So würde ich auch halbwegs POSIX (allerdings ohne Signale) bei mir unterbekommen ohne zu sehr die UNIX-Konzepte zu nutzen (und ich weiß endlich wofür fork() genutzt werden kann).

Wobei ich mir dann trotzdem noch was einfallen lassen muss um überhaupt den Runtime-Loader zum Laufen zu bekommen und auch wie ich meinen Storage-Server zum Laufen bekomme. Denn der Storage-Server wird ja benötigt um irgendwelche Dateien zu laden und genau das braucht der Runtime-Loader. Ich werde also wohl auch sowas wie erik machen müssen, eine lebend Geburt oder ich verpasse dem Runtime-Loader die Fähigkeit, das er auch nen Datei-Image direkt bekommt und dieses "ausführt" (könnte sowas noch woanders als beim Booten nützlich sein?).

Zitat von: svenska
Wenn ich ein paged-flat-memory-Speichermodell habe, dann gibt es die Adresse 0x1234 systemweit doch nur ein einziges Mal; wie kann dann jeder Prozess diese Adresse nutzen? Das ist doch der Sinn von flat memory? Nur Segmentierung erzeugt doch jedesmal einen neuen Adressraum? Ich hab da glaube grad ein Brett vorm Schädel, führ mal bitte genauer aus.
Der Sinn von Paging ist, das du so viele virtuelle (und das ist der Punkt) Adressräume haben kannst, wie der RAM hergibt. Du hast doch ein PageDirectory und jeder Prozess hat sein eigenes PD und somit seinen eigenen Adressraum.

Edit::

Ein Problem habe ich noch, wie bekommt man den Runtime-Loader wieder aus dem Adressraum des neuen Prozesses oder anderes gefragt, wie unmappt man gerade laufenden Code und springt zu neuem Code?
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: PNoob am 28. December 2010, 21:43
Moin

Das FLAT Memory Modell bezieht sich auf den Physischen Speicher, den du mit der GDT verwaltest.. Der Pseicherschutz wird virtuell durch das Paging bereitgestellt. es könnten Theoretisch Millionen Programme an der adresse 0x1234 sein. da jedesmal das PD(Page Directory) neugeladen wird, kann man jedem Prozess einen eiogenen Adressraum geben.

PNoob
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: Svenska am 28. December 2010, 21:56
Zitat von: svenska
Alternativ ist der Runtime Loader ein Teil des Kernels, aber das willst du sicherlich nicht.
Genau deswegen versuche ich mich mit nem Runtime-Loader anzufreunden. Damit ich das alles aus dem Kernel rausbekomme und der nur noch ne Art Blackbox ist, wo kein unbekannter Code rein kann und der auch ansonsten nicht viele Angriffspunkte biete.
Der Kernel muss Binaries ausführen können. Da kannst du mit Signaturen (oder vorgefertigten Listen im Kernel) arbeiten. Die weiteren Runtime-Loader können ja selbst wieder ELF-Dateien sein (finde ich aber unschön).

Ich bräuchte also nur nen fork() Syscall und nen createThread() Syscall. Der Runtime-Loader forkt sich selber (nachdem er überprüft hat ob die Datei die er ausführen soll in Ordnung ist) und erledigt dann die ganze Arbeit.

Somit würde es keinen exec() Syscall (oder halt createProcess()) geben, sondern das wäre nen RPC zum Runtime-Loader. So würde ich auch halbwegs POSIX (allerdings ohne Signale) bei mir unterbekommen ohne zu sehr die UNIX-Konzepte zu nutzen (und ich weiß endlich wofür fork() genutzt werden kann).
Du führst also alle Anwendungen als Teile des Runtime-Loaders aus? Das finde ich unschön. Der Sinn von Anwendungen ist es doch, als eigene Prozesse ausgeführt zu werden...?

Runtime-Loader wird vom Kernel gestartet (CreateUserspaceProcess) und bekommt als Parameter eine Datei. Diese wird geladen, validiert, mit allen Abhängigkeiten geladen (diese werden auch validiert) und schließlich führt der Runtime-Loader ein exec() auf das frisch geladene Image aus. Besser wäre, der Runtime-Loader erstellt einen neuen Process mit dem Speicher-Image (dann leaken keine Descriptoren/Datenstrukturen vom Loader in die Anwendungen).

Wobei ich mir dann trotzdem noch was einfallen lassen muss um überhaupt den Runtime-Loader zum Laufen zu bekommen und auch wie ich meinen Storage-Server zum Laufen bekomme. Denn der Storage-Server wird ja benötigt um irgendwelche Dateien zu laden und genau das braucht der Runtime-Loader. Ich werde also wohl auch sowas wie erik machen müssen, eine lebend Geburt oder ich verpasse dem Runtime-Loader die Fähigkeit, das er auch nen Datei-Image direkt bekommt und dieses "ausführt" (könnte sowas noch woanders als beim Booten nützlich sein?).
Hmm. Eine Idee: Du hast eine einzige Kernelfunktion CreateUserspaceProcessFromImage(), der du ein vorbereitetes Stück RAM übergibst. Alle Server, die du zum Booten brauchst, liegen bereits in diesem Format vor, werden also in den RAM geladen und direkt ausgeführt. Der Runtime-Loader liegt auch in diesem Format vor, liegt nur auf der Platte. Die Aufgabe des Runtime-Loaders ist es dann, ELF-Dateien in den RAM zu laden, zu validieren, dieses Format zu erzeugen und dann mittels dieser Funktion den Prozess zum Leben zu erwecken.

Das wäre ein Beispiel für das Binärformat, was ich die letzten Posts erwähnt hatte; quasi das "dumme", native Format des Kernels. Du kannst dafür übrigens auch gleich ELF nehmen, dann brauchst du keinen Runtime-Loader für ELF-Dateien mehr, sondern nur für "alles andere".

Zitat von: svenska
Wenn ich ein paged-flat-memory-Speichermodell habe, dann gibt es die Adresse 0x1234 systemweit doch nur ein einziges Mal; wie kann dann jeder Prozess diese Adresse nutzen? Das ist doch der Sinn von flat memory? Nur Segmentierung erzeugt doch jedesmal einen neuen Adressraum? Ich hab da glaube grad ein Brett vorm Schädel, führ mal bitte genauer aus.
Der Sinn von Paging ist, das du so viele virtuelle (und das ist der Punkt) Adressräume haben kannst, wie der RAM hergibt. Du hast doch ein PageDirectory und jeder Prozess hat sein eigenes PD und somit seinen eigenen Adressraum.
Stimmt, du tauschst ja beim Prozesswechsel einen Teil des Adressraumes aus. Bei der Segmentierung hast du mehrere Adressräume gleichzeitig in einem RAM, bei Paging hast du einen Adressraum, und mehrere RAMs (die sich beliebig überlappen).
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 28. December 2010, 22:17
Zitat von: svenska
Der Kernel muss Binaries ausführen können.
Da bin ich jetzt mal anderer Meinung. Das einzige was der Kernel können muss ist ein fork() bereitstellen, das reicht vollkommen aus!

Ich gehe jetzt einfach mal davon aus, dass das System schon läuft und man ein neues Programm ausführen will.
Man macht also nen Aufruf exec("./foobar") und das wiederum ruft den Runtime-Loader auf. Dieser lädt, meinetwegen die ersten 8KB, die Datei und guckt ob es ein Format ist das er unterstützt. Dann wird ein fork() gemacht und die Datei wird geparst und das Process-Image wird erstellt. Das Programm ist jetzt soweit fertig und der Runtime-Loader muss aus dem Process-Adressraum geunmappt werden und der Einsprungspunkt des Programms (meistens main()) muss ausgeführt werden.

Das einzige Mal wo der Kernel irgendetwas mit nem neuen Prozess erstellen zu tun hatte, war fork().

Zitat von: svenska
Du führst also alle Anwendungen als Teile des Runtime-Loaders aus? Das finde ich unschön. Der Sinn von Anwendungen ist es doch, als eigene Prozesse ausgeführt zu werden...?
Ein fork() erstellt doch im Endeffekt einen neuen Prozess, der dem alten halt nur verdammt ähnlich sieht. Exec() übernimmt dann das vorhandene PD und packt nen neuen Process-Image rein. Diesen ganzen exec()-Kram will ich dann im UserSpace vom Runtime-Loader machen lassen ohne das der Kernel das machen muss.

Zitat von: svenska
und schließlich führt der Runtime-Loader ein exec() auf das frisch geladene Image aus.
Korrigiere mich wenn ich unrecht habe, aber das entspricht so ziemlich fast genau dem was ich vorhabe, aber nicht dem wie es unter Linux läuft.
Unter Linux erstellt exec() das Image und lädt alle Dateien.

Zitat von: svenska
Das wäre ein Beispiel für das Binärformat, was ich die letzten Posts erwähnt hatte; quasi das "dumme", native Format des Kernels. Du kannst dafür übrigens auch gleich ELF nehmen, dann brauchst du keinen Runtime-Loader für ELF-Dateien mehr, sondern nur für "alles andere".
Ziel von mir ist es aber das ganze Zeug aus dem Kernel raus zu haben. Ich würde meinen Kernel gerne so flexibel wie möglich halten und da ist nunmal ein Runtime-Loader im UserSpace nötig (frag mich nicht warum ich das machen will, ist einfach so ;) ).

Wozu muss der Kernel auch mehr darüber wissen?

Ich muss nur noch gucken, das ich es hinbekomme meinen Bootvorgang flexibler zu gestalten, weil im Moment muss der Kernel sehr genau wissen welche Server zu starten sind und das ist mir alles noch zu unflexibel. Ich bräuchte halt doch sowas wie nen init-Process (schon wieder so ein UnixKonzept ;) ).
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: Svenska am 28. December 2010, 23:23
Zitat von: svenska
Der Kernel muss Binaries ausführen können.
Da bin ich jetzt mal anderer Meinung. Das einzige was der Kernel können muss ist ein fork() bereitstellen, das reicht vollkommen aus!
Nein. fork() kopiert einen vorhandenen Prozess. Der muss aber erstmal vorhanden sein! Der Kernel selbst ist an sich kein Prozess, außerdem willst du ihn nicht einfach duplizieren. Du brauchst also einen CreateUserspaceProcess-Syscall. Und der braucht entweder eine Binärdatei, die im RAM liegt (z.B. ELF) oder einen bereits präparierten Bereich im RAM.

Man macht also nen Aufruf exec("./foobar") und das wiederum ruft den Runtime-Loader auf. Dieser lädt, meinetwegen die ersten 8KB, die Datei und guckt ob es ein Format ist das er unterstützt. Dann wird ein fork() gemacht und die Datei wird geparst und das Process-Image wird erstellt. Das Programm ist jetzt soweit fertig und der Runtime-Loader muss aus dem Process-Adressraum geunmappt werden und der Einsprungspunkt des Programms (meistens main()) muss ausgeführt werden.
Anderer Ansatzpunkt, der mir besser gefällt: exec() ist eine Funktion der libc. Diese Funktion öffnet die Datei, sucht den passenden Runtime Loader, und startet ihn. Der Runtime-Loader lädt die ersten 8KB, konstruiert ein Prozess-Image und weist den Kernel mit einem speziellen Syscall an, aus diesem Prozess-Image einen neuen Userspace-Prozess zu bauen. Anschließend endet der Runtime-Loader, er ist also ein Prozess wie jeder andere, liegt aber im gleichen Format vor wie die Server.

Der Runtime-Loader lädt und analysiert die gesamte Datei, nicht nur die ersten 8K; das sollte (in meiner Welt) vorher geschehen. (Findet er dennoch Unsinn, bricht er natürlich trotzdem ab.)

Der Vorteil des speziellen Syscalls CreateUserProcessFromImage (toller Name) liegt darin, dass er keine Unterstützung vom Userspace benötigt, also benutzt werden kann, um den Userspace beim Booten zu erzeugen. Deine Server brauchen also nur in diesem Format irgendwo im RAM liegen und der Kernel kann sie von alleine starten; die libc kann damit ebenfalls Prozesse anlegen.

Ein fork() erstellt doch im Endeffekt einen neuen Prozess, der dem alten halt nur verdammt ähnlich sieht. Exec() übernimmt dann das vorhandene PD und packt nen neuen Process-Image rein. Diesen ganzen exec()-Kram will ich dann im UserSpace vom Runtime-Loader machen lassen ohne das der Kernel das machen muss.
Ich dachte eigentlich, du wolltest fork()/exec() nicht haben, weil dir das zu sehr Unix ist... und für den ersten Prozess im System kannst du fork() nicht benutzen (es gibt noch keine Vorlage) und exec() in der libc sollte ein Wrapper um einen CreateProcess-Syscall sein.

Zitat von: svenska
und schließlich führt der Runtime-Loader ein exec() auf das frisch geladene Image aus.
Korrigiere mich wenn ich unrecht habe, aber das entspricht so ziemlich fast genau dem was ich vorhabe, aber nicht dem wie es unter Linux läuft.
Unter Linux erstellt exec() das Image und lädt alle Dateien.
Ja, das exec() der libc tut das. Was der Syscall tut, weiß ich nicht. Ich vermute, der tut das alles nicht.

Ziel von mir ist es aber das ganze Zeug aus dem Kernel raus zu haben. Ich würde meinen Kernel gerne so flexibel wie möglich halten und da ist nunmal ein Runtime-Loader im UserSpace nötig (frag mich nicht warum ich das machen will, ist einfach so ;) ).
Stimmt. Du musst nur trotzdem in der Lage sein, den Runtime Loader zu starten, ohne ihn benutzen zu können und das setzt eine Möglichkeit voraus, einen Prozess erstellen zu können. Und diese Fähigkeit muss unabhängig von vorhandenem Userspace sein - du musst deine Server auch ohne den Runtime-Loader starten können, weil der ist noch nicht verfügbar.

Ich muss nur noch gucken, das ich es hinbekomme meinen Bootvorgang flexibler zu gestalten, weil im Moment muss der Kernel sehr genau wissen welche Server zu starten sind und das ist mir alles noch zu unflexibel. Ich bräuchte halt doch sowas wie nen init-Process (schon wieder so ein UnixKonzept ;) ).
Also "init" sollte keine notwendigen Server starten. Sinnvoll wäre, dass der Bootloader das Kernel-Image und die notwendigen Server lädt und dem Kernel mitteilt, dass diese gestartet werden sollen. Wenn alle Server fertig initialisiert sind und blocken, dann wird der Userspace gestartet. "init" ist der Einstieg in den Userspace, alles kernelartige ist dann schon fertig, alle notwendigen Treiber geladen.

Das noch weiter zu abstrahieren halte ich nicht für sinnvoll. Der Bootloader hat in der Regel nur sehr wenige Möglichkeiten, auf Hardware zuzugreifen (generischer HDD-Treiber, TFTP) und ist daher für den Ladevorgang sehr langsam. Er sollte also grundsätzlich nur wenige, bestimmte Server laden, um die Datenmenge klein zu halten. Diese notwendige Liste ist bekannt und relativ statisch. Wenn die notwendigen Server laufen, startet der Userspace. Wenn der Userspace einen Service benötigt, der noch nicht vorhanden ist, wird er nachträglich gestartet. (Ich bin ein Feind von Bluetooth-Daemons unter Linux, wenn ich keinen Bluetooth-Adapter habe. Oder die Funktionalität noch nicht benötige.)
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 29. December 2010, 10:56
Ich habe mir heute auf Arbeit nochmal Gedanken gemacht.

Die ersten 4MB eines jeden Prozesses sind bei mir immer frei (unter anderen um Null-Pointer abzufangen), die würde ich bzw. könnte ich für den Runtime-Loader nutzen.

Mein Bootloader müsste also den Runtime-Loader soweit fertig machen, das praktisch nur noch die Pages in ein PD kopiert werden müssen und dann kann der Runtime-Loader laufen.

Ein fork() Aufruf würde dann ein neues PD erstellen und den Runtime-Loader in die ersten 4MB packen. Der Runtime-Loader erledigt dann seine Arbeit und macht nen exec() Aufruf.

fork() wäre bei mir einfach nur das ein neuer Prozess (als Vater den aufrufenden Prozess) anlegen würde, in dem außer des Runtime-Loaders nichts anderes drin wäre.
exec() würde dann bei mir den Runtime-Loader wieder aus dem Adressraum entfernen und würde main() ausführen.

Ich sollte aber besser andere Namen für fork() und exec() wählen. Denn ansonsten wird es zu Missverständnissen kommen.

Zitat von: svenska
Ich dachte eigentlich, du wolltest fork()/exec() nicht haben, weil dir das zu sehr Unix ist... und für den ersten Prozess im System kannst du fork() nicht benutzen (es gibt noch keine Vorlage) und exec() in der libc sollte ein Wrapper um einen CreateProcess-Syscall sein.
Ich bin meistens anderer Meinung als die Unix-Konzepte (lasse mich aber gerne von diesen Konzepten überzeugen). Ich würde aber schon gerne Programme leicht auf mein OS portieren können und da kommt man dann dummerweise nicht an POSIX vorbei und das ist wie ich finde, nen zeimlicher Showstopper :( Ich hatte daher eh schon mit dem Gedanken gespielt fork() bei mir noch zusätzlich zu implementieren.

Zitat von: svenska
Stimmt. Du musst nur trotzdem in der Lage sein, den Runtime Loader zu starten, ohne ihn benutzen zu können und das setzt eine Möglichkeit voraus, einen Prozess erstellen zu können. Und diese Fähigkeit muss unabhängig von vorhandenem Userspace sein - du musst deine Server auch ohne den Runtime-Loader starten können, weil der ist noch nicht verfügbar.
Das will ich alles im Bootloader machen, sprich der lädt nur das was alles zum Laufen nötig ist (Kernel, Runtime-Loader, Storage-Server, Device-Server, die wichtigsten Treiber) und er übernimmt praktisch auch die Aufgabe des Runtime-Loaders und macht aus den Dateien (in meinem Fall ELF) fertige Process-Images. Diese müssen vom Kernel nur noch in ein PD gepackt werden (obwohl man das auch schon im Bootloader machen kann) und dann gestartet werden.

Zitat von: svenska
Also "init" sollte keine notwendigen Server starten. Sinnvoll wäre, dass der Bootloader das Kernel-Image und die notwendigen Server lädt und dem Kernel mitteilt, dass diese gestartet werden sollen. Wenn alle Server fertig initialisiert sind und blocken, dann wird der Userspace gestartet. "init" ist der Einstieg in den Userspace, alles kernelartige ist dann schon fertig, alle notwendigen Treiber geladen.

Das noch weiter zu abstrahieren halte ich nicht für sinnvoll. Der Bootloader hat in der Regel nur sehr wenige Möglichkeiten, auf Hardware zuzugreifen (generischer HDD-Treiber, TFTP) und ist daher für den Ladevorgang sehr langsam. Er sollte also grundsätzlich nur wenige, bestimmte Server laden, um die Datenmenge klein zu halten. Diese notwendige Liste ist bekannt und relativ statisch. Wenn die notwendigen Server laufen, startet der Userspace. Wenn der Userspace einen Service benötigt, der noch nicht vorhanden ist, wird er nachträglich gestartet. (Ich bin ein Feind von Bluetooth-Daemons unter Linux, wenn ich keinen Bluetooth-Adapter habe. Oder die Funktionalität noch nicht benötige.)
Ich brauche deswegen einen init-Prozess, weil ja irgendjemand die anderen Server starten muss und ich das am liebsten in irgendein Skript auslagern würde, so dass es möglich ist auch andere als die Standard-Server zu nutzen (ist ein Angriffspunkt, aber egal).

Was den Runtime-Loader und den Rest den der Bootloader lädt betrifft, die gebe ich auch über ein Skript beim Bootloader an, das ist also schon flexibel.

Was dein Bsp. mit dem Bluetooth-Daemon betrifft, da würde ich es so handhaben, dass der Bluetooth-Treiber einfach den Server startet und ansonsten läuft der nicht.
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: Svenska am 29. December 2010, 14:20
Mein Bootloader müsste also den Runtime-Loader soweit fertig machen, das praktisch nur noch die Pages in ein PD kopiert werden müssen und dann kann der Runtime-Loader laufen.
Dein Runtime-Loader läuft also immer, wenn das System läuft und es gibt prinzipiell nur einen. Kann man so machen.

Ein fork() Aufruf würde dann ein neues PD erstellen und den Runtime-Loader in die ersten 4MB packen. Der Runtime-Loader erledigt dann seine Arbeit und macht nen exec() Aufruf.
Du weißt aber schon, was fork() macht? Für ein fork() brauchst du den Runtime-Loader nämlich nicht, du führst ja keine auf Platte vorliegende Binärdatei aus.

fork() wäre bei mir einfach nur das ein neuer Prozess (als Vater den aufrufenden Prozess) anlegen würde, in dem außer des Runtime-Loaders nichts anderes drin wäre.
Das ist kein fork(), das ist ein CreateProcessFromELFFile(). Du brauchst den Runtime-Loader nicht, wenn die Datei bereits im Kernel-nativen Format vorliegt (für den Runtime-Loader selbst ist das nötig), und du brauchst ihn nicht, wenn der Prozess bereits läuft.

exec() würde dann bei mir den Runtime-Loader wieder aus dem Adressraum entfernen und würde main() ausführen.
Du musst unterscheiden zwischen exec(), wie es Anwendungen nutzen (also das fork/exec-Pärchen) und wie es der Runtime-Loader nutzt. Denn exec() ersetzt die laufende Anwendung durch eine auf Platte liegende Datei und benötigt dazu einen Runtime-Loader. Das geht offensichtlich nicht, wenn es der Runtime-Loader selbst ist... zumal, wenn der Runtime-Loader in den ersten 4MB liegt, die Anwendung dort gerade nicht liegt, du also nicht den Runtime-Loader mit exec() ersetzen kannst, ohne einen Spezialfall zu deklarieren.

Ich sollte aber besser andere Namen für fork() und exec() wählen. Denn ansonsten wird es zu Missverständnissen kommen.
Oder mit fork()/exec() das bezeichnen, was es ist... und für den Rest neue Namen erfinden.

Ich bin meistens anderer Meinung als die Unix-Konzepte (lasse mich aber gerne von diesen Konzepten überzeugen). Ich würde aber schon gerne Programme leicht auf mein OS portieren können und da kommt man dann dummerweise nicht an POSIX vorbei und das ist wie ich finde, nen zeimlicher Showstopper :( Ich hatte daher eh schon mit dem Gedanken gespielt fork() bei mir noch zusätzlich zu implementieren.
Also Perl implementiert ein fork() innerhalb des Interpreters...  ;-) Wenn du fork() zusätzlich implementierst, dann musst du es nicht fürs Booten erzeugen. Und wenn du fork() im POSIX-Layer implementierst, kannst du zum Booten trotzdem die nativen Funktionen benutzen. Denn fork() ist ein tolles Teil, aber damit kann man nicht alles erschlagen.

Das will ich alles im Bootloader machen, sprich der lädt nur das was alles zum Laufen nötig ist (Kernel, Runtime-Loader, Storage-Server, Device-Server, die wichtigsten Treiber) und er übernimmt praktisch auch die Aufgabe des Runtime-Loaders und macht aus den Dateien (in meinem Fall ELF) fertige Process-Images. Diese müssen vom Kernel nur noch in ein PD gepackt werden (obwohl man das auch schon im Bootloader machen kann) und dann gestartet werden.
Also ist der Runtime-Loader ein Server und du führst eine Lebendgeburt des Betriebssystems durch. Finde ich eher unelegant, aber gut.

Ich brauche deswegen einen init-Prozess, weil ja irgendjemand die anderen Server starten muss und ich das am liebsten in irgendein Skript auslagern würde, so dass es möglich ist auch andere als die Standard-Server zu nutzen (ist ein Angriffspunkt, aber egal).
Du musst unterscheiden zwischen dem Bootvorgang und dem Zeitraum, in dem das System läuft. Der Bootvorgang kann (und sollte) statisch sein, der Bootloader übergibt an den Kernel eine Liste mit den Services, die er bereits vorbereitet hat und fertig. Um diese Liste zu ändern, musst du den Bootloader konfigurieren (vgl. GRUB). Zur Laufzeit des Systems brauchst du nur die Fähigkeit, Services auch nachträglich starten und beenden zu können. Und das ist wieder unabhängig vom init-Prozess, sondern kann alles mögliche (und auch konfigurierbar) sein.

Was den Runtime-Loader und den Rest den der Bootloader lädt betrifft, die gebe ich auch über ein Skript beim Bootloader an, das ist also schon flexibel.
Eben. Der init-Prozess muss keine weiteren Services starten, solange sie nicht benötigt werden.

Was dein Bsp. mit dem Bluetooth-Daemon betrifft, da würde ich es so handhaben, dass der Bluetooth-Treiber einfach den Server startet und ansonsten läuft der nicht.
Jetzt habe ich aber einen Bluetooth-USB-Stick. Der USB-Stack stellt das fest, lädt den Treiber, startet den Bluetooth-Server und ist freut sich. Ich mag aber garkein Bluetooth nutzen... weil ich möchte heute nur Youtube gucken. Also ist der Server überflüssig, kostet RAM und Performance.

Das ist im Übrigen das, was der systemd tun soll, du kannst dir mal die Abstracts dazu anschauen, da sind schöne Gedanken dabei.

Was du vorschlägst, funktioniert. Ich finds nur nicht unbedingt hübsch. ;-)

Gruß,
Svenska
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 29. December 2010, 14:46
Zitat von: svenska
Dein Runtime-Loader läuft also immer, wenn das System läuft und es gibt prinzipiell nur einen. Kann man so machen.
Ich würde das nicht laufen nennen. Der ist halt einfach nur vorhanden, laufen tut er immer nur im Kontext des Prozess erstellens.

Eigentlich hatte ich geplant das man den Runtime-Loader per Add-Ons erweitern kann, da muss ich dann aber mal sehen wie ich das mache. Auch dort sollten dann 4MB vollkommen ausreichend sein.

Zitat von: svenska
Das ist kein fork(), das ist ein CreateProcessFromELFFile(). Du brauchst den Runtime-Loader nicht, wenn die Datei bereits im Kernel-nativen Format vorliegt (für den Runtime-Loader selbst ist das nötig), und du brauchst ihn nicht, wenn der Prozess bereits läuft.
Entweder willst du mich nicht verstehen oder verstehst mich wirklich nicht ;)

Es gibt bei mir kein Kernel-natives Format. Der Kernel hat damit rein gar nichts zu tun! Der Kernel erstellt einfach nur nen nackten Adressraum und kopiert den Runtime-Loader (der fix und fertig ist) in die ersten 4MB. Der Runtime-Loader erledigt dann die ganzen Sachen wie Parsen, Dateien laden und Adressen auflösen.

Was mein "exec"() betrifft, sollte ich vllt noch dazu schreiben, das nur der Runtime-Loader in der Lage ist diesen Syscall zu benutzen.

Ich sag mal mein fork() sollte eventuell createEmptyProcess heißen und mein exec() dann unmapRuntimeLoaderStartProcess oder sowas.

Zitat von: svenska
Also ist der Runtime-Loader ein Server und du führst eine Lebendgeburt des Betriebssystems durch. Finde ich eher unelegant, aber gut.
Anders gefragt, wie willst du das Problem mit der Lebendgeburt umgehen (bei einem MikroKernel)? Und mein Runtime-Loader ist kein Server, sieh es eher als einen Teil des Kernels, der im UserSpace liegt und läuft und auf der Platte auch eine extra Datei darstellt.

Zitat von: svenska
Der Bootvorgang kann (und sollte) statisch sein, der Bootloader übergibt an den Kernel eine Liste mit den Services, die er bereits vorbereitet hat und fertig.
Das funktioniert so nicht und soll es auch nicht machen. Mir geht es darum, das nirgends fest einprogrammiert ist, das der App-Server auch die Datei "app-server" sein muss (mal als Bsp.). Sicherlich kann ich das alles in mein Bootskript packen und der Bootloader parst dieses Skript und gibt die Daten dann fertig und einfach lesbar an den Kernel weiter und dieser dann an den Storage-Server, der dann die verbleibenden Server startet.

Zitat von: svenska
Jetzt habe ich aber einen Bluetooth-USB-Stick. Der USB-Stack stellt das fest, lädt den Treiber, startet den Bluetooth-Server und ist freut sich. Ich mag aber garkein Bluetooth nutzen... weil ich möchte heute nur Youtube gucken. Also ist der Server überflüssig, kostet RAM und Performance.
Dem muss ich erstmal entgegen halten, das man sowas manuel deaktivieren kann und ein anderes Bsp wäre, nur weil du den Sound gerade Stumm geschalten hast, wird nicht der Treiber beendet und alles was sonst noch zum Sound dazu gehört. Es ist also gang und gäbe das es so gehandhabt wird.

Um es mal deutlicher zu machen, wenn du Bluetooth eh nicht nutzt, warum dann nicht einfach den Stick (wenn man schon einen hat) abmachen?
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: Svenska am 29. December 2010, 15:45
Eigentlich hatte ich geplant das man den Runtime-Loader per Add-Ons erweitern kann, da muss ich dann aber mal sehen wie ich das mache. Auch dort sollten dann 4MB vollkommen ausreichend sein.
Plugin-Systeme im Kernel. Pfui. Du sollst nicht den ultimativen Runtime-Loader haben, sondern du willst einen kleinen, speziellen Runtime-Loader für jedes zu unterstützende Format haben. Weniger Code, weniger Fehlerquellen, weniger Verschwendung.

Es gibt bei mir kein Kernel-natives Format. Der Kernel hat damit rein gar nichts zu tun! Der Kernel erstellt einfach nur nen nackten Adressraum und kopiert den Runtime-Loader (der fix und fertig ist) in die ersten 4MB. Der Runtime-Loader erledigt dann die ganzen Sachen wie Parsen, Dateien laden und Adressen auflösen.
Dann ist das native Kernel-Format genau das, was du als "Runtime-Loader (der fix uns fertig ist)" bezeichnest. Man kann es dann nicht für andere Dinge benutzen, weil der Runtime-Loader somit ein Teil des Kernels ist (ein BLOB, was in jeden Prozess kopiert wird).

Was mein "exec"() betrifft, sollte ich vllt noch dazu schreiben, das nur der Runtime-Loader in der Lage ist diesen Syscall zu benutzen.
Also eher ein Exec (Syscall) statt ein exec() (Funktion), das meinte ich mit dem Spezialfall. Der Runtime-Loader ist also ein Teil des Kernels, läuft im Userspace-Kontext, hat keinen Zugriff auf die libc-Funktionalität, dafür aber einen speziellen Syscall und ist allgemein etwas ganz besonderes. Stimmt das soweit?

Ich sag mal mein fork() sollte eventuell createEmptyProcess heißen und mein exec() dann unmapRuntimeLoaderStartProcess oder sowas.
Damit sind fork() und exec() nicht mehr das, was man landläufig darunter versteht. ;-)

Was du als unmapRuntimeLoaderStartProcess bezeichnest, hatte ich CreateProcessFromImage genannt, mit einem kleinen Unterschied: Dein Runtime-Loader baut aus der ELF-Datei eine Umgebung auf, mit der du eine Wiedergeburt des aktuellen Prozesses vornimmst, mein Gedankengang baut eine neue Umgebung auf, die vom Kernel zu einem Prozess wird.

Was besser ist, weiß ich nicht. Ich halte meinen Ansatz für flexibler.

Anders gefragt, wie willst du das Problem mit der Lebendgeburt umgehen (bei einem MikroKernel)? Und mein Runtime-Loader ist kein Server, sieh es eher als einen Teil des Kernels, der im UserSpace liegt und läuft und auf der Platte auch eine extra Datei darstellt.
Hatte ich schonmal beschrieben... der Bootloader lädt den Kernel und die zwingend notwendigen Module (im kernel-nativen Binärformat, z.B. flat binary) in den RAM und übergibt eine Liste mit Zeigern auf diese Strukturen an den Kernel. Dann springt er in den Kernel, der fängt an zu laufen, initialisiert alles mögliche und ruft für jeden dieser Zeiger ein CreateProcessFromImage() auf. Dann laufen die bootkritischen Server und können verwendet werden. Wenn das geschehen ist, wird vom Kernel der eigentliche Userspace initialisiert, also konkret "init" gestartet. Das geht, weil ja alles, was dafür nötig ist, bereits läuft.

Der Runtime-Loader ist bei mir kein Teil des Kernels, sondern eine Anwendung wie jede andere auch, mit dem Unterschied, dass sie keinen Runtime-Loader benötigt, sondern bereits im kernel-nativen Binärformat vorliegen muss. Es gibt also ein Format, welches der Kernel ausführen kann und darauf kann der Runtime-Loader später aufbauen.

Zur Laufzeit erzeugt der Kernel keine Prozesse von selbst, zumindest fallen mir keine ein. Ich bitte um Gegenbeispiele. Mein Gedanke ist, dass neue Prozesse immer vom Userspace (Shell, GUI) aus erzeugt werden und das geschieht natürlich über die systemeigene libc/libsonstwas. Diese wickelt also das Starten von Prozessen ab und nutzt dazu den Runtime-Loader.

Zitat von: svenska
Der Bootvorgang kann (und sollte) statisch sein, der Bootloader übergibt an den Kernel eine Liste mit den Services, die er bereits vorbereitet hat und fertig.
Das funktioniert so nicht und soll es auch nicht machen. Mir geht es darum, das nirgends fest einprogrammiert ist, das der App-Server auch die Datei "app-server" sein muss (mal als Bsp.).
Dein Bootloader ist nicht konfigurierbar? Du lädst im Mikrokernel doch mehrere Dateien in den Speicher. Deren Name ist doch egal (der Bootloader kann auch 0x4000@0x94000000 im NAND-Flash laden). Der Kernel startet einfach alles, was da ist; die Services registrieren sich über das RPC selbst beim Kernel. (Ich möchte dazu jetzt kein Fass aufmachen.) Was interessiert es den Bootloader, ob der App-Server dabei ist? Fehlt am Ende des Tages der App-Server, gibts eine Kernel-Panic und gut ist.

Aufgabe des Benutzers ist es, die kritischen Dinge bereitzustellen, damit der Kernel überhaupt lebensfähig sein kann und dies dem Bootloader mitzuteilen (Konfiguration des Bootloaders, menu.lst im GRUB).

Sicherlich kann ich das alles in mein Bootskript packen und der Bootloader parst dieses Skript und gibt die Daten dann fertig und einfach lesbar an den Kernel weiter und dieser dann an den Storage-Server, der dann die verbleibenden Server startet.
Nein. Das Bootscript enthält eine Liste mit Dateien, die vom Bootloader an den Kernel übergeben werden. Mit diesen Dingen fängt der Kernel an zu leben. Alle weiteren Server werden aus dem Userspace gestartet, im Zweifelsfall von "init". Damit hat der Bootloader nichts mehr zu tun.

Zitat von: svenska
Jetzt habe ich aber einen Bluetooth-USB-Stick. Der USB-Stack stellt das fest, lädt den Treiber, startet den Bluetooth-Server und ist freut sich. Ich mag aber garkein Bluetooth nutzen... weil ich möchte heute nur Youtube gucken. Also ist der Server überflüssig, kostet RAM und Performance.
Dem muss ich erstmal entgegen halten, das man sowas manuel deaktivieren kann und ein anderes Bsp wäre, nur weil du den Sound gerade Stumm geschalten hast, wird nicht der Treiber beendet und alles was sonst noch zum Sound dazu gehört. Es ist also gang und gäbe das es so gehandhabt wird.
Also weil es eine Anwendung gibt, die potentiell den Wunsch haben könnte, einen Service zu benutzen, muss ich den Service dauerhaft bereitstellen? Das ist wie immer im ersten Gang fahren, ich könnte ja anfahren wollen...

Wenn ich stummschalte, dann senke ich die Lautstärke ab. Das ist etwas anderes, als den Treiber zu beenden. Wenn man den Linux-Ansatz nimmt, dann habe ich einen Soundserver (z.B. PulseAudio, ESound), der den Treiber benutzt. Beende ich diesen, weil ich im Büro der Mitarbeiter wegen kein lautes Audio haben darf, dann ist der letzte Nutzer des Audio-Servers weg und der Server würde somit automatisch beendet.

Andersrum: Was, wenn ich nur USB-Soundkarten habe? Der Treiber (USBAudioChipsatz-Server) startet beim Einstecken des Sticks. Der allgemeine Audio-Server, mit dem Anwendungen reden, startet aber noch nicht. Der startet erst, wenn Anwendungen wirklich Audio ausgeben wollen. Hat sich das erledigt, beendet er sich wieder. Und dabei setzt er vielleicht noch den USBAudioChipsatzServer in den Sleep-Modus, um Strom zu sparen.

Kann man drüber nachdenken, muss man nicht drüber nachdenken, aber man sollte es nicht komplett ignorieren.

Um es mal deutlicher zu machen, wenn du Bluetooth eh nicht nutzt, warum dann nicht einfach den Stick (wenn man schon einen hat) abmachen?
Weil er vielleicht im Notebook eingelötet ist? Außerdem sagt mir doch keiner, dass ich Bluetooth grundsätzlich nicht nutzen möchte. Ich möchte es nur jetzt nicht nutzen. Wenn ich die erste Bluetooth-Verbindung aufbauen möchte, startet der Server automatisch und wenn ich die letzte Bluetooth-Verbindung trenne (und die dazugehörigen Anwendungen schließe), wird der Server automatisch wieder beendet. Das ist im Übrigen eine Frage der Energieeffizienz: Was nicht verwendet wird, muss nicht laufen. Das spart CPU-Zyklen.

Gruß,
Svenska
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 29. December 2010, 16:16
Zitat von: svenska
Plugin-Systeme im Kernel. Pfui. Du sollst nicht den ultimativen Runtime-Loader haben, sondern du willst einen kleinen, speziellen Runtime-Loader für jedes zu unterstützende Format haben. Weniger Code, weniger Fehlerquellen, weniger Verschwendung.
Also nochmal, der Runtime-Loader läuft weder im Kernel noch ist er Bestandteil des Kernels (er liegt irgendwo dazwischen), er ist ein ganz "normales" Programm (welches keine Libraries bzw. shared-Libaries nutzen darf).

Das mit den Add-ons finde ich nicht weiter schlimm. Im Endeffekt registriert sich jedes Add-On im Runtime-Loader und dann wird bei jeder Datei, die Liste mit Add-Ons durchgegangen und wenn ein Add-On sagt, ok ich unterstütze dieses Format, erstellt es das Process-Image.

Ist im Endeffekt das gleiche wie für jedes Format nen Runtime-Loader.

Zitat von: svenska
Also eher ein Exec (Syscall) statt ein exec() (Funktion), das meinte ich mit dem Spezialfall. Der Runtime-Loader ist also ein Teil des Kernels, läuft im Userspace-Kontext, hat keinen Zugriff auf die libc-Funktionalität, dafür aber einen speziellen Syscall und ist allgemein etwas ganz besonderes. Stimmt das soweit?
Jein ;) Also der Runtime-Loader hat insofern zugriff auf irgendwelche Libraries, wenn er sie statisch mit in die Executeable packt und damit noch weit unter 4MB bleibt. Ich habe auch desweiteren eine Art exec() Funktion für alle Programme. Diese Funktion führt im Endeffekt mein createEmptyProcess() aus, welche dann den Runtime-Loader "startet". Der wiederum ruft dann den exec-Syscall auf und damit bekommt der aufrufende Prozess nen Rückgabewert und der neue Prozess wird gestartet.

Zitat von: svenska
Damit sind fork() und exec() nicht mehr das, was man landläufig darunter versteht.
Deswegen muss ich mir ja neue Namen einfallen lassen, mal sehen wie die Funktionen im Endeffekt heißen werden.

Zitat von: svenska
Was besser ist, weiß ich nicht. Ich halte meinen Ansatz für flexibler.
Wo siehst du deinen Ansatz flexibler und wo meinen unflexibel?

Zitat von: svenska
der Bootloader lädt den Kernel und die zwingend notwendigen Module (im kernel-nativen Binärformat, z.B. flat binary) in den RAM und übergibt eine Liste mit Zeigern auf diese Strukturen an den Kernel. Dann springt er in den Kernel, der fängt an zu laufen, initialisiert alles mögliche und ruft für jeden dieser Zeiger ein CreateProcessFromImage() auf. Dann laufen die bootkritischen Server und können verwendet werden. Wenn das geschehen ist, wird vom Kernel der eigentliche Userspace initialisiert, also konkret "init" gestartet. Das geht, weil ja alles, was dafür nötig ist, bereits läuft.
So viel anders ist meine Lebendgeburt auch nicht.

Bei mir wird es halt nur so sein, das der Kernel mit den schon vom Bootloader fertig erstellten Images einfach noch die nötigen Datenstrukturen anlegt und initialisert und dann einfach laufen lässt.

Zitat von: svenska
Der Runtime-Loader ist bei mir kein Teil des Kernels, sondern eine Anwendung wie jede andere auch, mit dem Unterschied, dass sie keinen Runtime-Loader benötigt, sondern bereits im kernel-nativen Binärformat vorliegen muss. Es gibt also ein Format, welches der Kernel ausführen kann und darauf kann der Runtime-Loader später aufbauen.
Und genau hier finde ich meinen Ansatz besser bzw. könnten die auch gleich sein/gemacht werden. Denn mein Runtime-Loader liegt auf der Platte als normale ELF-Datei vor, ist also ein Programm wie jedes andere auch (theoretisch, praktisch würde sich der Runtime-Loader sofort wieder beenden und nichts tun, wenn man ihn ausführt).

Dieses Format was der Kernel ausführen kann, wird entweder vom Bootloader oder vom Runtime-Loader erstellt.

Zitat von: svenska
Mein Gedanke ist, dass neue Prozesse immer vom Userspace (Shell, GUI) aus erzeugt werden und das geschieht natürlich über die systemeigene libc/libsonstwas. Diese wickelt also das Starten von Prozessen ab und nutzt dazu den Runtime-Loader.
Wird bei mir dann ungefähr genauso aussehen.

Zitat von: svenska
Dein Bootloader ist nicht konfigurierbar?
Doch.

In meinem Bootskript steht halt welche Datei der Kernel ist und welche Module noch geladen werden sollen und ich würde jetzt noch ein paar weitere Punkte (Runtime-Loader, Storage-Server, Device-Server, TUI-Server) hinzufügen.
Geladen werden nur die, die für den Bootvorgang auch benötigt werden, sprich der TUI-Server wird erst später vom Storage-Server geladen, aber ich möchte in diesem Bootskript schon alle wichtigen Server drin haben.

Zitat von: svenska
Was interessiert es den Bootloader, ob der App-Server dabei ist? Fehlt am Ende des Tages der App-Server, gibts eine Kernel-Panic und gut ist.
Weil es den Kernel einfacher und kompakter macht. Warum muss der Kernel nachgucken ob alles im Bootskript stand? Ich kann doch schon im Bootloader so viele Fehler wie möglich ausschließen ohne das System überhaupt geladen zu haben.

Zitat von: svenska
Alle weiteren Server werden aus dem Userspace gestartet, im Zweifelsfall von "init". Damit hat der Bootloader nichts mehr zu tun.
Und um nicht 2 Skripts zu haben oder 2 mal das selbe Skript parsen zu müssen (bzw. kann ich mir so dass ganze parsen außerhalb des Bootloaders vom Bootskript ganz sparen, weniger Fehler, weniger Code, weniger Speicherverbrauch, ...) mache ich das alles im Bootloader und gebe einfach nur eine Struktur an den Kernel weiter, wo alle Sachen die im Skript standen auch drin stehen, nur das diese Struktur wesentlich einfacher zu parsen ist.

Zitat von: svenska
Also weil es eine Anwendung gibt, die potentiell den Wunsch haben könnte, einen Service zu benutzen, muss ich den Service dauerhaft bereitstellen?
Um es mal auf die Spitze zu treiben, du erwartest doch auch das alle Treiber geladen werden, für die Geräte die vorhanden sind und nicht erst geguckt wird ob ein Gerät vorhanden ist, wenn es vllt irgendwann mal benutzt wird.

Was die Services betrifft, hängt das auch einfach vom Umfang ab, wenn ich dann 1min zum Starten des Services brauche, dann werden >90% der Nutzer sagen, lieber von Anfang an laufen lassen, als jedes Mal 1min zu warten bis ich es benutzen kann.

Zitat von: svenska
Das ist im Übrigen eine Frage der Energieeffizienz: Was nicht verwendet wird, muss nicht laufen. Das spart CPU-Zyklen.
Da hast du jetzt einen Denkfehler drin. Das einzige was du sparen kannst ist RAM! Denn wenn der Server nicht benutzt wird, läuft er auch nicht, er wartet das eine Anfrage an ihn gestellt wird und das kostet keine CPU-Zyklen.
Titel: Re: Programme laden/ausführen, Allgemeines
Beitrag von: Svenska am 29. December 2010, 17:20
Also nochmal, der Runtime-Loader läuft weder im Kernel noch ist er Bestandteil des Kernels (er liegt irgendwo dazwischen), er ist ein ganz "normales" Programm (welches keine Libraries bzw. shared-Libaries nutzen darf).
Ist also ein BLOB im Kernel.

Also der Runtime-Loader hat insofern zugriff auf irgendwelche Libraries, wenn er sie statisch mit in die Executeable packt und damit noch weit unter 4MB bleibt.
Also hat er keinen Zugriff auf Libraries. Wenn ich die Bibliothek nicht besuchen darf, habe ich keinen Zugriff darauf, auch wenn ich alle Bücher der Bibliothek selbst besitze und mitnehmen darf. ;-)

Ich habe auch desweiteren eine Art exec() Funktion für alle Programme. Diese Funktion führt im Endeffekt mein createEmptyProcess() aus, welche dann den Runtime-Loader "startet". Der wiederum ruft dann den exec-Syscall auf und damit bekommt der aufrufende Prozess nen Rückgabewert und der neue Prozess wird gestartet.
Also hast du in der libc ein exec(), welches den Runtime-Loader in einen neuen Prozess mappt und startet, und du hast einen Syscall Exec, der den Runtime-Loader aus einem Prozess entfernt und ihn resettet (diesmal an der realen Position).

Zitat von: svenska
Was besser ist, weiß ich nicht. Ich halte meinen Ansatz für flexibler.
Wo siehst du deinen Ansatz flexibler und wo meinen unflexibel?
Es gibt nur einen Runtime-Loader, der ist Teil des Kernels (wenn er auch nicht als solcher ausgeführt wird). Damit ist er prinzipiell nicht ersetzbar. Du hast einen speziellen Exec-Syscall für den Runtime-Loader, den auch nur dieser nutzen kann, und es gibt keine andere Möglichkeit, einen Prozess zu erzeugen.

Dein Kernel ist nicht in der Lage, Prozesse zu starten, ohne ein Dateisystem und die dazugehörigen Services geladen zu haben. Außerdem kannst du keine Prozesse starten, wenn der Runtime-Loader defekt ist oder ersetzt werden muss. Ich find das alles nicht so pralle, aber funktionieren dürfte es.

Zitat von: svenska
Der Runtime-Loader ist bei mir kein Teil des Kernels, sondern eine Anwendung wie jede andere auch, mit dem Unterschied, dass sie keinen Runtime-Loader benötigt, sondern bereits im kernel-nativen Binärformat vorliegen muss. Es gibt also ein Format, welches der Kernel ausführen kann und darauf kann der Runtime-Loader später aufbauen.
Und genau hier finde ich meinen Ansatz besser bzw. könnten die auch gleich sein/gemacht werden.
Das hatte ich erwähnt, als ich meinte, der Kernel könnte das ELF auch direkt parsen und alle anderen Dinge laufen durch den Runtime-Loader.

Denn mein Runtime-Loader liegt auf der Platte als normale ELF-Datei vor, ist also ein Programm wie jedes andere auch (theoretisch, praktisch würde sich der Runtime-Loader sofort wieder beenden und nichts tun, wenn man ihn ausführt).
Wer parst den Runtime-Loader, wenn der eine ELF-Datei ist? Tut es der Kernel selbst, brauchst du keinen Runtime-Loader mehr für ELF-Dateien und andere Formate kannst du komplett im Userspace implementieren.

Der Linux-Runtime-Loader gehört zur libc(!) und wenn du ihn startest, kannst du damit ELF-Dateien ausführen. Und zwar so, als ob du sie direkt ausgeführt hättest.

In meinem Bootskript steht halt welche Datei der Kernel ist und welche Module noch geladen werden sollen und ich würde jetzt noch ein paar weitere Punkte (Runtime-Loader, Storage-Server, Device-Server, TUI-Server) hinzufügen.
Geladen werden nur die, die für den Bootvorgang auch benötigt werden, sprich der TUI-Server wird erst später vom Storage-Server geladen, aber ich möchte in diesem Bootskript schon alle wichtigen Server drin haben.
Halte ich für den falschen Ansatz. Du möchtest dem Bootloader nicht alle Server mitgeben. Möchtest du nicht. Ist einfach falsch. Du möchtest im Betrieb neue Server definieren können. Server sind bei dir ganz normale Anwendungen mit ein paar Eigenheiten. Warum die im Bootloader statisch definieren?

Warum (und woran) sollte der Bootloader entscheiden, welche Server geladen werden müssen und welche nicht? Können die Server das nicht selbst entscheiden? Was passiert, wenn die Autodetection fehlschlägt?

Warum sollte der Storage-Server den TUI-Server laden? Die haben nichts miteinander zu tun. Der TUI-Server sollte vom Kernel (oder von mir aus dem Servermanagement-Server) geladen werden, wenn eine Konsole daran gebunden werden soll.

Zitat von: svenska
Was interessiert es den Bootloader, ob der App-Server dabei ist? Fehlt am Ende des Tages der App-Server, gibts eine Kernel-Panic und gut ist.
Weil es den Kernel einfacher und kompakter macht. Warum muss der Kernel nachgucken ob alles im Bootskript stand? Ich kann doch schon im Bootloader so viele Fehler wie möglich ausschließen ohne das System überhaupt geladen zu haben.
Der Bootloader soll dem Kernel nicht vorschreiben, was er wie zu tun hat. Der Bootloader soll den Kernel laden und starten und mehr nicht (zumindest ist das meine Definition).

Gedankenspiel: Jeder Server, der gestartet wird, registriert sich beim Kernel. Der App-Server (egal, welcher es ist) registriert sich als "APP". Wenn der Kernel jetzt darauf zugreifen möchte, dann ruft er über IPC nach einem Server mit dem Namen "APP". Ist keiner da: Panic. Damit kannst du im Betrieb den App-Server ändern (oder neustarten), ohne den gesamten Kernel neustarten zu müssen.

Bei dir muss man also, um einen Server zu registrieren, das System neustarten und zerschießt sich unter Umständen die Bootkonfiguration.

Ich halte das für nicht sinnvoll, aber diskutiere nicht weiter. Mach es, wie du es für richtig hältst.

Um es mal auf die Spitze zu treiben, du erwartest doch auch das alle Treiber geladen werden, für die Geräte die vorhanden sind und nicht erst geguckt wird ob ein Gerät vorhanden ist, wenn es vllt irgendwann mal benutzt wird.
Erstmal gibt es zwei Treiber. Einmal den hardwarespezifischen Treiber, der die Hardware ansteuert, und einmal einen allgemeinen Treiber, der mit den Anwendungen und dem hardwarespezifischem Treiber redet.

Konkret ein AC97-Treiber und ein Audio-Server. Letzterer stellt für Anwendungen eine definierte API für Mixer, Kanäle und so weiter zur Verfügung, kann Mischen und Remixen und was-auch-immer. Das kann man als Userspace-Programm (wie PulseAudio) lösen, halte ich aber nicht für sinnvoll, weil es an sich eine Kernfunktionalität von Betriebssystemen ist. Stecke ich jetzt meine USB-AC97-Soundkarte(*) dort an, wird der AC97-Treiber geladen. Fertig.

Der allgemeine Audio-Server wird nicht gestartet. Wenn eine Anwendung Audio ausgeben möchte, macht sie eine Anfrage (z.B. open /dev/audio). Diese Anfrage startet den Audio-Server und er schaut, welche Treiber vorhanden sind und gibt den Ton aus. Anschließend wird er wieder beendet. Die Treiber halten die Hardware ununterbrochen im Stromspar-Modus, solange sie niemand benutzt.

Gut, Audio ist da nicht unbedingt das beste Beispiel, weil man es ständig benutzt, aber für Bluetooth, UMTS oder WLAN ist das schon wesentlich sinnvoller. Außerdem verkürzt das die Bootzeit, weil Server erst gestartet werden, wenn die entsprechenden Anwendungen laufen.

(*) Ja ich weiß, sowas gibt es nicht.

Was die Services betrifft, hängt das auch einfach vom Umfang ab, wenn ich dann 1min zum Starten des Services brauche, dann werden >90% der Nutzer sagen, lieber von Anfang an laufen lassen, als jedes Mal 1min zu warten bis ich es benutzen kann.
Meine Lösung schließt ja nicht aus, dass es persistente Services geben kann. Aber sie macht es möglich, dass dem nicht so ist. Und man könnte es von externen Ereignissen abhängig machen (im Akkubetrieb sind alle Services "aus", im Netzbetrieb sind sie "an").

Da hast du jetzt einen Denkfehler drin. Das einzige was du sparen kannst ist RAM! Denn wenn der Server nicht benutzt wird, läuft er auch nicht, er wartet das eine Anfrage an ihn gestellt wird und das kostet keine CPU-Zyklen.
Er muss aber gestartet und verwaltet werden. Und der Start eines Servers kann recht teuer sein.

Aber wir driften ab, ich denke, wir werden uns da wieder nicht einigen können, daher lass ich es.

Gruß,
Svenska
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 29. December 2010, 17:50
Zitat von: svenska
Ist also ein BLOB im Kernel.
Naja, halt nicht so richtig. Sieh es als eine Library die immer benutzt wird, ob du es willst oder nicht.

Zitat von: svenska
Damit ist er prinzipiell nicht ersetzbar. Du hast einen speziellen Exec-Syscall für den Runtime-Loader, den auch nur dieser nutzen kann, und es gibt keine andere Möglichkeit, einen Prozess zu erzeugen.
Ersetzbar ist er in dem Sinne, das du im Bootskript einen anderen Runtime-Loader angeben kannst, aber dieser muss das selbe Interface unterstützen/nutzen.

Warum sollte es eine andere Möglichkeit geben einen Prozess zu erzeugen bzw. was unterscheidet meinen Runtime-Loader in dem Fall von dem von Linux (vorallem hat Linux eigentlich 2, einem im Kernel und einen in der libc)?

Zitat von: svenska
Dein Kernel ist nicht in der Lage, Prozesse zu starten, ohne ein Dateisystem und die dazugehörigen Services geladen zu haben. Außerdem kannst du keine Prozesse starten, wenn der Runtime-Loader defekt ist oder ersetzt werden muss.
Sagen wir mal jein. Also ohne Dateisysteme kann ich schon einen Prozess starten (muss ich auch, weil ich einfach alle nötigen Dateien an den Storage-Server übergeben will und dieser die schon geladenen Dateien nutzen kann ohne das er etwas von einem Speichermedium laden muss) und wenn der Runtime-Loader unter anderen OSs defekt ist, können auch keine Prozesse mehr gestartet werden (Vergleich: wenn dein Auto kaputt ist, kannst du solange damit nicht fahren bis es wieder in Ordnung ist).

Zitat von: svenska
Das hatte ich erwähnt, als ich meinte, der Kernel könnte das ELF auch direkt parsen und alle anderen Dinge laufen durch den Runtime-Loader.
Da frage ich mich dann was sind diese anderen Dinge? Denn was außer der ELF Datei zu parsen (und das Process-Image erzeugen) macht denn der Runtime-Loader noch so?

Zitat von: svenska
Wer parst den Runtime-Loader, wenn der eine ELF-Datei ist?
Habe ich doch geschrieben, das macht mein Bootloader (wo praktisch auch ein Runtime-Loader drin ist).

Zitat von: svenska
Halte ich für den falschen Ansatz. Du möchtest dem Bootloader nicht alle Server mitgeben. Möchtest du nicht. Ist einfach falsch. Du möchtest im Betrieb neue Server definieren können. Server sind bei dir ganz normale Anwendungen mit ein paar Eigenheiten. Warum die im Bootloader statisch definieren?
Richtig. Aber ich will die wichtigsten also nötigen Server definieren können. Also sowas wie Storage-Server und Device-Server.

Anders gefragt, wenn du die nicht irgendwo definierst, wer startet die dann und wenn dieser Jemand sie startet wurden sie ja doch irgendwo definiert. Du kannst ja schlecht den Benutzer danach fragen, das würde ja die Server schon vorraussetzen.

Zitat von: svenska
Warum sollte der Storage-Server den TUI-Server laden? Die haben nichts miteinander zu tun. Der TUI-Server sollte vom Kernel (oder von mir aus dem Servermanagement-Server) geladen werden, wenn eine Konsole daran gebunden werden soll.
Erstmal richtig, aber ich gehe halt davon aus, das z.B. entweder der TUI-Server oder der GUI-Server geladen wird und das muss ja irgendwo in irgendeinem Skript stehen und ich will nicht tausend Skripts haben.

Zitat von: svenska
Damit kannst du im Betrieb den App-Server ändern (oder neustarten), ohne den gesamten Kernel neustarten zu müssen.
Das kann ich auch so. Das schöne an einem MikroKernel (wenn er denn ein "richtiger" ist) ist doch das dir das als Kernel alles scheiß egal sein kann. Du machst als Kernel nichts weiter als IPC, VMM und Prozessmanagement. Wenn ein IPC Ziel nicht da ist, gibst du halt nen Fehler zurück, aber zu einem Kernel-Panic darf das nicht führen.

Der Kernel soll doch bei mir so wenig wie möglich darüber wissen. Also eigentlich gar nichts.

Zitat von: svenska
Bei dir muss man also, um einen Server zu registrieren, das System neustarten und zerschießt sich unter Umständen die Bootkonfiguration.
Jein. Ersten hatten wir es doch schonmal das einen Server zu resetten eher weniger schön ist bzw. bei einigen Sachen wahrscheinlich unmöglich und daher sowieso einen System Neustart erfordert und zweitens rede ich ja nur von den wirklich nötigen Servern. Mit allen anderen Servern habe ich nichts am Hut.

Zitat von: svenska
Der allgemeine Audio-Server wird nicht gestartet. Wenn eine Anwendung Audio ausgeben möchte, macht sie eine Anfrage (z.B. open /dev/audio). Diese Anfrage startet den Audio-Server und er schaut, welche Treiber vorhanden sind und gibt den Ton aus. Anschließend wird er wieder beendet. Die Treiber halten die Hardware ununterbrochen im Stromspar-Modus, solange sie niemand benutzt.
Also erstmal sowas wie ne USB-Soundkarte gibt es ;)

Was du bei der ganzen Sache vergisst (bzw. denke ich das ist deiner Linux Denkart geschuldet ;) ), wenn du einen Service nutzen willst muss dieser auch gestartet sein, sprich wenn du ein "open /dev/audio" machen willst, dann muss das auch vorhanden sein, das ist es aber nur wenn der Server auch gestartet ist, ansonsten gibt es das nicht.
Das kann man jetzt so lösen das jedes Programm welches einen bestimmten Service nutzen will, erstmal diesen starten muss und ich denke da sind wir uns beide einig, dass das weniger sinnvoll ist.
Ansonsten muss zumindest irgendeine Art Ansprechpartner vorhanden sein, der die Anfrage entgegen nimmt und den Server startet und dann die Anfrage weiterleitet und das wiederrum ist auch nicht wirklich sinnvoll und von Performance will ich erst gar nicht anfangen ;)

Zitat von: svenska
Er muss aber gestartet und verwaltet werden. Und der Start eines Servers kann recht teuer sein.
Genau das ist/war doch mein Punkt. Da der Start recht teuer sein kann, werden >90% der Nutzen sagen, das der Server lieber von Anfang an "laufen" soll als das man ihn jedes Mal startet wenn er benötigt wird.

Edit::

Habe ich doch glatt was vergessen.

Dynamisch ladbare Module/Add-Ons. Wie würde man sowas lösen mit nem Runtime-Loader der im UserSpace läuft?

Ich dachte da jetzt daran, das mein Runtime-Loader einfach immer im Adressraum bleibt und einfach als Systempages gekennzeichnet wird und wenn das Programm ein Modul laden will (dlopen() usw.) dann wird einfach der Runtime-Loader wieder "freigegeben" (also als Userpages markiert) und er führt sein dlopen() usw. aus.

Aus Sicherheitsgründen würde ich solange aber alle Threads des Prozesses anhalten, damit der Prozess nicht in den Daten des Runtime-Loader rumspielen kann.

Das würde auch heißen das ich einen weiteren Syscall (bzw. weitere Syscalls) bräuchte um den Runtime-Loader dann aufzurufen.

Noch eine Sache zu den Modulen/Add-Ons.

Sollte man für die Symboltabellen z.B. einen Patricia-Tree nehmen oder einfach nur ein großen Array, was man dann durchgeht? Oder anders gefragt ist Performance beim Symbol-Suchen wichtig und/oder erwünscht (würde ja mit etwas mehr Speicherverbrauch einhergehen)?
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: Svenska am 29. December 2010, 18:47
Warum sollte es eine andere Möglichkeit geben einen Prozess zu erzeugen bzw. was unterscheidet meinen Runtime-Loader in dem Fall von dem von Linux (vorallem hat Linux eigentlich 2, einem im Kernel und einen in der libc)?
Du musst allgemeine Prozesse erzeugen können, für die du vollständigen Userspace nutzen kannst (Unix-Prinzip ist fork()), aber du brauchst eine minimale Möglichkeit, Prozesse ohne Unterstützung starten zu können. Für dein Mikrokernelkonzept sind das im Speziellen die Services, die dir erst den Userspace geben.

Linux kann nativ ELF ausführen, der Runtime-Loader ist für den Userspace da.

wenn der Runtime-Loader unter anderen OSs defekt ist, können auch keine Prozesse mehr gestartet werden (Vergleich: wenn dein Auto kaputt ist, kannst du solange damit nicht fahren bis es wieder in Ordnung ist).
Ja. In einem Mikrokernel sollten aber zumindest die Services, die den Userspace überhaupt am Leben halten, auch ohne Unterstützung des Userspace gestartet werden können. (Der Bootvorgang ist eine Ausnahme, weil man dort eine Lebendgeburt machen kann.)

Da frage ich mich dann was sind diese anderen Dinge? Denn was außer der ELF Datei zu parsen (und das Process-Image erzeugen) macht denn der Runtime-Loader noch so?
Er erzeugt nicht nur ein Image für den Prozess, sondern muss auch zusätzlich benötigte Libraries finden, laden und daraus Symboltabellen generieren, die er der dynamisch gelinkte Anwendung mitgeben muss. Außerdem kommen eventuell noch Sicherheitsgedanken dazu, also z.B. eine Festlegung, welche Symbole eine bestimmte Anwendung in einem bestimmten Nutzerkontext sehen/nutzen darf. Da kann man einiges konstruieren.

Das native Kernel-Binärformat kann relativ dumm sein (statisch, keine Abhängigkeiten); im Userspace reicht das nicht - darum nimmt man ja einen Runtime-Loader. Wie du deine Services dort einsortierst, weiß ich nicht; es sind zwar Anwendungen, aber ich (als monolithisch versauter Mensch) trenne die streng vom "richtigen" Userspace.

Zitat von: svenska
Wer parst den Runtime-Loader, wenn der eine ELF-Datei ist?
Habe ich doch geschrieben, das macht mein Bootloader (wo praktisch auch ein Runtime-Loader drin ist).
OK.

Anders gefragt, wenn du die [Server] nicht irgendwo definierst, wer startet die dann und wenn dieser Jemand sie startet wurden sie ja doch irgendwo definiert. Du kannst ja schlecht den Benutzer danach fragen, das würde ja die Server schon vorraussetzen.
Also wenn ich mir die übliche GRUB-Konfiguration anschaue, dann übergebe ich bei Linux das Kernelbinary und eine initrd/initramfs. Alternativ kannst du ELF-Module laden lassen und er sagt dir sogar, wo er sie hingeladen hat.

-- Pseudo-Bootloader-Konfiguration --
KERNEL /boot/kernel
MODULE /modules/appserver
MODULE /modules/deviceserver
MODULE /modules/consoleserver
MODULE /modules/tuiserver
...

Der Kernel startet alle Module, die ihm vorgesetzt wurden. Alle weiteren Services, die nicht boot-kritisch sind, werden später geladen. Was ist daran so schlecht?

Erstmal richtig, aber ich gehe halt davon aus, das z.B. entweder der TUI-Server oder der GUI-Server geladen wird und das muss ja irgendwo in irgendeinem Skript stehen und ich will nicht tausend Skripts haben.
Du brauchst weder TUI noch GUI, solange keine Anwendungen irgendetwas ausgeben möchten. Da du in deinem Konzept IPC benötigst, wenden die Anwendungen (z.B. init) sich an einen well-known-service, der eine Funktionalität bereitstellt. Ist der noch nicht vorhanden, wird er geladen. Schlägt das Fehl, kriegt die Anwendung einen Fehler.

Was du machst, ist trotzdem möglich, aber (für mich) nicht schön.

Jein. Ersten hatten wir es doch schonmal das einen Server zu resetten eher weniger schön ist bzw. bei einigen Sachen wahrscheinlich unmöglich und daher sowieso einen System Neustart erfordert und zweitens rede ich ja nur von den wirklich nötigen Servern. Mit allen anderen Servern habe ich nichts am Hut.
Wenn der Server weg ist, der nötig ist, um ein Binary zu laden, dann ist ein Neustart nötig. Aber um den Bluetooth-Server registrieren zu können, müsste ich ihn bei dir in den Bootloader eintragen (Fehler: System kaputt) und neu starten. Das meinte ich. Wo das nicht mehr geht, geht das halt nicht mehr.

Was du bei der ganzen Sache vergisst (bzw. denke ich das ist deiner Linux Denkart geschuldet ;) ), wenn du einen Service nutzen willst muss dieser auch gestartet sein, sprich wenn du ein "open /dev/audio" machen willst, dann muss das auch vorhanden sein, das ist es aber nur wenn der Server auch gestartet ist, ansonsten gibt es das nicht.
Ich kann auch eine Anfrage an einen Server "SND" machen. Das OS sollte fähig sein, festzustellen, dass es diesen Service nicht gibt und ihn selbstständig nachladen können. Wenn ich in /dev/ eine Datei öffne, die nicht existiert, dann könnte man auch in den vorhandenen Modulen nachschauen, ob ein Modul existiert, welches diese Datei bereitstellt.

Das kann man jetzt so lösen das jedes Programm welches einen bestimmten Service nutzen will, erstmal diesen starten muss und ich denke da sind wir uns beide einig, dass das weniger sinnvoll ist.
Das ist Teil der Serververwaltung, nicht Teil der Anwendung. Richtig.

Ansonsten muss zumindest irgendeine Art Ansprechpartner vorhanden sein, der die Anfrage entgegen nimmt und den Server startet und dann die Anfrage weiterleitet und das wiederrum ist auch nicht wirklich sinnvoll und von Performance will ich erst gar nicht anfangen ;)
Wenn man sich das IPC als eine Art "Bus" vorstellt, dann hast du einen Service-Server, der diesen Bus abhört und weiß, welche Services gerade existieren. Wenn eine Anfrage nach "SND" kommt, es aber kein "SND" gibt, dann blockiert die Anfrage, bis der Service aktiv ist oder wird mit Fehlercode beantwortet, wenn der Server nicht existiert oder nicht gestartet werden konnte.

Das kann ich mir auch im Mikrokernel selbst vorstellen, denn der weiß ja, welche Services existieren.

Zitat von: svenska
Er muss aber gestartet und verwaltet werden. Und der Start eines Servers kann recht teuer sein.
Genau das ist/war doch mein Punkt. Da der Start recht teuer sein kann, werden >90% der Nutzen sagen, das der Server lieber von Anfang an "laufen" soll als das man ihn jedes Mal startet wenn er benötigt wird.
Ja, das hängt aber vom Server ab. Im Übrigen gehöre ich dann wohl zu den 10%, die sagen, dass ein Server, der sehr langsam startet, nicht beim Boot gestartet werden soll, wenn ich ihn nicht benötige.

Wenn er einmal läuft, soll er aber aktiv bleiben.

Dynamisch ladbare Module/Add-Ons. Wie würde man sowas lösen mit nem Runtime-Loader der im UserSpace läuft?

Ich dachte da jetzt daran, das mein Runtime-Loader einfach immer im Adressraum bleibt und einfach als Systempages gekennzeichnet wird und wenn das Programm ein Modul laden will (dlopen() usw.) dann wird einfach der Runtime-Loader wieder "freigegeben" (also als Userpages markiert) und er führt sein dlopen() usw. aus.
Dagegen. Ich würde dlopen() in der libc implementieren und zwar in einer Form, dass der Runtime-Loader selbst diese Funktion benutzen kann, um die Abhängigkeiten aufzulösen. Natürlich muss der Runtime-Loader die Funktion statisch eingelinkt haben (da der Kernel keine dynamischen Dateien ausführen kann).

Sollte man für die Symboltabellen z.B. einen Patricia-Tree nehmen oder einfach nur ein großen Array, was man dann durchgeht? Oder anders gefragt ist Performance beim Symbol-Suchen wichtig und/oder erwünscht (würde ja mit etwas mehr Speicherverbrauch einhergehen)?
Keine Ahnung, nie gehört. Bin kein Informatiker. ;-)

Gruß,
Svenska
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 29. December 2010, 19:12
Zitat von: svenska
Der Kernel startet alle Module, die ihm vorgesetzt wurden. Alle weiteren Services, die nicht boot-kritisch sind, werden später geladen. Was ist daran so schlecht?
Das Problem ist der Bootvorgang an sich. Dort muss eine bestimmte Reihenfolge eingehalten werden um die Sache nicht noch schwieriger zu machen. Als restes muss z.B. der Storage-Server gestartet werden, der bekommt alle Module übergeben und dann wird der Device-Server gestartet, dieser nutzt nur Treiber die schon geladen wurden (dazu muss der Storage-Server aber laufen), sind dann alle Treiber geladen und die entsprechenden Geräte funktionieren, werden weitere Treiber geladen (dafür braucht man wieder die Treiber die der Bootloader mit geladen hat) usw.

Zitat von: svenska
Also wenn ich mir die übliche GRUB-Konfiguration anschaue, dann übergebe ich bei Linux das Kernelbinary und eine initrd/initramfs. Alternativ kannst du ELF-Module laden lassen und er sagt dir sogar, wo er sie hingeladen hat.
Richtig, aber auch unter Linux wird ein Startskript ausgeführt, um aber sowas erstmal machen zu können, müsste ich schon einige Service geladen und gestartet haben und mein Bootskript ist dann ein sehr vereinfachtes Startskript.

Zitat von: svenska
Du brauchst weder TUI noch GUI, solange keine Anwendungen irgendetwas ausgeben möchten. Da du in deinem Konzept IPC benötigst, wenden die Anwendungen (z.B. init) sich an einen well-known-service, der eine Funktionalität bereitstellt. Ist der noch nicht vorhanden, wird er geladen. Schlägt das Fehl, kriegt die Anwendung einen Fehler.
Und genau damit habe ich jetzt ein Problem, wo legst du fest in welcher Datei und an welchem Ort sich dieser well-known-service befindet? Ich möchte halt nicht in irgendeinem Programmcode sagen das der TUI-Server an "/system/tui-server" liegt, sondern möchte das in einem Skript drin haben, wo steht "TUI-SERVER="/system/tui-server"" (oder noch besser UI-SERVER=...), so dass ich ihn auch austauschen könnte.

Vorallem ich möchte einen RPC an den TUI-Server machen also mache ich nen Syscall portGetByName("TUI-SERVER") und dieser gibt mir die Portnummer zurück oder nen Fehler. Was ist nun wenn dieser Server nicht geladen ist, wer soll ihn laden und wer legt fest welche Datei den Server repräsentiert?

Zitat von: svenska
Aber um den Bluetooth-Server registrieren zu können, müsste ich ihn bei dir in den Bootloader eintragen (Fehler: System kaputt) und neu starten. Das meinte ich. Wo das nicht mehr geht, geht das halt nicht mehr.
Das stimmt so nicht. Der Bluetooth-Server ist kein systemkritischer Server und somit ist der mir egal. Was für mich systemkritisch ist, wären Storage, Device, Input und einen Server für die Ausgabe auch der Net-Server wäre jetzt nicht systemkritisch (obwohl man ihn sehr wohl dazu packen könnte, spätestens wenn man über LAN bootet).
Alles was nicht systemkritisch ist und nicht zum Laufen des Systems beiträgt (so dass der User alle anderen Server zur Not per Hand starten kann) sind nicht im Bootskript drin bzw. würde ich die in ein optional-Bootskript auslagern.

Zitat von: svenska
Wenn man sich das IPC als eine Art "Bus" vorstellt, dann hast du einen Service-Server, der diesen Bus abhört und weiß, welche Services gerade existieren. Wenn eine Anfrage nach "SND" kommt, es aber kein "SND" gibt, dann blockiert die Anfrage, bis der Service aktiv ist oder wird mit Fehlercode beantwortet, wenn der Server nicht existiert oder nicht gestartet werden konnte.
Aber woher weiß dieser Service-Server welche Datei den SND-Service repräsentiert?

Ich bin dafür das man, wie unter Windows, die Services die möglich sind, erstmal alle als automatisch starten markiert und der Nutzer kann dann den jeweiligen Service gerne als manuel markieren, so dass dieser nicht mehr automatisch geladen wird, sondern nur noch auf Wunsch des Nutzers.

Zitat von: svenska
Dagegen. Ich würde dlopen() in der libc implementieren und zwar in einer Form, dass der Runtime-Loader selbst diese Funktion benutzen kann, um die Abhängigkeiten aufzulösen. Natürlich muss der Runtime-Loader die Funktion statisch eingelinkt haben (da der Kernel keine dynamischen Dateien ausführen kann).
Sowas in der Art will ich doch machen, aber dlopen() muss ja den Runtime-Loader nutzen, weil ich nicht die Funktionalität um Module (und damit wieder Executeables) parsen zu können nochmal in der libc haben will. Die libc würde nur nen Stub haben, der nen Syscall mit dlopen() macht (so funktioniert das glaub ich unter Linux auch) und dieser Syscall würde den Runtime-Loader in dem aufrufenden Prozess aktivieren und dieser würde dann sein dlopen() (für das entsprechende Format) ausführen.

Problem ist halt nur das der Prozess den Runtime-Loader nicht sehen können soll und d.h. das solange der Runtime-Loader sein dlopen() ausführt muss der komplette Prozess angehalten werden.

Ich denke ich werde für den Anfang einfach ein großes Array nutzen und später wenn alles läuft auf nen Patricia-Tree umsteigen, obwohl ja ELF schon ne Hash-Tabelle für sowas mitbringt, vllt nutze ich auch das.
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: Svenska am 29. December 2010, 20:01
Das Problem ist der Bootvorgang an sich. Dort muss eine bestimmte Reihenfolge eingehalten werden um die Sache nicht noch schwieriger zu machen.
Da der Bootloader die Module in der Reihenfolge lädt, in der sie in der Datei angegeben sind, sehe ich da kein Problem. Der Rest sind Implementationsdetails. Ich würde die gesamte Komplexität der Serververwaltung aus dem Bootloader herausnehmen (der hat damit nichts zu tun!) und in einen Service-Server stecken. Oder in den Kernel selbst.

Richtig, aber auch unter Linux wird ein Startskript ausgeführt, um aber sowas erstmal machen zu können, müsste ich schon einige Service geladen und gestartet haben und mein Bootskript ist dann ein sehr vereinfachtes Startskript.
Linux führt keinerlei Script aus, bis der Kernel geladen ist, läuft, und ein Userspace funktioniert. Du kannst immernoch ohne initrd booten, das erste Script, was läuft ist dann /sbin/init.

Und genau damit habe ich jetzt ein Problem, wo legst du fest in welcher Datei und an welchem Ort sich dieser well-known-service befindet? Ich möchte halt nicht in irgendeinem Programmcode sagen das der TUI-Server an "/system/tui-server" liegt, sondern möchte das in einem Skript drin haben, wo steht "TUI-SERVER="/system/tui-server"" (oder noch besser UI-SERVER=...), so dass ich ihn auch austauschen könnte.
Andersrum, deine Serverdateien enthalten Header, welche Services sie bereitstellen. Und alle Services liegen in einem well-known-Pfad, Linux-Kernelmodule liegen z.B. immer in /lib/modules/`uname -r`/

Du brauchst an sich kein Script, welches angibt, welcher Service was kann, sondern der Service selbst hat dann einen Header, den du zerpflücken kannst. Das heißt, dein Userland schaut sich alle Service-Dateien an, ermittelt, welche Services existieren (und in welchen Dateien sie auf Platte liegen).

Der TUI-Server stellt dann einen Dienst "TUI" bereit, der GUI-Server (die Diskussion hatten wir schon) stellt z.B. einen Dienst "GUI" und einen Dienst "TUI" bereit. Das heißt, es kann immer nur einer von beiden Diensten aktiv sein.

Vorallem ich möchte einen RPC an den TUI-Server machen also mache ich nen Syscall portGetByName("TUI-SERVER") und dieser gibt mir die Portnummer zurück oder nen Fehler. Was ist nun wenn dieser Server nicht geladen ist, wer soll ihn laden und wer legt fest welche Datei den Server repräsentiert?
Der Syscall könnte feststellen, dass "TUI-SERVER" nicht existiert und blockiert. Dann sucht er in den vorhandenen Dateien nach einem Service, der dieses RPC-/IPC-Target bereitstellt, lädt es, und gibt erst dann die Portnummer zurück oder einen Fehler, wenn es nicht geht.

Das stimmt so nicht. Der Bluetooth-Server ist kein systemkritischer Server und somit ist der mir egal. Was für mich systemkritisch ist, wären Storage, Device, Input und einen Server für die Ausgabe auch der Net-Server wäre jetzt nicht systemkritisch (obwohl man ihn sehr wohl dazu packen könnte, spätestens wenn man über LAN bootet).
Was systemkritisch ist und was nicht, legst nicht du fest. Wer sagt dir eigentlich, dass du nicht über OBEX-Bluetooth booten möchtest? Ich weiß, dass du ausschließlich PC@x86 und PC@x86_64 als Targets betrachtest, aber Input und Output sind auch nicht unbedingt systemkritisch (Systeme ohne Bildschirm & Tastatur).

Die Entscheidung, was im Einzelfall systemkritisch (d.h. zum Booten benötigt) ist, trifft der Benutzer und leitet dieses an den Bootloader weiter.

Alles was nicht systemkritisch ist und nicht zum Laufen des Systems beiträgt (so dass der User alle anderen Server zur Not per Hand starten kann) sind nicht im Bootskript drin bzw. würde ich die in ein optional-Bootskript auslagern.
Ich würde alles, was systemkritisch ist, vom Bootloader anhand dessen Konfiguration laden und alles, was nicht systemkritisch ist, dynamisch vom Userspace ausgehend, wenn es benötigt wird.

Aber woher weiß dieser Service-Server welche Datei den SND-Service repräsentiert?
Weil es in der Datei steht. Mach mal "sudo modinfo rtl8187"...

Ich bin dafür das man, wie unter Windows, die Services die möglich sind, erstmal alle als automatisch starten markiert und der Nutzer kann dann den jeweiligen Service gerne als manuel markieren, so dass dieser nicht mehr automatisch geladen wird, sondern nur noch auf Wunsch des Nutzers.
Pfui.

Sowas in der Art will ich doch machen, aber dlopen() muss ja den Runtime-Loader nutzen, weil ich nicht die Funktionalität um Module (und damit wieder Executeables) parsen zu können nochmal in der libc haben will.
Für mich wäre der Runtime-Loader eine Anwendung wie jede andere auch (nur mit well-known-path und well-known-name und statisch), daher sehe ich kein Problem, wenn dlopen() den Runtime-Loader aufruft. Das muss die libc bei einem exec() ja auch tun, also...

Wenn du aber den Runtime-Loader so sehr tief ins System integrierst, kannst du ihn dafür nicht mehr nutzen.

Gruß,
Svenska
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 29. December 2010, 20:27
Zitat von: svenska
Linux führt keinerlei Script aus, bis der Kernel geladen ist, läuft, und ein Userspace funktioniert. Du kannst immernoch ohne initrd booten, das erste Script, was läuft ist dann /sbin/init.
Und genau um den UserSpace zum Laufen zu bekommen brauche ich Services (das ist ein Problem von einem MikroKernel, erstmal alles zum Laufen zu bekommen) und dafür möchte ich ein Skript nutzen um das möglichst flexibel zu gestalten.

Zitat von: svenska
Du brauchst an sich kein Script, welches angibt, welcher Service was kann, sondern der Service selbst hat dann einen Header, den du zerpflücken kannst. Das heißt, dein Userland schaut sich alle Service-Dateien an, ermittelt, welche Services existieren (und in welchen Dateien sie auf Platte liegen).
Und wie willst du auf die Platte zugreifen um den Storage-Server zu laden und selbst wenn du den schon hast wie willst du ohne Treiber/Device-Server nach einem anderen Server suchen und was machst du wenn du mehrere Dateien findest die die gleichen Services anbieten (das Problem hatten wir beim Treibermanagement schonmal)?

Am liebsten wäre mir ein Skript, wo ich alle wichtigen bzw. alle Server reinpacke die gestartet werden sollen und dieses Skript wird dann abgearbeitet. Dazu bräuchte ich aber nen funktionierenden UserSpace um das Skript von z.B. sh ausführen zu lassen und das wiederum setzt die Server voraus (Henne-Ei-Problem).

Dann gefällt mir bei deinem Ansatz noch nicht, das die Suche nach so einem Service auch mal länger dauern kann. Desweiteren hätte ich Sicherheits Bedenken bei dieser Vorgehensweise, weil wie hindere ich diesen Service-Server daran einen Server zu starten von einem Programm was das eigentlich gar nichts soll (z.B. ist der PC zwar an einem Netzwerk, aber es sollen weder Daten raus noch rein kommen)?

Zitat von: svenska
Was systemkritisch ist und was nicht, legst nicht du fest.
Erstmal richtig, das macht mein Skript ;)

Zitat von: svenska
Wer sagt dir eigentlich, dass du nicht über OBEX-Bluetooth booten möchtest? Ich weiß, dass du ausschließlich PC@x86 und PC@x86_64 als Targets betrachtest, aber Input und Output sind auch nicht unbedingt systemkritisch (Systeme ohne Bildschirm & Tastatur).
Also ich habe durchaus vor mein OS auch auf ARM zu portieren und an x86_64 habe ich noch keine Gedanken verschwendet.
Was das Booten über Bluetooth betrifft, das ist möglich? Sehr interessant und ja sowas will ich eigentlich auch unterstützen, aber deswegen meinte ich ja auch, das man die wichtigsten Server in das Skript packt und alles was sonst noch wichtig ist, wird als Modul geladen und kann dann über den Storage-Server auch ausgeführt werden und wenn ich über Bluetooth booten möchten, dann wird bestimmt der Bluetooth-Server als Modul mitgeladen und wird auch gestartet.

Was Systeme ohne Bildschirm+Tastatur betrifft auch sowas möchte ich unterstützen, aber um mir und den Programmen/Programmierern das Leben nicht schwer zu machen soll alles so laufen als wäre beides vorhanden. Der Input-Server holt sich dann bspw. den Input vom seriellen Port und der TUI-Server leitet den Output zum seriellen Port weiter.
So können alle Programme ganz normal arbeiten und der Bootvorgang läuft auch wie gewöhnt. Bzw. wird der Input-Server einfach den seriellen Port als Stdin weiterleiten und der TUI-Server wird Stdout an den seriellen Port weiterleiten.

Zitat von: svenska
Weil es in der Datei steht. Mach mal "sudo modinfo rtl8187"...
Ich glaube das hatten wir schon, der Linux-Kernel hat ne Liste die zur Compilezeit statisch festlegt welche Module möglich sind und welche nicht (oder?).

Zitat von: svenska
Für mich wäre der Runtime-Loader eine Anwendung wie jede andere auch (nur mit well-known-path und well-known-name und statisch), daher sehe ich kein Problem, wenn dlopen() den Runtime-Loader aufruft. Das muss die libc bei einem exec() ja auch tun, also...
Das verstehe ich jetzt nicht, wie kommt der Runtime-Loader dann an die Symboltabelle ran und wie kann er das Modul in den Prozess integrieren, wenn er als eigenständiger Prozess läuft?

Zitat von: svenska
Wenn du aber den Runtime-Loader so sehr tief ins System integrierst, kannst du ihn dafür nicht mehr nutzen.
Hier verstehe ich jetzt nicht was du meinst. Wofür kann ich den Runtime-Loader dann nicht mehr nutzen?
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: Svenska am 29. December 2010, 20:59
Und genau um den UserSpace zum Laufen zu bekommen brauche ich Services (das ist ein Problem von einem MikroKernel, erstmal alles zum Laufen zu bekommen) und dafür möchte ich ein Skript nutzen um das möglichst flexibel zu gestalten.
Nimm doch die Konfigurationsdatei des Bootloaders (und nenn diese nicht Script). Was ist das Problem? Die setzt du statisch auf genau die Server, die du brauchst, um Userspace zum Laufen zu bekommen. Fertig.

Und wie willst du auf die Platte zugreifen um den Storage-Server zu laden und selbst wenn du den schon hast wie willst du ohne Treiber/Device-Server nach einem anderen Server suchen und was machst du wenn du mehrere Dateien findest die die gleichen Services anbieten (das Problem hatten wir beim Treibermanagement schonmal)?
Storage-Server, Device-Server, App-Server sind bootkritisch, sind also vom Bootloader bereits geladen worden und laufen. Die ganze dynamische Konfiguration, Zugriffe auf die Platte und so weiter werden vom Userspace getriggert, der muss also per Definition schon da sein.

Dann gefällt mir bei deinem Ansatz noch nicht, das die Suche nach so einem Service auch mal länger dauern kann.
Du erzeugst aus diesen Headern eine Datei, die alle wesentlichen Informationen enthält. Wann immer du Server einträgst oder entfernst, musst du diese Datei aktualisieren. Die Suche nach einem Service dauert dann nur so lange, wie du diese Datei durchsuchen kannst. Das ist akzeptabel.

Desweiteren hätte ich Sicherheits Bedenken bei dieser Vorgehensweise, weil wie hindere ich diesen Service-Server daran einen Server zu starten von einem Programm was das eigentlich gar nichts soll (z.B. ist der PC zwar an einem Netzwerk, aber es sollen weder Daten raus noch rein kommen)?
Das ist ein Implementationsdetail. Das Starten von Services wird von irgendwo koordiniert (schließlich muss der Service identifiziert werden, der passende Server lokalisiert und gestartet). An der Stelle noch ein Flag setzen, dass der Server nicht automatisch gestartet werden soll, ist jetzt nicht mehr soo schwer.

Was das Booten über Bluetooth betrifft, das ist möglich?
Keine Ahnung.

Sehr interessant und ja sowas will ich eigentlich auch unterstützen, aber deswegen meinte ich ja auch, das man die wichtigsten Server in das Skript packt und alles was sonst noch wichtig ist, wird als Modul geladen und kann dann über den Storage-Server auch ausgeführt werden und wenn ich über Bluetooth booten möchten, dann wird bestimmt der Bluetooth-Server als Modul mitgeladen und wird auch gestartet.
Wenn du über OBEXFS oder WLAN booten möchtest, dann brauchst du (theoretisch) nur im Bootloader etwas eintragen:

MODULE /modules/bt/hostadapter-driver
MODULE /modules/bt/btstack-server OBEXFS=geraet,blablub
...
MODULE /modules/storage-server ROOTFS=btstack:geraet:pfad

Da du das Root-Dateisystem ohnehin irgendwo angeben musst, und die Server ihre Services (je nachdem) als Dateisystem angeben können, geht das problemlos. Sehe ich weniger ein Problem, du musst nur irgendwie die Parameter in den Servern verarbeiten können.

Was Systeme ohne Bildschirm+Tastatur betrifft auch sowas möchte ich unterstützen, aber um mir und den Programmen/Programmierern das Leben nicht schwer zu machen soll alles so laufen als wäre beides vorhanden. Der Input-Server holt sich dann bspw. den Input vom seriellen Port und der TUI-Server leitet den Output zum seriellen Port weiter.
Der TUI-Server setzt einfach ein character input und ein character output voraus, und wenn das dein RS232-Server ist, dann ist der das halt. Mach nicht den Fehler und arbeite mit Dummy-Interfaces.

Bedenke, dass die ANSI-Emulation bei RS232 nicht die gleiche ist, wie bei der VGA-Karte.

Zitat von: svenska
Weil es in der Datei steht. Mach mal "sudo modinfo rtl8187"...
Ich glaube das hatten wir schon, der Linux-Kernel hat ne Liste die zur Compilezeit statisch festlegt welche Module möglich sind und welche nicht (oder?).
Nein. Module liegen in /lib/modules/`uname -r`/* und haben einen Header. Jedes Modul hat zur Compilezeit diesen Header verpasst gekriegt und der enthält, welche Geräte von diesem Modul unterstützt werden.

Erweitere das Prinzip und du hast einen Header für Treiber, welche Geräte sie unterstützen und für Server, welche Services sie bereitstellen.

Zitat von: svenska
Für mich wäre der Runtime-Loader eine Anwendung wie jede andere auch (nur mit well-known-path und well-known-name und statisch), daher sehe ich kein Problem, wenn dlopen() den Runtime-Loader aufruft. Das muss die libc bei einem exec() ja auch tun, also...
Das verstehe ich jetzt nicht, wie kommt der Runtime-Loader dann an die Symboltabelle ran und wie kann er das Modul in den Prozess integrieren, wenn er als eigenständiger Prozess läuft?
Hmm, valides Argument. Dazu müsste der Runtime-Loader in die libc integriert sein. Das könnte sogar funktionieren. ;-)

Zitat von: svenska
Wenn du aber den Runtime-Loader so sehr tief ins System integrierst, kannst du ihn dafür nicht mehr nutzen.
Hier verstehe ich jetzt nicht was du meinst. Wofür kann ich den Runtime-Loader dann nicht mehr nutzen?
Entweder, du hast den Runtime-Loader als Kopie ständig im Adressraum jedes Prozesses verfügbar, um dlopen() zu unterstützen, oder du lädst ihn jedesmal neu dort rein. Ich find das nicht soo schön.

;-)
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 29. December 2010, 21:23
Zitat von: svenska
Nimm doch die Konfigurationsdatei des Bootloaders (und nenn diese nicht Script). Was ist das Problem? Die setzt du statisch auf genau die Server, die du brauchst, um Userspace zum Laufen zu bekommen. Fertig.
Das sage ich doch die ganze Zeit ;)

Zitat von: svenska
Du erzeugst aus diesen Headern eine Datei, die alle wesentlichen Informationen enthält. Wann immer du Server einträgst oder entfernst, musst du diese Datei aktualisieren. Die Suche nach einem Service dauert dann nur so lange, wie du diese Datei durchsuchen kannst. Das ist akzeptabel.
Das klingt nach einer Art Registry nur in Form von vielen Dateien (Linux typisch und viele bemämgeln das, also die vielen Konfigurationsdateien). Sowas will ich allerdings nicht, weil das würde ja nur funktionieren, wenn mein OS läuft, nur dann könnte diese Datei aktualisiert werden und damit habe ich ein Problem, aber auch das hatten wir schon bei den Treibern.
Allerdings muss ich dir recht geben was die Services betrifft, also mit dem Header, weil sowas will ich ja bei den Treibern nutzen. Ich sehe noch nicht so richtig wie ich das machen sollte, ohne das ich einen Service-Server habe, weil im Kernel würde ich das ungern machen wollen (also Programme laden lassen, zumal das eh schwierig werden dürfte mit meinem Runtime-Loader Konzept).

Zitat von: svenska
An der Stelle noch ein Flag setzen, dass der Server nicht automatisch gestartet werden soll, ist jetzt nicht mehr soo schwer.
Das klingt irgendwie genau nach der Windows Art und Weise, also immer laden lassen, bis es von Hand umgestellt wird ;)

Zitat von: svenska
Da du das Root-Dateisystem ohnehin irgendwo angeben musst, und die Server ihre Services (je nachdem) als Dateisystem angeben können, geht das problemlos. Sehe ich weniger ein Problem, du musst nur irgendwie die Parameter in den Servern verarbeiten können.
Was das betrifft (also das Root-Dateisystem und solche Konzepte), habe ich mir überhaupt noch keinen Kopf gemacht.

Zitat von: svenska
Hmm, valides Argument. Dazu müsste der Runtime-Loader in die libc integriert sein. Das könnte sogar funktionieren.
Genau da sehe ich ein noch größeres Problem (wennd er Runtime-Loader in der libc ist). Denn das hieße ja, das du immer erstmal die libc in einen neuen Prozess packen musst um den Prozess zu erstellen, was ist aber wenn du einen Prozess hast, der keine libc nutzt? Ansonsten ist die Idee gar nicht mal so schlecht. Mal davon abgesehen, das sie sich nicht so viel von meiner unterscheidet, außer das ich den Runtime-Loader noch vor dem bösen bösen Prozess schützen möchte.

Zitat von: svenska
Entweder, du hast den Runtime-Loader als Kopie ständig im Adressraum jedes Prozesses verfügbar, um dlopen() zu unterstützen, oder du lädst ihn jedesmal neu dort rein. Ich find das nicht soo schön.
Er ist in jedem Prozess drin, der Prozess kann ihn nur nicht sehen und wenn du den Runtime-Loader in der libc hättest, wäre er auch in jedem Prozess drin, hätte allerdings den Vorteil das du keinen Syscall machen musst um dlopen() aufzurufen und dafür den Nachteil, das dir das Programme deine Daten zerschießen kann (obwohl das in dem Fall kein Problem sein sollte, bei mir geht es nur darum, das außer dem Runtime-Loader keiner auf bestimmte Syscall Zugriff haben sollen und dazu ist es erforderlich das du den auch nicht kaputt bekommst).
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: Svenska am 29. December 2010, 21:44
Das klingt nach einer Art Registry nur in Form von vielen Dateien (Linux typisch und viele bemämgeln das, also die vielen Konfigurationsdateien). Sowas will ich allerdings nicht, weil das würde ja nur funktionieren, wenn mein OS läuft, nur dann könnte diese Datei aktualisiert werden und damit habe ich ein Problem, aber auch das hatten wir schon bei den Treibern.
Du kannst jeden Header durchsuchen, um einen Server zu finden. Das ist bei wenigen Servern eine recht übersichtliche Sache und geht auch recht schnell. Wenn du viele Server hast (wie bei Linux die Module), dann dauert das. Du würdest das Ergebnis der Suche nur Cachen; die Primärquelle bleibt der Header in den Modulen!

Allerdings muss ich dir recht geben was die Services betrifft, also mit dem Header, weil sowas will ich ja bei den Treibern nutzen. Ich sehe noch nicht so richtig wie ich das machen sollte, ohne das ich einen Service-Server habe, weil im Kernel würde ich das ungern machen wollen (also Programme laden lassen, zumal das eh schwierig werden dürfte mit meinem Runtime-Loader Konzept).
Darum versuche ich ja, dir das auszureden. ;-)

Zitat von: svenska
An der Stelle noch ein Flag setzen, dass der Server nicht automatisch gestartet werden soll, ist jetzt nicht mehr soo schwer.
Das klingt irgendwie genau nach der Windows Art und Weise, also immer laden lassen, bis es von Hand umgestellt wird ;)
Du willst sie beim Systemstart laden lassen!

Was das betrifft (also das Root-Dateisystem und solche Konzepte), habe ich mir überhaupt noch keinen Kopf gemacht.
Die Idee mit der Kernel Command Line finde ich extrem genial. ;-)

Genau da sehe ich ein noch größeres Problem (wennd er Runtime-Loader in der libc ist). Denn das hieße ja, das du immer erstmal die libc in einen neuen Prozess packen musst um den Prozess zu erstellen, was ist aber wenn du einen Prozess hast, der keine libc nutzt?
Hmm. Ich bin trotzdem dafür, dass der Runtime-Loader ein eigener, statisch gelinkter Prozess ist, den der Kernel ausführen kann.

In der libc kannst du den Runtime-Loader ja mit fork()/exec() starten, dann bist du im Adressraum des aktuellen Prozesses, also kann der Runtime-Loader ja die Symboltabelle in den Prozess injizieren. Wie man das konkret umsetzt, keine Ahnung.

Er ist in jedem Prozess drin, der Prozess kann ihn nur nicht sehen und wenn du den Runtime-Loader in der libc hättest, wäre er auch in jedem Prozess drin,
Ich würde sowas lieber als externes Hilfsprogramm sehen. Sonst schießt du dir später in den Fuß, weil so gut kannst du den Loader garnicht vor den bösen Programmen schützen.

Gruß,
Svenska
Titel: Re:runtime loader - Programme laden/ausführen
Beitrag von: FlashBurn am 29. December 2010, 22:20
Zitat von: svenska
Du kannst jeden Header durchsuchen, um einen Server zu finden. Das ist bei wenigen Servern eine recht übersichtliche Sache und geht auch recht schnell. Wenn du viele Server hast (wie bei Linux die Module), dann dauert das. Du würdest das Ergebnis der Suche nur Cachen; die Primärquelle bleibt der Header in den Modulen!
Naja, das Problem ist weniger die Anzahl der Server, sondern die Anzahl der Dateien in dem Verzeichnis.

Zitat von: svenska
In der libc kannst du den Runtime-Loader ja mit fork()/exec() starten, dann bist du im Adressraum des aktuellen Prozesses, also kann der Runtime-Loader ja die Symboltabelle in den Prozess injizieren. Wie man das konkret umsetzt, keine Ahnung.
Also das mit dem eigenständigen Prozess wird schwierig bis unmöglich. Da kommst du auch mit fork (da änderst du ja nichts im eigentlichen Prozess) und exec (damit löscht du praktisch die Kopie des alten Prozesses) nicht weiter.
Und in der libc ist auch nicht so toll.

Zitat von: svenska
Ich würde sowas lieber als externes Hilfsprogramm sehen. Sonst schießt du dir später in den Fuß, weil so gut kannst du den Loader garnicht vor den bösen Programmen schützen.
Nenne mir mal eine Möglichkeit wie oder wo ich ihn nicht schützen kann. Denn so wie ich mir das vorstelle, hat der Prozess keine Möglichkeit auf die Daten in den ersten 4MB zu zugreifen.