【发布时间】:2020-06-08 06:04:33
【问题描述】:
我正在开发一个玩具操作系统,从保护模式切换回实模式时出现问题。我已成功切换到保护模式,调用将文本写入 [0xb8000] 视频内存的内核,返回给调用者并(可能)切换回实模式。我正在尝试使用实模式下的 bios 中断,因此我不必编写自己的设备驱动程序。
然而,切换回实模式后似乎不会执行中断。 它们不会像在保护模式下那样使系统崩溃,所以我想我是在实模式下。
minrep.asm(引导加载程序)
boot.header:
[BITS 16]
[ORG 0x7c00]
mov ax, cs
mov ds, ax
xor ax, ax
mov ds, ax
cli
mov ss, ax
mov sp, 0x7c00
sti
call main
jmp $
disk.read_sectors:
reset:
xor ax,ax
int 0x13
jc reset
floppy:
xor bx,bx
mov ah,0x2
mov al, [esp+6]
mov cx,[esp+4]
mov dh,0x0
mov dl, 0x80
mov bx, ds
mov es, bx
mov bx, [esp+2]
int 0x13
jc error
mov ax, 0
ret
error:
mov ax, 1
ret
main:
push word 16 ; 16 sectors for stage2
push word 2 ; starts at sector 2
push word 0x1000 ; into 0x1000 memory buffer
call disk.read_sectors
pop bx
pop bx
pop bx
jmp 0000:0x1000
mov ax, 0
ret
footer:
times 510-($-boot.header) db 0
dw 0xAA55
minrep_st2.asm(stage2,进入prot并返回real)
[BITS 16]
[ORG 0x1000]
stage2.header:
mov ax, cs
mov ds, ax
jmp stage2.main
stage2.main:
mov al, 'B'
mov ah, 0x0E
mov bh, 0x00
mov bl, 0x07
int 0x10
call switch_to_protected
switch_to_protected:
[ bits 16 ]
cli
switch_to_pm:
lgdt [ gdt_descriptor ]
mov eax , cr0
or eax , 0x1
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
sti
[BITS 32]
switch_to_real:
mov [0xb8000], byte 'D'
[BITS 32]
cli
mov eax, cr0
and eax, 0x7FFFFFFF ; clear PG bit
mov cr0, eax
xor eax,eax ; A convenient zero
mov cr3,eax ; Flush the TLB
mov eax, cr0
and eax, 0xFFFFFFFE ; clear PE bit
mov cr0, eax
lidt [idtr]
jmp 0:continue
[BITS 16]
continue:
sti
mov al, 'C'
mov ah, 0x0E
mov bh, 0x00
mov bl, 0x07
int 0x10
hlt
GDT:
idtr:
dw 0x3ff
dd 0
gdt_start:
gdt_null:
dd 0x0 ;
dd 0x0
gdt_code:
dw 0xffff
dw 0x0
db 0x0
db 10011010b ; 1 st flags , type flags
db 11001111b ; 2 nd flags , Limit ( bits 16 -19)
db 0x0
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b ; 1 st flags , type flags
db 11001111b ; 2 nd flags , Limit ( bits 16 -19)
db 0x0
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
stage2.footer:
times 8192-($-stage2.header) db 0
如何编译:
nasm.bat minrep.asm -o disk_p1.bin
nasm minrep_st2.asm -o disk_p2.bin
copy /b disk_pt1.bin + disk_pt2.bin disk.img
call qemu disk.img
编辑:
如果我这样做只是为了得到保护,那么在实模式下移动到 0xb800 会清除第一个字符但不能正确打印它(空白字符而不是字节 'Z')
[ bits 16 ]
cli
switch_to_pm:
lgdt [ gdt_descriptor ]
mov eax , cr0
or eax , 0x1
mov cr0 , eax
jmp CODE_SEG:init_pm
[ bits 32 ]
init_pm:
sti 后的 print char 'Z' 继续:
mov ax, 0xb800;
mov es, ax;
mov [es:0000], byte 'Z'
【问题讨论】:
-
评论不用于扩展讨论;这个对话是moved to chat。
标签: assembly kernel nasm x86-16 bootloader