The purpose of this code is to let us know about LDT (Local Descriptor Table), which is similar to GDT, except that the selector TI bit must be set to 1. When using it, you need to load ldtr with the lldt instruction. The lldt operand is gdt Descriptor used to describe ldt in ldt. This example just adds a code segment LABEL_CODE_A to ldt. If data segment and stack segment are added, a single task can be encapsulated in an LDT. This is the prototype of a multitasking processor
The segmentation mechanism in the protected mode.
We can see that the real mode (16-bit) has no segmentation concept, which is similar to the operation of a single-chip microcomputer without a system. However, when jumping to the protected mode, you can see that the segment is used. The jump performed by the segment mechanism is similar to the use of interrupts in the MCU to switch to another task, and there is also a regulation of the segment range. Access to addresses beyond the segment limit is prohibited. This is undoubtedly one of the segments. This kind of protection, the section attribute defines the behavior and nature of a section from various aspects, and it is still a kind of protection from a functional point of view.
;======================================
;pmtest3.asm
;编译方法:nasm pmtest3.asm -o pmtest3.bin
;======================================
%include "pm.inc"; 常量,宏 以及一些说明
;org 07c00h
org 0100h
jmp LABEL_BEGIN
[SECTION .gdt]
;GDT 段基址 段界限 属性
LABEL_GDT: Descriptor 0, 0, 0 ;空描述符
LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ; NORMAL描述符
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32;
LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C;
LABEL_DESC_DATA: Descriptor 0, DataLen-1, DA_DRW; Data
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32;
;LABEL_DESC_TEST: Descriptor 0500000h, 0ffffh, DA_DRW;
LABEL_DESC_VIDEO : Descriptor 0B8000h, 0ffffh, DA_DRW; 显存首地址
LABEL_DESC_LDT : Descriptor 0, LDTLen - 1, DA_LDT; LDT
;GDT 就是一个数组结构
GdtLen equ $-LABEL_GDT ;GDT长度
GdtPtr dw GdtLen - 1 ;GDT 界限
dd 0 ; GDT基地址
;GdtPtr也是一个数据结构 前2字节是GDT界限 后4字节是GDT基地址
;GDT 选择子
SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT
SelectorData equ LABEL_DESC_DATA - LABEL_GDT
SelectorStack equ LABEL_DESC_STACK - LABEL_GDT
;SelectorTest equ LABEL_DESC_TEST - LABEL_GDT
SelectorLDT equ LABEL_DESC_LDT - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
; END of [SECTION .gdt]
[SECTION .data1] ;数据段
ALIGN 32
[BITS 32]
LABEL_DATA:
SPValueInRealMode dw 0; 字符串
PMMessage: db "In Protect Mode now.^_^", 0; 在保护模式中显示
OffsetPMMessage equ PMMessage - $$
StrTest: db "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0;
OffsetStrTest equ StrTest - $$
DataLen equ $-LABEL_DATA
;end of[section.data1]
;全局堆栈段
[SECTION .gs]
ALIGN 32
[BITS 32]
LABEL_STACK:
times 512 db 0
TopOfStack equ $-LABEL_STACK-1
;end of [section.gs]
;这是一个16位代码段 这个程序修改了gdt中的一些值 然后执行跳转到第三个section
[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0100h
mov [LABEL_GO_BACK_TO_REAL+3], ax
mov [SPValueInRealMode],sp
;初始化16位的代码段描述符
xor eax, eax
mov ax, cs
shl eax, 4
add eax, LABEL_SEG_CODE16
mov word [LABEL_DESC_CODE16 +2], ax
shr eax, 16
mov byte [LABEL_DESC_CODE16 +4], al
mov byte [LABEL_DESC_CODE16 +7], ah
;初始化32位代码段描述符
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
; 初始化数据段描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_DATA
mov word [LABEL_DESC_DATA + 2], ax
shr eax, 16
mov byte [LABEL_DESC_DATA + 4], al
mov byte [LABEL_DESC_DATA + 7], ah
; 初始化堆栈段描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_STACK
mov word [LABEL_DESC_STACK + 2], ax
shr eax, 16
mov byte [LABEL_DESC_STACK + 4], al
mov byte [LABEL_DESC_STACK + 7], ah
;初始化LDT在GDT中的描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_LDT
mov word [LABEL_DESC_LDT + 2], ax
shr eax, 16
mov byte [LABEL_DESC_LDT + 4], al
mov byte [LABEL_DESC_LDT + 7], ah
; 初始化 LDT 中的描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_CODE_A
mov word [LABEL_LDT_DESC_CODEA + 2], ax
shr eax, 16
mov byte [LABEL_LDT_DESC_CODEA + 4], al
mov byte [LABEL_LDT_DESC_CODEA + 7], ah
;为加载GDTR作准备
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_GDT; eax <- gdt基地址
mov dword [GdtPtr + 2], eax; [GdtPtr + 2] <- gdt 基地址
;加载GDTR
lgdt [GdtPtr]
;关中断
cli
;打开地址线A20
in al, 92h
or al, 00000010b
out 92h, al
;准备切换到保护模式
mov eax, cr0
or eax, 1
mov cr0, eax
;真正进入保护模式
jmp dword SelectorCode32:0 ; 执行这句会把SelectorCode32装入CS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LABEL_REAL_ENTRY: ;从保护模式跳回到实模式就到了这里
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, [SPValueInRealMode] ;指针调到了堆栈中 返回到实模式
in al, 92h
and al, 11111101b; 关闭A20地址线
out 92h, al
sti; 开中断
mov ax, 4c00h;
int 21h; 回到dos
;end of section .s16
[SECTION .s32]
[BITS 32]
LABEL_SEG_CODE32:
mov ax, SelectorData
mov ds, ax; 数据段选择子
; mov ax, SelectorTest; 测试段选择子
; mov es, ax
mov ax, SelectorVideo; 视频段选择子
mov gs, ax
mov ax, SelectorStack
mov ss, ax; 堆栈段选择子
mov esp, TopOfStack
;下面显示一个字符串
mov ah, 0Ch; 0000黑底 1100红字
xor esi, esi
xor edi, edi
mov esi, OffsetPMMessage; 源数据偏移
mov edi, (80*10 + 10) * 2; 目的数据偏移 屏幕第10行第0列
cld ;告诉字符串向前移动
.1:
lodsb ;将字符串中的si指针所指向的一个字节装入al中
test al, al ;判断al是否为空 为空跳转到2
jz .2
mov [gs:edi], ax ;不为空显示当前字符
add edi, 2 ;edi加二
jmp .1
.2: ;当第一条字符串显示完毕
call DispReturn ;回车 换行
; Load ldt
mov ax, SelectorLDT
lldt ax
jmp SelectorLDTCodeA:0 ; 跳入局部任务
;-------------------------------------------------------------------------
DispReturn:
push eax
push ebx
mov eax, edi
mov bl, 160
div bl
and eax, 0FFh
inc eax
mov bl, 160
mul bl
mov edi, eax
pop ebx
pop eax
ret
;disreturn 结束-------------------------------------------
SegCode32Len equ $-LABEL_SEG_CODE32
;end of section .s32
;16位的代码段 由32位代码段跳入 跳出后到实模式
[SECTION .s16code]
ALIGN 32
[BITS 16]
LABEL_SEG_CODE16:
;跳回实模式
mov ax, SelectorNormal
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov eax, cr0
and al, 11111110b
mov cr0, eax
LABEL_GO_BACK_TO_REAL:
jmp 0:LABEL_REAL_ENTRY; 段地址会在程序开始处被设置为正确的值
Code16Len equ $ - LABEL_SEG_CODE16
;end of section .s16code
;LDT
[SECTION .ldt]
ALIGN 32
LABEL_LDT:
; 段基址 段界限 属性
LABEL_LDT_DESC_CODEA: Descriptor 0, CodeALen - 1, DA_C + DA_32
LDTLen equ $ - LABEL_LDT
;ldt 选择子 +SA_TIL将选择子SelectorLDTCodeA的TI位置一,用来区别
;是GDT的选择子还是LDT的选择子
SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL
; end of section .ldt
;codeA (ldt 32位代码段)
[SECTION .la]
ALIGN 32
[BITS 32]
LABEL_CODE_A:
mov ax, SelectorVideo
mov gs, ax
mov edi, (80 * 12 + 0) * 2 ;
mov ah, 0Ch
mov al, 'Z'
mov [gs:edi], ax
jmp SelectorCode16:0
CodeALen equ $ - LABEL_CODE_A
;end of section .la