【OS】11 – 实模式到保护模式(中)【从16位代码段进入到32位代码段,从实模式进入到保护模式】
保护模式的编程
从16位代码段进入到32位代码段,从实模式进入到保护模式;
inc.asm
; Segment Attribute
DA_32 equ 0x4000
DA_DR equ 0x90
DA_DRW equ 0x92
DA_DRWA equ 0x93
DA_C equ 0x98
DA_CR equ 0x9A
DA_CCO equ 0x9C
DA_CCOR equ 0x9E
; Selector Attribute
SA_RPL0 equ 0
SA_RPL1 equ 1
SA_RPL2 equ 2
SA_RPL3 equ 3
SA_TIG equ 0
SA_TIL equ 4
; 描述符
; usage: Descriptor Base, Limit, Attr
; Base: dd
; Limit: dd (low 20 bits available)
; Attr: dw (lower 4 bits of higher byte are always 0)
%macro Descriptor 3 ; 段基址, 段界限, 段属性
dw %2 & 0xFFFF ; 段界限1
dw %1 & 0xFFFF ; 段基址1
db (%1 >> 16) & 0xFF ; 段基址2
dw ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 属性1 + 段界限2 + 属性2
db (%1 >> 24) & 0xFF ; 段基址3
%endmacro ; 共 8 字节
loader.asm
%include "inc.asm"
org 0x9000
jmp CODE16_SEGMENT
[section .gdt]
; GDT definition
;第0项用来占位, 定义: 段基址, 段界限, 段属性;
GDT_ENTRY : Descriptor 0, 0, 0
CODE32_DESC : Descriptor 0, Code32SegLen - 1, DA_C + DA_32
; GDT en;
GdtLen equ $ - GDT_ENTRY
GdtPtr:
dw GdtLen - 1 ;2字节的偏移
dd 0 ;4字节的起始地址
; GDT Selector
; Code32Selector 用于访问CODE32_DESC里的成员
; CODE32_DESC 位于gdt表中的第1位。 "0x0001 << 3" 是选择子当中的段描述符索引
Code32Selector equ (0x0001 << 3) + SA_TIG + SA_RPL0
; end of [section .gdt]
[section .s16]
[bits 16]
CODE16_SEGMENT:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7c00
; initialize GDT for 32 bits code segment
mov eax, 0
mov ax, cs
shl eax, 4
add eax, CODE32_SEGMENT ;得到32位代码段的物理地址,也就是CODE32_DESC需要的段基址
;初始化段描述符的值,把基地址放到对应的内存地址处
mov word [CODE32_DESC + 2], ax ; 前2个字节放到偏移为2字节地址处,低16位放到段基址
shr eax, 16
mov byte [CODE32_DESC + 4], al ; 第3个字节放到偏移为4字节地址处,8位
mov byte [CODE32_DESC + 7], ah ; 第4个字节放到偏移为7字节地址处,8位
; initialize GDT pointer struct
mov eax, 0
mov ax, ds
shl eax, 4
add eax, GDT_ENTRY
mov dword [GdtPtr + 2], eax;地址放到结构体GdtPtr的4字节处
; 1. load GDT
lgdt [GdtPtr]
; 2. close interrupt
cli
; 3. open A20地址线
in al, 0x92
or al, 00000010b
out 0x92, al
; 4. enter protect mode 把寄存器对应的bit置为1
mov eax, cr0
or eax, 0x01
mov cr0, eax ; 进入32位的模式
; 5. jump to 32 bits code
; 刷新流水线,强制将之后的代码按照32位的方式来处理后续代码,这里必须强制跳转
jmp dword Code32Selector : 0
[section .s32]
[bits 32]
CODE32_SEGMENT:
mov eax, 0;打断点验证
jmp CODE32_SEGMENT
Code32SegLen equ $ - CODE32_SEGMENT ;指定32位代码段的段界限
调试验证:
反汇编,确定地址,下断点调试