Eigenes OS?



  • abc.w schrieb:

    Package Pin Count and Type 388 PBGA
    das ist nicht dein ernst?! 🙂 Nix für meinen "Schlitz"-Lötkolben. 🙂

    ach, du hast doch bestimmt irgendwo 'nen backofen rumstehen.

    abc.w schrieb:

    Genau, ich stehe auf Basteln. MyCPU ist interessant, wenn man aber bereits mal mit FPGAs in Berührung gekommen ist und zufällig ein FPGA-Board besitzt, dann, nun ja, 8-Bit CPU, hm, hm... 🙂
    Und wenn man zufällig ein Paar alte 80386 CPUs besitzt, wo man an die Pins auch noch mit nem "Schlitz"-Lötkolben drankommt, warum nicht irgendwas damit bauen.

    datenbusbreite ist doch nicht wichtig. 8-bitter können auch schnell sein. wenn du sowieso mit FPGA's rumfummelst, musste dir auch keine schaltung aus alten schrott-ICs basteln. mach dir 'nen x86-core und etwas peripherie in deinen FPGA rein, und fertig.
    🙂



  • was ist eigentlich aus f-cpu geworden ?



  • Hab die 13 C.zip bei mir mal ausprobiert und hatte schon wieder diese komische Fehlermeldung von mingw make (möchte aus welchen Gründen auch immer MinGW Tools verwenden :), habe auch noch die Verzeichnisse in PATH für nasm und DJGPP gar nicht angepasst und benutze im Makefile absolute Pfadangaben):

    del kernel.o
    process_begin: CreateProcess(NULL, del kernel.o, ...) failed.
    make (e=2): Das System kann die angegebene Datei nicht finden.
    make: *** [all] Error 2
    

    Dann im makefile die Aufrufe von del wie den Aufruf von copy geändert:

    cmd /c del kernel.o
    
    	cmd /c del ckernel.o
    	cmd /c del video.o
    	cmd /c del keyboard.o
    	cmd /c del math.o
    	cmd /c del util.o
    
    	cmd /c del ckernel.bin
    	cmd /c del boot.bin
    

    Und es funktioniert auch mit dem mingw make...
    Mit der make.exe, die in der zip-Datei mit dabei ist, funktioniert es auch ohne zusätzliches "cmd /c ". Ich sehe grade, dass die make.exe aus der zip-Datei die gleiche ist wie die c:\djgpp\bin\make.exe.
    Hm, mingw scheint irgendwie eigenwilliger als DJGPP zu sein. Kleine Inkompatibilitäten und so was...



  • +fricky schrieb:

    datenbusbreite ist doch nicht wichtig. 8-bitter können auch schnell sein. wenn du sowieso mit FPGA's rumfummelst, musste dir auch keine schaltung aus alten schrott-ICs basteln. mach dir 'nen x86-core und etwas peripherie in deinen FPGA rein, und fertig.

    Bezüglich x86 Core habe ich mir mal echt darüber Gedanken gemacht, einen in VHDL zu implementieren. Die "Komplexität" hat mich abgeschreckt, Real Mode, Protected Mode, elf Adressierungsarten, Anzahl der Befehle, Codierung der Befehle wie irgendwelche Präfixe, die mal auf die Berechnung der Adresse, mal auf die Operandenbitbreite Auswirkung haben usw... Ich habe auch mal darüber nachgedacht, eine Art Untermenge von 386 zu "implementieren", einen Core, der bereits im Protected Mode ist, nur wenige Befehle kann usw. Und dann ist noch die Sache bezüglich "lad mal nen Core", man muss ja noch das Programm irgendwie mitladen, wenn denn auf dem FPGA Platz dafür ist...
    Gibt es irgendwo einen freien x86 IP ab 80386, am Besten in VHDL?


  • Mod

    @abc.w: danke für deine Tests mit mingw. Geht denn jetzt auch das Linken? Wie hast Du das geschafft?

    Den Code zum Keyboard Driver habe ich hoffentlich noch etwas klarer gemacht. Vielleicht schaffe ich noch eine vereinfachte Variante mit nur einer Keymap und ohne Shift-Abfrage. Muss mir mal andere keymaps anschauen, ob diese einem allgemeinen Standard folgen, denn wir wollen ja auch unsere deutsche Tastatur durch einfaches Übernehmen anderer keymaps nutzen.

    Kapitel zum Keyboard Driver im Tutorial:
    http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId185043
    (dort ist auch der Sourcecode zum Download bereit)

    Ich hoffe, dass man es noch versteht, was ich da von mir gebe.
    Die Grundideen sind ziemlich einfach:
    Man holt den Scancode von Port 0x60, analysiert Bit7 (key pressed or released?),
    filtriert (=unterdrückt) den Shift-Tasten Scancode, speichert das Ergebnis in einer Variable ShiftKeyDown
    und gibt dann den Scancode der nachfolgenden Taste zurück.
    Damit steigt man dann in die richtige Keymap (Shift oder Non-Shift) und gibt mittels k_getch() das zum Scancode passende Zeichen zurück.
    Das ganze geht sicher auch einfacher, aber ich möchte die Bildung des Scancodes aus Pressed/Released-Bit und 7-Bit-Tasten-Nummerierung klar machen. Da fehlt noch ein Bild.

    Dieser kleine ohne Schnörkel daher kommende Text im Internet hat mir am besten geholfen, das Thema Scancode zu verstehen: 🙂
    http://www.qzx.com/pc-gpe/keyboard.txt

    Das nächste logische Thema wären dann wohl Interrupts, was denkt ihr? 😕

    @abc.w:

    Ich habe mich auch mal mit einem eigenen OS in Assembler beschäftigt zwecks endlich mal den Protected Mode der Intel CPUs zu verstehen. Habe aber diesbezüglich versagt und daraus wurde nichts. Hm, vertane Lebenszeit... hätte lieber in was anderes und sinnvolleres investieren sollen.

    Ich hoffe, Du bist dem Protected Mode schon etwas näher gekommen. 😉



  • abc.w schrieb:

    Gibt es irgendwo einen freien x86 IP ab 80386, am Besten in VHDL?

    http://www.opencores.org/?do=project&who=zet86
    🙂


  • Mod

    Beim Recherchieren habe ich eine ausführliche neue Tutorial-Serie (bisher 19 Teile) gefunden, didaktisch allerdings nicht geschickt gemacht, dafür in englisch und vollgestopft mit Detail-Infos:
    http://brokenthorn.com/Resources/OSDev1.html



  • @Erhard: Bezüglich Linken mit mingw hab ich es leider nicht hingegriegt. Benutze nun DJGPP. Es ist nur so, dass meine Pfade auf mingw Verzeichnisse eingestellt sind und wenn ich make in der Eingabeaufforderung aufrufe, mingw make ausgeführt wird. Und da kamen wieder die komischen Fehlermeldungen. Und ich wollte wissen, woran es liegt...

    Bezüglich des nächsten logischen Themas über Interrupts: Ich halte grade ein älteres Buch von Klaus-Dieter Thies "Die Innovativen 80286/80386 Architekturen" Teil 2. Im ersten Kapitel Basis-Programmier-Modell gibt es einen Unterkapitel "Ausnahmen und Interrupts". Vielleicht wäre das nächste logische Thema nicht nur über Interrupts alleine (als asynchrone Ereignisse), sondern auch über Ausnahmen (als synchrone Ereignisse) sinnvoll...

    Erhard Henkes schrieb:

    @abc.w:

    Ich habe mich auch mal mit einem eigenen OS in Assembler beschäftigt zwecks endlich mal den Protected Mode der Intel CPUs zu verstehen. Habe aber diesbezüglich versagt und daraus wurde nichts. Hm, vertane Lebenszeit... hätte lieber in was anderes und sinnvolleres investieren sollen.

    Ich hoffe, Du bist dem Protected Mode schon etwas näher gekommen. 😉

    Hm, ja, bisschen 🙂 Aber noch weit davon entfernt, mal aus dem Stegreif eigene Tasks anlegen zu können, die sich nicht gegenseitig kaputtmachen könnten 🙂

    +fricky schrieb:

    abc.w schrieb:

    Gibt es irgendwo einen freien x86 IP ab 80386, am Besten in VHDL?

    http://www.opencores.org/?do=project&who=zet86

    16 bit Zet processor equivalent to an Intel 80186. Ich hätte gerne einen ab 80386... 🙂 Ich hatte auch mal danach recherchiert, es gibt irgendwie keine, nicht mal "kostenpflichtige", warum auch immer.


  • Mod

    Vielleicht wäre das nächste logische Thema nicht nur über Interrupts alleine (als asynchrone Ereignisse), sondern auch über Ausnahmen (als synchrone Ereignisse) sinnvoll...

    Ja, das gehört zusammen: Gates, Interrupts, Traps, Exceptions.
    Ich bin am nachdenken, wie man dieses Kapitel am besten anpackt.
    Mir war es nur wichtig zu zeigen, dass man auch ohne Interrupts Daten per Polling aus dem Tastaturpuffer abholen kann. Das ist aber, als würde man ständig an der Tür stehen, um zu öffnen, falls jemand kommt (eben weitgehend unnötiger Aufwand). Nun wird nach dem Umzug nach PM wieder die "Klingel" eingeführt, damit wir asynchron auf "echten" Bedarf reagieren können. 😉



  • Erhard Henkes schrieb:

    Ja, das gehört zusammen: Gates, Interrupts, Traps, Exceptions.
    Ich bin am nachdenken, wie man dieses Kapitel am besten anpackt.

    diese 'call gates' sind eine x86-spezialität. die würde ich getrennt erwähnen.
    🙂


  • Mod

    Ich habe eine Nomenklatur-Frage. Man benötigt in den verschiedenen C-Modulen immer wieder eine ganze Menge extern definierter Funktionen. Dies erfolgt oft durch Inkludieren einer Header-Datei namens "system.h", in der man dann alle "externen" Funktionen und einiges andere deklariert/definiert. Mir gefällt der Name "system.h" nicht besonders, weil er nicht wirklich verständlich ist. System kann alles und nichts sein. 🙄

    Folgende Ideen habe ich bisher:

    functions.h
    function_prototypes.h
    kernel.h
    operating_system.h
    os.h

    Wie würdet ihr diesen Header nennen, der dann fast in jedem Modul am Anfang zu finden ist? Mein Favorit ist bisher "os.h". Lässt man geistig das "o" weg, landet man tatsächlich bei "system.h".
    Vielleicht hat jemand eine viel bessere Idee. 🙂



  • #include <PrettyOS.h> ?


  • Mod

    Die Idee ist o.k. Ich wollte den Namen aber noch ändern können, ist nur der Entwicklungs-Deckname. 😉
    Habe mich vorerst für os.h entschieden.


  • Mod

    Ich benötige eure Unterstützung, weil ich die Lücke nicht finde. 🙄

    Exceptions und Timer Interrupt IRQ 0 gehen.
    Wenn ich den keyboard_handler (polling geht ja bestens) zum Testen auf den IRQ0 (18,222 Ticks/sec) umlege, funktioniert er wie beabsichtigt.

    Allerdings kommt der Keyboard Interrupt IRQ1 nicht an. 😕 EDIT: Er wird nicht ausgelöst, weil der Tastatur-Puffer nicht leer ist (das berühmte "flushen" hat mich wieder eingeholt).

    Hier der gesamte - noch nicht funktionierende - Sourcecode: http://www.henkessoft.de/OS_Dev/Downloads/14 C Test IRQ1 funktioniert nicht.zip

    Ich denke, dass der C-Code für die Interrupt-Behandlung in Ordnung ist, habe ihn mehrfach gecheckt. Vielleicht liegt es am Assemblercode isr.asm (Stack?) oder am Linker-Script? Hier ein Screenshot vom OS (timer IRQ geht, habe ihn auf eine Minute im Bildschirm-Ausdruck eingestellt, Zeit stimmt unter Bochs aber nicht): http://www.henkessoft.de/OS_Dev/Downloads/IRQ_Test.PNG

    Ich hoffe, das jemand den blöden Fehler bezüglich IRQ1 und vielleicht auch der anderen (welchen kann man am einfachsten testen?) findet, damit wir rasch weiter kommen. Wie gesagt, IRQ0 geht bestens (einfach mal auf key_handler umlegen).
    Wenn man mit

    __asm__("int $0x21");
    

    im Kernel Programm main()
    den IRQ1 (--> 33 = 0x21) selbst auslöst, kommt auch der keyboard_handler ins Spiel.

    Das heißt, warum wird der IRQ1 nicht weiter geleitet? (IDT Problem?)

    @Nobuo T, abc.w, Bitsy, +fricky et.al.:
    Lasst mich bitte nicht hängen! Wer diesen Mist-Fehler findet, wird im Tutorial extrem gelobt. EDIT: Hauptproblem inzwischen gelöst, aber ich würde mich freuen, wenn ihr trotzdem mal über den Code schaut. Das Thema IDT, IDTR, ISR, Exceptions, ... ist wichtig.

    EDIT: In einem anderen Forum habe ich erfahren, dass man den Tastatur-Puffer leeren muss, damit neue Interrupts gesendet werden. Klingt logisch. Daher habe ich einfach folgendes gemacht:

    Ein einmaliges

    __asm__("int $0x21");
    

    reicht bereits aus, um den Prozess zu starten.
    Soll ich ein

    keyboard_init(){__asm__("int $0x21");}
    

    schreiben, das ich einmal zu Beginn der main() aufrufe??

    Es gibt noch eine zweite - evtl. bessere - Lösung:

    void keyboard_init()
    {
        /* Wait until buffer is empty */
        while (inportb(0x64) & 0x01)
          inportb(0x60);
    
        // __asm__("int $0x21"); // ? 
    };
    

    Hier ist jetzt der funktionierende Code, allerdings alles noch im Experimentierstadium:

    http://www.henkessoft.de/OS_Dev/Downloads/14_C_Test_IRQ1_funktioniert.zip

    Welchen Interrupt würdet ihr nach IRQ0 (Zeit-Ticks) und IRQ1 (Tastatur) als nächstes probieren?

    Speichermanagement, Multitasking, ... warten. Allerdings muss ich zugeben, dass das gesamte Thema OSDEV ziemlich knifflig ist und man die Tools wirklich beherrschen muss. meine Tool-Schwachpunkte sind AT&T Syntax und Linker-Skript. Der verwendete DJGPP mit gcc 3.1 ist auf jeden Fall die richtige Wahl.



  • Probiere mal irgendeinen von 3-8, wobei man das anzusteuernde Device auch auf einen der oberen Interrupts legen können sollte, und dann kümmere Dich um den 2er, weil Du den brauchst, wenn Du an die oberen 8 ran willst. Wenn das Gerät dann auch z.B. mit dem 10er ansprechbar ist, stehen überhaupt erst mal alle IRQs zur Verfügung! Also - erst eine einfache Interruptgeschichte 'unten', und dann schauen, dass sie auch 'oben' läuft.

    Wenn der 2er Probleme macht - ich sollte noch einen Sourcecode haben, bei dem ich eine vierfache Serielle angesteuert habe, wobei der letzte Kanal eben nur über IRQ 10 erreichbar war. Die waren damals sehr dankbar, dass es überhaupt mal ein Stück Software gab, mit dem man den überhaupt ansprechen konnte 😉

    Freut mich übrigens, dass der 3er DJGPP soweit funktioniert - hatte Dir ja in der Mail die Problematik erklärt.


  • Mod

    @Bitsy:
    Das sind die Mechanismen, die versuchsweise eingebaut sind, muss aber noch prüfen, ob alles wirklich funktioniert, bisher wurden ja nur IRQ0 (clock) und IRQ1 (keyboard) behandelt:

    ..

    Daher kann ich mit

    __asm__("int $0x21"); // 0x21 = 33, gemappt auf IRQ1 (Keyboard)
    

    den Keyboard-Interrupt selbst anstoßen.

    Das mit den Interrupts finde ich ganz lustig. Die Keyboard-Ports und der Keyboard-Puffer haben mich fast aus der OS-Kreisbahn geworfen, weil man diesbezüglich viel unausgegorenes und verwirrendes Zeug im Internet findet.

    @Bitsy: Hast Du eine Idee, wie man das Linker-Problem (mit dem a.out Format) des mingw überwinden könnte? abc.w präferiert diese Toolchain. 😕



  • Bezüglich Linker-Problem mit mingw würde mich zwar interessieren, wie man es irgendwie hinkriegen könnte. Aber, wenn es nicht geht, aus welchen Gründen auch immer, ist auch nicht schlimm. Ich habe ja noch DJGPP.
    Ich habe mir den Quellcode 14_C_Test_IRQ1_funktioniert geholt und ausprobiert. Eines stört mich jetzt ein wenig. Zunächst, auf der einen Seite haben wir Assembler-Dateien, die mit nasm assembliert werden. Auf der anderen Seite gibt es c-Dateien, die aber hie und da eine Funktion mit Assembler Inline-Code enthalten. Das ist irgendwie nicht konsistent. Einmal nasm, dann gcc, dann inline-gcc. Wäre vielleicht sinnvoll, wenn c-Datei, dann C, wenn Assembler-Datei, dann Assembler nasm. Und die Funktionen mit Assembler Inline-Code rein in Assembler implementieren? Nur als Vorschlag. Optimal wäre natürlich, statt nasm GNU as zu verwenden, weiss aber jetzt nicht genau, ob man 16-Bit Assembler Quellcode mit as assemblieren kann. Vorteil davon wäre noch, dass man nur ein Tool bräuchte: DJGGP. GNU as ist nämlich in DJGPP mitenthalten.



  • Eine andere Sache, wollte ein Paar Ausnahmen provozieren mit diesem Code:

    .global _k_zero_divide
    .global _k_undefined_op
    .global _k_null_pointer
    
    .section .text
    
    _k_zero_divide:
        movl $0, %eax
        div %eax
        ret
    
    _k_undefined_op:
        ud2
        ret
    
    _k_null_pointer:
        movl $0, %eax
        movl %eax, (%eax)
        ret
    

    Division durch 0 und undefinierter Op 👍
    Die Funktion k_null_pointer() wir aber ausgeführt und das System läuft 😕 Oder ist Zugriff mit Offset Null ok 😕



  • Erhard:
    Irgendwie habe ich inzwischen ein wenig den Ueberblick verloren. Kannst du mal irgendwie ein Verzeichnis oder eine Seite einrichten, wo man waehrend der Entwicklung immer mal die aktuellen Codes runterladen kann?

    Bei deinem ersten KB-Polling hat mich ehrlich gesagt schon etwas gewundert, dass das ueberhaupt funktionierte. Klassischerweise macht man das AFAIR so, dass man einen Handler fuer IRQ 1 installiert. Dort checkt man erstmal, ob etwas im input buffer ist (port 64h, Bit0). Falls was dran liegt, port 60h auslesen und irgendwie verarbeiten (scancodes oder evtl. sonstige spezial-codes).
    Zum Abschluss immer ACK an das keyboard, indem ein reset ausgefuehrt wird: Kurz aus- und wieder einschalten ueber Port 61h, Bit7. Zum Ende natuerlich noch EOI an den PIC. Ist dann zwar immer noch ziemlich primitiv, sollte so aber zumindest keine Probleme geben...

    abc.w:
    Ich kann nur vermuten, dass einfach (noch?) kein Paging aktiviert ist, mit dem eine Ausnahme beim Zugriff auf einen 0-Pointer ausgeloest wuerde. An der physikalischen Adresse 0 ist nun mal einfach normaler RAM, also an sich kein Problem.


  • Mod

    nasm, dann gcc, dann inline-gcc. Wäre vielleicht sinnvoll, wenn c-Datei, dann C, wenn Assembler-Datei, dann Assembler nasm. Und die Funktionen mit Assembler Inline-Code rein in Assembler implementieren?

    Du hast völlig Recht. Die bisherige "gemischte" Lösung liegt an meinen Problemen mit der AT&T Syntax. Auf der einen Seite ist es wichtig, dass Einsteiger sehen, wie einfach man zwischen C- und ASM-Code hin und her springen kann. Man benötigt nur global, extern und den führenden Unterstrich. Auf der anderen Seite führt dies zu einem Hin- und Hergehüpfe. Ich werde daher versuchen, Deine Idee aufzunehmen. Vielleicht kann Nobuo T da etwas unterstützen. 🙂

    ... statt nasm GNU as zu verwenden, weiss aber jetzt nicht genau, ob man 16-Bit Assembler Quellcode mit as assemblieren kann. Vorteil davon wäre noch, dass man nur ein Tool bräuchte: DJGGP. GNU as ist nämlich in DJGPP mitenthalten.

    Habe mir die Syntax von as bisher noch nicht angeschaut. AT&T?

    Kannst du mal irgendwie ein Verzeichnis oder eine Seite einrichten, wo man waehrend der Entwicklung immer mal die aktuellen Codes runterladen kann?

    @Nobuo T:
    Ja, wird sofort gemacht: Den letzten Code erhält man ab jetzt immer unter diesem Link (wurde aber im Tutorial noch nicht beschrieben, weil er sich im Entwicklungs-/Testzustand befindet; daher sind gute Ideen - wie oben von abc.w zum Thema Exception - immer gerne gesehen. Bitte ausreichend kommentieren.):

    ➡ ➡ ➡ Link zur jeweils aktuellsten Test-Version:
    http://www.henkessoft.de/OS_Dev/Downloads/PrettyOS_last_version.zip

    Was abc.w anspricht ist mein Hin- und Herhüpfen zwischen C-Code (vor allem zum Thema Interrupts) und isr.asm.


Anmelden zum Antworten