Ich habe mir die OS-Seite von Erhard Henkes angeshen...



  • und bin positiv überrascht. 🙂

    Ich teste das Betriebssystem unter Virtual PC und habe mir eine vfd (Virtual Disk)-Datei erstellt. Dann habe ich die boot.bin und die kernel.bin in die Datei myos.img anhand des Cmd-Befehls "copy" kopiert. Die Datei myos.img habe ich dann per RawDisk auf die virtuelle Diskette geschrieben.

    Als ich das Betriebssystem dann testen wollte, hing sich der Computer stets auf... Selbst der Bootloader wurde nicht geladen.

    Woran könnte das liegen? Bei den Tutorials davor - als noch Bootloader und Kernel in einer asm-Datei lagen - hatte ich keine Probleme. Da lief noch das Betriebssystem.



  • Kommt denn irgendeine (Fehler-)Meldung?

    Ansonsten würde ich es einfach mal in der von ehenkes geschilderten Art und Weise versuchen (also keine vfd-Datei), und diese in VPC laden.



  • Eine Fehlermeldung erscheint nicht. Das Betriebssystem hängt sich lediglich dabei auf und es erscheint überhaupt keine Meldung. Wie meinst du das ohne vfd-Datei? Ein Diskettenlaufwerk habe ich jetzt nicht.



  • Zeig mal deinen Code und beschreib genau wie du das zusammenkopierst. Vielleicht ist da irgendwo ein kleiner Fehler.



  • ;boot.asm
    
    org 0x7C00 ; set up start address 
    
        ; setup a stack 
        mov ax, 0x9000  ; address of the stack SS:SP
        mov ss, ax      ; SS = 0x9000 (stack segment)
        xor sp, sp      ; SP = 0x0000 (stack pointer)
    
        ; start
        mov [bootdrive], dl ; boot drive from DL
        call load_kernel    ; load kernel
    
        ; jump to kernel
        jmp 0x1000:0x0000   ; address of kernel
    
        bootdrive db 0      ; boot drive
        loadmsg db "bootloader message: loading kernel ...",13,10,0
    
        ; print string
    print_string:
        lodsb             ; grab a byte from SI
        or al, al         ; NUL?
        jz .done          ; if the result is zero, get out
        mov ah, 0x0E
        int 0x10          ; otherwise, print out the character!
        jmp print_string
     .done:
        ret
    
        ; read kernel from floppy disk
    load_kernel:
        mov dl,[bootdrive] ; select boot drive 
        xor ax, ax         ; mov ax, 0  => function "reset"
        int 0x13          
        jc load_kernel     ; trouble? try again
    
    load_kernel1:
        mov ax, 0x1000    
        mov es, ax         ; ES:BX = 0x10000
        xor bx, bx         ; mov bx, 0
    
        ; set parameters for reading function
        ; 8-Bit-wise for better overview
        mov dl,[bootdrive] ; select boot drive
        mov al,10          ; read 10 sectors
        mov ch, 0          ; cylinder = 0
        mov cl, 2          ; sector   = 2
        mov dh, 0          ; head     = 0
        mov ah, 2          ; function "read"  
        int 0x13          
        jc load_kernel1    ; trouble? try again
    
              ; show loading message
        mov si,loadmsg
        call print_string 
        ret
    
        times 510-($-$$) hlt
        db 0x55
        db 0xAA
    
    ;kernel.asm
    
    mov ax, 0x1000  ; set up segments
      mov ds, ax
      mov es, ax
    
      mov si, welcome
      call print_string
    
    loop:
      mov si, prompt
      call print_string
    
      mov di, buffer
      call get_string
    
      mov si, buffer
      cmp byte [si], 0  ; blank line?
      je loop           ; yes, ignore it
    
      mov di, cmd_hi    ; "hi" command
      call strcmp
      jz .helloworld
    
      mov si, buffer
      mov di, cmd_help  ; "help" command
      call strcmp
      jz .help
    
      mov si, buffer
      mov di, cmd_questionmark  ; "?" command
      call strcmp
      jz .help
    
      mov si, buffer
      mov di, cmd_exit  ; "exit" command
      call strcmp
      jz .exit
    
      mov si,badcommand
      call print_string
      jmp loop 
    
    .helloworld:
      mov si, msg_helloworld
      call print_string
    
      jmp loop
    
    .help:
      mov si, msg_help
      call print_string
    
      jmp loop
    
    .exit:
      mov si, msg_exit
      call print_string
      jmp 0xffff:0x0000  ; Reboot
    
    welcome db 'HenkesSoft 0.01 (version from Mar 14, 2009)', 13, 10, 0
    msg_helloworld db 'Hello World!', 13, 10, 0
    badcommand db 'Command unknown.', 13, 10, 0
    prompt db '>', 0
    cmd_hi db 'hi', 0
    cmd_help db 'help', 0
    cmd_questionmark db '?', 0
    cmd_exit db 'exit', 0
    msg_help db 'Commands: hi, help, ?, exit', 13, 10, 0
    msg_exit db 'Reboot starts now.', 13, 10, 0
    
    buffer times 32 db 0
    
    ; ================
    ; calls start here
    ; ================
    
    print_string:
      lodsb        ; grab a byte from SI
    
      or al, al    ; logical or AL by itself
      jz .done     ; if the result is zero, get out
    
      mov ah, 0x0E
      int 0x10       ; otherwise, print out the character!
    
      jmp print_string
    
    .done:
      ret
    
    get_string:
      xor cl, cl
    
    .loop:
      xor ah, ah    ; mov ah, 0
      int 0x16      ; wait for keypress
    
      cmp al, 8     ; backspace pressed?
      je .backspace ; yes, handle it
    
      cmp al, 13    ; enter pressed?
      je .done      ; yes, we're done
    
      cmp cl, 31    ; 31 chars inputted?
      je .loop      ; yes, only let in backspace and enter
    
      mov ah, 0x0E
      int 0x10      ; print out character
    
      stosb  ; put character in buffer
      inc cl
      jmp .loop
    
    .backspace:
      or cl, cl     ; zero? (start of the string)
      jz .loop      ; if yes, ignore the key
    
      dec di
      mov byte [di], 0  ; delete character
      dec cl        ; decrement counter as well
    
      mov ax, 0x0E08
      int 0x10      ; backspace on the screen
    
      mov al, ' '
      int 0x10      ; blank character out
    
      mov al, 8
      int 0x10      ; backspace again
    
      jmp .loop     ; go to the main loop
    
    .done:
      mov al, 0     ; null terminator
      stosb
    
      mov ax, 0x0E0D
      int 0x10
      mov al, 0x0A
      int 0x10      ; newline
    
      ret
    
    strcmp:
    .loop:
      mov al, [si]   ; fetch a byte from SI
      cmp al, [di]   ; are SI and DI equal?
      jne .done      ; if no, we're done.
    
      or al, al      ; zero?
      jz .done       ; if yes, we're done.
    
      inc di         ; increment DI
      inc si         ; increment SI
      jmp .loop      ; goto .loop
    
    .done:    
      stc            
      ret
    


  • florida schrieb:

    Eine Fehlermeldung erscheint nicht. Das Betriebssystem hängt sich lediglich dabei auf und es erscheint überhaupt keine Meldung. Wie meinst du das ohne vfd-Datei? Ein Diskettenlaufwerk habe ich jetzt nicht.

    Ich weiß nicht, wie ehenkes das macht, aber ich nehme an, er hat irgendwo mal ein Diskettenabbild erstellt (roh, kein vfd).


  • Mod

    http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId427538

    nasm boot.asm   -f bin -o boot.bin
    nasm kernel.asm -f bin -o kernel.bin
    cmd /c copy /b boot.bin + kernel.bin MyOS.bin
    partcopy MyOS.bin 0 400 -f0
    
    1. Schau dir MyOS.bin mit dem Hex-Editor an, ob alles dabei ist.
    2. Achte darauf, dass die Daten nach dem Kopieren wirklich im Bootsektor anfangen (da liegt offensichtlich dein Fehler)

    Probiere es mal mit http://www.chrysocome.net/dd anstelle rawwrite (Das verwende ich nicht mehr)

    So kopiere ich z.B. das aktuelle Image auf eine Floppy zum Booten:

    dd if=FloppyImage.img of=\\.\A:
    

    Vielleicht kann man das auf die virtuelle Floppy übertragen.

    Ansonsten verwende qemu:

    qemu.exe -fda MyOS.bin
    

    ... oder bochs: (Bochs config-Datei)

    floppya: 1_44=MyOS.bin, status=inserted
    

    oder

    floppya: 1_44=G:\OSDev\Test\MyOS.bin, status=inserted
    

    Umkopieren ist auf jeden Fall falsch. Dieses Binärformat ist bereits Rohformat, also die binären Daten, Byte für Byte, wie sie auf den ersten beiden Sektoren (jeweils 512 == 0x200 Byte) auftauchen sollen.

    Geübter Umgang mit den Tools ist bei OSDev wichtig. Probiere also bitte die ganze Kiste durch. Es gibt auch noch VBox und VMWare Player.



  • Bei Qemu kommt jetzt "Lade Kernel..." und dann hängt sich gleich das OS auf.

    ... Hab den Fehler gefunden ...

    ;kernel.asm
    times 510-($-$$) hlt  ; as alternative to db 0
    


  • Könnte man den Kernel anstatt mit C vielleicht auch in Pascal schreiben?



  • Ja, kann man. Du kannst das hier als Ansatz dafür nehmen. Alles weitere läuft so ähnlich wie in C, nur eben mit anderer Syntax. Die Pascal-Runtime steht dir erstmal nicht zur Verfügung - wenn der Compiler meckert, dass er irgendeine Funktion aus der Runtime brauch, aber nicht findet, dann musst du in der system.pas die entsprechenden Funktionen implementieren.


  • Mod

    Könnte man den Kernel anstatt mit C vielleicht auch in Pascal schreiben?

    C wurde extra für die Erstellung von Betriebssystemen geschaffen, soweit ich weiß. Pascal ist sicher auch möglich, aber man sondert sich damit ab, genau wie mit D. Dann würde ich eher C++ anpeilen.



  • Pascal und C nimmt sich nicht viel. Da bist du unter Umständen mit C++ von den Konzepten her weiter weg. Was natürlich wahr ist, ist, dass so gut wie alle Beispiele in C geschrieben sind. Lesen sollte man es also schon können.



  • taljeth schrieb:

    Pascal und C nimmt sich nicht viel. Da bist du unter Umständen mit C++ von den Konzepten her weiter weg. Was natürlich wahr ist, ist, dass so gut wie alle Beispiele in C geschrieben sind. Lesen sollte man es also schon können.

    Wer C++ kann, kann C lesen. Also wäre C++ keine schlechte Basis für einen OS-Entwickler. Wobei ich selbst sagen muss, dass ich einige Kniffe in C erst durch die Anwendung in PrettyOS gelernt habe, obwohl ich vorher schon halbwegs gut C++ konnte.



  • Ist die Menge derjenigen, die C++ wirklich beherrschen nicht so überschaubar, dass die Aussage irrelevant ist? 😉

    Ich habe schon genug Leute gesehen, die von sich behauptet haben, C++ zu können und dann an den C-Beispielen grandios gescheitert sind. Die ideale Programmiersprache für OS-Dev ist diejenige, die man in- und auswendig kennt. Wenn du mit Nebensächlichkeiten wie der Sprache oder dem Compiler kämpfen musst, wird ein sowieso schon schwieriges Projekt wie ein OS nochmal deutlich schwieriger. (Andererseits darf man das auch nicht zu sehr überbewerten: tyndur war mein erstes ernsthaftes Projekt in C)


  • Mod

    Wichtig ist, dass man am Ball und neugierig bleibt. Entweder hat man diese innere Kraft oder man hat sie nicht. Hat man sie, geht es immer weiter, und es wird nicht wirklich langweilig. 🙂



  • Erhard ich glaube ich habe einen Fehler in deinem Tutorial entdeckt:D:-P.
    Bei Seite 1 wo es um die outportb und set_cursor Funktion geht, steht, man würde an die Ports 0x0E und 0x0F Befehle senden, aber das stimmt doch gar nicht. Man sendet doch bei VGA an den Port 0x3D4 den Befehl 0x0E um dann an 0x3D5 das High Byte zu senden und dann 0x0F an 0x3D4 um dan an 0x3D5 das Low byte zu senden oder nicht? Zudem sind glaube ich auch bei der Funktion outportb die Parameter port und value vertauscht. müsste port nicht value sein und value port 😉 😃 ? Oder ich verstehe das gerade komplett falsch?
    Eine frage habe ich auch noch, was genau passiert durch den rechtsschift um 8 und dann dem UND mit 0xFF beim High byte und dem UND mit 0xFF bei dem Low Byte?

    Lg freeG


  • Mod

    kannst du bitte den code genau darstellen? IST und das, was du für richtig hältst.



  • Erhard Henkes schrieb:

    kannst du bitte den code genau darstellen? IST und das, was du für richtig hältst.

    Sorry, mein Fehler, hatte ganz vergessen, dass ja AT&T Syntax verwendet wird, bzw dass dort eben die Operanden im Vergleich zur Intel Syntax vertauscht sind. Von daher stimmt alles;-), hier trotzdem mal der Code den ich meinte. Aber wie gesagt, passt alles 😃 🙂

    inline void outportb(unsigned int port,unsigned char value)
    {
        asm volatile ("outb %%al,%%dx"::"d" (port), "a" (value));
    };
    
    void update_cursor(int row, int col)
    {
        unsigned short position = (row*80) + col;
    
        // cursor HIGH port to vga INDEX register
        outportb(0x3D4, 0x0E);
        outportb(0x3D5, (unsigned char)((position>>8)&0xFF));
    
        // cursor LOW port to vga INDEX register
        outportb(0x3D4, 0x0F);
        outportb(0x3D5, (unsigned char)(position&0xFF));
    };
    

    Lg freeG


  • Mod

    Sorry, mein Fehler, hatte ganz vergessen, dass ja AT&T Syntax verwendet wird

    Na, dann ist doch alles bestens. 🙂



  • Jap, allerdings ist mir was anderes aufgefallen. Man muss doch als Limit der GDT fürs GDT-Register die Größe der GDT in Bytes-1 angeben. In deinem Tutorial wird allerdings einfach nur 24 Byte,also 3 Einträge verwendet und nicht 23 Byte. Wieso hast du das minus 1 weggelassen?

    Lg freeG


Anmelden zum Antworten