[英]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/
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.