简体   繁体   中英

Bootloader - Loading assembly kernel, problems with memory addresses and copying data

I am trying to finish the first part of my operating system project. This part involves running a boot loader assembly file through the emulator qemu and having that boot loader load and execute an arbitrary amount (hopefully over 512 bytes) of my kernel.

I'm having problems accomplishing this, I can't pinpoint it exactly but I've possibly narrowed it down to two things.

One, I am lacking in my understanding of memory addresses, and using the stack to load my kernel and execute it.

Two, I am copying my two files (the boot loader and the kernel files) incorrectly into the floppy disk image.

Here is my code for the first part, the boot loader. boot.asm

;;;
;;; Header information
;;; 

BITS 16

ORG 0

START:  jmp MAIN

;;;
;;; Parameters
;;; 

SectorsPerTrack     dw  18
HeadsPerTrack       dw  2
BytesPerSector      dw  512
DriveNumber         db  0

;;;
;;; Variables
;;; 

absSector           db  0x00
absHead             db  0x00
absTrack            db  0x00

;;;
;;; Print function
;;; Input:
;;; - SI => Null terminated string
;;; Output:
;;; - None
;;; 

PRINT:
    lodsb
    or al, al
    jz PRINTDONE
    int 10h
    jmp PRINT
PRINTDONE:
    ret

;;;
;;; LBA to CHS
;;; Input:
;;; - AX => LBA address
;;; - SectorsPerTrack => Sectors per track
;;; - HeadsPerTrack => Heads per track
;;; Output:
;;; - absSector => CHS sector address
;;; - absHead => CHS head address
;;; - absTrack => CHS track address
;;; 

LBACHS:
    xor dx, dx
    div WORD [SectorsPerTrack]
    inc dl
    mov BYTE [absSector], dl
    xor dx, dx
    div WORD [HeadsPerTrack]
    mov BYTE [absHead], dl
    mov BYTE [absTrack], al
    ret

;;;
;;; Read sectors
;;; Input:
;;; - CX => Number of sectors to read
;;; - AX => LBA address to start from
;;; Output:
;;; - ES:BX => Loaded sector address:offset
;;; 

READSECTORS:
READSECTORSMAIN:    
          mov     di, 0x0005
READSECTORSLOOP:    
          push    ax
          push    bx
          push    cx
          call    LBACHS
          mov     ah, 0x02
          mov     al, 0x01
          mov     ch, BYTE [absTrack]
          mov     cl, BYTE [absSector]
          mov     dh, BYTE [absHead]
          mov     dl, BYTE [DriveNumber]
          int     0x13
          jnc     READSECTORSDONE
          xor     ax, ax
          int     0x13
          dec     di
          pop     cx
          pop     bx
          pop     ax
          jnz     READSECTORSLOOP
          int     0x18
READSECTORSDONE:    
          pop     cx
          pop     bx
          pop     ax
          add     bx, WORD [BytesPerSector]
          inc     ax
          loop    READSECTORSMAIN
          ret

;;;
;;; Main section
;;; 

MAIN:
    cli                 ; Move registers for offset of BIOS 0x07C0 load point
    mov ax, 0x07C0      ; OFFSET
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov ax, 0x0000      ; Initialize the stack
    mov ss, ax
    mov sp, 0xFFFF
    sti

    mov ax, 0x01        ; LBA number 1 for sector number 2
    mov cx, 0x01        ; Read one sector from the floppy disk

    call READSECTORS    ; Call the read sectors function

    jmp [es:bx]         ; Address ES offset BX returned from read sectors

;;;
;;; Footer information
;;; 

times 510-($-$$) db 0
dw 0xAA55

Here is my code for the second part, the kernel. kernel.asm

BITS 16

ORG 0

START:  jmp MAIN

message db 'Kernel Loaded', 13, 10, 0

PRINT:
    lodsb
    or al, al
    jz PRINTDONE
    int 10h
    jmp PRINT
PRINTDONE:
    ret

MAIN:
    mov si, message
    call PRINT

    jmp $

times 510-($-$$) db 0
dw 0xAA55

Here is how I am compiling, copying, and emulating both files and their binaries, I am running on Ubuntu Desktop x64.

nasm -f bin -o boot.bin boot.asm
nasm -f bin -o kernel.bin kernel.asm
cat kernel.bin >> boot.bin
dd status=noxfer conv=notrunc if=boot.bin of=floppy.fda
qemu-system-x86_64 -fda floppy.fda

If you attempt to run, compile, and emulate this. You will see that the kernel is never loaded and does not print out what it should.

I have no idea what to do beyond this point, I have tried researching how to properly load second stage boot loaders into a floppy image and came up short. I have also hit a brick wall with what I might be doing wrong in loading my kernel from my boot loader.

If you have any advice or fixes, it would be greatly appreciated. Also, if there are any errors in my code or anything you need clarified in order to better help me, please don't hesitate to ask.

