本章用另一种写法解释GDT,以及进入32位模式的方法
代码解析参照:https://blog.csdn.net/jinold/article/details/86561133
; 编译方法:nasm 32mode_VGA.asm -o 32mode_VGA.img
;--------------------------------------------------------------
mov eax,cs
mov ss,eax
mov sp,0x7c00
;-------------------- GDT ---------------------
;计算GDT所在的逻辑段地址
mov eax,[cs:GdtPtr + 0x7c00 + 0x02] ;GDT的32位线性基地址
xor edx,edx ;edx设置为0
mov ebx,16
div ebx ;eax和edx被分解成16位逻辑地址
mov ds,eax ;令DS指向该段以进行操作
mov ebx,edx ;段内起始偏移地址
;创建0#描述符,它是空描述符,这是处理器的要求
mov dword [ebx + 0x00], 0x00000000
mov dword [ebx + 0x04], 0x00000000
;创建1#描述符,这是一个数据段,对应0~4GB的线性地址空间
mov dword [ebx + 0x08], 0x0000ffff ;基地址为0x000A0000,段界限为0xffff
mov dword [ebx + 0x0c], 0x00cf920A ;粒度为4KB,存储器段描述符
;创建#2描述符,保护模式下初始代码段描述符
mov dword [ebx + 0x10], 0x7c0001ff ;基地址为0x00007c00,段界限为512字节
mov dword [ebx + 0x14], 0x00409800 ;粒度为1个字节,代码段描述符
;创建#3描述符,以上代码段的别名描述符
mov dword [ebx + 0x18], 0x7c0001ff ;基地址为0x00007c00,段界限为512字节
mov dword [ebx + 0x1c], 0x00409200 ;粒度为1个字节,数据段描述符
;创建#4描述符
mov dword [ebx + 0x20], 0x7c00fffe ;基地址为0x00007c00,段界限为0xfffe
mov dword [ebx + 0x24], 0x00cf9600
;初始化描述符表寄存器GDTR
mov word [cs: GdtPtr + 0x7c00], 39 ;描述符表的界限
lgdt [cs: GdtPtr + 0x7c00]
;--------------------以下设置显示模式(VGA) 开始 ---------------------
;INT 10H
;功能号:00H
;功能:设置显示模式
;入口参数:AH=00H
; AL=显示模式
;显示模式列表:
;显示模式 显示模式属性
; 00H 40×25 16色 文本
; 01H 40×25 16色 文本
; 02H 80×25 16色 文本
; 04H 320×200 4色
; 05H 320×200 4色
; 06H 640×200 2色
; 07H 80×25 2色 文本
; 08H 160×200 16色
; 09H 320×200 16色
; 0AH 640×200 4色
; 0BH 保留
; 0CH 保留
; 0DH 320×200 16色
; 0EH 640×200 16色
; 0FH 640×350 2色(单色)
; 10H 640×350 4色
; 11H 640×480 2色
; 12H 640×480 16色
; 13H 320×200 256色
MOV AH,0x00
MOV AL,0x13 ; VGA 320x200x8bit Color
INT 0x10
;--------------------以上设置显示模式(VGA)结束 ---------------------
;PIC的初始化,关闭PIC0(主PIC)和PIC1(从PIC), 必须是在cli指令之前完成
;PIC是中断控制寄存器,我们通常接触的PC机有主PIC和从PIC
MOV AL,0xff
OUT 0x21,AL ;pic0(主PIC)的端口
NOP ;太快了,可能出问题,所以在这儿等会儿
OUT 0xa1,AL ;pic1(从PIC)的端口
;--------------------VGA 320x200x8bit Color ---------------------
cli ; 禁用可屏蔽中断
mov eax,cr0 ; cr0是80386CPU中的控制寄存器
or eax,1 ; 第0位,即PE位,用来控制是否进入保护模式(是/否:1/0)
mov cr0,eax ; 设置PE位
;以下进入保护模式... ...
jmp dword 0x0010:flush ;16位的描述符选择子:32位偏移
[bits 32]
flush:
mov ax,1*8 ;加载1#描述符的选择子,即数据段(0..4GB)选择子,
mov ds,ax ;设置ds, es, fs, gs, ss的段地址为0x000a0000
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
mov ebx,0x000a0000 ; 暂时不用段地址,直接指向VGA端口
printScreen:
;输出颜色到屏幕
MOV AL,0ah ;绿色
MOV ECX,ebx
MOV [ECX],AL
inc ebx
loop printScreen
hlt
GdtPtr dw 0
dd 0x00007e00 ;GDT的物理地址
;-------------------------------------------------------------------------------
times 510-($-$$) db 0
db 0x55,0xaa
[bits 32] 部分代码调整下
不直接指定0x000a0000,而是在GDT(1#描述符)获取0x000a0000。
[bits 32]
flush:
mov ax, 1*8 ;加载1#描述符的选择子,即数据段(0..4GB)选择子,
mov ds, ax ;设置ds, es, fs, gs, ss的段地址为0x000a0000
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov edi, 0
printScreen:
;输出颜色到屏幕
mov AL, 0ah ;绿色
mov [gs:edi], AL ;0x000a0000:0开始
inc edi
loop printScreen
hlt
GdtPtr dw 0
dd 0x00007e00 ;GDT的物理地址