BIOS INT 10,AH=0E 第二阶段的奇怪行为
BIOS INT 10, AH=0E odd behavior in second stage
我已经开发我的内核大约一年了,只是使用 GRUB 作为引导加载程序。但是,现在我想开始为我的内核开发引导加载程序。
尽管我很努力,但我似乎无法解决加载器第二阶段的一个奇怪问题。
生成文件:
BOOTLOADER_FOLDER := boot
KERNEL_FOLDER := kernel
BOOTLOADER_SOURCES := $(shell find $(BOOTLOADER_FOLDER) -type f -iname "*.asm")
BOOTLOADER_OBJECTS := $(subst .asm,.bin,$(BOOTLOADER_SOURCES))
BOOTLOADER_IMAGE := $(BOOTLOADER_FOLDER)/boot.img
KERNEL_SOURCES := $(shell find . -type f -iname "*.c")
KERNEL_OBJECTS := $(foreach x,$(basename $(C_SOURCES)),$(x).o)
OS_IMAGE := os.img
ALLFILES := $(BOOTLOADER_SOURCES) $(KERNEL_SOURCES)
NASM := nasm
NASM_FLAGS := -f bin
DD := dd
DD_FLAGS := bs=512
GCC := GCC
GCC_FLAGS := -g -std=gnu99 -Wall -Wextra -pedantic -Wshadow -Wpointer-arith \
-Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations \
-Wredundant-decls -Wnested-externs -Winline -Wno-long-long \
-Wconversion -Wstrict-prototypes
QEMU := qemu-system-i386
QEMU_FLAGS := -fda
all: clean compile todo run
clean:
-rm -r $(BOOTLOADER_OBJECTS) $(KERNEL_OBJECTS) $(BOOTLOADER_IMAGE) $(OS_IMAGE)
compile: $(BOOTLOADER_OBJECTS) $(KERNEL_OBJECTS)
%.bin:%.asm
@$(NASM) $(NASM_FLAGS) $< -o $@
%.o:%.c
@$(GCC) $(GCC_FLAGS) -o $@ $<
$(BOOTLOADER_IMAGE):$(BOOTLOADER_OBJECTS)
@$(foreach file,$(BOOTLOADER_OBJECTS),dd bs=512 if=$(file) >> $(BOOTLOADER_IMAGE);)
$(KERNEL_IMAGE):$(KERNEL_OBJECTS)
$(OS_IMAGE):$(BOOTLOADER_IMAGE) $(KERNEL_IMAGE)
@$(DD) $(DD_FLAGS) if=$(BOOTLOADER_IMAGE) >> $(OS_IMAGE)
run:$(OS_IMAGE)
@DISPLAY=:0 \
$(QEMU) $(QEMU_FLAGS) $(OS_IMAGE);
todo:
-@for file in $(ALLFILES:Makefile=); do fgrep -H -e TODO -e FIXME $$file; done; true
stage1.asm:
[BITS 16]
[ORG 0x7C00]
jmp 0x0:main
print_string:
lodsb
or al, al
jz .done
mov ah, 0x0E
int 0x10
jmp print_string
.done:
ret
loading_message db "Loading bootloader...", 0xD, 0x0A, 0x0
stage1_address dw 0x500
reset_disk:
mov ah, 0x0
mov dl, 0x0
int 0x13
jc reset_disk
jmp .done
.done:
ret
read_disk:
mov ah, 0x02
int 0x13
cmp ah, 0x0
jmp .done
cmp ah, 0x80
jmp .try_again
.try_again:
pusha
call reset_disk
popa
jmp read_disk
.done:
ret
main:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFF
sti
mov si, loading_message
call print_string
call reset_disk
mov al, 0x1
mov ch, 0x0
mov cl, 0x2
mov dh, 0x0
mov dl, 0x0
mov bx, stage1_address
call read_disk
jmp 0x000:stage1_address
cli
hlt
TIMES 510-($-$$) db 0
db 0x55
db 0xAA
stage2.asm:
[BITS 16]
[ORG 0x500]
jmp main
print_string:
lodsb
or al, al
jz .done
mov ah, 0x0E
int 0x10
jmp print_string
.done:
ret
loading_message db "Loading...", 0x0
main:
mov si, loading_message
call print_string
cli
hlt
我预计这只会打印 Loading...
并停止系统。但是,它会打印:☺↕Loading...
为了解决这个问题,我将 loading_message
的声明移到了 print_string
之前。令我惊讶的是,它产生了不同的输出:link
我最初的想法是字符串以某种方式被 运行 作为代码,但这是不可能的,因为我跳过了它。但是,我在字符串中添加了换行符,它似乎在 print_string
(link) 之前声明时切换视频模式 (?)
当在代码片段的位置声明时,它不输出任何内容。所以它必须以某种方式将其作为代码执行?
关于为什么会发生这种情况有什么想法吗?
(如果您想查看任何其他文件或反汇编,请随时询问!)
您的错误是 stage1_address dw 0x500
,它在内存中将其声明为数据字,但您随后继续将其用作符号。将其更改为 stage1_address equ 0x500
.
学习使用反汇编器和调试器。
我已经开发我的内核大约一年了,只是使用 GRUB 作为引导加载程序。但是,现在我想开始为我的内核开发引导加载程序。
尽管我很努力,但我似乎无法解决加载器第二阶段的一个奇怪问题。
生成文件:
BOOTLOADER_FOLDER := boot
KERNEL_FOLDER := kernel
BOOTLOADER_SOURCES := $(shell find $(BOOTLOADER_FOLDER) -type f -iname "*.asm")
BOOTLOADER_OBJECTS := $(subst .asm,.bin,$(BOOTLOADER_SOURCES))
BOOTLOADER_IMAGE := $(BOOTLOADER_FOLDER)/boot.img
KERNEL_SOURCES := $(shell find . -type f -iname "*.c")
KERNEL_OBJECTS := $(foreach x,$(basename $(C_SOURCES)),$(x).o)
OS_IMAGE := os.img
ALLFILES := $(BOOTLOADER_SOURCES) $(KERNEL_SOURCES)
NASM := nasm
NASM_FLAGS := -f bin
DD := dd
DD_FLAGS := bs=512
GCC := GCC
GCC_FLAGS := -g -std=gnu99 -Wall -Wextra -pedantic -Wshadow -Wpointer-arith \
-Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations \
-Wredundant-decls -Wnested-externs -Winline -Wno-long-long \
-Wconversion -Wstrict-prototypes
QEMU := qemu-system-i386
QEMU_FLAGS := -fda
all: clean compile todo run
clean:
-rm -r $(BOOTLOADER_OBJECTS) $(KERNEL_OBJECTS) $(BOOTLOADER_IMAGE) $(OS_IMAGE)
compile: $(BOOTLOADER_OBJECTS) $(KERNEL_OBJECTS)
%.bin:%.asm
@$(NASM) $(NASM_FLAGS) $< -o $@
%.o:%.c
@$(GCC) $(GCC_FLAGS) -o $@ $<
$(BOOTLOADER_IMAGE):$(BOOTLOADER_OBJECTS)
@$(foreach file,$(BOOTLOADER_OBJECTS),dd bs=512 if=$(file) >> $(BOOTLOADER_IMAGE);)
$(KERNEL_IMAGE):$(KERNEL_OBJECTS)
$(OS_IMAGE):$(BOOTLOADER_IMAGE) $(KERNEL_IMAGE)
@$(DD) $(DD_FLAGS) if=$(BOOTLOADER_IMAGE) >> $(OS_IMAGE)
run:$(OS_IMAGE)
@DISPLAY=:0 \
$(QEMU) $(QEMU_FLAGS) $(OS_IMAGE);
todo:
-@for file in $(ALLFILES:Makefile=); do fgrep -H -e TODO -e FIXME $$file; done; true
stage1.asm:
[BITS 16]
[ORG 0x7C00]
jmp 0x0:main
print_string:
lodsb
or al, al
jz .done
mov ah, 0x0E
int 0x10
jmp print_string
.done:
ret
loading_message db "Loading bootloader...", 0xD, 0x0A, 0x0
stage1_address dw 0x500
reset_disk:
mov ah, 0x0
mov dl, 0x0
int 0x13
jc reset_disk
jmp .done
.done:
ret
read_disk:
mov ah, 0x02
int 0x13
cmp ah, 0x0
jmp .done
cmp ah, 0x80
jmp .try_again
.try_again:
pusha
call reset_disk
popa
jmp read_disk
.done:
ret
main:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFF
sti
mov si, loading_message
call print_string
call reset_disk
mov al, 0x1
mov ch, 0x0
mov cl, 0x2
mov dh, 0x0
mov dl, 0x0
mov bx, stage1_address
call read_disk
jmp 0x000:stage1_address
cli
hlt
TIMES 510-($-$$) db 0
db 0x55
db 0xAA
stage2.asm:
[BITS 16]
[ORG 0x500]
jmp main
print_string:
lodsb
or al, al
jz .done
mov ah, 0x0E
int 0x10
jmp print_string
.done:
ret
loading_message db "Loading...", 0x0
main:
mov si, loading_message
call print_string
cli
hlt
我预计这只会打印 Loading...
并停止系统。但是,它会打印:☺↕Loading...
为了解决这个问题,我将 loading_message
的声明移到了 print_string
之前。令我惊讶的是,它产生了不同的输出:link
我最初的想法是字符串以某种方式被 运行 作为代码,但这是不可能的,因为我跳过了它。但是,我在字符串中添加了换行符,它似乎在 print_string
(link) 之前声明时切换视频模式 (?)
当在代码片段的位置声明时,它不输出任何内容。所以它必须以某种方式将其作为代码执行?
关于为什么会发生这种情况有什么想法吗?
(如果您想查看任何其他文件或反汇编,请随时询问!)
您的错误是 stage1_address dw 0x500
,它在内存中将其声明为数据字,但您随后继续将其用作符号。将其更改为 stage1_address equ 0x500
.
学习使用反汇编器和调试器。