Eigenes OS?



  • Ist auch einfach die Frage, wie komfortabel Du das überhaupt gestalten möchtest.
    Ein grundlegender Kommandointerpreter könnte ja einen eigenen Editor mitbringen, sodaß etwas Rudimentäres vollkommen ausreicht. Auf der anderen Seite kannst Du's im Kernel aber bis zum kompletten Memoryhexeditor treiben 😉



  • IMHO haben konkrete Reaktionen auf Tasteneingaben im IRQ-Handler (HW-Treiber) nichts zu suchen. Das sind Teile einer Anwendung. Ist vielleicht so zu Demo-Zwecken ganz nett, aber mit brauchbarem OS-Design hat das nichts zu tun.
    Irgendwie macht das so immer noch den Eindruck, als wuerdest du die Sache ein wenig wie dieses erste Polling-Relikt behandeln.
    Also entweder ueberlegst du dir ein vernuenftiges Treiber-Design und machst bei keyboard und video dann mal langsam die Kiste zu (das bedeutet auch, dass du kapselnde Funktionen brauchst, falls du mal mit dem Entwurf einer echten API anfaengst), dann kannst du auf diesen abgeschlossenen Treibern auch etwas rumbasteln, das ueber den Rest des Tutorials im Prinzip so funktionieren sollte, oder du beschraenkst dich hier nur auf das absolut notwendigste. Solche aufwendigen, dennoch halbgaren und bestenfalls bis zum Ende dieses Kapitels brauchbaren Basteleien sind IMHO kontraproduktiv.


  • Mod

    IMHO haben konkrete Reaktionen auf Tasteneingaben im IRQ-Handler (HW-Treiber) nichts zu suchen. Das sind Teile einer Anwendung. Ist vielleicht so zu Demo-Zwecken ganz nett, aber mit brauchbarem OS-Design hat das nichts zu tun.

    Ja, das ist völlig richtig. Ich werde jetzt bei video.c und keyboard.c aufhören, als kleine Demo reichen diese Funktionen bereits. "Externe Anwendungen" sind noch nicht lauffähig. Was ich auf der Stufe noch einfügen möchte, ist ein Kommandozeileninterpreter mit nachgeschaltetem strcmp(...) und entsprechenden Reaktionen so wie beim Real Mode, am besten in main(), diesmal nur in C programmiert und ohne BIOS. Diese Parallele erwartet man irgendwie. 🙂
    Dann geht's im zweiten Teil thematisch mit Paging, Heap, Designfragen weiter. Das wird dann aber alles elend komplex. Da knabbere ich noch dran. Zur Zeit beschimpft mich sogar schon mein Linker, weil ich Paging und Heap modular nicht sauber auseinander halte. Übel, übel, .... 😃
    EDIT: zumindest das endlich geschafft. 😃

    @Nobuo T: Wenn ich Dich richtig verstanden habe, würdest Du im Keyboard Handler die Information in eine Queue stecken. Der Kommandozeilen-Interpreter (wo gehört der als "Anwendung" hin? Für mich ist dies noch Teil des Kernels.) müsste sich diese dann dort abholen und verarbeiten, so wie jetzt - zur Demo - bereits im Keyboard Handler erfolgt, richtig? Der Kommandozeilen-Interpreter muss ein Prompt drucken, nach ENTER die Zeile (ohne Prompt) schlucken und verarbeiten mittels strcmp und switch/case-Struktur (wie bei einer Windows-Nachrichten-Pumpe).



  • Der Keyboardhandler sollte die Eingaben nicht in eine eigene Queue fließen lassen, sondern gleich an die Queue der aktiven Anwendung.
    Deshalb würde ich als nächstes damit beginnen Grundstrukturen für Anwendungen zu definieren. Da gehören dann auch die Schnittstellen zu Treibern dazu.

    Wenn man die Grundstrukturen hat, dann am besten gleich Multitasking/threading und nen einfach Scheduler einbauen, dann macht es einfach mehr Spaß.

    Man kann auch erst mal die Schnittstellen zu den Treibern weglassen und einfach ein paar Anwendungen laufen lassen. Die könnten dann ja alle gleichzeitig in den Bildschirm malen.

    Wenn man erst mal zwischen Anwendungen und Kern/System getrennt hat, dann ist es einfacher die Schnittstellen zu entdecken und zu bauen. Das diese dann gleich so angenehm wie möglich sind ist natürlich noch eine ganz andere Frage.

    jenz


  • Mod

    zwischen Anwendungen und Kern/System getrennt

    Ja, das ist wohl der entscheidende Punkt.

    Der Keyboardhandler sollte die Eingaben nicht in eine eigene Queue fließen lassen, sondern gleich an die Queue der aktiven Anwendung.

    Ja, das klingt sinnvoll, damit es keine Verwechslungsprobleme beim Leeren eines gemeinsamen Briefkastens gibt. Das Problem ist, dass wir noch keine Anwendungen laufen lassen können, weil die Strukturen hierzu noch fehlen. Würdest Du den Kommandozeileninterpreter bereits als Anwendung in Privilegstufe 3 laufen lassen?

    Am besten gleich Multitasking/Threading und 'nen einfachen Scheduler einbauen, dann macht es einfach mehr Spaß.

    Spaß klingt gut. 🙂

    Man kann auch erst mal die Schnittstellen zu den Treibern weglassen und einfach ein paar Anwendungen laufen lassen. Die könnten dann ja alle gleichzeitig in den Bildschirm malen.

    Das mache ich momentan mit dem Timer und dem "Editor" Keyboard Handler ja auch, deshalb musste ich schon den Cursor speichern.

    Ich experimentiere gerade mit einem Paging-/Heap-Modul, ist kompliziert (schlecht für Didaktik), miteinander vernetzt und klappt leider noch nicht, wie ich es will. Das wollte ich als nächsten Schritt einfügen, noch bevor die Anwendungen im Multitasking laufen. Das gehört aber alles nach Teil 2, der leider viel Zeit braucht (liegt an meinen beschränkten Fähigkeiten und Erfahrungen in diesem Bereich). Macht aber nichts, fahre ja kein Wettrennen.

    Teil 1 wollte ich mit einem kleinen Befehlsinterpreter im Kernel (Analogie zur Vorgehensweise im RM) beenden, damit die eingetippten Zeichen Sinn machen. Kann man aber in Teil 2 wohl alles wegwerfen, da hat Nobuo T leider Recht. 🙄
    Sehe ich aber nicht als großes Problem.
    EDIT: Vielleicht kann man die Idee mit dem BIOS-Briefkasten und dem Abholen der Post dort durch einen Befehlsinterpreter kombinieren. 🙂



  • Klar waere es ein praktisches Konzept, eine KB-queue pro Anwendung einzurichten. Da das OS in diesem Stadium aber noch nicht mal ein Konzept fuer Anwendungen hat, ist das alles noch Zukunftsmusik und erst im naechsten Kapitel ausfuehrlich zu diskutieren.
    Eine globale queue zum Ablegen der KB-Codes (so macht es das BIOS auch) waere im Moment sicher am praktischsten. Diese liesse sich spaeter auch relativ einfach entsprechend den Beduerfnissen des Multitaskings anpassen.
    Die ISR liest also die Scancodes vom KB, setzt die Flags, wandelt in ASCII-Codes um, o.Ae. und eine getch-Funktion (vgl. int 16h, ah=0) liest die queue dann im Rahmen der Anwendung (hier einfach des "Kerns") wieder aus.



  • Ja, ich würde die Anwendung erst mal im Kern laufen lassen. Erst mal alle Anwendungen.

    Die dürfen natürlich von Anfang an nur über entsprechende Methodenaufrufe auf Systemfunktionen zugreifen, da kann man dann den Wechsel von Rang 0 auf 3 oder wie herum auch immer Transparent einbauen.

    Aber erst mal muss was laufen. Dann hat man auch leichter die Möglichkeit Aufgaben abzugeben und jemand anderes kann dir Testanwendungen zusammenbauen oder an Treiberfunktionen schrauben.

    Ich würde (habe) es (mal mehr mal weniger) schön mit C++, nicht mit C machen (gemacht).

    jenz


  • Mod

    Ich würde (habe) es (mal mehr mal weniger) schön mit C++, nicht mit C machen (gemacht).

    Im Kernel bleiben wir bei C.

    @Nobuo T: welche Flags meinst Du genau (nehmen wir die BDA als Vorbild) setzen? Diesen Bereich bei 40:17? Gibt es bereits eine vereinfachte (oder auch die komplette) BDA Struktur als C-Struct, die man einsetzen könnte oder muss man das selbst aufbauen? Da könnte man ja auch die statische Queue gleich ablaufen lassen.
    Im BDA wird offenbar 40:1E - 40:3D als "circular queue buffer" (32 Byte) verwendet.



  • Schade, kann ich die Begründung weiter oben im Thread lesen?
    Wenn nicht, wieso?



  • Erhard Henkes schrieb:

    welche Flags meinst Du genau (nehmen wir die BDA als Vorbild) setzen? Diesen Bereich bei 40:17?

    Jup, genau die.

    Erhard Henkes schrieb:

    Gibt es bereits eine vereinfachte (oder auch die komplette) BDA Struktur als C-Struct, die man einsetzen könnte oder muss man das selbst aufbauen? Da könnte man ja auch die statische Queue gleich ablaufen lassen.
    Im BDA wird offenbar 40:1E - 40:3D als "circular queue buffer" (32 Byte) verwendet.

    Keine Ahnung, ob es da bereits etwas fertiges gibt. Da was eigenes zu implementieren sollte aber wohl schneller erledigt sein, als nun erst was zu suchen. 😉

    Musst ja erstmal auch nicht alles implementieren, und auch nicht genau wie in der BDA. Nicht vergessen: Das ist nur ein moegliches Konzept, das in der Form wahrscheinlich auch nicht gerade ideal fuer Multitasking geeignet ist.

    ... ...
    Evtl. bietet es sich als naechstes dann doch schon mal an, vorausschauend grob etwas ueber das Treiber-Design nachzudenken. zB. erstmal:
    Was hast du an Input von der HW? Was davon willst du welchen Anwendungen in welchem Fall mitteilen? Welche Datenstruktur koennte sich dazu eignen? Was fuer Interface-Funktionen koennte man darauf benutzen?

    jenz schrieb:

    Schade, kann ich die Begründung weiter oben im Thread lesen?
    Wenn nicht, wieso?

    Ja, das wurde bereits diskutiert und einvernehmlich befunden, dass die Nachteile beim Einsatz von C++ die Vorteile bisher ueberwiegen.



  • Nobuo T schrieb:

    IMHO haben konkrete Reaktionen auf Tasteneingaben im IRQ-Handler (HW-Treiber) nichts zu suchen. Das sind Teile einer Anwendung. Ist vielleicht so zu Demo-Zwecken ganz nett, aber mit brauchbarem OS-Design hat das nichts zu tun.
    Irgendwie macht das so immer noch den Eindruck, als wuerdest du die Sache ein wenig wie dieses erste Polling-Relikt behandeln.
    Also entweder ueberlegst du dir ein vernuenftiges Treiber-Design und machst bei keyboard und video dann mal langsam die Kiste zu (das bedeutet auch, dass du kapselnde Funktionen brauchst, falls du mal mit dem Entwurf einer echten API anfaengst), dann kannst du auf diesen abgeschlossenen Treibern auch etwas rumbasteln, das ueber den Rest des Tutorials im Prinzip so funktionieren sollte, oder du beschraenkst dich hier nur auf das absolut notwendigste. Solche aufwendigen, dennoch halbgaren und bestenfalls bis zum Ende dieses Kapitels brauchbaren Basteleien sind IMHO kontraproduktiv.

    alle daumen hoch. dem muss man nichts mehr hinzufügen.

    jenz schrieb:

    Der Keyboardhandler sollte die Eingaben nicht in eine eigene Queue fließen lassen, sondern gleich an die Queue der aktiven Anwendung.

    würde ich nicht so machen. die queue gehört in den keyboard-treiber bzw. in den kernel und anwendungen können sich was daraus abholen. ebenso würde ich mit maus-events verfahren. auch würde ich mir die möglichkeit offen lassen, mehrere mäuse und mehrere keyboards anschliessen zu können, also von vorn herein modulare, objektorientierte strukturen zu schaffen, finde ich ziemlich wichtig.

    Erhard Henkes schrieb:

    Der Kommandozeilen-Interpreter (wo gehört der als "Anwendung" hin? Für mich ist dies noch Teil des Kernels.)

    nee, ein komandozeilen-interpreter ist bestenfalls eine sogenannte 'shell', also eine art bindeglied zwischen benutzer und bestimmten system-services. der gehört genau so wenig in den kernel, wie ein editor oder eine tabellenkalkulation.

    jenz schrieb:

    Schade, kann ich die Begründung weiter oben im Thread lesen?
    Wenn nicht, wieso?

    C++ ist unglaublich mächtig, aber auch komplex und 'esoterisch'. man könnte natürlich c++ verwenden, aber dann bräuchte man knallharte coding-richtlinien und leute, die diszipliniert und perfekt im umgang mit dieser sprache sind, sonst wird das nix. C ist im vergleich dazu primitiv und einfach strukturiert. das ist aber der entscheidende vorteil: weniger ist mehr. z.b. sind fehler in einem C-programm, im vergleich zu C++, trivial, leicht zu finden/debuggen und haben weniger weitreichende folgen.
    🙂


  • Mod

    Mir würde C++ leichter fallen als C, aber ich weiß von den Robotik-Anwendungen, dass man nur gewisse Features sinnvoll nutzen kann, sozusagen gekapseltes C mit Klassen ist der Idealstil, aber das schafft man auch anders. Daher trage ich die Entscheidung für C eindeutig mit. Wenn man vernünftig damit umgeht, ist es ein herrliches Bindeglied zwischen Assembler und der Hochsprachen-Welt, im OS-Bereich sicher die richtige Wahl.



  • stimmt, objektorientiert kann man auch mit c entwickeln. ist aber aus meiner sicht eben fehleranfälliger und auch aufwendiger beim schreiben. aber okay, entscheidung ist gefallen.

    warum sollen sich die anwendungen denn die ereignisse selbst abholen? man kann die doch besser von anfang gleich eventgesteuert implementieren.
    pollen ist doch nicht wirklich schön

    jenz



  • Hat es angesichts der Diskussion über das weitere Vorgehen noch einen Sinn, den jeweils aktuellen Quellcode mal unter die Lupe zu nehmen?



  • jenz schrieb:

    warum sollen sich die anwendungen denn die ereignisse selbst abholen?

    weil das z.b. für sequenziell ablaufende programme (ein stinknormales c-programm z.b. das mit 'main' beginnt) einfacher ist und es bedeutet auch weniger verwaltungsaufwand im kernel (der schiebt einfach daten in die dazugehörigen queues und kümmert sich nicht weiter drum). falls du auf sowas wie eventgesteuerte gui-anwendnungen anspielst, die sind ja clients eines 'window-managers', der prinzipiell selber bloss eine anwendung ist. er würde dann z.b. beim eintreffen eines zeichens die window-prozedur des entsprechenden fensterchens aufrufen und damit hätte die gui-anwendung ihre events.

    jenz schrieb:

    man kann die doch besser von anfang gleich eventgesteuert implementieren.
    pollen ist doch nicht wirklich schön.

    mit dem 'selbstabholen' hat man doch beide möglichkeiten. beispiele mit einem non-blocking getchar()...

    event-gesteuert:

    int c;
    wait_for_event (KEYBOARD_EVENT);  // die task schläft, bis mindestens 1 zeichen in der queue ist
    c = getchar();  // zeichen abholen
    

    polling:

    int c;
    c = getchar();  // zeichen abholen, -1 bei fehlschlag
    if (c > 0)
    {
      // ein zeichen ist da
    }
    else
    {
      // war leider nix
    }
    

  • Mod

    Hat es angesichts der Diskussion über das weitere Vorgehen noch einen Sinn, den jeweils aktuellen Quellcode mal unter die Lupe zu nehmen?

    Da gäbe es zwei Aspekte, wo ich Unterstützung/Zustimmung brauchen könnte:

    1. Ich habe mal versuchsweise einen Paging/Heap-Mechanismus eingebaut, der aber sehr kompliziert ist, also für den ersten Schritt noch vereinfacht werden sollte, und leider noch nicht funktioniert, habe Testroutinen eingebaut, um zu sehen, wo der Code ausflippt: z.Z. beim Umschalten auf das Paging (wahrscheinlich sind Speicheradressen falsch vorgegeben), echte Tüftelei.
      Da könnte sich jemand auf die Dateien ordered_array.h/c, kheap.h/c und paging.h/c konzentrieren und diese aus didaktischen Gründen vereinfachen und in PrettyOS zum Laufen bringen (da beiße ich gerade dran rum und komme nicht wirklich weiter). Ich habe diesen Code mal hochgeschickt, in der Hoffnung, dass mir jemand einen guten Tipp gibt:
      http://www.henkessoft.de/OS_Dev/Downloads/20_paging_heap_problems.zip

    2. s.u. (Circular Queue: füllen, leeren)



  • Erhard Henkes schrieb:

    Da könnte sich jemand auf die Dateien ordered_array.h/c, kheap.h/c und paging.h/c konzentrieren...

    woher ist der code? oder haste alles selbst geschrieben?
    🙂



  • ah, schon gefunden: http://www.jamesmolloy.co.uk/tutorial_html/7.-The Heap.html
    ist die frage, ob da bugs drin sind, oder ob du nachträglich was fehlerhaftes reinbastelt hast. ich würde vorschlagen, du machst sowas wie 'nen unit-test, also ein kleines testprogramm für den heap, das (unter windoofs, mit msvc z.b.) ohne dein OS läuft. dann kannste auch besser debuggen.
    🙂


  • Mod

    @+fricky: Der ganze Code gefällt mir nicht, da er schwierig zu verstehen und vor allem bezüglich paging und heap nicht voneinander unabhängig ist, aber ich habe bisher noch kein besseres Beispiel gefunden, wollte die Mechanismen auf die Schnelle ausprobieren und analysieren, was man für einen ersten Einstieg wirklich benötigt. James Molloy ist einer der Moderatoren und führenden Köpfe bei osdev.net. Sein Code basiert teilweise auf älteren Arbeiten im Rahmen von Bran's Tutorial.

    Die Idee mit dem unit test ist brauchbar.

    Wenn man sti() vor der Paging-Initialisierung anschaltet, kracht es noch früher, für mich momentan nicht nachvollziehbar. 🙄


  • Mod

    zu 2) Ich mache mir momentan Gedanken im Verständnis des Queue-Mechanismus:
    Wie bewegt man die beiden Zeiger Head and Tail am sinnvollsten? Der buffer verändert ja seine inhaltsbedeutende Größe. Tail ist der Eingang und wird vom Keyboard Handler versorgt. Der wandert bei jedem Key Entry Event eins nach "links", so dass die Zeichen in einer Kette angeordnet werden. Nun aber zum Head: Wenn die KeyQueue (KQ) leer ist, sind doch Head und Tail deckungsgleich und der Key an dieser Stelle wird auf ??? gesetzt. Man kann ja prüfen ob Head und Tail verschieden sind, wenn nein ist die KQ leer (Head minus Tail == 0), wenn ja, stehen Head minus Tail Zeichen drinnen. Sobald Zeichen rein kommen, wandern Head und Tail auseinander, Tail nach links, Head bleibt stehen. Sobald eine "Anwendung" ein Zeichen abholt, wandert Head ebenfalls eins nach links. Habe so etwas noch nie gebaut, daher die Frage, ob das so stimmt. man muss ja noch den Circular-Mechanismus einbauen: Bei Zeiger < KEYQUEUE springt man auf KEYQUEUE+KQSIZE-1, richtig?

    Nun zu den "Zeichen" in der KQ: Ein Zeichen besteht ja aus dem ASCII-Zeichen plus Flags (Sonderzeichen), d.h. pro Zeichen müsste man eigentlich mindestens zwei Byte ablegen, eins enthält das ASCII-Zeichen (da könnte man Shift auch gleich verarbeiten, also im Flag weglassen) und eins die Zusatz-Info, z.B. (Shift links/rechts), ALT/ALT Gr, CTRL links/rechts, usw. bzw. Kombinationen davon. (Bisher analysiere ich im Handler ja nur die Shift-Taste, rechts/links noch gleich).

    Ich hoffe, ihr versteht, was ich da schreibe. 😕
    Ich verstehe momentan nicht wie BIOS/BDA das machen, weil dort ja die Sondertasten-Bits stehen. Zu jedem Tastenanschlag gehört ja je nach design entweder nur eine Taste (shift/non-shift) oder eine Kombination aus Sondertasten und Taste (vielleicht zu kompliziert). Momentan kommen wir an ALT Gr aber nicht ran.


Anmelden zum Antworten