Bootloader - 加载程序集内核,内存地址问题和复制数据

时间:2014-12-30 00:29:55

标签: assembly kernel bootloader

我正在尝试完成操作系统项目的第一部分。这部分涉及通过模拟器qemu运行引导加载程序组件文件,并加载该引导加载程序并执行我内核的任意数量(希望超过512字节)。

我在完成这项工作时遇到了问题,我无法确切地指出这一点,但我可能会将其缩小为两件事。

一,我缺乏对内存地址的理解,并使用堆栈加载内核并执行它。

二,我将我的两个文件(引导加载程序和内核文件)错误地复制到软盘映像中。

这是第一部分的代码,即引导加载程序。 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

这是第二部分内核的代码。 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

以下是我编译,复制和模拟文件及其二进制文件的方法,我在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

如果您尝试运行,编译和模拟它。您将看到内核从未加载,并且不会打印它应该的内容。

我不知道在这一点之后该做什么,我已经尝试研究如何将第二阶段引导加载程序正确加载到软盘映像中并且变得简短。我在从引导加载程序加载内核时遇到了一些错误。

如果您有任何建议或修正,我们将不胜感激。此外,如果我的代码中有任何错误或需要澄清的任何内容以便更好地帮助我,请不要犹豫。

修改

以下是我用来创建此代码的教程,如果您需要引用它们。

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

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

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

2 个答案:

答案 0 :(得分:1)

int 13/02期望es:bx作为输入,但您只需设置esbx未初始化。您应该将其设置为要加载数据的位置,注意不要覆盖自己的引导扇区。因此,mov bx, 512听起来不错。

另一个问题是,您的READSECTORS会返回bx的最终值,即下一个可用地址,而不是原始加载地址。

此外,jmp [es:bx]不会跳转到es:bx,而是会从该地址获取指针并跳转到指向的地方。您还需要考虑您的内核也使用org 0,因此您应该使用0的偏移量进行远程跳转。如果在引导扇区之后加载内核,则意味着jmp 0x7e0:0应该可以解决问题。刚发现你的内核也希望设置ds

PS:你应该设置一个调试环境,否则你很难解决问题。


这是一个工作版本:

;;;
;;; 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

内核:

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

答案 1 :(得分:0)

示例代码使用0的组织,它可能应该是7c00h的组织。 PC将分区或引导扇区加载到十六进制0000:7c00。在Microsoft分区扇区的情况下,代码自身向下移动到十六进制0000:0600,在0000:0600之后跳转到某个点以继续,并最终在十六进制0000:7c00处加载引导扇区。

另外,您使用的nasm版本是否会生成16位实模式代码?