Autor Thema: Design für mein OS  (Gelesen 9558 mal)

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« am: 25. July 2011, 16:01 »
Moin,

Ich bin gerade dabei für mein Betriebssystem (wieder einmal) einen neuen Kernel zu schreiben. Da die anderen alle vor die Hunde gegangen sind, versuch ich jetzt aus meinen Fehlern zu lernen :)
Zum Beispiel hab ich dieses Mal eine Spezifikation geschrieben bevor ich überhaupt Quellcode getippt habe.

Damit der Kernel nicht auch schief geht, würde ich euch einfach mal Fragen ob ihr die Spezifikation mal durchlesen könnt.
Kleinere Fehler würden mir bei der Implementation selber auffallen aber größere sind dann wieder sehr nervig.

Hier kann man die Spezifikation lesen, die erste Datei ist design.txt:
http://lf-os.googlecode.com/svn/branches/Kernel%204/doc/

Falls die Sonderzeichen nicht stimmen: einfach auch UTF-8 stellen.

PS.: Die Spezifikationen für ABI und IPC sind noch in Arbeit - die also nicht so genau nehmen ;)

Zusammenfassung:
 - der Kernel wird ein Hybridkernel (Kernel mit Modulen im Kernelmode)
 - alles ist eine Datei, sogar der Prozesor
 - es gibt immer mindestens ein Modul, das Plattformmodul. Dieses muss ein CPU Gerät und ein Gerät zur Textein/-ausgabe registrieren
 - Bevor der Kernel gestartet wird, läuft ein Plattformspezifischer Starter (steht noch nicht in den docs)
 - als IPC Kommt SharedMemory und RPC zum einsatz
 - Syscalls, Interrupts und Exceptions werden auf Events gemappt

Danke für eure Hilfe :)

Grüße,
LittleFox

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 25. July 2011, 21:35 »
Hallo,

die (Text-)Grafiken sind etwas kaputt. :-)

- Sämtliche architekturspezifischen Dinge ["x86"] in ein Modul auszulagern, finde ich unschön, da der (binäre) Kernel selbst ja ohnehin schon für eine Architektur kompiliert und damit darauf festgenagelt ist. Die plattformspezifischen Dinge ["IBM PC"] in Module auszulagern ist sinnvoll. [Wenn du nur ein paar bestimmte Funktionen überschreiben willst, z.B. statt Interruptcode Code für SYSENTER/SYSCALL oder Initialisierungen wie z.B. CPUID aktivieren für Cyrix-Prozessoren oder so Zeug, dann ist das okay.]

- "Das Plattformmodul muss eine Console registrieren" ist ebenfalls unschön, da nicht jedes Gerät eine Console über einen Plattformtreiber bereitstellen kann (AT- oder PS/2-Tastaturen ja, bei USB-Tastaturen ohne Legacy-Emulation wird das schwierig). Außerdem wird die VGA-Grafikkarte irgendwann abgeschaltet und durch einen Grafiktreiber angesteuert, dann fliegt dir die Console sowieso weg. [Wenn diese Console nur für Debugausgaben da ist, kein Problem. Als Primärconsole solltest du sie aber nicht verwenden, sondern dafür andere Treiber nutzen.]

- Zwei ABIs zu verwenden ist unelegant, da solltest du dich lieber auf eine gemeinsame für Programme und Treiber festlegen. Allerdings dürfen gerne zwei verschiedene APIs dahinterstehen.

- Polling für RPC als einzige IPC-Methode ist unelegant weil langsam. Eine asynchrone Zustellmethode sollte alternativ möglich sein.

- Im VFS wirst du wahrscheinlich vier Callbacks brauchen: read(), write(), seek() für Blockdevices und ioctl() für Devices.

</besserwisser>
Das wäre meine Meinung dazu. ;-)

Gruß,
Svenska

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #2 am: 25. July 2011, 22:34 »
Moin,

erstmal danke für die Antwort und die Arbeit dich durch meine Texte zu wühlen :), sind zum großen Teil im Zug entstanden ...  :roll:

Das die Konsole nur beim Start verwendbar ist , ist schon klar. Die wird verwendet bis ein spezialisiertes Modul geladen wurde. Ich dachte da an einen Mechanismus wie "ich bin ein generischer Treiber" bzw.: "ich bin ein spezialisierter Treiber"; ein spezialisierter Treiber würde einen generischen verdrängen.

Grafiken kaputt? Sch**** Sieht man was gemeint ist? Sonst muss ich es nochmal repariert uploaden.

x86 in Modul auslagern: finde ich schöner weil der Sourcecode sauber bleibt. Keine Makros, Präprozessordirektiven o.ä.

Zitat
- "Das Plattformmodul muss eine Console registrieren" ist ebenfalls unschön, da nicht jedes Gerät eine Console über einen Plattformtreiber bereitstellen kann
Dann wird eben eine dummy Konsole registriert und ein entsprechender spezialisierter Treiber geladen ;)

Mit dem ABI/API begriff komm ich immer wieder durcheinander ... ABI = Syscalls, API = LibC?

Als IPC Methode gibt es außerdem auch noch Shared Memory - siehe Zusammenfassung. Das sollte ja ausreichend schnell sein. Polling ist für kleine Nachrichten gedacht - ähnlich SendMessage bei Windoof

VFS: ok, seek brauch ich wirklich; aber was ist ioctl?

Grüße,
LittleFox

btw.: wundert mich das erik noch nicht geantwortet hat ;)

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 25. July 2011, 22:46 »
Ob du seek brauchst, ist die Frage. pread/pwrite könnte auch reichen (also bei jedem Aufruf das Offset explizit mitgeben). ioctl ist auch eher optional.

ioctl sind einfach zusätzliche Funktionen, die ein Treiber für eine Datei bereitstellt. Unter POSIX bekommt ioctl() die Datei, eine ioctl-Nummer und je nach Nummer unterschiedlich lange Daten dazu.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 26. July 2011, 15:01 »
Mit dem ABI/API begriff komm ich immer wieder durcheinander ... ABI = Syscalls, API = LibC?

Also ich verstheh darunter:
API := Funktions Menge (z.B. libC, sysCalls, etc)
ABI := Aufruf konventionen, (parameter in registern, syscall aufrufe via int/syscall/sysenter, wer räumt den stack auf usw.)
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 26. July 2011, 16:38 »
Meine Definition wäre: API ist auf Quellcodeebene, ABI auf Binärebene. Was natürlich auf dasselbe rauskommt wie MNemos Definition.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 26. July 2011, 17:35 »
Grafiken kaputt? Sch**** Sieht man was gemeint ist? Sonst muss ich es nochmal repariert uploaden.
Tu das. Ich hab mir die Grafiken aber ehrlich gesagt nicht weiter angeguckt. Du hast beim Tippen bestimmt den falschen Font benutzt (wo die Zeichen verschieden breit sind). ;-)

x86 in Modul auslagern: finde ich schöner weil der Sourcecode sauber bleibt. Keine Makros, Präprozessordirektiven o.ä.
Bringt aber wenig, weil du ein Kernelbinary sowieso nicht auf verschiedenen Architekturen einsetzen kannst. Trenne lieber den Sourcecode übersichtlich in architekturunabhängig (generic) und architekturabhängig (x86, MIPS). Als erstzuladendes Modul wäre dann die Plattform angemessen ("IBM PC", "Apple EFI" oder "FritzBox 3020"). Dann kannst du dasselbe Kernelbinary für alle verwandten Prozessoren benutzen, aber trotzdem durch das Plattformmodul auf verschiedenen Geräten einsetzen.

Wobei die Gesamtfrage eh davon abhängt, ob du real portieren möchtest oder nicht.

Als IPC Methode gibt es außerdem auch noch Shared Memory - siehe Zusammenfassung. Das sollte ja ausreichend schnell sein.
Aber nur, wenn du Ereignisse verschicken kannst, dass im Shared Memory jetzt etwas passiert ist. Sonst musst du nämlich dort eine Semaphore pollen...

VFS: ok, seek brauch ich wirklich; aber was ist ioctl?
ioctl = I/O Control. Es gibt Devices, die möchte man auch einstellen können und dann kann man dem Devicefile auch eine direkte (interne) Nachricht schicken. Beispielsweise kann man ein CD-Laufwerk in den Audio-Modus schalten (die Blöcke einer Audio-CD haben nicht 2048 Byte, sondern 2352 Bytes inklusive Fehlerkorrektur) oder bei der seriellen Schnittstelle die Baudrate, Parität, Zeichen-/Zeilenverarbeitung umschalten.

Gruß,
Svenska

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 26. July 2011, 20:23 »
Hallo,


btw.: wundert mich das erik noch nicht geantwortet hat ;)
Dein Artikel war gerade mal 6,5 Stunden online und da wunderst Du Dich das ich noch nicht geantwortet habe?
Ich weiß jetzt ehrlich nicht ob ich mich jetzt überfordert fühlen soll weil von mir so eine kurze Reaktionszeit erwartet wird oder ob ich mich geschmeichelt fühlen soll weil meine Meinung hier offensichtlich einen so hohen Stellenwert hat.
:?


