Eigenes OS?



  • Erhard Henkes schrieb:

    "na und? dann polle ich eben in der timer-isr. ca. 18 anschläge/s als samplingrate sollte doch reichen".

    Da der Timer alle 18,2 ms mit IRQ0 Alarm schlägt

    wieso haste ihn so schnell eingestellt? normerweise tickert der mit 18.2Hz, nicht kHz.
    🙂


  • Mod

    @+fricky: Ja, Du hast völlig Recht, das habe ich durcheinander gebracht:

    By default, this channel of the timer is set to generate an IRQ0 18.222 times per second.

    Habe das oben korrigiert, um niemanden zu verwirren.

    Im Sourcecode timer.c läuft das zur Zeit so (muss in Bochs nicht exakt stimmen):

    #include "os.h"
    
    int timer_ticks = 0;
    
    /* timer fires 18.222 times per second.*/
    void timer_handler(struct regs* r)
    {
        ++timer_ticks;
        static int z=10;
        if ((timer_ticks % 1093) == 0) // 1093 = 60*18.222
        {
            k_printf("One minute has passed", ++z, 0x0B);
        }
    }
    
    void timer_wait(int ticks)
    {
        unsigned long eticks;
        eticks = timer_ticks + ticks;
        while(timer_ticks < eticks);
    }
    
    void timer_install()
    {
        /* Installs 'timer_handler' to IRQ0 */
        irq_install_handler(0, timer_handler);
    }
    

  • Mod

    dynamische konfigurierbare Prioritäten?

    Das ist ein interessantes Thema. Aber da wird noch viel Code den Compiler durchfließen, bevor ich da anlange.

    Momentan denke ich darüber nach, welche völlig neuen Impulse man setzen könnte, aber zuerst muss man das alte praktisch nachempfinden, sonst fehlt das Verständnis. Die Verschaltung der Hardware macht ja auch gewisse Vorgaben, die man leider akzeptieren muss.



  • Erhard Henkes schrieb:

    void timer_wait(int ticks)
    {
        unsigned long eticks;
        eticks = timer_ticks + ticks;
        while(timer_ticks < eticks);
    }
    

    ^^das sieht nicht überlauffest aus
    🙂


  • Mod

    Was ist schon "überlauffest" auf der Welt?

    #include "os.h"
    
    unsigned long timer_ticks = 0;
    
    /* timer fires 18.222 times per second.*/
    void timer_handler(struct regs* r)
    {
        ++timer_ticks;
        static unsigned long z=10;
        const unsigned long N = 109; // 109 = 60/10*18.222
        if (!(timer_ticks % N))
            k_printf("10 seconds have passed", ++z, 0x0B);
    }
    
    void timer_wait(unsigned long ticks)
    {
        unsigned long eticks;
        eticks = timer_ticks + ticks;
        while(timer_ticks < eticks);
    }
    
    void timer_install()
    {
        /* Installs 'timer_handler' to IRQ0 */
        irq_install_handler(0, timer_handler);
    }
    

    Besser?



  • Erhard Henkes schrieb:

    Besser?

    ist doch immer noch das selbe.
    so z.b:

    unsigned long eticks;
    
    void timer_handler(struct regs* r)
    {
      ...
      if (eticks)
        eticks--;
    }
    
    void timer_wait (unsigned long ticks)
    {
        disable_timer_interrupt();
        eticks = ticks;
        enable_timer_interrupt();
    
        // busy wait...
        while (eticks)
          ;
    }
    

    🙂


  • Mod

    Ja, gute Idee, habe es umgesetzt. Thanks @ +fricky.

    So sieht momentan timer.c aus:

    #include "os.h"
    
    unsigned long timer_ticks = 0;
    unsigned long eticks;
    
    void timer_handler(struct regs* r)
    {
        ++timer_ticks;
        if (eticks)
            --eticks;
    
        //TEST
        char bufferTimerticks[20];            k_itoa (timer_ticks, bufferTimerticks);
    	k_printf("             ",  6, 0x0B);  k_printf(bufferTimerticks, 6, 0x0B);
        char bufferWaitticks[20];         	  k_itoa (eticks, bufferWaitticks);
        k_printf("             ",  7, 0x0B);  k_printf(bufferWaitticks,  7, 0x0B);
        //TEST
    }
    
    void timer_wait (unsigned long ticks)
    {
        timer_uninstall();
        eticks = ticks;
        timer_install();
    
        // busy wait...
        while (eticks)
        {
            k_printf("waiting time runs",   8, 0x0B);
            /* do nothing */;
        };
        k_printf("waiting time has passed", 9, 0x0B);
    }
    
    void sleepSeconds (unsigned long seconds)
    {
        // based upon timer tick frequence of 18.222 Hz
        timer_wait((unsigned long)18.222*seconds);
    }
    
    void timer_install()
    {
        /* Installs 'timer_handler' to IRQ0 */
        irq_install_handler(0, timer_handler);
    }
    
    void timer_uninstall()
    {
        /* Uninstalls IRQ0 */
        irq_uninstall_handler(0);
    }
    

    ckernel.c:

    #include "os.h"
    
    int main()
    {
        k_clear_screen();
    
        // GDT, IDT, ISRS, IRQ, timer, keyboard
        gdt_install();
        idt_install();
        isrs_install();
        irq_install();
        timer_install();
        keyboard_install();
    
    	k_printf("   ************************************************", 0, 0xA);
    	k_printf("   *                                              *", 1, 0xA);
    	k_printf("   *          Welcome to PrettyOS 0.05            *", 2, 0xA);
    	k_printf("   *                                              *", 3, 0xA);
    	k_printf("   *        The C kernel has been loaded.         *", 4, 0xA);
    	k_printf("   *                                              *", 5, 0xA);
    	k_printf("   ************************************************", 6, 0xA);
    
    	update_cursor(8, 0);
            sti();
    	while(TRUE)
    	{
    	    static int zz=10;
    	    sleepSeconds(20);
    	    k_printf("20 sec have passed", ++zz, 0x0B);
    	};
    	return 0;
    };
    

    Es gibt ein offenbar bisher unerkanntes Problem:
    Solange man die Finger vom Keyboard lässt läuft der timer_handler. Sobald man aber die erste Taste nach dem Drücken los lässt, bleibt der Timer (die gezählten timer_ticks) stehen. Nur bei gedrückter Taste läuft er wieder weiter. Rattenscharfer Effekt. 😃

    Allerdings blicke ich momentan nicht durch, warum das passiert. Da fehlt noch einiges im Keyboard-Bereich. Ich habe den Code hoch geladen, damit ihr euch das mal anschauen könnt. 🙂
    http://www.henkessoft.de/OS_Dev/Downloads/PrettyOS_last_version.zip

    Bei Keyboard Port 0x60 u. 0x64 muss ich noch mal richtig lesen. Da klafft noch eine echte Wissenslücke bei mir.

    @Nobuo T: Würdest Du Dir bitte keyboard.c anschauen. Da muss ja der Wurm lauern. Deine konkreten Vorschläge von oben zum Thema Keyboard Controller wurden noch nicht umgesetzt. Mich würde interessieren, was genau den IRQ0 beim Taste-Loslassen "outknockt" und beim Taste-Drücken wieder aktiviert. 😉



  • Ok, mal wieder der Reihe nach:

    Bitsy schrieb:

    Ich glaube, der vorrangigste Punkt wäre nun eine Diskussion über die Architektur des OS an sich - und ob und wie solch ein 'Wunsch-OS' auf dem PC realisierbar ist.

    Ich gehe mal davon aus, dass Erhard sich da schon einen groben Plan gemacht hat, was fuer eine Art von OS er fabrizieren will. Das ob ist da wohl keine Frage, das wie wird hier aktuell diskutiert. 😉

    Was du da weiter anfuehrst, sind doch eher Spezialfaelle und Teilgebiete, des Themenbereichs Scheduling (Echtzeit-Prozesse). Solche Ansaetze wie Prioritaetensteuerung oder verschiedene Ansaetze fairer Ressourcenverteilung mit verschiedensten abgefahrenen queue-Konstrukten (da gibt es wirklich eine Menge weit komplizierteres als einfache Prioritaetensteuerung) kann man da vielleicht in einem Ueberblick kurz anschneiden, aber um den Rahmen nicht zu sprengen, waere mein Vorschlag, sich schliesslich einfach auf Round Robin zu beschraenken.

    Und DMA-Gefrickel ist ja nun voellig abgehoben. Immer im Hinterkopf behalten, dass das ein Internet-Tutorial und kein Kompendium zur OS-Entwicklung werden soll - das wird wie ich das sehe schon so eine ordentliche Portion Stoff. 😃

    [OT]BTW ist das Basteln eines Synths auch auf dem PC selbst unter Windows kein groesseres Problem als unter DOS - solange man gute Hardware (am besten mit HW Wavetable Synth) oder zumindest sehr gute Treiber (zumindest directX) hat.[/OT]

    Erhard Henkes schrieb:

    Würdest Du Dir bitte keyboard.c anschauen. Da muss ja der Wurm lauern. Deine konkreten Vorschläge von oben zum Thema Keyboard Controller wurden noch nicht umgesetzt. Mich würde interessieren, was genau den IRQ0 beim Taste-Loslassen "outknockt" und beim Taste-Drücken wieder aktiviert. 😉

    Scharfer Effekt -> reichlich daemlicher Fehler, wenn ich mich nicht verschielt habe:
    FetchAndAnalyzeScancode landet in einer Endlosschleife, wenn eine Taste losgelassen wird. Mal abgesehen von dem fehlenden EOI an den PIC duerfte das geloeschte IF wohl ausschlaggebend dafuer sein, dass sich in diesem Fall dann so lange nichts mehr tut, bis du wieder eine Taste drueckst.

    Kurz: Die Endlosschleife hat in FetchAndAnalyzeScancode nichts zu suchen.

    BTW: Ich hatte in meiner Auflistung noch vergessen, sich mal mit der Kernel-API (und einem HW-Abstraktions/Treiber-Prinzip) deines OS zu befasssen. Alle Kernel-Funktionen, Treiber etc. einfach nur ueber C-Funktionen und header zur Verfuegung zu stellen ist sicher nicht das Wahre. 🙂
    Ich wuerde die Einrichtung eines kleinen Sets der wichtigsten Funktionen zum I/O und spaeter dann Speicher- und Prozessverwaltung ueber Interrupts aehnlich DOS oder Linux vorschlagen.

    Je nachdem, was fuer einen Kern du basteln willst (Micro oder Monolith), waere es evtl. sinnvoll, das schon ganz am Anfang beim Aufbauen der ersten abstrakteren OS-Funktionen wie RAM-Verwaltung zu diskutieren, statt erst bei Adressraumtrennung, Privilegien und IPC. Evtl. mit Verweis auf diese spaeteren Themen zur Begruendung.


  • Mod

    FetchAndAnalyzeScancode landet in einer Endlosschleife, wenn eine Taste losgelassen wird. ...
    Kurz: Die Endlosschleife hat in FetchAndAnalyzeScancode nichts zu suchen.

    Uups, stimmt. Ich dachte, es wäre etwas komplizierteres. 🙄
    Da wimmelt es ja nur so von Endlosschleifen. Shit Polling! 😃

    Mal abgesehen von dem fehlenden EOI an den PIC duerfte das geloeschte IF wohl ausschlaggebend dafuer sein, dass sich in diesem Fall dann so lange nichts mehr tut, bis du wieder eine Taste drueckst.

    Thanks.



  • Erhard Henkes schrieb:

    ... 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?

    Ja, AT&T Syntax mit dem Nachteil von links nach rechts Lesen, so wie man es normalerweise jahrelange macht, und dem Haufen Intel-Doku, wo man von rechts nach links lesen muss. Aber Lesbarkeit scheint ja sowieso der Punkt zu sein, auf den ich hier alleine bestehe.

    Ich habe mal aus Neugier die Assembler-Dateien boot.asm, kernel.asm und isr.asm nach AT&T umgesetzt und erfolgreich versucht, einmal allein mit DJGPP (im Sinne ohne nasm) und einmal mit mingw Tools eine funktionierende MyOS.bin zu bauen. Nicht, dass ich darauf bestehe, vollständig auf diese Tools umzusteigen. Ist nur "Machbarkeitsstudie". Mein Makefile dazu sieht so aus:

    all:
    	@echo Select target: mingw or djgpp.
    	@echo Exit.
    
    djgpp:
    	@echo Building with djgpp:
    	c:\djgpp\bin\as boot.s -o boot.o
    	c:\djgpp\bin\ld boot.o -Ttext 0x7C00 -e _start -o boot.exe
    	c:\djgpp\bin\objcopy --strip-all --only-section .text --output-target binary boot.exe boot.bin
    	c:\djgpp\bin\as kernel.s -o kernel.o
    	c:\djgpp\bin\as isr.s -o isr.o
    
    	c:\djgpp\bin\gcc -Wall -c ckernel.c -o ckernel.o -O1   
    	c:\djgpp\bin\gcc -Wall -c video.c -o video.o -O1
    	c:\djgpp\bin\gcc -Wall -c math.c -o math.o -O1
    	c:\djgpp\bin\gcc -Wall -c util.c -o util.o -O1
    	c:\djgpp\bin\gcc -Wall -c gdt.c -o gdt.o
    	c:\djgpp\bin\gcc -Wall -c idt.c -o idt.o
    	c:\djgpp\bin\gcc -Wall -c isrs.c -o isrs.o
    	c:\djgpp\bin\gcc -Wall -c irq.c -o irq.o
    	c:\djgpp\bin\gcc -Wall -c timer.c -o timer.o
    	c:\djgpp\bin\gcc -Wall -c keyboard.c -o keyboard.o
    	c:\djgpp\bin\ld -T kernel.ld kernel.o isr.o ckernel.o video.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o -o ckernel.bin
    
    	cmd /c copy /b boot.bin + ckernel.bin MyOS    
    
    	cmd /c del MyOS.bin
    	cmd /c rename MyOS MyOS.bin
    	cmd /c erase ..\MyOS.bin
    	cmd /c copy MyOS.bin ..\MyOS.bin
    
    mingw:
    	@echo Building with mingw:
    	as boot.s -o boot.o
    	ld boot.o -Ttext 0x7C00 -e _start -o boot.exe
    	objcopy --strip-all --only-section .text --output-target binary boot.exe boot2.bin
    	dd if=boot2.bin of=boot.bin bs=512 count=1
    	as kernel.s -o kernel.o
    	as isr.s -o isr.o
    
    	gcc -Wall -c ckernel.c -o ckernel.o -O1 -s
    	gcc -Wall -c video.c -o video.o -O1 -s
    	gcc -Wall -c math.c -o math.o -O1 -s
    	gcc -Wall -c util.c -o util.o -O1 -s
    	gcc -Wall -c gdt.c -o gdt.o -s
    	gcc -Wall -c idt.c -o idt.o -s
    	gcc -Wall -c isrs.c -o isrs.o -s
    	gcc -Wall -c irq.c -o irq.o -s
    	gcc -Wall -c timer.c -o timer.o -s
    	gcc -Wall -c keyboard.c -o keyboard.o -s
    	ld -Ttext 0x8000 -e _start kernel.o isr.o ckernel.o video.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o -o ckernel.exe
    	objcopy --strip-all --output-target binary ckernel.exe ckernel.bin
    	cmd /c copy /b boot.bin + ckernel.bin MyOS    
    
    	cmd /c del MyOS.bin
    	cmd /c rename MyOS MyOS.bin
    	cmd /c erase ..\MyOS.bin
    	cmd /c copy MyOS.bin ..\MyOS.bin
    

    Das einzige Programm, das nicht Teil von DJGPP und mingw ist, ist dd. Ich weiss nicht, wie man unter WinXP eine fest definierte Anzahl von Bytes aus einer Datei in eine andere kopieren kann, also habe ich dd benutzt, was ja von *nix stammt. Wie dem auch sei, so scheint zu gehen, ohne nasm...
    Ein Nachteil bezüglich mingw ist noch, dass AntiVir bei von mingw as erzeugten Dateien meckert, sind angeblich irgendwelche Trojanische Pferde 😃

    Erhard Henkes schrieb:

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

    Genauer meine ich, dass der gcc spezifische inline-Code in den c-Dateien nicht schön ist, weil, nun, sehr gcc spezifisch...



  • Kann GAS nicht inzwischen auch Intel-Syntax? Das wuerde die Sache sicher vereinfachen.



  • Erhard Henkes schrieb:

    Ja, gute Idee, habe es umgesetzt. Thanks @ +fricky.

    keine ursache. später aber, wenn du mal multitasking machen willst, kannste die funktion so nicht mehr verwenden. dann besser einen counter in den 'task control block' (der struct, die den zustand einer task kontrolliert) einbauen, und beim warten nicht einfach rechenzeit verbraten, sondern zur nächten task weiterschalten (plus einer möglichkeit, den 'wait' abbrechen zu können, z.b. von einer anderen task oder aus einem interrupt).
    🙂



  • Nobuo T schrieb:

    Kann GAS nicht inzwischen auch Intel-Syntax? Das wuerde die Sache sicher vereinfachen.

    echt, ne? diese bescheuerte at&t-syntax würde mich auch völlig nerven. welcher gehirnamputierte hat sich das bloss ausgedacht?
    🙂


  • Mod

    boot.asm, kernel.asm und isr.asm nach AT&T umgesetzt

    Würdest Du mir diese Files bitte schicken oder - noch besser - hier posten? Damit ich die AT&T Syntax endlich besser lerne, denn isr.asm könnte man vielleicht auch weitgehend oder völlig in den C-Modulen aufgehen lassen, falls das bezüglich Ordnung mehr Sinn macht. Für mich ist z.B. die Intel Syntax eindeutig besser lesbar.

    Das sieht doch irgendwie unnötig kompliziert aus:

    static void idt_load(){ asm volatile("lidt %0" : "=m" (idt_register)); } // load IDT register (IDTR)
    

    Das einzige Programm, das nicht Teil von DJGPP und mingw ist, ist dd. Ich weiss nicht, wie man unter WinXP eine fest definierte Anzahl von Bytes aus einer Datei in eine andere kopieren kann.

    Nicht-Linux-User kennen dd nicht, verwenden partcopy (das ist, was Du anstelle dd suchst) oder rawwrite.

    Ich bin da aber flexibel, nur möchte ich alles auf MS Windows ermöglichen, was ja bisher keinerlei Problem ist.

    Ich möchte auch den Hinweis auf gvim (am Anfang fand ich das nicht uninteressant , weil OSDEV bezüglich des Flairs eher archaische Instrumente benötigt. 😃 ) verwerfen, weil notepad++ besser aussieht und weniger störrisch ist. Seht ihr das ähnlich? 😕



  • +fricky schrieb:

    Nobuo T schrieb:

    Kann GAS nicht inzwischen auch Intel-Syntax? Das wuerde die Sache sicher vereinfachen.

    echt, ne? diese bescheuerte at&t-syntax würde mich auch völlig nerven. welcher gehirnamputierte hat sich das bloss ausgedacht?
    🙂

    Total! 😃 👍
    Wahrscheinlich irgendein weltfremder, idealistischer, langhaariger Linux-Frickler mit Strick-Polunder und Taxischein. 🕶

    Erhard Henkes schrieb:

    Ich möchte auch den Hinweis auf gvim (am Anfang fand ich das nicht uninteressant , weil OSDEV bezüglich des Flairs eher archaische Instrumente benötigt. 😃 ) verwerfen, weil notepad++ besser aussieht und weniger störrisch ist. Seht ihr das ähnlich? 😕

    Wie ich das sehe, kann man sich vielleicht denken. 🙂



  • Erhard Henkes schrieb:

    Ich möchte auch den Hinweis auf gvim (am Anfang fand ich das nicht uninteressant , weil OSDEV bezüglich des Flairs eher archaische Instrumente benötigt. 😃 ) verwerfen, weil notepad++ besser aussieht und weniger störrisch ist. Seht ihr das ähnlich?

    klar, wenn man assembler-code auf tiefster low-level ebene schreibt, muss man noch lange keine prähistorischen tools verwenden.
    🙂



  • Bezüglich der Assembler-Dateien in AT&T, die Kommentare sind alle unverändert. boot.s (hier habe ich, glaube, nur die Anzahl der Sektoren auf 40 geändert):

    .global _start
    .section .text
    .code16
    
    .equ kernel_start, _start + 1024
    
    ##################################
    # setup a stack and segment regs #
    ##################################
    
    _start:
        xorw %ax, %ax
        movw %ax, %ds
        movw %ax, %es
        movw %ax, %ss
        movw %ax, %sp
    
    ################################
    # read kernel from floppy disk #
    ################################
    
        movb %dl, bootdrive # boot drive stored by BIOS in DL.
                            # we save it to [bootdrive] to play for safety.
    
    load_kernel:
        xorw %ax, %ax       # mov ax, 0  => function "reset"
        int $0x13         
        jc load_kernel      # trouble? try again
    
        mov $0x8000, %bx    # set up start address of kernel
    
        # set parameters for reading function
        # 8-bit-wise for better overview
        movb bootdrive, %dl # select boot drive
        mov $40, %al        # read 40 sectors
        mov $0, %ch         # cylinder = 0
        mov $2, %cl         # sector   = 2
        mov $0, %dh         # head     = 0
        mov $2, %ah         # function "read" 
        int $0x13         
        jc load_kernel      # trouble? try again
    
        # show loading message
        mov $loadmsg, %si
        call print_string
    
    ##################
    # jump to kernel #
    ##################
    
        jmp kernel_start    # address of kernel. "jmp bx" might also work.
    
    #######################
    # call "print_string" #
    #######################
    
    print_string:
        mov $0x0E, %ah    # VGA BIOS fnct. 0x0E: teletype
    1:   
        lodsb             # grab a byte from SI
        testb %al, %al    # NUL?
        jz 2f             # if the result is zero, get out
        int $0x10         # otherwise, print out the character!
        jmp 1b
    2:
        ret
    
    ########
    # data #
    ########
    
    bootdrive: .byte 0    # boot drive
    loadmsg: .asciz "bootloader message: loading kernel ...\n\r"
    
    . = _start + 510
    
    .byte 0x55
    .byte 0xAA
    
    .end
    

    Die Datei kernel.s:

    ###############################################
    # HenkesSoft 0.04 (version from Mar 26, 2009) #
    ###############################################
    
    .global RealMode
    .global _start
    .section .text
    .code16
    
    #############
    # Real Mode #
    #############
    
    _start:
    RealMode:
        xorw %ax, %ax         # set up segments
        mov %ax, %es
        mov %ax, %ds
        mov %ax, %ss
        mov %ax, %sp
    
        mov $welcome, %si
        call print_string
    
        addw $-0x40, %sp    # make room for input buffer (64 chars)
    
    loop_start:
        mov $prompt, %si    # show prompt
        call print_string
    
        mov %sp, %di        # get input
        call get_string
        jcxz loop_start   # blank line? -> yes, ignore it   
    
        mov %sp, %si
        mov $cmd_hi, %di    # "hi" command
        call strcmp
        je helloworld
    
        mov %sp, %si
        mov $cmd_help, %di  # "help" command
        call strcmp
        je help
    
        mov %sp, %si
        mov $cmd_questionmark, %di  # "?" command
        call strcmp
        je help
    
        mov %sp, %si
        mov $cmd_exit, %di  # "exit" command
        call strcmp
        je exit
    
        mov %sp, %si
        mov $cmd_pm, %di    # "pm (protected mode)" command
        call strcmp
        je pm
    
        mov $badcommand, %si # unknown command
        call print_string
        jmp loop_start
    
    helloworld:
        mov $msg_helloworld, %si
        call print_string
        jmp loop_start
    
    help:
        mov $msg_help, %si
        call print_string
        jmp loop_start
    
    exit:
        mov $msg_exit, %si
        call print_string
        xorw %ax, %ax
        int $0x16          # Wait for keystroke
        jmp $0xffff, $0x0000 # Reboot
    
    pm:
        call clrscr
        mov $msg_pm, %si
        call print_string
        call Waitingloop
    
        cli               # clear interrupts
    
        lgdt gdtr         # load GDT via GDTR
    
    # we actually only need to do this ONCE, but for now it doesn't hurt to do this more often when
    # switching between RM and PM
        inb $0x92, %al       # switch A20 gate via fast A20 port 92
        cmpb $0xFF, %al     # if it reads 0xFF, nothing's implemented on this port
        je 1f
    
        orb $2, %al         # set A20_Gate_Bit (bit 1)
        andb $0xFE, %al     # clear INIT_NOW bit (don't reset pc...)
        outb %al, $0x92
        jmp 2f
    1:         # no fast shortcut -> use the slow kbc...
        call empty_8042  
    
        movb 0xD1, %al      # kbc command: write to output port
        outb %al, $0x64
        call empty_8042
    
        movb $0xDF, %al     # writing this to kbc output port enables A20
        outb %al, $0x60
        call empty_8042
    2:
        mov %cr0, %eax      # switch-over to Protected Mode
        orl $1, %eax        # set bit 0 of CR0 register
        movl %eax, %cr0
    
    jump_to_protected_mode:
        ljmp $8, $ProtectedMode
    
    #########
    # Calls #
    #########
    
    empty_8042:
        call Waitingloop
        inb $0x64, %al
        cmpb $0xFF, %al     # ... no real kbc at all?
        je 1f
    
        testb $1, %al       # something in input buffer?
        jz 2f
        call Waitingloop
        inb $0x60, %al       # yes: read buffer
        jmp empty_8042      # and try again
    2:
        testb $2, %al       # command buffer empty?
        jnz empty_8042      # no: we can't send anything new till it's empty
    1:
        ret
    
    print_string:
        movb $0x0E, %ah
    1:
        lodsb               # grab a byte from SI
        testb %al, %al      # test AL
        jz 2f               # if the result is zero, get out
        int $0x10           # otherwise, print out the character!
        jmp 1b
    2:
        ret
    
    get_string:
        xorw %cx, %cx
    1:
        xorw %ax, %ax
        int $0x16           # wait for keypress
        cmpb $8, %al        # backspace pressed?
        je 2f               # yes, handle it
        cmpb $13, %al       # enter pressed?
        je 3f               # yes, we're done
        cmpb $63, %cl       # 63 chars inputted?
        je 1b               # yes, only let in backspace and enter
        movb $0x0E, %ah
        int $0x10           # print out character
        stosb               # put character in buffer
        inc %cx
        jmp 1b
    
    2:
        jcxz 1b             # zero? (start of the string) if yes, ignore the key
        dec %di
        movb $0, (%di)      # delete character
        dec %cx             # decrement counter as well
        movb $0x0E, %ah
        int $0x10           # backspace on the screen
        movb $32, %al
        int $0x10           # blank character out
        movb $8, %al
        int $0x10           # backspace again
        jmp 1b              # go to the main loop
    
    3:
        movb $0, (%di)      # null terminator
        movw $0x0E0D, %ax
        int $0x10
        movb $0x0A, %al
        int $0x10           # newline
        ret
    
    strcmp:
    1:
        movb (%si), %al       # grab a byte from SI
        cmpb (%di), %al       # are SI and DI equal?
        jne 2f          # no, we're done.
    
        testb %al, %al        # zero?
        jz 2f           # yes, we're done.
    
        inc %di             # increment DI
        inc %si             # increment SI
        jmp 1b             # loop!
    
    2:   
        ret
    
    clrscr:
        movw $0x0600, %ax
        xorw %cx, %cx
        mov $0x174F, %dx
        mov $0x07, %bh
        int $0x10
        ret
    
    ##################
    # Protected Mode #
    ##################
    
    .section .text
    .code32
    
    .p2align 4
    
    ProtectedMode:
        movw $0x10, %ax
        mov %ax, %ds      # data descriptor --> data, stack and extra segment
        mov %ax, %ss
        mov %ax, %es
        xorl %eax, %eax    # null desriptor --> FS and GS
        mov %ax, %fs
        mov %ax, %gs
        mov $0x200000, %esp # set stack below 2 MB limit
    
        call clrscr_32
        movb $0x01, %ah
    1:
        call Waitingloop
        incb %ah
        andb $0x0F, %ah
        mov $msg_pm2, %esi   # 'OS currently uses Protected Mode.'
        call PutStr_32
        cmpl $(25 * 80 * 2 + 0xB8000), PutStr_Ptr
        jb 1b
        movl $0xB8000, PutStr_Ptr   # text pointer wrap-arround
    
      call _kernel_main # ->-> C-Kernel
      jmp . 
    
    Waitingloop:                   
        mov $0x9FFFF, %ebx
    1:
        dec %ebx     
        jnz 1b
        ret         
    
    PutStr_32:     
        movl PutStr_Ptr, %edi
    1:
        lodsb
        testb %al, %al
        jz 2f
        stosw
        jmp 1b
    2:
        movl %edi, PutStr_Ptr
        ret 
    
    clrscr_32:
        movl $0xb8000, %edi
        movl %edi, PutStr_Ptr
        movl $1000, %ecx
        movl $0x07200720, %eax
        rep stosl
        ret
    
    PutStr_Ptr: .long 0xb8000
    
    # You load the address you want to output to in [PutStr_Ptr],
    # the address of the string (has to be NUL terminated)
    # you want to print in esi and the attributes in ah
    # lodsb loads one byte from esi into al, then increments esi,
    # then it checks for a NUL terminator,
    # then it moves the char into the write position in video memory,
    # then increments edi and writes the attributes,
    # loops until it finds NUL pointer at which point it breaks ...
    
    ###########
    # Strings #
    ###########
    
    welcome: .asciz "HenkesSoft 0.05 (test version from Apr 03, 2009)\n\r"
    msg_helloworld: .asciz "Hello World!\n\r"
    badcommand: .asciz "Command unknown.\n\r"
    prompt: .asciz ">"
    cmd_hi: .asciz "hi"
    cmd_help: .asciz "help"
    cmd_questionmark: .asciz "?"
    cmd_exit: .asciz "exit"
    cmd_pm: .asciz "pm"
    msg_help: .asciz "Commands: hi, help, ?, pm, exit\n\r"
    msg_exit: .asciz "Reboot starts now. Enter keystroke, please.\n\r"
    msg_pm: .asciz "Switch-over to Protected Mode.\n\r"
    msg_pm2: .asciz "OS currently uses Protected Mode.  "
    
    ############
    # Includes #
    ############
    
    ###################################
    ## Global Descriptor Table (GDT) ##
    ###################################
    
    NULL_Desc:
    .long 0
    .long 0
    
    CODE_Desc:
    .word 0xFFFF    # segment length  bits 0-15 ("limit")    
    .word 0         # segment base    byte 0,1      
    .byte 0         # segment base    byte 2    
    .byte 0b10011010    # access rights
    .byte 0b11001111    # bit 7-4: 4 flag bits:  granularity, default operation size bit, 2 bits available for OS
                        # bit 3-0: segment length bits 16-19 
    .byte 0             # segment base    byte 3    
    
    DATA_Desc:
    .word 0xFFFF        # segment length  bits 0-15
    .word 0             # segment base    byte 0,1
    .byte 0             # segment base    byte 2
    .byte 0b10010010    # access rights
    .byte 0b11001111    # bit 7-4: 4 flag bits:  granularity, big bit (0=USE16-Segm., 1=USE32-Segm.), 2 bits avail.
                        # bit 3-0: segment length bits 16-19
    .byte 0             # segment base    byte 3       
    
    gdtr:
    Limit: .word 24     # length of GDT
    Base: .long NULL_Desc    # base of GDT ( linear address: RM Offset + Seg<<4 )
    

    Die Datei isr.s:

    # Interrupt Service Routine isr0 ... isr32  
    .global _isr0
    .global _isr1
    .global _isr2
    .global _isr3
    .global _isr4
    .global _isr5
    .global _isr6
    .global _isr7
    .global _isr8
    .global _isr9
    .global _isr10
    .global _isr11
    .global _isr12
    .global _isr13
    .global _isr14
    .global _isr15
    .global _isr16
    .global _isr17
    .global _isr18
    .global _isr19
    .global _isr20
    .global _isr21
    .global _isr22
    .global _isr23
    .global _isr24
    .global _isr25
    .global _isr26
    .global _isr27
    .global _isr28
    .global _isr29
    .global _isr30
    .global _isr31
    
    .global _irq0
    .global _irq1
    .global _irq2
    .global _irq3
    .global _irq4
    .global _irq5
    .global _irq6
    .global _irq7
    .global _irq8
    .global _irq9
    .global _irq10
    .global _irq11
    .global _irq12
    .global _irq13
    .global _irq14
    .global _irq15
    
    .section .text
    
    #  0: Divide By Zero Exception
    _isr0:
        cli
        pushl $0
        pushl $0
        jmp isr_common_stub
    
    #  1: Debug Exception
    _isr1:
        cli
        pushl $0
        pushl $1
        jmp isr_common_stub
    
    #  2: Non Maskable Interrupt Exception
    _isr2:
        cli
        pushl $0
        pushl $2
        jmp isr_common_stub
    
    #  3: Int 3 Exception
    _isr3:
        cli
        pushl $0
        pushl $3
        jmp isr_common_stub
    
    #  4: INTO Exception
    _isr4:
        cli
        pushl $0
        pushl $4
        jmp isr_common_stub
    
    #  5: Out of Bounds Exception
    _isr5:
        cli
        pushl $0
        pushl $5
        jmp isr_common_stub
    
    #  6: Invalid Opcode Exception
    _isr6:
        cli
        pushl $0
        pushl $6
        jmp isr_common_stub
    
    #  7: Coprocessor Not Available Exception
    _isr7:
        cli
        pushl $0
        pushl $7
        jmp isr_common_stub
    
    #  8: Double Fault Exception (With Error Code!)
    _isr8:
        cli
        pushl $8
        jmp isr_common_stub
    
    #  9: Coprocessor Segment Overrun Exception
    _isr9:
        cli
        pushl $0
        pushl $9
        jmp isr_common_stub
    
    # 10: Bad TSS Exception (With Error Code!)
    _isr10:
        cli
        pushl $10
        jmp isr_common_stub
    
    # 11: Segment Not Present Exception (With Error Code!)
    _isr11:
        cli
        pushl $11
        jmp isr_common_stub
    
    # 12: Stack Fault Exception (With Error Code!)
    _isr12:
        cli
        pushl $12
        jmp isr_common_stub
    
    # 13: General Protection Fault Exception (With Error Code!)
    _isr13:
        cli
        pushl $13
        jmp isr_common_stub
    
    # 14: Page Fault Exception (With Error Code!)
    _isr14:
        cli
        pushl $14
        jmp isr_common_stub
    
    # 15: Reserved Exception
    _isr15:
        cli
        pushl $0
        pushl $15
        jmp isr_common_stub
    
    # 16: Floating Point Exception
    _isr16:
        cli
        pushl $0
        pushl $16
        jmp isr_common_stub
    
    # 17: Alignment Check Exception
    _isr17:
        cli
        pushl $0
        pushl $17
        jmp isr_common_stub
    
    # 18: Machine Check Exception
    _isr18:
        cli
        pushl $0
        pushl $18
        jmp isr_common_stub
    
    # 19: Reserved
    _isr19:
        cli
        pushl $0
        pushl $19
        jmp isr_common_stub
    
    # 20: Reserved
    _isr20:
        cli
        pushl $0
        pushl $20
        jmp isr_common_stub
    
    # 21: Reserved
    _isr21:
        cli
        pushl $0
        pushl $21
        jmp isr_common_stub
    
    # 22: Reserved
    _isr22:
        cli
        pushl $0
        pushl $22
        jmp isr_common_stub
    
    # 23: Reserved
    _isr23:
        cli
        pushl $0
        pushl $23
        jmp isr_common_stub
    
    # 24: Reserved
    _isr24:
        cli
        pushl $0
        pushl $24
        jmp isr_common_stub
    
    # 25: Reserved
    _isr25:
        cli
        pushl $0
        pushl $25
        jmp isr_common_stub
    
    # 26: Reserved
    _isr26:
        cli
        pushl $0
        pushl $26
        jmp isr_common_stub
    
    # 27: Reserved
    _isr27:
        cli
        pushl $0
        pushl $27
        jmp isr_common_stub
    
    # 28: Reserved
    _isr28:
        cli
        pushl $0
        pushl $28
        jmp isr_common_stub
    
    # 29: Reserved
    _isr29:
        cli
        pushl $0
        pushl $29
        jmp isr_common_stub
    
    # 30: Reserved
    _isr30:
        cli
        pushl $0
        pushl $30
        jmp isr_common_stub
    
    # 31: Reserved
    _isr31:
        cli
        pushl $0
        pushl $31
        jmp isr_common_stub
    
    # Common ISR stub saves processor state, sets up for kernel mode segments, calls the C-level fault handler,
    # and finally restores the stack frame.
    isr_common_stub:
        pusha
        push %ds
        push %es
        push %fs
        push %gs
        mov $0x10, %ax
        mov %ax, %ds
        mov %ax, %es
        mov %ax, %fs
        mov %ax, %gs
        mov %esp, %eax
        push %eax
        mov $_fault_handler, %eax
        call *%eax
        pop %eax
        pop %gs
        pop %fs
        pop %es
        pop %ds
        popa
        add $8, %esp
        iret
    
    # 32: IRQ0
    _irq0:
        cli
        pushl $0
        pushl $32
        jmp irq_common_stub
    
    # 33: IRQ1
    _irq1:
        cli
        pushl $0
        pushl $33
        jmp irq_common_stub
    
    # 34: IRQ2
    _irq2:
        cli
        pushl $0
        pushl $34
        jmp irq_common_stub
    
    # 35: IRQ3
    _irq3:
        cli
        pushl $0
        pushl $35
        jmp irq_common_stub
    
    # 36: IRQ4
    _irq4:
        cli
        pushl $0
        pushl $36
        jmp irq_common_stub
    
    # 37: IRQ5
    _irq5:
        cli
        pushl $0
        pushl $37
        jmp irq_common_stub
    
    # 38: IRQ6
    _irq6:
        cli
        pushl $0
        pushl $38
        jmp irq_common_stub
    
    # 39: IRQ7
    _irq7:
        cli
        pushl $0
        pushl $39
        jmp irq_common_stub
    
    # 40: IRQ8
    _irq8:
        cli
        pushl $0
        pushl $40
        jmp irq_common_stub
    
    # 41: IRQ9
    _irq9:
        cli
        pushl $0
        pushl $41
        jmp irq_common_stub
    
    # 42: IRQ10
    _irq10:
        cli
        pushl $0
        pushl $42
        jmp irq_common_stub
    
    # 43: IRQ11
    _irq11:
        cli
        pushl $0
        pushl $43
        jmp irq_common_stub
    
    # 44: IRQ12
    _irq12:
        cli
        pushl $0
        pushl $44
        jmp irq_common_stub
    
    # 45: IRQ13
    _irq13:
        cli
        pushl $0
        pushl $45
        jmp irq_common_stub
    
    # 46: IRQ14
    _irq14:
        cli
        pushl $0
        pushl $46
        jmp irq_common_stub
    
    # 47: IRQ15
    _irq15:
        cli
        pushl $0
        pushl $47
        jmp irq_common_stub
    
    irq_common_stub:
        pusha
        push %ds
        push %es
        push %fs
        push %gs
    
        mov $0x10, %ax
        mov %ax, %ds
        mov %ax, %es
        mov %ax, %fs
        mov %ax, %gs
        mov %esp, %eax
    
        push %eax
        mov $_irq_handler, %eax
        call *%eax
        pop %eax
    
        pop %gs
        pop %fs
        pop %es
        pop %ds
        popa
        add $8, %esp
        iret
    

    Nicht zu lange draufgucken, schadet den Augen 😃



  • Erhard Henkes schrieb:

    Das einzige Programm, das nicht Teil von DJGPP und mingw ist, ist dd. Ich weiss nicht, wie man unter WinXP eine fest definierte Anzahl von Bytes aus einer Datei in eine andere kopieren kann.

    Nicht-Linux-User kennen dd nicht, verwenden partcopy (das ist, was Du anstelle dd suchst) oder rawwrite.
    Ich bin da aber flexibel, nur möchte ich alles auf MS Windows ermöglichen, was ja bisher keinerlei Problem ist.

    Ich habe grade geguckt, woher ich dd auf meinem System habe... aus dem Verzeichnis C:\Compiler\WinAVR-20081205\utils\bin. Nicht schön. Benutze ein Programm und weiss überhaupt nicht, woher ich es habe. Das kommt davon, wenn man die PATH Variable einfach mal so modifiziert...

    Erhard Henkes schrieb:

    Ich möchte auch den Hinweis auf gvim (am Anfang fand ich das nicht uninteressant , weil OSDEV bezüglich des Flairs eher archaische Instrumente benötigt. 😃 ) verwerfen, weil notepad++ besser aussieht und weniger störrisch ist. Seht ihr das ähnlich? 😕

    Ich benutze in letzter Zeit ausschliesslich gvim... 🙂



  • Nobuo T schrieb:

    +fricky schrieb:

    Nobuo T schrieb:

    Kann GAS nicht inzwischen auch Intel-Syntax? Das wuerde die Sache sicher vereinfachen.

    echt, ne? diese bescheuerte at&t-syntax würde mich auch völlig nerven. welcher gehirnamputierte hat sich das bloss ausgedacht?
    🙂

    Total! 😃 👍
    Wahrscheinlich irgendein weltfremder, idealistischer, langhaariger Linux-Frickler mit Strick-Polunder und Taxischein. 🕶

    Ich glaube, AT&T Syntax ist älter als Linux und Intel und GNU zusammen. Ich sehe es so, dass allein aus der Tatsache, dass diese Syntax noch nicht "ausgestorben" ist und eine so lange Periode überdauert hat, muss etwas dahinter stecken. Ich hatte mich am Anfang auch wegen % und $ unbehaglich gefühlt, aber jetzt, sooo schlimm ist das nicht und die Syntax finde ich durchdachter und konsequenter in jeder Hinsicht als jede andere. Wenn wir hier in diesem Thread zurückschauen, wieviele Probleme gab es mit jmp und wieviel Ungewissheit, zumindest bei mir, ob jmp word oder jmp dword, nur weil nasm sowohl das eine als auch das andere erlaubt...


  • Mod

    @abc.w: Danke für die Übersetzung von Intel nach AT&T und für das DJGPP / mingw makefile. Es sollte nicht von zu vielen Kleinigkeiten und/oder Geschmacksachen abhängen, ob jemand den Zugang zu OSDEV findet. 🙂


Anmelden zum Antworten