EDIT

Here are the tutorials I've been using to create this code if you need to reference them.

http://www.brokenthorn.com/Resources/

http://www.osdever.net/tutorials/view/lba-to-chs

http://www.osdever.net/tutorials/view/loading-sectors

int 13/02 expects es:bx as input, but you only set up es , bx is uninitialized. You should set it to point where you want to load your data, careful not to overwrite your own boot sector. As such, mov bx, 512 sounds like a good idea.

Another problem is that your READSECTORS returns the final value of bx , that is the next available address and not the original load address.

Also, jmp [es:bx] will not jump to es:bx , rather, it will fetch a pointer from that address and jump wherever that points to. You also need to consider that your kernel also used org 0 so you should do a far jump using an offset of 0 . If you load your kernel after the boot sector, that means jmp 0x7e0:0 should do the trick. Just spotted that your kernel also expects ds to be set up as well.

PS: you should set up a debugging environment, otherwise you will have a hard time fixing problems.


Here is a working version:

;;;
;;; Header information
;;;

BITS 16

ORG 0

START:  jmp MAIN

;;;
;;; Parameters
;;;

SectorsPerTrack     dw  18
HeadsPerTrack       dw  2
BytesPerSector      dw  512
DriveNumber         db  0

;;;
;;; Variables
;;;

absSector           db  0x00
absHead             db  0x00
absTrack            db  0x00

;;;
;;; Print function
;;; Input:
;;; - SI => Null terminated string
;;; Output:
;;; - None
;;;

PRINT:
    lodsb
    or al, al
    jz PRINTDONE
    mov ah, 0eh
    int 10h
    jmp PRINT
PRINTDONE:
    ret

;;;
;;; LBA to CHS
;;; Input:
;;; - AX => LBA address
;;; - SectorsPerTrack => Sectors per track
;;; - HeadsPerTrack => Heads per track
;;; Output:
;;; - absSector => CHS sector address
;;; - absHead => CHS head address
;;; - absTrack => CHS track address
;;;

LBACHS:
    xor dx, dx
    div WORD [SectorsPerTrack]
    inc dl
    mov BYTE [absSector], dl
    xor dx, dx
    div WORD [HeadsPerTrack]
    mov BYTE [absHead], dl
    mov BYTE [absTrack], al
    ret

;;;
;;; Read sectors
;;; Input:
;;; - CX => Number of sectors to read
;;; - AX => LBA address to start from
;;; Output:
;;; - ES:BX => Loaded sector address:offset
;;;

READSECTORS:
READSECTORSMAIN:
          mov     di, 0x0005
READSECTORSLOOP:
          push    ax
          push    bx
          push    cx
          call    LBACHS
          mov     ah, 0x02
          mov     al, 0x01
          mov     ch, BYTE [absTrack]
          mov     cl, BYTE [absSector]
          mov     dh, BYTE [absHead]
          mov     dl, BYTE [DriveNumber]
          int     0x13
          jnc     READSECTORSDONE
          xor     ax, ax
          int     0x13
          dec     di
          pop     cx
          pop     bx
          pop     ax
          jnz     READSECTORSLOOP
          int     0x18
READSECTORSDONE:
          pop     cx
          pop     bx
          pop     ax
          add     bx, WORD [BytesPerSector]
          inc     ax
          loop    READSECTORSMAIN
          ret

;;;
;;; Main section
;;;

MAIN:
    cli                 ; Move registers for offset of BIOS 0x07C0 load point
    mov ax, 0x07C0      ; OFFSET
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov ax, 0x0000      ; Initialize the stack
    mov ss, ax
    mov sp, 0xFFFF
    sti

    mov ax, 0x01        ; LBA number 1 for sector number 2
    mov cx, 0x01        ; Read one sector from the floppy disk
    mov bx, 0x200

    call READSECTORS    ; Call the read sectors function

    jmp 0x7e0:0

;;;
;;; Footer information
;;;

times 510-($-$$) db 0
dw 0xAA55

kernel:

BITS 16

ORG 0

START:  jmp MAIN

message db 'Kernel Loaded', 13, 10, 0

PRINT:
    lodsb
    or al, al
    jz PRINTDONE
    mov ah, 0eh
    int 10h
    jmp PRINT
PRINTDONE:
    ret

MAIN:
    mov ax, cs
    mov ds, ax
    mov si, message
    call PRINT

    jmp $

times 512-($-$$) db 0

The example code uses an org of 0, it probably should be an org of 7c00h. PC's load the partition or boot sector at hex 0000:7c00. In the case of Microsoft partition sectors, the code moves itself down to hex 0000:0600, jumps to some point after 0000:0600 to continue, and eventually loads a boot sector at hex 0000:7c00.

Also, does version of nasm that you are using produce 16 bit real mode code?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM