【发布时间】:2016-02-09 18:53:22
【问题描述】:
我正在尝试制作自己的自定义操作系统,我需要一些关于我的代码的帮助。 这是我的 bootloader.asm:
[ORG 0x7c00]
start:
cli
xor ax, ax
mov ds, ax
mov ss, ax
mov es, ax
mov [BOOT_DRIVE], dl
mov bp, 0x8000
mov sp, bp
mov bx, 0x9000
mov dh, 5
mov dl, [BOOT_DRIVE]
call load_kernel
call enable_A20
call graphics_mode
lgdt [gdtr]
mov eax, cr0
or al, 1
mov cr0, eax
jmp CODE_SEG:init_pm
[bits 32]
init_pm:
mov ax, DATA_SEG
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000
mov esp, ebp
jmp 0x9000
[BITS 16]
graphics_mode:
mov ax, 0013h
int 10h
ret
load_kernel:
; load DH sectors to ES:BX from drive DL
push dx ; Store DX on stack so later we can recall
; how many sectors were request to be read ,
; even if it is altered in the meantime
mov ah , 0x02 ; BIOS read sector function
mov al , dh ; Read DH sectors
mov ch , 0x00 ; Select cylinder 0
mov dh , 0x00 ; Select head 0
mov cl , 0x02 ; Start reading from second sector ( i.e.
; after the boot sector )
int 0x13 ; BIOS interrupt
jc disk_error ; Jump if error ( i.e. carry flag set )
pop dx ; Restore DX from the stack
cmp dh , al ; if AL ( sectors read ) != DH ( sectors expected )
jne disk_error ; display error message
ret
disk_error :
mov bx , ERROR_MSG
call print_string
hlt
[bits 32]
; prints a null - terminated string pointed to by EDX
print_string :
pusha
mov edx , VIDEO_MEMORY ; Set edx to the start of vid mem.
print_string_loop :
mov al , [ ebx ] ; Store the char at EBX in AL
mov ah , WHITE_ON_BLACK ; Store the attributes in AH
cmp al , 0 ; if (al == 0) , at end of string , so
je print_string_done ; jump to done
mov [edx] , ax ; Store char and attributes at current
; character cell.
add ebx , 1 ; Increment EBX to the next char in string.
add edx , 2 ; Move to next character cell in vid mem.
jmp print_string_loop ; loop around to print the next char.
print_string_done :
popa
ret ; Return from the function
[bits 16]
; Variables
ERROR_MSG db "Error!" , 0
BOOT_DRIVE: db 0
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
%include "a20.inc"
%include "gdt.inc"
times 510-($-$$) db 0
db 0x55
db 0xAA
我用这个编译它:
nasm -f bin -o boot.bin bootloader.asm
这是kernel.c:
call_main(){main();}
void main(){}
我用这个编译它:
gcc -ffreestanding -o kernel.bin kernel.c
然后:
cat boot.bin kernel.bin > os.bin
我想知道我做错了什么,因为当我使用 QEMU 进行测试时,它不起作用。有人可以提供一些提示来改进kernel.c,这样我就不必使用 call_main() 函数了吗?
测试时我使用:
qemu-system-i386 -kernel os.bin
我的其他文件
a20.inc:
enable_A20:
call check_a20
cmp ax, 1
je enabled
call a20_bios
call check_a20
cmp ax, 1
je enabled
call a20_keyboard
call check_a20
cmp ax, 1
je enabled
call a20_fast
call check_a20
cmp ax, 1
je enabled
mov bx, [ERROR]
call print_string
enabled:
ret
check_a20:
pushf
push ds
push es
push di
push si
cli
xor ax, ax ; ax = 0
mov es, ax
not ax ; ax = 0xFFFF
mov ds, ax
mov di, 0x0500
mov si, 0x0510
mov al, byte [es:di]
push ax
mov al, byte [ds:si]
push ax
mov byte [es:di], 0x00
mov byte [ds:si], 0xFF
cmp byte [es:di], 0xFF
pop ax
mov byte [ds:si], al
pop ax
mov byte [es:di], al
mov ax, 0
je check_a20__exit
mov ax, 1
check_a20__exit:
pop si
pop di
pop es
pop ds
popf
ret
a20_bios:
mov ax, 0x2401
int 0x15
ret
a20_fast:
in al, 0x92
or al, 2
out 0x92, al
ret
[bits 32]
[section .text]
a20_keyboard:
cli
call a20wait
mov al,0xAD
out 0x64,al
call a20wait
mov al,0xD0
out 0x64,al
call a20wait2
in al,0x60
push eax
call a20wait
mov al,0xD1
out 0x64,al
call a20wait
pop eax
or al,2
out 0x60,al
call a20wait
mov al,0xAE
out 0x64,al
call a20wait
sti
ret
a20wait:
in al,0x64
test al,2
jnz a20wait
ret
a20wait2:
in al,0x64
test al,1
jz a20wait2
ret
gdt.inc:
gdt_start:
dd 0 ; null descriptor--just fill 8 bytes dd 0
gdt_code:
dw 0FFFFh ; limit low
dw 0 ; base low
db 0 ; base middle
db 10011010b ; access
db 11001111b ; granularity
db 0 ; base high
gdt_data:
dw 0FFFFh ; limit low (Same as code)
dw 0 ; base low
db 0 ; base middle
db 10010010b ; access
db 11001111b ; granularity
db 0 ; base high
end_of_gdt:
gdtr:
dw end_of_gdt - gdt_start - 1 ; limit (Size of GDT)
dd gdt_start ; base of GDT
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
【问题讨论】:
-
你应该提供一个完整的例子。例如,您的问题中没有
a20.inc和gdt.inc文件。 -
您没有设置 SS(堆栈段)。在您的 16 位代码中(在 cli 之后)
-
您可能希望看到我给出的关于 bootloaders 的答案。特别是第 1 项。您应该将 DS 设置为 0(类似于
xor ax, axmov ds, ax)。您至少需要确保 DS 设置为 0,因为您已将 ORG 设置为 0x7c00。 BIOS 不能保证在加载时设置了 SS/DS/ES。DL将启动驱动器号,物理地址 0x00007c00 将是代码执行的开始位置。 不要假设其他任何事情都是有效的或你所期望的 -
你能提供一个实际编译的bootloader.asm、gdt.inc和a20.inc吗?例如
ox90000是一个错误,应该是`0x90000(它甚至不应该编译)。 %include 指令应该在它们周围加上引号等。关键是您需要提供给我们的代码至少应该可供 nasm 使用。 a20.inc 中也缺少一些函数。 -
gcc -ffreestanding -o kernel.bin kernel.c是错误的。这不会创建平面二进制文件。它输出一个精灵对象。你的代码有很多问题,我认为你需要找到一个关于创建引导加载程序和内核的好教程。
标签: assembly x86 kernel bootloader osdev