assembly - 切换到保护模式后如何正确跳转到内核
问题描述
我目前正在开发一个简单的操作系统,我决定从头开始编写。在引导加载程序的第二阶段,当我切换到保护模式时,它在切换后立即卡住,并且模拟器(QEMU)重新启动。
这是引导加载程序阶段 1:
org 0x7C00
;SEGMENTS
;bootloadter stage 1: 0x0000:0x7C00
;bootloader stage 2: 0x07E0:0x0100
;public data segment: 0x08E0:0x0000
;gdt: 0x1000:0x0000
;idt: 0x1000:0x0200
;kernel: 0x2000:0x0000
init:
;sets up the temporary data segment
xor ax,ax
mov ds, ax
;set up the stack
xor ax, ax
mov ss, ax
mov sp, 0x7C00
<<save the drive number>>
;reset the drive
call drive_reset
;loads IDT but does not load the idtr until we're in protected mode
call load_idt
;loads GDT
call load_gdt
lgdt [0x9E]
call load_stage2
call _wait
jmp 0x07E0:0x0100
jmp $
load_data_segment:
<<loads the shared data segment from disk>>
ret
load_stage2:
<<loads second stage from disk>>
ret
print:
<<print function>>
boot_failure:
<<boot failure function (alerts the user and halts the system)>>
_wait:
<<wait function (wait for the user to press a key)>>
reboot:
<<reboot function>>
;loads the initial gdt table from sector 9 to 0x1000:0x0000 (512 byte)
load_gdt:
mov si, 0x00
call print
mov ah, 0x2 ;subroutine
mov al, 0x1 ;numbers of sectors to be read
mov dl, [0xAA] ;drive number
mov ch, 0 ;cylinder number
mov dh, 0 ;head number
mov cl, 9 ;start sector (the first sector has index 1)
mov bx, 0x1000 ;segment
mov es, bx
mov bx, 0x0000 ;segment offset
int 0x13 ;drive low level routines
jc process_error
call drive_reset
call process_done
ret
;loads the initial idt table from sector 10 to 0x1000:0x0200 (512 bytes)
load_idt:
mov si, 0x10
call print
mov ah, 0x2 ;subroutine
mov al, 0x4 ;numbers of sectors to be read
mov dl, [0xAA] ;drive number
mov ch, 0 ;cylinder number
mov dh, 0 ;head number
mov cl, 0xA ;start sector (the first sector has index 1)
mov bx, 0x1000 ;segment
mov es, bx
mov bx, 0x200 ;segment offset (512 bytes), right after gdt
int 0x13 ;drive low level routines
jc process_error
call drive_reset
call process_done
ret
process_done:
<<print "[DONE]">>
process_error:
<<print "[ERROR]" and halts the system>>
drive_reset:
<<drive reset function>>
drive_number: db 0
times 510-($-$$) db 0x0
dw 0xAA55
引导加载程序阶段 2:
org 0x0100
;segment 0x07E0
;offset 0x0100
init:
cli
;sets up the data segment
mov ax, 0x08E0
mov ds, ax
;sets up the stack
mov ax, 0x07E0
mov ss, ax
mov sp, 0x0100
sti
;loads the kernel
mov si, 0x63 ;loading kernel...
call print
call load_kernel
call process_done
;enable A20
checkA20:
mov si, 0x20 ;checking A20...
call print
call A20_test
cmp ax, 1
je A20_enabled_func
jmp A20_disabled_func
continue: ;return point from A20 procedures
jmp enable_protected
_wait:
mov si, 0xB7
call print
mov ah, 0
int 0x16
ret
A20_disabled_func:
<<calls enable_A20 procedure and jumps to 'continue'>>
A20_enabled_func:
<<print "ENABLED">>
print:
<<print function>>
process_done:
<<prints "[DONE]">>
process_error:
<<prints "[ERROR]" and halts the system>>
A20_test:
pushf
push ds
push es
push di
push si
cli
xor ax, ax
mov es, ax
mov di, 0x0500
mov ax, 0xffff
mov ds, ax
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 A20_test_exit
mov ax, 1
A20_test_exit:
pop si
pop di
pop es
pop ds
popf
ret
enable_A20:
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
load_kernel:
mov ah, 0x2 ;subroutine
mov al, 0x1 ;numbers of sectors to be read
mov dl, [0xAA] ;drive number
mov ch, 0 ;cylinder number
mov dh, 0 ;head number
mov cl, 21 ;start sector (the first sector has index 1)
mov bx, 0x2000 ;segment
mov es, bx
mov bx, 0x0 ;segment offset
int 0x13 ;drive low level routines
jc process_error
ret
enable_protected:
mov si, 0x43 ;switching to protected mode...
call print
call _wait
mov eax, cr0
or eax, 1
mov cr0, eax ;--------HERE IS THE PROBLEM--------
bits 32
mov ax, 0x8
mov cs, ax
jmp 0x2000
times 2560-($-$$) db 0xAE
我在 x86 架构上使用 nasm 编译器和 qemu 作为模拟器。我感谢任何读过这篇文章而没有改变主意的人:D 我希望我可以发布所有内容,但该网站说它看起来像垃圾邮件......
解决方案
推荐阅读
- javascript - 如何使用 HTML 中的弹出式机制打开未知数量的图像
- vba - 如何使用 VBA 更改图表的数据范围
- twitter-bootstrap - 透明的btn-成功
- java - 从 Fragment 中完全移除 Action Bar
- swift - Dropbox SDK 请求错误
- scala - 错误:找到:需要 AnyVal:Int,如何在 Scala 中进行自动类型转换
- javascript - Vue 方法“logout”未在实例上定义,但在渲染期间引用
- javascript - 如何在 daterangepicker 中设置自定义范围标签
- java - fillRect() 使用哪个坐标?
- angular - 下拉菜单的角度 6 自定义指令不起作用