Nachladen des Kernels durch eigenen Bootloader


  • Mod

    Du kannst in diesem Fall mehr als 18 Sektoren am Stück lesen, wenn du ein relativ modernes BIOS hast, das die Berechnungen für dich übernimmt.

    Danke für den Hinweis.

    Ich habe bisher folgenden Code, der aber nicht zum Erfolg führt:

    mov [bootdrive], dl ; boot drive stored by BIOS in DL.
                            ; we save it to [bootdrive] to play for safety.
    
    load_kernel1:
        xor ax, ax         ; mov ax, 0  => function "reset"
        int 0x13         
        jc load_kernel1     ; 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,[bootdrive] ; 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_kernel1    ; trouble? try again
    
    load_kernel2:	
        xor ax, ax        ; mov ax, 0  => function "reset"
        int 0x13         
        jc load_kernel2   ; trouble? try again
    
    	mov bx, 0xFE00     ; 
    	mov dl,[bootdrive] ; select boot drive
    	mov al, 63         ; read n sectors
    	mov ch,  0         ; cylinder = 1
        mov cl, 11         ; sector   = 11
        mov dh,  1         ; head     = 1
        mov ah,  2         ; function "read" 
        int 0x13         
        jc load_kernel2    ; trouble? try again
    

    Ideen:

    C 0      0      1      1
    H 0      1      0      1 
    S 1...18 1...18 1...18 1...18
    

    0x8000 + (63*0x200) = 0xFE00 für zweite Runde Sektoren laden.

    Könnte das natürlich auch 18er weise machen.
    Muss ich jedes mal resetten?


  • Mod

    Den Sektor 63 kannst du allerdings nicht adressieren, wenn er nicht existiert.

    mov [bootdrive], dl ; boot drive stored by BIOS in DL.
                            ; we save it to [bootdrive] to play for safety.
    
    load_kernel1:
        xor ax, ax         ; mov ax, 0  => function "reset"
        int 0x13         
        jc load_kernel1     ; 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,[bootdrive] ; select boot drive
        mov al, 62         ; read n sectors
        mov ch,  0         ; cylinder 
        mov cl,  2         ; sector   
        mov dh,  0         ; head     
        mov ah,  2         ; function "read" 
        int 0x13         
    	jc load_kernel1    ; trouble? try again
    
    load_kernel2:	
        ;xor ax, ax        ; mov ax, 0  => function "reset"
        ;int 0x13         
        ;jc load_kernel2   ; trouble? try again
    
    	mov bx, 0xFC00     ; 
    	mov dl,[bootdrive] ; select boot drive
    	mov al, 52         ; read n sectors
    	mov ch,  1         ; cylinder 
        mov cl, 10         ; sector   
        mov dh,  1         ; head     
        mov ah,  2         ; function "read" 
        int 0x13         
        jc load_kernel2    ; trouble? try again
    

    geht auch nicht.


  • Mod

    mov [bootdrive], dl ; boot drive stored by BIOS in DL.
                            ; we save it to [bootdrive] to play for safety.
    
    load_kernel1:
        xor ax, ax         ; mov ax, 0  => function "reset"
        int 0x13         
        jc load_kernel1     ; 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,[bootdrive] ; select boot drive
        mov al, 17         ; read n sectors
        mov ch,  0         ; cylinder 
        mov cl,  2         ; sector   
        mov dh,  0         ; head     
        mov ah,  2         ; function "read" 
        int 0x13         
    	jc load_kernel1    ; trouble? try again
    
    load_kernel2:	
        ;xor ax, ax        ; mov ax, 0  => function "reset"
        ;int 0x13         
        ;jc load_kernel2   ; trouble? try again
    
    	mov bx, 0xA200     ; 
    	mov dl,[bootdrive] ; select boot drive
    	mov al, 63         ; read n sectors
    	mov ch,  0         ; cylinder 
        mov cl,  1         ; sector   
        mov dh,  1         ; head     
        mov ah,  2         ; function "read" 
        int 0x13         
        jc load_kernel2    ; trouble? try again
    

    ... auch nicht. Habe auch cyl/head 0 und 1 umgekehrt probiert.


  • Mod

    Most BIOSes support "multitrack" reads, where the value in AL exceeds the number of sectors remaining on the track, in which case any additional sectors are read beginning at sector 1 on the following head in the same cylinder

    Also wäre doch der Ansatz

    C 0      0      1      1
    H 0      1      0      1
    S 1...18 1...18 1...18 1...18
    

    nicht verkehrt. Offenbar geht das ja auch Cylinder-übergreifend, allerdings nur bis sector 63.



  • Evtl erst 62 Sektoren von CHS:0/0/2 nach 0x8000, dann 63 Sektoren von 0/1/1 nach 0xFC00?


  • Mod

    Das hatte ich im mittleren Versuch bereits probiert (mit 52 im zweiten Satz).

    mov bx, 0xFC00     ;
        mov dl,[bootdrive] ; select boot drive
        mov al, 52         ; read n sectors
        mov ch,  1         ; cylinder
        mov cl, 10         ; sector  
        mov dh,  1         ; head    
        mov ah,  2         ; function "read"
        int 0x13
    

    Ich teste allerdings mit Bochs, vielleicht verkehrt (das mit 63 in einem Ansatz hat bisher jedoch auf bochs funktioniert).

    Ein in Bochs lauffähiges OS lief nun nicht in real life auf einem PC, daher macht das jetzt auch keinen Sinn ein "schwieriges" OS so zu testen.

    Mist! Bin wohl langsam doch mürbe für Linux und GRUB. Man wird meistens nur an-/ausgelacht, wenn man sich mit eigenem Bootloader und Windows quält. 🙄

    Was ich benötige, ist ein Vorbild eines Bootloaders, der einen Kern größer 63 Sektoren laden muss. Habe dies bisher nichr gefunden. Pls help. 🙂


  • Mod

    Das Problem scheint eine harte Begrenzung bei 64K zu sein.
    http://groups.google.com/group/de.comp.lang.assembler.x86/browse_thread/thread/67307a357a9ca137/e62f588a36e8ad46?lnk=raot

    CHS habe ich im Griff:
    http://lowlevel.brainsware.org/forum/index.php?topic=2219.msg25073#msg25073

    Daher habe ich nun versucht, meinen Kernel nach 0x10000 zu verlagern, denn obwohl ich CHS richtig gesteuert habe, knallt es bei 0xFE00 einfach brutal und verlagern auf ein anderes Segment hilft nicht!

    Leider besteht hier mit der neuen Kernel-Adresse noch ein Problem - entweder mit dem Target-Puffer ES:BX oder mit dem far jump zum PM:

    ...
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; 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 08:0x10000    ; 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 
    
    ...
    

    (EDIT: gekürzt)

    kernel.ld:

    OUTPUT_FORMAT("binary")
    ENTRY(KernelStart)
    SECTIONS
    { 
      . = 0x00010000;
      .text   : { *(EXCLUDE_FILE(shared_pages.o).text) } 
      . = 0x00015000;
      .text1  : { shared_pages.o(.text)                } 
      . = 0x00016000;
      .data   : { *(.data)                             } 	
      .rodata : { *(.rodata)                           }
      .bss    : { *(.bss)                              }  
    }
    

    kernel.asm:

    [Bits 32]
    section .text          ; ld needs that for coff format
    
    [global KernelStart]
    KernelStart:
        mov    ax, 0x10
        mov    ds, ax      ; data descriptor --> data, stack and extra segment
        mov    ss, ax           
        mov    es, ax
        xor    eax, eax    ; null desriptor --> FS and GS
        mov    fs, ax
        mov    gs, ax
        mov    esp, 0x200000 ; set stack below 2 MB limit
    
    [extern _main]         ; entry point in ckernel.c
    	call _main ; ->-> C-Kernel
        jmp $
    

    Wenn ich den far jump auf
    jmp 0x1000:0x0000
    abändere, hilft das leider auch nicht.
    Bochs resettet in jedem Fall.
    Kann jemand helfen?

    PS: Kein Wunder, das alle GRUB einsetzen. Bootloader scheint aufgrund einiger schwer überwindbarer antiker Strukturen ein wirklich hartes Brot zu sein. 🙄



  • Bei deinem Sprung ("jmp 0x8:0x10000") gibt mein Assembler (NASM) sogar eine Warnung aus: warning: word data exceeds bounds

    Er assembliert das also zu jmp word 0x8:0x0000. Was ja auch klar ist, wenn man im Real Mode ist, weil Segment und Offset halt 16 Bit sind.

    Du solltest auf deine Ausgaben gucken, oder deinen Assembler updaten.

    Aber was für ein Glück, dass man das Offset auf 32 Bit erweitern kann: jmp dword 0x8:0x10000


  • Mod

    jmp dword 08:0x10000

    Thx! 👍
    Gibt man "jmp dword 08:0x10000" in Google ein, findet man nur uns hier:
    http://www.google.de/search?hl=de&q="jmp+dword+08%3A0x10000"&btnG=Suche&meta= 😕 (Ich liebe solche Unikate)

    Du solltest auf deine Ausgaben gucken

    werde ich beherzigen.


  • Mod

    Allerdings dürfte der nächste Schlag nun bei einem Kernel mit mehr als 128 Sektoren vorprogrammiert sein (EDIT: ich habe es ausprobiert: es stimmt!). Weiß da jemand etwas Genaues, wie man diese harte Begrenzung umgeht?



  • Wie in dem Verlinkten Thema steht, duerfte das an dem antike DMA-Controller fuer Floppys scheitern. Einen direkten Workarround bei diesen ISA-Fossilien kenne ich auch nicht.
    Es wird dir also wohl nichts anderes uebrig bleiben, als dich damit zu arrangieren. Moeglichkeiten gibt es schliesslich viele (von denen einige eigentlich auch vom BIOS selbst umgesetzt werden koennen sollten, aber egal...).
    Naheliegend waere es zB., in einen guenstig gelegenen Buffer einzulesen und von dort Sektor fuer Sektor an die gewuenschte Adresse zu kopieren oder eben selbst genau darauf zu achten, dass du dem DMA mit seinen 64K-Pages nicht in's Gehege kommst.


  • Mod

    Merkwürdigerweise finde ich zu diesem Thema keine Vorbilder. Bootloader für solche Anwendungen sind offenbar ein eher "verstecktes" Thema. In Foren wird man sofort auf GRUB zugesteuert.

    Naja, 64KB (128 Sektoren) ist schon eine Menge für einen Hobby-Kernel. 😃
    Immerhin wurde nun die durch 6 Bit bedingte 63-Sektoren-Grenze durch die eigene Berechnung der CHS geschafft. Immer step-by-step oder "festina lente" wie der Lateiner sagt.



  • Evtl hilft auch der offen liegende Code von GRUB weiter? Hab ihn mir interessehalber gerade auch mal angesehen, dies hier müsste der Boot-Code sein (ansonsten DL für alles hier).


  • Mod

    Danke für den Link zu GRUB!

    Ärgerlich finde ich, dass ich den Kernel nun ab 0x10000 beginnen musste. Wir hatten ihn ja extra nach 0x8000 gelegt, um den Speicher zu "schonen". 😉 Naja, immerhin versteht man nun besser, warum man typischerweise dort beginnt.

    MitGRUBwärDasNichPassiert

    In meinem Tutorial versuche ich GRUB solange zu vermeiden, bis es wirklich notwendig wird. Bisher wurde immer ein work-around gefunden. Man lernt mit eigenem Bootloader auch eindeutig mehr über die Basics (z.B. die harte Grenze durch ISA DMA oder die eigene CHS-Berechnung 0,0,1...18 | 0,1,1...18 | 1,0,1...18 | 1,1,1...18 | 2,0,1...18 | ... ). 🙂

    Damit kann man auch große Kernel nachladen:

    org 0x7C00  ; set up start address of bootloader
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; setup a stack and segment regs ;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
        xor ax, ax
        mov ds, ax
        mov es, ax
        mov ss, ax
        mov sp, ax
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;   read kernel from floppy disk                           ;
    ;   starting from C(ylinder) H(ead) S(ector): 0 0 2        ;
    ;   17 + 18 + 18 + 18 + 57 = 128 (hard segment limit)      ; 
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
        mov si,loadmsg     ; show loading message
        call print_string
        call Waitingloop
        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, 0x1000     
    	mov es, bx         ; target in memory: segment
        mov bx, 0x0000     ; target in memory: offset 
        mov dl,[bootdrive] ; select boot drive
        mov al, 17         ; 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
    
    load_kernel2:
        xor ax, ax         ; mov ax, 0  => function "reset"
        int 0x13         
        jc load_kernel2    ; trouble? try again
    
        mov bx, 0x2200     ; target in memory: offset 
        mov dl,[bootdrive] ; select boot drive
        mov al, 18         ; read n sectors
        mov ch,  0         ; cylinder 
        mov cl,  1         ; sector   
        mov dh,  1         ; head     
        mov ah,  2         ; function "read" 
        int 0x13         
        jc load_kernel2    ; trouble? try again
    
    load_kernel3:
        xor ax, ax         ; mov ax, 0  => function "reset"
        int 0x13         
        jc load_kernel3    ; trouble? try again
    
        mov bx, 0x4600     ; target in memory: offset 
        mov dl,[bootdrive] ; select boot drive
        mov al, 18         ; read n sectors
        mov ch,  1         ; cylinder 
        mov cl,  1         ; sector   
        mov dh,  0         ; head     
        mov ah,  2         ; function "read" 
        int 0x13         
        jc load_kernel3     ; trouble? try again	
    
    load_kernel4:
        xor ax, ax         ; mov ax, 0  => function "reset"
        int 0x13         
        jc load_kernel4    ; trouble? try again
    
        mov bx, 0x6A00     ; target in memory: offset 
        mov dl,[bootdrive] ; select boot drive
        mov al,  18        ; read n sectors
        mov ch,  1         ; cylinder 
        mov cl,  1         ; sector   
        mov dh,  1         ; head     
        mov ah,  2         ; function "read" 
        int 0x13         
        jc load_kernel4     ; trouble? try again	
    
    load_kernel5:
        xor ax, ax         ; mov ax, 0  => function "reset"
        int 0x13         
        jc load_kernel5    ; trouble? try again
    
        mov bx, 0x8E00     ; target in memory: offset 
        mov dl,[bootdrive] ; select boot drive
        mov al,  57        ; read n sectors (max. 57!!! due to max. 128)
        mov ch,  2         ; cylinder 
        mov cl,  1         ; sector   
        mov dh,  0         ; head     
        mov ah,  2         ; function "read" 
        int 0x13         
        jc load_kernel5     ; trouble? try again	
    
    ; new segment
    load_kernel10:
        xor ax, ax         ; mov ax, 0  => function "reset"
        int 0x13         
        jc load_kernel10     ; trouble? try again
    
    	mov bx, 0x2000     ; next segment
    	mov es, bx         ; target in memory: segment
        mov bx, 0x0000     ; target in memory: offset 
        mov dl,[bootdrive] ; select boot drive
        mov al, 63         ; read n sectors
        mov ch,  3         ; cylinder 
        mov cl,  4         ; sector   
        mov dh,  1         ; head     
        mov ah,  2         ; function "read" 
        int 0x13         
        jc load_kernel10     ; trouble? try again	
    
    	call Waitingloop
    
    ;;;;;;;;;;;;;
    ; 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 08:0x10000    ; 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    
        loadmsg db "bootloader message: loading kernel ...",13,10,0
    
        times 510-($-$$) hlt
        db 0x55
        db 0xAA
    

    Nun fehlt nur noch ein netter Algorithmus, der ES:BX und CHS sektorenweise berechnet, dann könnte man dies in einer Schleife für n Sektoren erledigen.

    Den Teil "LBA2CHS" findet man hier:
    http://en.wikipedia.org/wiki/CHS_conversion#Assembler_code_example

    GetCHS proc
                mov         AX, LBA
                xor         DX, DX
                mov         BX, SPT
                div         BX
                inc         DX
                mov         SECT, DL
                xor         DX, DX
                mov         BX, HPC
                div         BX
                mov         CYL, AL
                mov         HEAD, DL
                ret	
    GetCHS endp
    

  • Mod

    Nun fehlt nur noch ein netter Algorithmus, der ES:BX und CHS sektorenweise berechnet, dann könnte man dies in einer Schleife für n Sektoren erledigen.

    Read-Algorithmus wurde von PorkChicken (LowLevel-Forum) vorgeschlagen.

    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, 500
    	mov di, bx 
    	mov bx, 0x0800 ; 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: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 
    ;;;;;;;;;
    ; 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:
    .next:
        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
    
        times 510-($-$$) hlt
        db 0x55
        db 0xAA
    

    Stack wurde von 0x10000 nach 0x7000 verlegt, weil er im Weg war.



  • cool 👍 Aber das klappt nur, wenn der Kernel maximal 128KB groß ist? Das mit dem ISA DMA hab ich noch nicht ganz verstanden, soweit ich das verstanden hatte, konnte man "nur" nicht über eine 64KB-Grenze im RAM lesen?


  • Mod

    Aber das klappt nur, wenn der Kernel maximal 128KB groß ist?

    Nein, mit diesem Code kann der Kernel größer sein. Hier werden mit einem "zum Testen künstlich aufgepumpten" Kernel z.B. 500 Sektoren gelesen: http://www.henkessoft.de/OS_Dev/Downloads/20090712_69b.zip
    http://www.henkessoft.de/OS_Dev/OS_Dev3.htm#mozTocId882541

    Das mit dem ISA DMA hab ich noch nicht ganz verstanden, soweit ich das verstanden hatte, konnte man "nur" nicht über eine 64KB-Grenze im RAM lesen?

    Ja, das stimmt, wird z.B. bei Linux 0.01 auch bereits erwähnt. Kernel wurde damals nach 0x10000 geladen.

    Linux 0.01 boot.s:
    http://www.linuxgrill.com/anonymous/kernel/Archive/historic/linux-0.01.tar.bz2

    | This routine loads the system at address 0x10000, making sure
    | no 64kB boundaries are crossed. We try to load it as fast as
    | possible, loading whole tracks whenever we can.
    |
    | in: es - starting address segment (normally 0x1000)

    Ich bin noch nicht völlig sicher, ob der Aufbau ausreichend robust ist, aber das Design mit dem Stack bei 0x7000, dem Bootloader bei 0x7C00 und dem Kernel ab 0x8000 gefällt mir nach wie vor recht gut.



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


Anmelden zum Antworten