Eigenes OS?


  • Mod

    @Nobuo T: An dem Punkt bin ich auch schon ins Grübeln gekommen, weil dies alles andere als intuitiv ist. Hier kam genau dazu eine Frage aus einem anderen internationalen Forum:
    http://forum.osdev.org/viewtopic.php?f=1&t=19451&p=152668#p152668

    One thing that caught my eye is this:

    Code:
    xor ax, ax
    [...]
    mov ss, ax
    mov sp, ax
    [...]
    call print_string

    You zero SS and SP and then you use the stack (implicitly by CALL). That looked strange first. It's not broken, but it is not very intuitive. Maybe you want to consider to note this in your text (I didn't see anything about that, maybe I just missed it) and explain why and how that works.

    Vielleicht kannst Du da noch etwas zu Deiner Idee erläutern. Da klafft noch eine "didaktische Lücke". 😃
    Das Thema Stack würde ich gerne auch noch beschreiben (Prinzip, SS, SP, Nutzung durch call, ...). Ich war allerdings über deine Lösung so verblüfft, dass ich erst mal genauer hinschauen wollte.

    Auch diese Zeile wirkt auf den ersten Blick merkwürdig.
    add sp, -0x40 ; make room for input buffer (64 chars)



  • Erhard Henkes schrieb:

    Auch diese Zeile wirkt auf den ersten Blick merkwürdig.
    add sp, -0x40 ; make room for input buffer (64 chars)

    na, so machste platz auf'm stack. macht ein c-compiler z.b auch so ähnlich, wenn du ein lokales array aus 64 bytes anlegst.
    🙂



  • Zum Thema Emulatoren könntest Du doch ein eigenes Kapitel machen, indem kurz beschrieben wird, wie man damit das OS zum laufen kriegt und welche Vor-/Nachteile das Programm hat, anstatt gelegentlich zwischendurch weitere Emulatoren vorzustellen...



  • @fricky: SP dürfte aber zu dem zeitpunkt auf 0 sein, weshalb das subtrahieren von 40h (= addieren von -40h?) komisch ist.
    Zumindestens kommt es mir komisch vor, wo liegt der (mein) denkfehler?


  • Mod

    Zum Thema Emulatoren könntest Du doch ein eigenes Kapitel machen, indem kurz beschrieben wird, wie man damit das OS zum laufen kriegt und welche Vor-/Nachteile das Programm hat, anstatt gelegentlich zwischendurch weitere Emulatoren vorzustellen...

    Ja, ist mir auch aufgefallen. Ursprünglich wollte ich nur Bochs verwenden, allerdings sind die Emulatoren so wichtig, dass man alle vorstellen sollte. Werde das konzentrieren. Allerdings erst hinten, denn vorne lenkt das doch stark ab. Nicht jeder arbeitet gerne gleichzeitg mit 10-15 Tools. 😉


  • Mod

    na, so machste platz auf'm stack.

    Das man den Stackpointer nach "unten" wandern lässt, um Platz zu schaffen, ist klar. Aber wie gesagt, ist der Wert vorher bei 0, wenn ich nicht irre. Also hinterher -40. Warten wir auf den Kommentar von Nobuo T. Das hat er genial "verbrochen". Vorher hatten wir den Stack bei 0x90000 (http://www.henkessoft.de/OS_Dev/Bilder/Speicherbelegung.JPG), wo viele ihn hin knallen. Unten bei 0 ist doch auch die IVT. Aber es läuft, das ist die Hauptsache, die theor. Erklärung kommt sicher noch. Vielleicht ein genialer "wrap" 😃



  • Richtig, +fricky. Push macht Platz auf dem Stack, indem 2 (oder 4, oder wie gross der Operand auch immer ist) Byte von (e)sp subtrahiert werden und schreibt dann den Operand dann nach ss:(e)sp.
    Hier wird halt nur Platz auf dem Stack reserviert, erstmal ohne was rein zu schreiben.

    Zu ss und sp mit 0 initialisieren:
    Ist vielleicht nicht sofort intuitiv, aber hier IMHO ziemlich praktisch.
    Wie gesagt hat man es beim x86 mit einem full descending stack zu tun. Wenn also bei sp=0 etwas auf den Stack gepackt wird, gibt es beim Subtrahieren von sp erstmal einen schoenen Ueberlauf, bzw. wrap-arround: zB. 0 - 2 = 0xFFFE. Genau da landet dann der erste Wert.

    Der Code sieht ansonsten beim ersten drueber schauen ganz gut aus. Aber meine msg00 haettest du eigentlich auch gleich ganz loeschen koennen, statt sie nur zu verschieben. War da nur zu debug-zwecken. Die Ausgabe habe ich wie es aussieht auch wieder entfernt, aber den Text vergessen. 😃

    Und zum Teil ueber die A20 zunaechst noch: Ueber die Ports 60h und 64h sprichst du erstmal nur mit dem Controller auf dem Mainboard. Darueber kannst du dann (seriell) etwas an die Tastatur schicken. Und D1 an 64h ist einfach ein Kommando, das bewirkt, dass das naechste Byte auf Port 60h beim outputport landet, statt bei der Tastatur.

    edit: Hui, haette nicht gedacht, dass einfache Integer-Arithmetik (signed/unsigned Addition vs. Subtraktion und Ueberlaeufe) hier fuer solche Verwirrung sorgt. 😕
    Oder hat das damit zu tun, dass da der Stack involviert ist? Das spielt wie gesagt in dem Zusammenhang ueberhaupt keine Rolle.



  • Habe mal die zip Datei 20090321_eh_os.zip runtergeladen, Makefile ein wenig angepasst (wegen meiner nasm Installation), das ganze mit meinen Werkzeugen gebaut und mit den binär Dateien in der zip-Datei verglichen. Alles gleich 🙂
    Unter bochs ausprobiert - es läuft.
    Nun wollte ich mal mit ndisasm ein wenig disassemblieren, hie und da mal schauen und schon gibt es ein kleines "Problem" mit kernel.bin. In der kernel.asm gibt es ja mal 16-Bit, mal 32-Bit Code, was mit [Bits 32] und [BITS 16] "umgeschaltet" wird. Nun, ndisasm kommt damit nicht klar oder ich kenne noch nicht die Möglichkeit, wie man es hinkriegt, dass alles zusammen sauber disassembliert wird... Wäre vielleicht ein Splittern der kernel.asm in zwei Dateien sinnvoll? Eine mit [BITS 16], die andere mit [BITS 32]?
    Eine Sache bezüglich Disassemblieren noch: Am Ende des Bootloaders und des Kernels wird mit Nullen aufgefüllt (X ist 510 oder 1024):

    times X-($-$$) db 0
    

    Was würde gegen z.B. so was sprechen:

    times X-($-$$) hlt
    

    Also Auffüllen mit HLT-Befehlen... Ist nur ein Vorschlag, aber ich persönlich sehe ein Paar Vorteile:
    - beim Disassemblieren sieht man sofort, wo das Ende ist (ok, mit Nullen sieht man es auch, aber man hat lauter add [bx+si],al stehen, was irgendwie unschön ist)
    - zumindest psychologische Wirkung, man fühlt sich ruhiger, weil, wenn die CPU dort warum auch immer ankommt, bleibt sie dort stehen und es passiert nichts 🙂



  • abc.w schrieb:

    Nun wollte ich mal mit ndisasm ein wenig disassemblieren, hie und da mal schauen und schon gibt es ein kleines "Problem" mit kernel.bin. In der kernel.asm gibt es ja mal 16-Bit, mal 32-Bit Code, was mit [Bits 32] und [BITS 16] "umgeschaltet" wird. Nun, ndisasm kommt damit nicht klar oder ich kenne noch nicht die Möglichkeit, wie man es hinkriegt, dass alles zusammen sauber disassembliert wird...

    Ja, ist ein Problem. Die Situation hat man auch nicht all zu haeufig, dass man 16- und 32-Bit code in einem binary hat.
    Ehrlich gesagt bin ich in die Verlegenheit auch noch nicht wirklich gekommen, bzw. hoechstens in einem Debugger - den kann man oft bei Bedarf umschalten.

    abc.w schrieb:

    Wäre vielleicht ein Splittern der kernel.asm in zwei Dateien sinnvoll? Eine mit [BITS 16], die andere mit [BITS 32]?

    Problem beim Aufteilen waere, dass man entweder beim 2. Teil mit dem Start-Offet (org) aufpassen muesste, oder Verschnitt haette, wenn man es an eine groessere, festgelegte Adresse packt.
    Da ist die uebersichtliche Disassemblierbarkeit mit einem einfachen disasm IMHO irgendwie nachrangig.

    abc.w schrieb:

    Eine Sache bezüglich Disassemblieren noch: Am Ende des Bootloaders und des Kernels wird mit Nullen aufgefüllt (X ist 510 oder 1024):

    times X-($-$$) db 0
    

    Was würde gegen z.B. so was sprechen:

    times X-($-$$) hlt
    

    Also Auffüllen mit HLT-Befehlen... Ist nur ein Vorschlag, aber ich persönlich sehe ein Paar Vorteile:
    - beim Disassemblieren sieht man sofort, wo das Ende ist (ok, mit Nullen sieht man es auch, aber man hat lauter add [bx+si],al stehen, was irgendwie unschön ist)
    - zumindest psychologische Wirkung, man fühlt sich ruhiger, weil, wenn die CPU dort warum auch immer ankommt, bleibt sie dort stehen und es passiert nichts 🙂

    Naja, grundsaetzlich vielleicht nicht schlecht, was die Uebersicht beim Disassemblieren betrifft, hat aber ansonsten nicht viel Zweck. Ob der Rechner nun stehen bleibt bis zum naechsten IRQ oder gleich ein wenig dummes Zeug rechnet ist bei so einem gravierenden Problem dann wohl auch ein wenig egal. :p


  • Mod

    Jungs, ihr seid richtig kreativ! Macht richtig Spaß mit euch. Der eine baut einen Wrap in den Stack, dass den Profis vom osdev.org der Verstand stehen bleibt und ein anderer schlägt "times X-(-$) hlt" vor. 😃

    Das mit dem Stack auf 0 habe ich bisher noch nicht gesehen, finde es aber richtig gut. Ich habe es mir einfach als wrap vorgestellt, wie damals beim A20-Gate.

    Ich habe mal "times X-(-$) hlt" in Google eingegeben. Null Fundstellen!
    Das ist doch echt ein Grund, dies zu verwenden. 😉 Die massenweise F4 im Hex-Editor sehen richtig lustig aus: http://www.henkessoft.de/OS_Dev/Bilder/boot_bin_hex.JPG

    @abc.w: die "hlt" sind schon im Tut eingebaut und hochgeladen. 👍

    Die msg00 ist schon entfernt (ich hatte sie mal aufgehoben, weil ich dachte vielleicht bauen wir sie didaktisch noch ein, so mit keystroke und weiter ...). 😃



  • Erhard Henkes schrieb:

    Jungs, ihr seid richtig kreativ! Macht richtig Spaß mit euch. Der eine baut einen Wrap in den Stack, dass den Profis vom osdev.org der Verstand stehen bleibt und ein anderer schlägt "times X-(-$) hlt" vor. 😃

    Tja, in der Tat. 😃 So viel war hier schon laenger nicht mehr los. Ist AFAIR uebrigens inzwischen auch der laengste Thread in diesem Forum. 👍


  • Mod

    Ich habe mal "times X-(-$) hlt" in Google eingegeben. Null Fundstellen!

    Das X muss man natürlich ersetzen:
    "times 510-(-)db0"380Fundstellen(auchnichtgeradeviel,wirsindschondabei)"times510() db 0" 380 Fundstellen (auch nicht gerade viel, wir sind schon dabei) "times 510-(-$$) hlt" 1 Fundstelle: http://kldp.org/node/89199 (leider sind wir nicht Erster! 🙄 )

    "times 1024-(-)db0"20Fundstellen"times1024() db 0" 20 Fundstellen "times 1024-(-$$) hlt" 0 Fundstellen


  • Mod

    Und zum Teil ueber die A20 zunaechst noch: Ueber die Ports 60h und 64h sprichst du erstmal nur mit dem Controller auf dem Mainboard. Darueber kannst du dann (seriell) etwas an die Tastatur schicken. Und D1 an 64h ist einfach ein Kommando, das bewirkt, dass das naechste Byte auf Port 60h beim outputport landet, statt bei der Tastatur.

    Ich habe das nun hoffentlich klar genug dargestellt:
    http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId13510

    Hier würde ein Bild helfen. Muss mal nachdenken.



  • Hier ein kleiner Hinweis zur Übersicht:

    loop:
    
    (...)
    
     jmp loop :confused:
    

    Es verwirrt beim Lesen wenn ein Labelname wie ein Opcode klingt. Es wäre vielleicht besser, Opcodenamen wie "Reservierte Worte" nicht als Bezeichner zu verwenden.

    Noch was zum "Voodoo-Mode": 🙂
    Drauf verlassen kann man sich ja, solange eben nichts und niemand die Segmentregister verändert. Das wäre z.B. der Fall, wenn man vorhat, ein RM-OS zu schreiben *wegduck* und dann das Format für ausführbare Programme selbst festlegt. Oder (viel einfacher) bei bootfähigen Programmen, die die Hardware testen, oder wirklich schnell mal eine Zahl ausrechnen sollen.


  • Mod

    Es verwirrt beim Lesen wenn ein Labelname wie ein Opcode klingt. Es wäre vielleicht besser, Opcodenamen wie "Reservierte Worte" nicht als Bezeichner zu verwenden.

    Sehr guter Hinweis. Wird geändert.



  • @Erhard Henkes:
    Die Screenshots auf deiner Webseite würde ich eher im PNG-Format abspeichern und nicht als JPEG. Das hätte folgende Vorteile gegenüber JPEG:

    1. Keine unscharfen Kanten, Text bleibt daher gut lesbar.
    2. Oft kleinere Dateigröße.

  • Mod

    Die Screenshots auf deiner Webseite würde ich eher im PNG-Format abspeichern und nicht als JPEG

    Danke für den Tipp 👍
    EDIT: Ist deutlich performanter als JPG. Werde mich wohl umgewöhnen müssen. 😉



  • Noch etwas zur Integer-Arithmetik (signed/unsigned Addition vs. Subtraktion).
    Weitergeführt bis zum "Ende" würde die "RealMode" dann in etwa aussehen wie folgt:

    RealMode:
     add sp, -0x40     ; space for input buffer (64 chars)
    (...)
     add sp,  0x40     ; clean it, please
     ret
    

    Besser wäre da die "klassische" (und verständliche) Logik:

    RealMode:
     sub sp,  0x40     ; space for input buffer (64 chars)
    (...)
     add sp,  0x40     ; clean it, please
     ret
    


  • Ob nun sub oder add ist in diesem Fall wohl reine Geschmackssache. Ich versuche sub wenn moeglich aus dem Weg zu gehen, da ich das uebersichtlicher finde (es gehen auch Mythen ueber einen Geschwindigkeitsvorteil um...).
    Und wer nicht erkennt, dass
    +(-40) == -(+40)
    ist, hat noch andere Probleme als sich mit OS-Entwicklung zu befassen. 😃
    Was hat das mit "klassischer Logik" zu tun?

    Was das "clean please" betrifft: Hast natuerlich prinzipiell recht. So wuerde/koennte man das sauber in einer Prozedur mit lokalen Variablen loesen. Evtl. koennte man einen entsprechenden Kommentar platzieren.
    Der Code fuer den Prompt (was du wohl "RealMode" nennst?) ist allerdings keine klassische Prozedur und hat deshalb auch keinen Ausgang, bei dem das irgendwie sinnvoll unterzubringen waere. Anders ausgedrueckt: Wenn der Prompt verlassen und der angelegte Puffer damit nicht mehr gebraucht wird, also freigegeben werden koennte, wird jedes Mal der RM-Stack unmittelbar danach eh eingestampft.
    Assembler ist in der Hinsicht nun mal einfach keine Sprache fuer Sauberkeitsfanatiker. 😃



  • wann geht's denn nun endlich mit dem OS los?
    🙂


Anmelden zum Antworten