;pm.inc文件定义
;----------------------------------------------------------------------------; 描述符类型值说明; 其中:
; DA_ : Descriptor Attribute
; D : 数据段
; C : 代码段
; S : 系统段
; R : 只读
; RW : 读写
; A : 已访问
; 其它 : 可按照字面意思理解
;----------------------------------------------------------------------------
DA_32 EQU 4000h ; 32 位段
DA_DPL0 EQU 00h ; DPL = 0
DA_DPL1 EQU 20h ; DPL = 1
DA_DPL2 EQU 40h ; DPL = 2
DA_DPL3 EQU 60h ; DPL = 3
;----------------------------------------------------------------------------
; 存储段描述符类型值说明
;----------------------------------------------------------------------------
DA_DR EQU 90h ; 存在的只读数据段类型值
DA_DRW EQU 92h ; 存在的可读写数据段属性值
DA_DRWA EQU 93h ; 存在的已访问可读写数据段类型值
DA_C EQU 98h ; 存在的只执行代码段属性值
DA_CR EQU 9Ah ; 存在的可执行可读代码段属性值
DA_CCO EQU 9Ch ; 存在的只执行一致代码段属性值
DA_CCOR EQU 9Eh ; 存在的可执行可读一致代码段属性值
;----------------------------------------------------------------------------
; 系统段描述符类型值说明
;----------------------------------------------------------------------------
DA_LDT EQU 82h ; 局部描述符表段类型值
DA_TaskGate EQU 85h ; 任务门类型值
DA_386TSS EQU 89h ; 可用 386 任务状态段类型值
DA_386CGate EQU 8Ch ; 386 调用门类型值
DA_386IGate EQU 8Eh ; 386 中断门类型值
DA_386TGate EQU 8Fh ; 386 陷阱门类型值
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
; 选择子类型值说明
; 其中:
; SA_ : Selector Attribute
SA_RPL0 EQU 0 ; ┓
SA_RPL1 EQU 1 ; ┣ RPL
SA_RPL2 EQU 2 ; ┃
SA_RPL3 EQU 3 ; ┛
SA_TIG EQU 0 ; ┓TI
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 & 0FFFFh ; 段界限 1 (2 字节)
dw %1 & 0FFFFh ; 段基址 1 (2 字节)
db (%1 >> 16) & 0FFh ; 段基址 2 (1 字节)
dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ; 属性 1 + 段界限 2 + 属性 2 (2 字节)
db (%1 >> 24) & 0FFh ; 段基址 3 (1 字节)
%endmacro ; 共 8 字节
byte7 | byte6 | byte5 | byte4 | byte3 | byte2 | byte1 | byte0 |
段基址24-31位 |
| 段基址0-23位 | 段界限0-15位 |
byte5和byte6
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
G | D/B | 0 | AVL | 段界限16-19位 | P | DPL | S | TYPE |
D/B位:
1.可执行代码描述符中,为D位,D=1,默认使用32位地址及32位或8位操作数;D=0,默认使用16位地址及16位或8位操作数。
2.数据段描述符中,为B位,B=1,段界限4GB;B=0,段界限64KB。
3.堆栈段描述符中,为B位,B=1,使用ESP;B=0,使用SP。
0位:
AVL位:保留给系统软件使用。
P位:P=1,内存中存在;P=0,内存中不存在。
DPL:特权,0-3。
S位:S=1,数据段/代码段描述符;S=0,系统段/门描述符
type:
Type值 | 数据段和代码段描述符 | 系统段和门描述符 |
0 | 只读 | <未定义> |
1 | 只读,已访问 | 可用286TSS |
2 | 读/写 | LDT |
3 | 读/写,已访问 | 忙的286TSS |
4 | 只读,向下扩展 | 286调用门 |
5 | 只读,向下扩展,已访问 | 任务门 |
6 | 读/写,向下扩展 | 286中断门 |
7 | 读/写,向下扩展,已访问 | 286陷阱门 |
8 | 只执行 | <未定义> |
9 | 只执行,已访问 | 可用386TSS |
A | 执行/读 | <未定义> |
B | 执行/读,已访问 | 忙的386TSS |
C | 只执行,一致码段 | 386调用门 |
D | 只执行,一致码段,已访问 | <未定义> |
E | 执行/读,一致码段 | 386中断门 |
F | 执行/读,一致码段,已访问 | 386陷阱门 |
;
; 门
; usage: Gate Selector, Offset, DCount, Attr
; Selector: dw
; Offset: dd
; DCount: db
; Attr: db
%macro Gate 4
dw (%2 & 0FFFFh) ; 偏移 1 (2 字节)
dw %1 ; 选择子 (2 字节)
dw (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 属性 (2 字节)
dw ((%2 >> 16) & 0FFFFh) ; 偏移 2 (2 字节)
%endmacro ; 共 8 字节
; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
%include "pm.inc"
org 07c00h
jmp label_begin
[section .gdt]
label_gdt: Descriptor 0, 0, 0
label_desc_code32: Descriptor 0, segcode32len - 1, DA_C + DA_32
label_desc_video: Descriptor 0b8000h, 0ffffh, DA_DRW
;gdt的结构如下,gdtptr和gdt结构一致
32位基地址 | 16位界限 |
gdtlen equ $ - label_gdt
gdtptr dw gdtlen - 1 ;16位界限
dd 0 ;32位基地址
selectorcode32 equ label_desc_code32 - label_gdt
selectorvideo equ label_desc_video - label_gdt
段选择子结构,TI为LDT使用。
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
段描述符索引 | TI | RPL |
[section .s16]
[bits 16]
label_begin:
mov ax, cs
mov ss, ax
mov sp, 0100h
;设置label_desc_code32段描述符的入口地址
xor eax, eax
mov ax, cs
shl eax, 4
add eax, label_seg_code32
mov word [label_desc_code32 + 2], ax
shr eax, 16
mov byte [label_desc_code32 + 4], al
mov byte [label_desc_code32 + 7], ah
;设置gdt的32位基地址
xor eax, eax
mov ax, cs
shl eax, 4
add eax, label_gdt
mov dword [gdtptr + 2], eax
lgdt [gdtptr]
cli ;关中断
;打开A20。
in al, 92h
or al, 00000010b
out 92h, al
;cr0的PE置位
mov eax, cr0
or eax, 1
mov cr0, eax
31 | 30 | 29 | 28-19 | 18 | 17 | 16 | 15-6 | 5 | 4 | 3 | 2 | 1 | 0 |
PG | CD | NW | 无 | AM | 无 | WP | 无 | NE | ET | TS | EM | MP | PE |
jmp dword selectorcode32:0
[section .s32]
[bits 32]
label_seg_code32:
mov ax, selectorvideo
mov gs, ax
mov edi, 0
mov ah, 0ch
mov al, 'p'
mov [gs:edi], ax
jmp $
segcode32len equ $ - label_seg_code32