Eigener Bootloader klappt noch nicht perfekt
-
Für den über 63 Sektoren (32256 Bytes) hinaus wachsenden Kernel von PrettyOS ... http://www.henkessoft.de/OS_Dev/OS_Dev3.htm und
http://www.c-plusplus.net/forum/viewtopic-var-t-is-236354-and-start-is-540.html
... benötigte ich einen Bootloader, der auch große Kernel nachladen kann.Folgende boot.asm funktioniert soweit, dennoch bitte ich um weitere Verbesserungsvorschläge, um GRUB noch eine Weile zu entgehen (passt einfach nicht zu MS Windows ).
Hauptproblem: Laufwerkslampe erlischt nicht, hört also nicht auf zu laden (oder was auch immer?).
Frage: Liegt der Stack bei 0x7000 brauchbar (er wurde dorthin verlagert, damit man ggf. den Kernel auch bei 0x8000 nachladen kann).
org 0x7C00 ; set up start address of bootloader ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; setup a stack and segment regs ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; xor ax, ax mov ds, ax mov es, ax mov ax, 0x7000 ; stack address mov ss, ax xor sp, sp ; set stackpointer to 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; read kernel from floppy disk ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; read_kernel: mov si,loadmsg call print_string mov [bootdrive], dl ; boot drive stored by BIOS in DL. ; di: number of sectors, bx: segment, ch, dh, cl: cylinder, head, sector mov bx, 100 mov di, bx mov bx, 0x1000 ; kernel start address (cf. linker script) mov ch, 0 mov dh, 0 mov cl, 2 call read_sectors ;;;;;;;;;;;;; ; A20-Gate ; ;;;;;;;;;;;;; switch_a20: in al, 0x92 ; switch A20 gate via fast A20 port 92 cmp al, 0xff ; if it reads 0xFF, nothing's implemented on this port je .no_fast_A20 or al, 2 ; set A20_Gate_Bit (bit 1) and al, ~1 ; clear INIT_NOW bit (don't reset pc...) out 0x92, al jmp .A20_done .no_fast_A20: ; no fast shortcut -> use the slow kbc... call empty_8042 mov al, 0xD1 ; kbc command: write to output port out 0x64, al call empty_8042 mov al, 0xDF ; writing this to kbc output port enables A20 out 0x60, al call empty_8042 .A20_done: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Load GDT, switch to PM, and jump to kernel ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; load_gdt: cli ; clear interrupts lgdt [gdtr] ; load GDT via GDTR (defined in file "gtd.inc") switch_to_PM: mov eax, cr0 ; switch-over to Protected Mode or eax, 1 ; set bit 0 of CR0 register mov cr0, eax ; jmp_to_PM: jmp dword 08:0x00010000 ; this is a 16-bit-FAR-Jmp, but CS is loaded with "index" 8 in GDT ; hence, the code will be interpreted as 32 bit from here on ; the address can be found in the linker script ;;;;;;;;; ; Calls ; ;;;;;;;;; print_string: mov ah, 0x0E ; VGA BIOS fnct. 0x0E: teletype .loop: lodsb ; grab a byte from SI test al, al ; NUL? jz .done ; if the result is zero, get out int 0x10 ; otherwise, print out the character! jmp .loop .done: ret empty_8042: call Waitingloop in al, 0x64 cmp al, 0xff ; ... no real kbc at all? je .done test al, 1 ; something in input buffer? jz .no_output call Waitingloop in al, 0x60 ; yes: read buffer jmp empty_8042 ; and try again .no_output: test al, 2 ; command buffer empty? jnz empty_8042 ; no: we can't send anything new till it's empty .done: ret Waitingloop: mov cx,0xFFFF .loop_start: dec cx jnz .loop_start ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; read sectors from floppy disk to buffer ES:BX in memory ; ; ; ; input: ; ; di - number of sectors ; ; bx - segment ; ; ch, dh, cl - cylinder, head, sector ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; read_sectors: .reset_floppy: xor ax, ax ; mov ax, 0 => function "reset" int 0x13 jc .reset_floppy ; trouble? try again .next: mov si, progressmsg ; show progress call print_string mov es, bx xor bx, bx .again: mov dl, [bootdrive] mov ax, 0x0201 int 0x13 jc .again inc cl cmp cl, 19 jl .loop mov cl, 1 inc dh cmp dh, 2 jl .loop mov dh, 0 inc ch cmp ch, 80 jae .error .loop: mov bx, es add bx, 512/16 sub di, 1 jnz .next .done: ret .error: mov si, errormsg ; show error message call print_string .end: jmp .end ;;;;;;;;;;;; ; Includes ; ;;;;;;;;;;;; %include "gdt.inc" ;;;;;;;; ; data ; ;;;;;;;; bootdrive db 0 loadmsg db "bootloader message: loading kernel ...",13,10,0 errormsg db "bootloader message: sector read error ...",13,10,0 progressmsg db "*",0 times 510-($-$$) hlt db 0x55 db 0xAA
-
Die Lösung für das Ausschalten des Motors und Lichtes habe ich inzwischen gefunden:
http://lowlevel.brainsware.org/forum/index.php?PHPSESSID=e0d117469cb94ea64b66af28231d57fc&action=printpage;topic=983.0.done: push dx mov dx,0x3F2 ; switch off floppy disk motor mov al,0x0C out dx,al pop dx ret
Gibt es noch weitere Ideen zur Optimierung?
-
Das wirklich Schwierige bei einem eigenen Bootloader ist, dass man bei einem Fehler beim Ausführen des OS nicht sicher sein kann, dass es am OS-Code liegt, denn es kann auch an der Diskette selbst bzw. am Schreib- oder Lesevorgang liegen.
Welches Schreibprogramm würdet ihr - gesteuert aus makefile - empfehlen? Es sollte verifizieren, ob die Daten komplett auf den Sektoren angekommen sind.
-
Hast du den Start eigentlich mal mit einem USB-Stick versucht? Vielleicht gibt das einige Probleme weniger und es gibt ja sowieso kaum noch Leute, die Diskettenlaufwerke an ihrem Heim-PC haben.
-
Hast du den Start eigentlich mal mit einem USB-Stick versucht?
Nein, sollte ich mir wirklich mal anschauen, denn der USB-Stick ist heute die "Diskette".
-
Da ich dem neuen Bootloader noch nicht "traue" und es bei einigen PC zu Problemen mit PrettyOS kommt, wollte ich zum Vergleich den alten einfachen Bootloader testen. Er lädt auch brav mit Bochs von Disk, startet aber nicht auf "real PC". Was habe ich vergessen?
boot.asm:
org 0x7C00 ; set up start address of bootloader ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; setup a stack and segment regs ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; xor ax, ax mov ds, ax mov es, ax ; mov ax, 0x7000 mov ss, ax xor sp, sp ; set stackpointer to 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; read kernel from floppy disk ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; mov si,loadmsg ; show loading message ; call print_string ;mov [bootdrive], dl ; boot drive stored by BIOS in DL. ; we save it to [bootdrive] to play for safety. load_kernel: xor ax, ax ; mov ax, 0 => function "reset" int 0x13 jc load_kernel ; trouble? try again mov bx, 0x8000 ; set up start address of kernel ; set parameters for reading function ; 8-bit-wise for better overview mov dl, 0 ; select boot drive mov al, 63 ; read n 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_kernel ; trouble? try again ;;;;;;;;;;;;; ; A20-Gate ; ;;;;;;;;;;;;; in al, 0x92 ; switch A20 gate via fast A20 port 92 cmp al, 0xff ; if it reads 0xFF, nothing's implemented on this port je .no_fast_A20 or al, 2 ; set A20_Gate_Bit (bit 1) and al, ~1 ; clear INIT_NOW bit (don't reset pc...) out 0x92, al jmp .A20_done .no_fast_A20: ; no fast shortcut -> use the slow kbc... call empty_8042 mov al, 0xD1 ; kbc command: write to output port out 0x64, al call empty_8042 mov al, 0xDF ; writing this to kbc output port enables A20 out 0x60, al call empty_8042 .A20_done: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Load GDT, switch to PM, and jump to kernel ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; cli ; clear interrupts lgdt [gdtr] ; load GDT via GDTR (defined in file "gtd.inc") mov eax, cr0 ; switch-over to Protected Mode or eax, 1 ; set bit 0 of CR0 register mov cr0, eax ; jmp dword 0x8:0x00008000 ; this is a 16-bit-FAR-Jmp, but CS is loaded with "index" 8 in GDT ; hence, the code will be interpreted as 32 bit from here on ; the address can be found in the linker script (phys) ;;;;;;;;; ; Calls ; ;;;;;;;;; print_string: mov ah, 0x0E ; VGA BIOS fnct. 0x0E: teletype .loop: lodsb ; grab a byte from SI test al, al ; NUL? jz .done ; if the result is zero, get out int 0x10 ; otherwise, print out the character! jmp .loop .done: ret empty_8042: call Waitingloop in al, 0x64 cmp al, 0xff ; ... no real kbc at all? je .done test al, 1 ; something in input buffer? jz .no_output call Waitingloop in al, 0x60 ; yes: read buffer jmp empty_8042 ; and try again .no_output: test al, 2 ; command buffer empty? jnz empty_8042 ; no: we can't send anything new till it's empty .done: ret Waitingloop: mov cx,0xFFFF .loop_start: dec cx jnz .loop_start ret ;;;;;;;;;;;; ; Includes ; ;;;;;;;;;;;; %include "gdt.inc" ;;;;;;;; ; data ; ;;;;;;;; ;bootdrive db 0 ; boot drive ;loadmsg db "bootloader message: loading kernel ...",13,10,0 times 510-($-$$) hlt db 0x55 db 0xAA
gdt.inc:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Global Descriptor Table (GDT) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; NULL_Desc: dd 0 dd 0 CODE_Desc: dw 0xFFFF ; segment length bits 0-15 ("limit") dw 0 ; segment base byte 0,1 db 0 ; segment base byte 2 db 10011010b ; access rights db 11001111b ; bit 7-4: 4 flag bits: granularity, default operation size bit, 2 bits available for OS ; bit 3-0: segment length bits 16-19 db 0 ; segment base byte 3 DATA_Desc: dw 0xFFFF ; segment length bits 0-15 dw 0 ; segment base byte 0,1 db 0 ; segment base byte 2 db 10010010b ; access rights db 11001111b ; 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 db 0 ; segment base byte 3 gdtr: Limit dw 24 ; length of GDT Base dd NULL_Desc ; base of GDT ( linear address: RM Offset + Seg<<4 )
kernel.ld:
OUTPUT_FORMAT("binary") ENTRY(KernelStart) SECTIONS { . = 0x8000; .text : { __code_start = .; *(EXCLUDE_FILE(shared_pages.o data.o).text) } . = 0xc000; .text1 : { shared_pages.o(.text) } . = 0xd000; .text2 : { data.o(.text) } .data : { __data_start = .; *(.data) } .rodata : { __rodata_start = .; *(.rodata) } .bss : { __bss_start = .; *(.bss) *(COMMON) } __end = .; }
Ist wichtig, dass ich das auf real PC zum Laufen bekomme, um sicher sein zu können, dass es nicht am neuen Bootloader-Algo für größere Kernel liegt.
EDIT: Inzwischen habe ich heraus gefunden, dass der Bootloader funktioniert. Ein gewisser Zweifel bleibt immer, aber momentan liegen Fehler eher im Kernel.
-
Dieser Thread wurde von Moderator/in Nobuo T aus dem Forum Assembler in das Forum Projekt: OS-Development verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.