有人也遇到了同样的问题这里。我尝试删除 read_disk 函数中的
mov dl, 0
但仍然不起作用。这家伙似乎还有一个重置功能,当他在打印字符串时遇到空字符时,它会重置软盘。我认为这个功能不是必需的,因为我已经删除了mov dl, 0
。但是,我怀疑重置功能是必要的。
我正在构建一个操作系统,并遇到一个挑战,引导加载程序成功打印其消息,但内核的消息未显示。这是一个细分:
汇编器和环境:
文件:
bootloader.asm
[org 0x7c00]
[bits 16]
jmp main
_message_read_err: db 'Error in reading floppy!', 0
_message_boot: db 'Booting SSoS...', 0
_sectors_per_track: dw 18
_head_count: dw 2
_kernel_start_LBA: dw 1
_kernel_size: dw 1
_stack_ptr_addr: dw 0x7b00
_es_start: dw 0x7c0
; Arguments:
; None
; Returns:
; None
; Used registers:
; ax, ds, ss, sp, es, si
main:
mov ax, 0 ; can't write to ds and ss directly
mov ds, ax
mov ss, ax
mov sp, [_stack_ptr_addr] ; stack pointer
mov ax, [_es_start] ; address * 16 = real address -> 0x7c0 * 16 (dec) = 0x7c00
mov es, ax
mov si, _message_boot
call puts
; Converting LBA to CHS
mov ax, [_kernel_start_LBA]
call LBA_to_CHS ; after this call, CH, CL, and DH will have cylinder, sector, and head values
mov bx, 0x200
mov al, [_kernel_size] ; number of sectors to read
call read_disk
jmp far [es:bx]
; Arguments:
; si - Points to the string to be printed
; Returns:
; None
; Used registers:
; ah, al
puts:
.begin:
mov ah, 0x0E
lodsb
cmp al, 0
je .done
int 10h
jmp .begin
.done:
ret
; Arguments:
; ax - Contains the LBA value to be converted
; Returns:
; ch - Cylinder value
; cl - Sector value
; dh - Head value
; Used registers:
; ax, dx, cx, ch, dh, cl
LBA_to_CHS:
; Save original LBA value
push ax
; Compute Cylinder (LBA / (heads * sectors per track))
; AX = LBA, DX = 0 (from division)
xor dx, dx
mov cx, [_head_count]
mul cx
div word [_sectors_per_track]
mov ch, al
; Temp now in AX. (LBA % (heads * sectors per track))
; Compute Head (Temp / sectors per track)
div word [_sectors_per_track]
mov dh, al
; Compute Sector (Temp % sectors per track + 1)
; AL already contains the remainder from the previous div
; which is Temp % sectors per track
inc al
mov cl, al
; Restore original LBA value
pop ax
ret
; Arguments:
; bx - Address to load the data
; ch, cl, dh - CHS values
; al - Number of sectors to read
; Returns:
; None
; Used registers:
; ax, dl, si
read_disk:
push ax
mov ax, 4
.retry:
dec ax
cmp ax, 0
je .read_error
mov ah, 02h
mov dl, 0
int 13h
jc .retry
pop ax
ret
.read_error:
mov si, _message_read_err
call puts
cli
hlt
times 510-($-$$) db 0
dw 0aa55h
内核.asm
[org 0x7E00]
[bits 16]
jmp main
_message: db 'Hello from kernel!', 0
main:
mov si, _message
call puts
cli
hlt
puts:
mov ah, 0x0E
.begin:
lodsb
cmp al, 0
je .done
int 10h
jmp .begin
.done:
ret
生成文件
BUILD_DIR = build
SRC_DIR = src
IMG_NAME = dev
dev: image
qemu-system-i386 -fda $(BUILD_DIR)/$(IMG_NAME).img
image: $(BUILD_DIR)/bootloader.bin $(BUILD_DIR)/kernel.bin
@dd if=$(BUILD_DIR)/bootloader.bin of=$(BUILD_DIR)/$(IMG_NAME).img bs=512
@dd if=$(BUILD_DIR)/kernel.bin of=$(BUILD_DIR)/$(IMG_NAME).img bs=512 seek=1
@truncate -s 1440k $(BUILD_DIR)/$(IMG_NAME).img
@hexdump -C $(BUILD_DIR)/$(IMG_NAME).img
@objdump -b binary -m i8086 -M intel -D build/dev.img
clean:
rm -f $(BUILD_DIR)/bootloader.bin $(BUILD_DIR)/kernel.bin
$(BUILD_DIR)/%.bin: $(SRC_DIR)/%.asm
nasm $^ -f bin -o $@
启动时,显示“Booting SSoS...”消息,但内核显示“Hello from kernel!”消息不是。
请阅读上面的重要说明。 我怀疑问题可能出在引导加载程序中的 read_disk 函数中。 尽管没有显示错误消息,但 qemu-system-i386 命令似乎不寻常。 _sectors_per_track 和驱动器编号(read_disk 函数中的寄存器 dl)等常量似乎是准确的。然而,即使我尝试了不同的磁盘读取方法,问题仍然出现。
我知道这是一个复杂且低级的主题,需要对操作系统有深入的了解。这就是为什么我感谢所有试图帮助我的人。非常感谢!
我尝试了不同的读取软盘的方法(例如直接使用 CHS 寻址读取),但都不起作用。我还仔细检查了我的常量并查看了图像的可拆卸性,但一切似乎都是正确的。我查看了其他代码,但我的代码似乎(几乎除了它不是那么完美)相同。
我在
%include "kernel.asm"
之前添加了 jmp main
到 bootloader.asm。
然后 nasm 打印错误消息:
kernel.asm:1: error: program origin redefined
bootloader.asm:23: error: label `main' inconsistently redefined
kernel.asm:8: info: label `main' originally defined here
bootloader.asm:52: error: label `puts' inconsistently redefined
kernel.asm:15: info: label `puts' originally defined here
bootloader.asm:53: error: label `puts.begin' inconsistently redefined
kernel.asm:17: info: label `puts.begin' originally defined here
bootloader.asm:60: error: label `puts.done' inconsistently redefined
kernel.asm:23: info: label `puts.done' originally defined here
所以我更改了 kernel.asm 中的标签
jmp main1
_message: db 'Hello from kernel!', 0
main1:
mov si, _message
call puts1
cli
hlt
puts1:
mov ah, 0x0E
.begin1:
lodsb
cmp al, 0
je .done1
int 10h
jmp .begin1
.done1:
ret
并删除了线条
[org 0x7E00]
[bits 16]
结果: