pmtest3.asm

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

Guess you like

Origin blog.csdn.net/u012323667/article/details/79339094