按照于渊书里的例子改了一下,结果发现跳转不到保护模式:
;------head.bin
org 0100h
BaseAddress equ 0
jmp START
%include "segment.inc"
BaseOfLoader equ 09000h ; Head.bin被加载的地址
BasePhyAddr equ BaseOfLoader*10h
;-----设置代码段、数据段描述符
LABEL_GDT: Descriptor 0, 0, 0 ; 第一个GDT不使用,必须为0
LABEL_DESC_CR: Descriptor 0, 0fffffh, PST_C_R | F_G | F_D ; 只读,4GB的32位代码段
LABEL_DESC_DRW: Descriptor 0, 0fffffh, PST_D_W | F_G | F_D ; 可写,4GB的32位数据段
LABEL_DESC_VEDIO: Descriptor 0B800h, 0fffffh, PST_D_W | F_G | F_D ; 可写,4GB的32位数据段
;-----设置lgdt操作数:6字节,低2字节段界限,高4字节段基地址
GdtLen equ $ - LABEL_GDT
GdtPtr dw GdtLen - 1
dd BasePhyAddr + LABEL_GDT ; 此处为物理地址
;-----设置段选择符(其实就是Descriptor在GDT表中的序号)
Selector_C equ LABEL_DESC_CR-LABEL_GDT
Selector_D equ LABEL_DESC_DRW-LABEL_GDT
Selector_V equ LABEL_DESC_VEDIO-LABEL_GDT
START:
mov ax, 0B800h
mov gs, ax
mov ah, 0Fh ; 0000: 黑底 1111: 白字
mov al, 'J'
mov bx, ax
mov [gs:((80 * 0 + 20) * 2)], bx ; 屏幕第 0 行, 第 39 列。
;-----Initialize hardware environment----
xor eax, eax
lgdt [GdtPtr] ; 此时程序位于GDT表中(因为GdtPtr的基地址就为GDT的地址)
cli ; 关中断
in al,0x92 ; 找到A20 I/O端口
or al,00000010b ; 0x92快速A20 GATE格式如下:
; Bit 0 – 设成1来快速重设 (用于返回实模式)
; Bit 1 - 0: 关闭 A20; 1:开启 A20
; Bit 2 –制造商定义
; Bit 3 –电源口令(CMOS bytes 0x38-0x3f或0x36-0x3f). 0: 可访问 , 1:不可访问
; Bits 4-5 -制造商定义
; Bits 6-7 - 00: HDD 活动LED 灭;其他 "亮"
out 0x92,al ; 设置A20引脚
xor eax, eax
mov eax, cr0 ; 设置CR0的PE位为1
or eax, 1
mov cr0, eax
jmp dword Selector_C:(BaseOfLoader*10h + LABEL_PM_START) ; 表示跳转到代码段的LABEL_PM_START处
; jmp LABEL_PM_START:0
LABEL_PM_START:
mov ax, Selector_V
mov gs, ax
mov ah, 0Ch ; 0000: 黑底 1111: 白字
mov al, 'M'
mov [gs:((80 * 7 + 40) * 2)], ax ; 屏幕第 0 行, 第 39 列。
jmp $ ; 到此停住
用BOCHS调试的时候发现就是无法跳转到保护模式,不会显示字符‘M’,也不会将光标停留住。
已经困扰我很久了,跪求大神解答啊啊啊啊啊啊啊啊啊啊啊啊!
------解决方案--------------------------------------------------------
;代码清单11-1
;文件名:c11_mbr.asm
;文件说明:硬盘主引导扇区代码
;创建日期:2011-5-16 19:54
;设置堆栈段和栈指针
mov ax,cs
mov ss,ax
mov sp,0x7c00
;计算GDT所在的逻辑段地址
mov ax,[cs:gdt_base+0x7c00] ;低16位
mov dx,[cs:gdt_base+0x7c00+0x02] ;高16位