繁体   English   中英

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

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

我正在尝试完成操作系统项目的第一部分。 这部分涉及通过仿真器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

int 13/02期望es:bx作为输入,但是您仅设置了es ,因此bx未初始化。 您应该将其设置为指向要加载数据的位置,请注意不要覆盖自己的引导扇区。 因此, 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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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