Zu Deinem Design wurden IMHO bereits alle offensichtlichen Kritikpunkte angesprochen so das ich da eigentlich nichts mehr hinzuzufügen habe.
Ansonsten muss ich ehrlich sagen dass das als Design oder gar Spezifikation noch ein bisschen wenig ist, das fällt eher in die Kategorie "erste Ideen-Skizze", aber das weißt Du ja bereits selber. ;)
Auf jeden Fall finde ich es sehr gut das Du überhaupt etwas in dieser Richtung machst bevor Du Code tippst.


Grüße
Erik


PS.: Ich bin der Meinung das dieser Beitrag ein klassischer Erik-Beitrag ist der hoffentlich allen Erwartungen voll gerecht wird (von der hohen Latenz einmal abgesehen).
Reality is that which, when you stop believing in it, doesn't go away.

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #8 am: 26. July 2011, 21:46 »
Moin,

OK, ihr habt mich überzeugt das Plattformmodul etwas kleiner zu halten (IBM PC) und alles Prozessorspezifische in den Kernel zu linken.

@erik zu der Zeit als ich das geschrieben hab, warst du gerade online, deswegen die Verwunderung ;)Das das ganze nur eine Ideenskizze ist - ok, muss ich eben ausführlicher schreiben.

Die Grafiken hat Google kaputt gemacht. Beim Tippen hatte ich eine Monospace Schriftart, nach dem SVN Upload war es im SVN Viewer von Googlecode kaputt - jetzt kommt mein Fehler - ich hab versucht es über das Webinterface zu fixen ... Das Ergebnis habt ihr ja gesehen.

ioctl muss ich mir nochmal angucken - bringt nix das einzubauen wenn man nicht weiß wie :) Danke für den Hinweis :)

seek werde ich auch einbauen; pread/pwrite bauen dann darauf auf.

Vielen Dank für eure Hilfe und Hinweise, einfach ein Klasse Forum hier (musste mal gesagt werden :))

Grüße,
LittleFox

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 27. July 2011, 04:15 »
Moin,

ioctl muss ich mir nochmal angucken - bringt nix das einzubauen wenn man nicht weiß wie :)
Ich würde das als treiberspezifische API mit definierter Semantik bezeichnen. :-P

seek werde ich auch einbauen; pread/pwrite bauen dann darauf auf.
Das geht nicht ohne weiteres, da pread/pwrite den Dateizeiger nicht verändern, was genau die Aufgabe von seek ist. Wenn du seek mit pread/pwrite simulierst, sparst du außerdem einen Syscall.

Gruß,
Svenska

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 27. July 2011, 10:15 »
Hallo,


@erik zu der Zeit als ich das geschrieben hab, warst du gerade online, deswegen die Verwunderung ;)
Keine Angst ich, ich nehme Dir Deine Verwunderung nicht übel. Ich wollte mit einer Antwort nur warten bis ich Deine Beschreibungen auch komplett gelesen hatte und dann ist Svenska mir zuvor gekommen und hat eigentlich schon alles wesentliche geschrieben.

Das das ganze nur eine Ideenskizze ist - ok, muss ich eben ausführlicher schreiben.
Naja, für mein Projekt hab ich weit über 200 kB Text + eine umfangreiche OpCode-Tabelle und noch mal einiges an defines u.ä. in Header-Dateien (wo der Aufbau etlicher Controll-Register beschrieben und mit Kommentaren erklärt ist). Aber ich plane auch eine komplette Plattform und nicht nur ein OS. Also mach Dir nichts draus wenn ich Dein Konzept noch als etwas dünn bezeichne.

seek werde ich auch einbauen; pread/pwrite bauen dann darauf auf.
Also ich würde seek aus dem vfs draußen halten und nur pread/pwrite anbieten. Dafür müsste der Datei-Pointer in der libc verwaltet werden was aber spätestens dann zum Problem wird wenn Du Datei-Descriptoren vererben möchtest. Es ist also eine schwierige Entscheidung, solange Du keine POSIX-Konforme Vererbung willst kannst Du den leichten und performanteren Weg gehen und das in der libc lassen so das Dein vfs nur pread/pwrite anbieten muss, sobald Du POSIX-Konforme Vererbung benötigst musst Du Dir eine passende Lösung einfallen lassen.


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

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 27. July 2011, 10:20 »
Ja, wenn es POSIX-kompatibel werden soll, führt wohl kein Weg um read/write/seek herum. pread/pwrite müssen dann halt zusätzlich dazu. (Genau das LIOv2-Interface, wobei read/write im Kernel nur ein dünner Wrapper um pread/pwrite sind)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 27. July 2011, 11:39 »
Hallo,


was das Vererben angeht, welches vorwiegend für Streams wie stdin/stdout/stderr benutzt wird, hatte ich da http://forum.lowlevel.eu/index.php?topic=2622.msg29758#msg29758 (am besten die ganze Seite lesen) schon mal ein paar Gedanken niedergeschrieben wie man das auch ohne echtes POSIX-Konformes Vererben realisieren könnte.

Da ich nach wie vor der Meinung bin das Vererbung für richtige Dateien keine Rolle spielt sehe ich die Möglichkeit im VFS trotzdem mit nur pread/pwrite auszukommen.


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

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 27. July 2011, 12:52 »
Keine Frage dass es auch ohne geht, aber ohne POSIX-konformes Vererben ist man eben nicht POSIX-konform.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 27. July 2011, 13:16 »
Hallo,


aber ohne POSIX-konformes Vererben ist man eben nicht POSIX-konform.
Ach, Du kommst ja auf Ideen. ;)
Die Frage ist ob das spürbare Auswirkungen hat. Wenn man alles was ein Stream ist (was Umleitungen in/aus Dateien und TCP-Sockets mit einschließt) korrekt/konform vererben kann sollte das IMHO reichen. Ich kenne jedenfalls kein Anwendungsszenario für den parallelen Zugriff auf echte Dateien mit geteiltem Datei-Pointer. Wichtig wäre hierbei vor allem das die libc das merkt wenn man echte Dateien vererben möchte so das es im unwahrscheinlichsten Fall der Fälle wenigstens zu einer aussagekräftigen Fehlermeldung kommt und nicht nur zu merkwürdigen Phänomenen.


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

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 27. July 2011, 13:20 »
Hallo,

aber ohne POSIX-konformes Vererben ist man eben nicht POSIX-konform.
Die Frage ist ob das spürbare Auswirkungen hat.
Ja. Wo kein POSIX drin ist, darf man auch kein POSIX draufschreiben und ob es wirklich spürbare Auswirkungen hat, merkst du erst, wenn du zwei Jahre später auf die Nase geplumpst bist. Und dann liegt das Kind tot im Brunnen.

Gruß,
Svenska

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 27. July 2011, 14:17 »
Für das Benutzen eines gemeinsamen Dateizeigers mag es bei regulären Dateien nur konstruierte Fälle geben - weiß ich nicht - aber für Vererben ohne gemeinsames Nutzen gibt es schon Gründe. Wie unterscheidest du automatisch, ob nur FD_CLOEXEC vergessen worden ist oder ob der Vaterprozess die Datei als nächstes schließt?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 27. July 2011, 15:07 »
Hallo,


aber für Vererben ohne gemeinsames Nutzen gibt es schon Gründe.
Und für die benötigt man wieder keinen (gemeinsamen) Datei-Zeiger im VFS, sondern es reicht ein lokaler in der libc.

Wie unterscheidest du automatisch, ob nur FD_CLOEXEC vergessen worden ist oder ob der Vaterprozess die Datei als nächstes schließt?
Gar nicht, es sollte schon beim Vererben zu einem Fehler kommen (an der Stelle muss die libc klar ganz genau aufpassen aber das dürfte kein großes Problem sein) und dann kann ich mir den Source ansehen und passend korrigieren.


Wo kein POSIX drin ist, darf man auch kein POSIX draufschreiben
Ich behaupte doch gar nicht das diese Idee POSIX-Konform wäre, das ist auch gar nicht das Ziel dieser Überlegungen, alles was ich erreichen möchte ist das man mit möglichst wenig Aufwand eine möglichst hohe Performance und die Lauffähigkeit möglichst vieler real existierender Programme erreicht.


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

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 27. July 2011, 16:49 »
Aber wenn du Vererben grundsätzlich verbietest, verbietst du doch auch die harmlosen Fälle mit?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 27. July 2011, 18:32 »
Hallo,


Aber wenn du Vererben grundsätzlich verbietest, verbietst du doch auch die harmlosen Fälle mit?
Welche harmlosen Fälle? Sämtliche Streams will ich ja unterstützen und für echte Dateien sehe ich keinen Sinn. Oder meinst Du es gibt Fälle wo ein Prozess eine Datei öffnet, manipuliert (zumindest den Datei-Pointer), das ganze an einen Kindprozess vererbt, dieser auch wieder den Datei-Pointer und/oder den Datei-Inhalt manipuliert, der Kindprozess sich beendet und zum Schluss der Elternprozess dann wieder mit der Datei weiter arbeitet (natürlich mit geupdateten Datei-Pointer/Inhalt)? Für soetwas fällt mir einfach kein Anwendungsszenario ein. Das einzigste wo das Sinn ergibt sind IMHO Streams. Ich kann mir vorstellen das eine Datei mehrfach unabhängig voneinander geöffnet wird und die Prozesse dann eventuell mit Locking von Teilbereichen arbeiten o.ä. aber in solchen Szenarien stört ein lokaler Datei-Pointer in der libc auch nicht.


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

 

Einloggen