我正在尝试完成操作系统项目的第一部分。这部分涉及通过模拟器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/
答案 0 :(得分:1)
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
答案 1 :(得分:0)
示例代码使用0的组织,它可能应该是7c00h的组织。 PC将分区或引导扇区加载到十六进制0000:7c00。在Microsoft分区扇区的情况下,代码自身向下移动到十六进制0000:0600,在0000:0600之后跳转到某个点以继续,并最终在十六进制0000:7c00处加载引导扇区。
另外,您使用的nasm版本是否会生成16位实模式代码?