这是引导加载程序小示例的代码的一部分。
它仅显示“myos”,但不显示“ok”。
. . .
mov si, statement1
call print_string
; load second sector into memory
mov ah, 0x02 ; load second stage to memory
mov al, 1 ; numbers of sectors to read into memory
mov dl, 0x80 ; sector read from fixed/usb disk
mov ch, 0 ; cylinder number
mov dh, 0 ; head number
mov cl, 2 ; sector number
mov bx, _OS_Stage_2 ; load into es:bx segment :offset of buffer
int 0x13 ; disk I/O interrupt
jmp _OS_Stage_2 ; jump to second stage
. . .
statement1 db "myos", 0
; boot loader magic number
times ((0x200 - 2) - ($ - $$)) db 0x00 ;set 512 bytes for boot sector which are necessary
dw 0xAA55 ; boot signature 0xAA & 0x55
_OS_Stage_2:
. . .
mov si, statement2
call print_string
statement2 db "ok", 0
; add how much memory we need
times (1024 - ($-$$)) db 0x00
以下是跳转到_OS_Stage_2的代码。它不起作用。
此处包含完整的源代码
bits 16] ; tell assembler that working in real mode(16 bit mode)
[org 0x7c00] ; organize from 0x7C00 memory location where BIOS will load us
start: ; start label from where our code starts
xor ax,ax ; set ax register to 0
mov ds,ax ; set data segment(ds) to 0
mov es,ax ; set extra segment(es) to 0
mov bx,0x8000
mov ax,0x13 ;clears the screen
int 0x10 ;call bios video interrupt
mov ah,02 ;clear the screen with big font
int 0x10 ;interrupt displayt
; cursor position
mov al, 2
mov ah, 0
mov bl, 4
mov bh, 0
int 0x10
mov si, command_prompt
call print_string
mov ax,0x00 ; get keyboard input
int 0x16 ; interrupt for hold & read input
; load second sector into memory
mov ah, 0x02 ; load second stage to memory
mov al, 1 ; numbers of sectors to read into memory
mov dl, 0x80 ; sector read from fixed/usb disk
mov ch, 0 ; cylinder number
mov dh, 0 ; head number
mov cl, 2 ; sector number
mov bx, _OS_Stage_2 ; load into es:bx segment :offset of buffer
int 0x13 ; disk I/O interrupt
jmp _OS_Stage_2 ; jump to second stage
int 0x19
print_string:
mov ah, 0x0E ; value to tell interrupt handler that take value from al & print it
.repeat_next_char:
lodsb ; get character from string
cmp al, 0 ; cmp al with end of string
je .done_print ; if char is zero, end of string
int 0x10 ; otherwise, print it
jmp .repeat_next_char ; jmp to .repeat_next_char if not 0
.done_print:
ret ;return
command_prompt db "myos", 0
; boot loader magic number
times ((0x200 - 2) - ($ - $$)) db 0x00 ;set 512 bytes for boot sector which are necessary
dw 0xAA55 ; boot signature 0xAA & 0x55
_OS_Stage_2:
mov al,2 ; set font to normal mode
mov ah,0 ; clear the screen
int 0x10 ; call video interrupt
mov si, statement
call print_string
statement db "ok", 0
; add how much memory we need
times (1024 - ($-$$)) db 0x00
上面的代码是通过 NASM 在 ubuntu 上使用 qemu 模拟器通过 ./build-linux.sh (文件) 进行汇编的,如下所示。
#!/bin/sh
if test "`whoami`" != "root"
then
echo "You must be logged in as root to build (for loopback mounting)"
echo "Enter 'su' or 'sudo bash' to switch to root"
exit
fi
if [ ! -e disk_images/os.flp ] then
echo ">>> Creating new OS floppy image..."
mkdosfs -C disk_images/os.flp 1440 || exit
fi
echo ">>> Assembling bootloader..."
nasm -O0 -w+orphan-labels -f bin -o source/bootload/nasma/boot.bin source/bootload/nasma/boot.asm || exit
echo ">>> Adding bootloader to floppy image..."
dd status=noxfer conv=notrunc if=source/bootload/nasma/boot.bin of=disk_images/os.flp || exit
echo ">>> Creating CD-ROM ISO image..."
rm -f disk_images/os.iso
mkisofs -quiet -V 'OS' -input-charset iso8859-1 -o disk_images/os.iso -b os.flp disk_images/ || exit
echo '>>> Done!'
test-linux(文件)运行程序如下
#!/bin/sh
qemu-system-i386 -soundhw pcspk -drive format=raw,file=disk_images/os.flp,index=0,if=floppy
最佳答案
主要问题:您将单元 80h 硬编码为从引导加载单元加载,但您将镜像作为软盘驱动器传递到 qemu,因此您应该使用单元 00h。
解决方案:保留 dl
寄存器(dx
的一部分),因为它在进入加载程序时保持不变。先前的加载程序将当前的引导加载单元传递给您在此寄存器中,因此只需使用它即可。
其他挑剔:
没有错误处理,失败时只会崩溃。
堆栈应由您的代码设置,以避免可能干扰您的扇区负载。
运行完成后,您应该进行某种无限循环来结束,而不是让执行继续到代码末尾。我围绕
sti
\hlt
做了一个循环以节省电量。您列出的完整源代码还有另一个错误,它缺少
bits
指令的左方括号[
。 (这似乎是 NASM 允许的,但这是错误的。)删除右方括号也是有效的,有两种形式的bits
指令,带括号或不带括号。您没有在构建脚本中安装任何内容,因此您不需要成为 root 用户。
此时您不需要创建 ISO 镜像,实际上也没有使用它来运行您的程序。
如果您只是覆盖前两个扇区,则无需创建 DOS 文件系统,这会导致文件系统无法使用。我用另一个 dd 命令替换了它。
这是我的固定脚本和源代码,但错误处理和堆栈设置仍然缺失。脚本:
#!/bin/sh
if [ ! -e disk_images/os.flp ]
then
echo ">>> Creating new OS floppy image..."
dd if=/dev/zero of=disk_images/os.flp bs=1024 count=1440 || exit
fi
echo ">>> Assembling bootloader..."
nasm -O0 -w+orphan-labels -f bin -o source/bootload/nasma/boot.bin source/bootload/nasma/boot.asm || exit
echo ">>> Adding bootloader to floppy image..."
dd status=noxfer conv=notrunc if=source/bootload/nasma/boot.bin of=disk_images/os.flp || exit
echo '>>> Done!'
来源:(注意 push dx
、pop dx
和 sti
\hlt
循环。)
[ bits 16] ; tell assembler that working in real mode(16 bit mode)
[org 0x7c00] ; organize from 0x7C00 memory location where BIOS will load us
start: ; start label from where our code starts
xor ax,ax ; set ax register to 0
mov ds,ax ; set data segment(ds) to 0
mov es,ax ; set extra segment(es) to 0
mov bx,0x8000
push dx
mov ax,0x13 ;clears the screen
int 0x10 ;call bios video interrupt
mov ah,02 ;clear the screen with big font
int 0x10 ;interrupt displayt
; cursor position
mov al, 2
mov ah, 0
mov bl, 4
mov bh, 0
int 0x10
mov si, command_prompt
call print_string
mov ax,0x00 ; get keyboard input
int 0x16 ; interrupt for hold & read input
; load second sector into memory
mov ah, 0x02 ; load second stage to memory
mov al, 1 ; numbers of sectors to read into memory
pop dx
; mov dl, 0x80 ; sector read from fixed/usb disk
mov ch, 0 ; cylinder number
mov dh, 0 ; head number
mov cl, 2 ; sector number
mov bx, _OS_Stage_2 ; load into es:bx segment :offset of buffer
int 0x13 ; disk I/O interrupt
jmp _OS_Stage_2 ; jump to second stage
int 0x19
print_string:
mov ah, 0x0E ; value to tell interrupt handler that take value from al & print it
.repeat_next_char:
lodsb ; get character from string
cmp al, 0 ; cmp al with end of string
je .done_print ; if char is zero, end of string
int 0x10 ; otherwise, print it
jmp .repeat_next_char ; jmp to .repeat_next_char if not 0
.done_print:
ret ;return
command_prompt db "myos", 0
; boot loader magic number
times ((0x200 - 2) - ($ - $$)) db 0x00 ;set 512 bytes for boot sector which are necessary
dw 0xAA55 ; boot signature 0xAA & 0x55
_OS_Stage_2:
mov al,2 ; set font to normal mode
mov ah,0 ; clear the screen
int 0x10 ; call video interrupt
mov si, statement
call print_string
haltloop:
sti
hlt
jmp haltloop
statement db "ok", 0
; add how much memory we need
times (1024 - ($-$$)) db 0x00
关于assembly - 第二个扇区无法加载到引导文件中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72498957/