本文主要是介绍自制OS3-1到3-16==保护模式(GDT、选择子、寄存器)、多任务由来(LDT)、内核态和用户态ring0和ring3、特权级切换(TSS-CPL-DPL-RPL-门)、时钟中断、保护模式中断编程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
保护模式
前面我们可以任意的访问内存,寄存器在段式内存中,其实没有界限,操作系统和用户程序实际上做不到内存的隔离。
用户程序所访问的逻辑地址,实际上就是物理地址。
用户程序可以随意修改段基址(mbr es=7c00 loader=b800)
保护模式将16位寄存器扩展到了32位
向下兼容,原先得段+偏移这种编程寻址结构,不破坏这种结构。
INTEL专门设计了一个数据结构来描述这个寻址,全局描述符表GDT
由于这个一个复杂的数据结构,放在内存中
在这个GDT中有一个叫做段描述符的,用一个叫做GDTR的寄存器指向他。
将一个数据的访问分成三个部分,CPU要把他拼起来,这个过程叫做保护模式下的寻址。
可以看下INTEL 80386的手册。
验证 寄存器
以保护模式的方式访问物理地址 0B8000h
;----------------------------------------------------------------------------
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_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
;----------------------------------------------------------------------------
%macro Descriptor 3dw %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 ;org 07c00hjmp LABEL_BEGIN[SECTION .gdt]
; GDT
; 段基址, 段界限 , 属性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32 ; 非一致代码段, 32
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址
; GDT 结束GdtLen equ $ - LABEL_GDT ; GDT长度
GdtPtr dw GdtLen - 1 ; GDT界限dd 0 ; GDT基地址; GDT 选择子
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
; END of [SECTION .gdt][SECTION .s16]
[BITS 16]
LABEL_BEGIN:mov ax, csmov ds, axmov es, axmov ss, axmov sp, 0100h; 初始化 32 位代码段描述符xor eax, eax mov ax, csshl eax, 4add eax, LABEL_SEG_CODE32mov word [LABEL_DESC_CODE32 + 2], axshr eax, 16mov byte [LABEL_DESC_CODE32 + 4], almov byte [LABEL_DESC_CODE32 + 7], ah; 为加载 GDTR 作准备xor eax, eaxmov ax, dsshl eax, 4add eax, LABEL_GDT ; eax <- gdt 基地址mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址; 加载 GDTRlgdt [GdtPtr]; 关中断cli; 打开地址线A20in al, 92hor al, 00000010bout 92h, al; 准备切换到保护模式mov eax, cr0or eax, 1mov cr0, eax; 真正进入保护模式jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0 处
; END of [SECTION .s16][SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS 32]LABEL_SEG_CODE32:mov ax, SelectorVideomov gs, ax ; 视频段选择子(目的)mov edi, (80 * 3 + 0) * 2 ; 屏幕第 3 行, 第 0 列。mov ah, 0Ch ; 0000: 黑底 1100: 红字mov al, 'D'mov [gs:edi], ax; 到此停止jmp $SegCode32Len equ $ - LABEL_SEG_CODE32
; END of [SECTION .s32]
times 361 db 0
dw 0xaa55
编写上述p1.asm,编译成p1.bin,通过dd写入虚拟磁盘,然后用虚拟机加载虚拟磁盘
E:\>nasm p1.asm -o p1.bin
E:\>dd if=p1.bin of=dingst.vhd bs=512 count=1
rawwrite dd for windows version 0.5.
Written by John Newbigin <jn@it.swin.edu.au>
This program is covered by the GPL. See copying.txt for details
1+0 records in
1+0 records out
从上述代码可以发现,我们不是直接使用的物理地址0B8000h,用的另外一种方式将想要显示的数据放到了 0B8000h
16位实模式下:物理地址=逻辑地址=段首址+偏移
32位保护模式下:不是简单的16位的增强,特指CPU可以使用32位状态下的保护模式
想让每一个应用程序都可以独立的享有4G的空间。但是只有32位的地址线,理论下之后2的32次方也就是4G的物理地址,32位CPU有32根地址线,物理地址=2^32=4294967296=4GB,但是在实际应用中,PCI内存范围占用了大量的地址范围——接近750MB,导致最后系统物理地址只有3.25GB左右。所以怎么能够做到让每一个应用程序都可以独立的享有4G的空间?
1、必须要有硬件的支持 这个硬件叫做MMU。将MMU映射到实际的物理地址中。
2、编址的观念必须变化
由此应用程序就不用考虑使用哪些物理地址,都拥有4G的可用虚拟地址 ,所有程序都有自己的段0-4G,这就是线性地址。但是为了使用好地址翻译0-4G线性,我们必须规定,你的所有的内存的访问:
1、在定义程序的段、段界限,要附加段的特权、段的类型,防止内存的误操作
2、cs 、ds这些所谓的在16位实模式下的段寄存器,不再是段基址的概念,而要变成段选择子,而变成段选择子,就放弃了直接访问物理内存的能力。
只有段选择子和段描述符结合,才能真怎访问物理地址,这是硬件赋予的保护能力。
应用程序只需要调用MMU,实际的物理地址由MMU自动分配。
所以我们需要一个全新的数据结构去管理这个内容→GDT
GDT由GDTR管理。
OS管理计算机的硬件软件,他可以做任何事情。但是应用程序绝对不可以,我们希望应用程序只能访问自己的数据,及时这个程序要跳转,那么也只能在自己的各个代码段中进行跳转。
如果我们的OS是一个多用户多任务的系统,那么我们使用实模式不设防的内存访问,很有可能造成程序崩溃,因为可能这个程序使用的地址被另一个程序更改了。
=======================================================================
内存的访问
为了能让程序在内存中自由定位那么我们设计了段,但是在保护模式下,对每一个段,必须登记。登记的段的信息,称为段的描述字descriptor。段的描述字规定为8个字节(64位),所有允许的描述字构成了全局描述符表。GDT=global descriptor table,为整个软硬件服务,所以必须在进入保护模式之前定义它。先有工商局,工商局先有商店门类规范,你才能去申请开店。
段的描述字/符组成如图:
查询因特尔的手册
在保护模式下,我们可以通过GDT来约束应用程序访问内存的权限。
在访问之前,必须先在GDT中定义你要访问的段。描述符不是用户程序自己建立的,而是在加载的时候,由OS根据你的程序结构建立。用户程序无法建立和修改GDT。
实现保护模式流程:
首先初始化GDT(填申请表并提交到特定地址)
第二将内存中的表,通过LGDT加载(OS去特定地址审核填的表)
关闭A20地址线
打开CR0寄存器(段寻址切换到段选择子)
进入保护模式
GDT翻译后,线性地址经过MMU变成实际的物理地址
保护模式实战:
使用虚拟机启动DOS622操作系统,用于学习保护模式。
GDT 选择子 寄存器
选择刚才创建的ISO文件,即可发现文件出现在了DOS622的R盘中。
1、准备GDT
2、用LGDT加载GDT
3、打开A20
4、打开CR0寄存器
5、jmp跳入保护模式的地址
DA_32 EQU 4000h;32位
DA_C EQU 98h; 只执行代码段的属性
DA_DRW EQU 92h;可读写的数据段
DA_DRWA EQU 93h;存在的已访问的可读写的%macro Descriptor 3dw %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
%endmacroorg 0100h ;因为我们dos下调试程序,那么0100是可用区域jmp PM_BEGIN ;跳入到标号为PM_BEGIN的代码段开始推进[SECTION .gdt]
;GDT
; 段基址,段界限,属性
PM_GDT: Descriptor 0, 0, 0
PM_DESC_CODE32: Descriptor 0, SegCode32Len -1,DA_C+DA_32
PM_DESC_DATA: Descriptor 0, DATALen-1, DA_DRW
PM_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32
PM_DESC_TEST: Descriptor 0200000h,0ffffh, DA_DRW
PM_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW
;end of definiton gdt
GdtLen equ $ - PM_GDT
GdtPtr dw GdtLen - 1
dd 0 ; GDT 基地址;GDT 选择子
SelectoerCode32 equ PM_DESC_CODE32 - PM_GDT
SelectoerDATA equ PM_DESC_DATA - PM_GDT
SelectoerSTACK equ PM_DESC_STACK - PM_GDT
SelectoerTEST equ PM_DESC_TEST - PM_GDT
SelectoerVideo equ PM_DESC_VIDEO - PM_GDT
;END of [SECTION .gdt][SECTION .data1]
ALIGN 32
[BITS 32]
PM_DATA:
PMMessage : db "Potect Mode", 0;
OffsetPMessage equ PMMessage - $$
DATALen equ $- PM_DATA
;END of [SECTION .data];全局的堆栈段
[SECTION .gs]
ALIGN 32
[BITS 32]
PM_STACK:times 512 db 0
TopOfStack equ $ - PM_STACK -1
;END of STACK [SECTION .s16]
[BITS 16]
PM_BEGIN:mov ax,csmov ds,axmov es,axmov ss,axmov sp,0100h;初始化32位的代码段xor eax,eaxmov ax,csshl eax,4add eax,PM_SEG_CODE32mov word[PM_DESC_CODE32+2],axshr eax,16mov byte [PM_DESC_CODE32+4],almov byte [PM_DESC_CODE32+7],ah;初始化32位的数据段xor eax,eaxmov ax,dsshl eax,4add eax,PM_DATAmov word[PM_DESC_DATA+2],axshr eax,16mov byte [PM_DESC_DATA+4],almov byte [PM_DESC_DATA+7],ah;初始化32位的stack段xor eax,eaxmov ax,dsshl eax,4add eax,PM_STACKmov word[PM_DESC_STACK+2],axshr eax,16mov byte [PM_DESC_STACK+4],almov byte [PM_DESC_STACK+7],ah;加载GDTRxor eax,eaxmov ax,dsshl eax,4add eax,PM_GDTmov dword [GdtPtr +2 ],eaxlgdt [GdtPtr];A20cliin al,92hor al,00000010bout 92h,al;切换到保护模式mov eax,cr0or eax,1mov cr0,eaxjmp dword SelectoerCode32:0[SECTION .s32] ;32位的代码段
[BITS 32]
PM_SEG_CODE32 :mov ax,SelectoerDATA ;通过数据段的选择子放入ds寄存器,就可以用段+偏移进行寻址mov ds,axmov ax,SelectoerTEST ;通过测试段的选择子放入es寄存器,就可以用段+偏移进行寻址mov es,axmov ax,SelectoerVideomov gs,axmov ax,SelectoerSTACKmov ss,axmov esp,TopOfStackmov ah,0Chxor esi,esixor edi,edimov esi,OffsetPMessagemov edi,(80*10 +0) *2cld.1:lodsbtest al,aljz .2mov [gs:edi],axadd edi,2jmp .1.2: ;显示完毕;测试段的寻址mov ax, 'A'mov [es:0],axmov ax,SelectoerVideomov gs,ax mov edi,(80*15 +0) *2mov ah,0Chmov al,[es:0]mov [gs:edi],axjmp $SegCode32Len equ $ - PM_SEG_CODE32
nasm pm.asm -o pm.exe
生成ISO文件后挂载到DOS622
然后执行
从上面可知已经突破BIOS 1M的寻址,实现了之前MBR+LOADER的相同功能,只是使用的不再是实模式,而是使用的保护模式了。
多任务的由来:LDT=>GDT
LDT局部描述符表 TSS
DA_32 EQU 4000h;32位
DA_C EQU 98h; 只执行代码段的属性
DA_DRW EQU 92h;可读写的数据段
DA_DRWA EQU 93h;存在的已访问的可读写的
DA_LDT EQU 82h;省局SA_TIL EQU 4 ;具体的任务%macro Descriptor 3dw %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
%endmacroorg 0100h ;因为我们dos下调试程序,那么0100是可用区域jmp PM_BEGIN ;跳入到标号为PM_BEGIN的代码段开始推进[SECTION .gdt]
;GDT
; 段基址,段界限,属性
PM_GDT: Descriptor 0, 0, 0
PM_DESC_CODE32: Descriptor 0, SegCode32Len -1,DA_C+DA_32
PM_DESC_DATA: Descriptor 0, DATALen-1, DA_DRW
PM_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32
PM_DESC_TEST: Descriptor 0200000h,0ffffh, DA_DRW
PM_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRWLABEL_DESC_LDT: Descriptor 0, LDTLen -1, DA_LDT
;end of definiton gdt
GdtLen equ $ - PM_GDT
GdtPtr dw GdtLen - 1
dd 0 ; GDT 基地址;GDT 选择子
SelectoerCode32 equ PM_DESC_CODE32 - PM_GDT
SelectoerDATA equ PM_DESC_DATA - PM_GDT
SelectoerSTACK equ PM_DESC_STACK - PM_GDT
SelectoerTEST equ PM_DESC_TEST - PM_GDT
SelectoerVideo equ PM_DESC_VIDEO - PM_GDT
SelectoerLDT equ LABEL_DESC_LDT - PM_GDT
;END of [SECTION .gdt][SECTION .data1]
ALIGN 32
[BITS 32]
PM_DATA:
PMMessage : db "Potect Mode", 0;
OffsetPMessage equ PMMessage - $$
DATALen equ $- PM_DATA
;END of [SECTION .data];全局的堆栈段
[SECTION .gs]
ALIGN 32
[BITS 32]
PM_STACK:times 512 db 0
TopOfStack equ $ - PM_STACK -1
;END of STACK [SECTION .s16]
[BITS 16]
PM_BEGIN:mov ax,csmov ds,axmov es,axmov ss,axmov sp,0100h;初始化32位的代码段xor eax,eaxmov ax,csshl eax,4add eax,PM_SEG_CODE32mov word[PM_DESC_CODE32+2],axshr eax,16mov byte [PM_DESC_CODE32+4],almov byte [PM_DESC_CODE32+7],ah;初始化32位的数据段xor eax,eaxmov ax,dsshl eax,4add eax,PM_DATAmov word[PM_DESC_DATA+2],axshr eax,16mov byte [PM_DESC_DATA+4],almov byte [PM_DESC_DATA+7],ah;初始化32位的stack段xor eax,eaxmov ax,dsshl eax,4add eax,PM_STACKmov word[PM_DESC_STACK+2],axshr eax,16mov byte [PM_DESC_STACK+4],almov byte [PM_DESC_STACK+7],ah;初始化32位的LDT,得把省局注册到全国xor eax,eaxmov ax,dsshl eax,4add eax,LABEL_LDT ;//to do mov word[LABEL_DESC_LDT+2],axshr eax,16mov byte [LABEL_DESC_LDT+4],almov byte [LABEL_DESC_LDT+7],ah;根据GDT,把LDT管理的具体公司初始化,得把省局注册到全国xor eax,eaxmov ax,dsshl eax,4add eax, LABEL_CODE_A ;//to do mov word[LABEL_LDT_DESC_CODEA+2],axshr eax,16mov byte [LABEL_LDT_DESC_CODEA +4],almov byte [LABEL_LDT_DESC_CODEA +7],ah;加载GDTRxor eax,eaxmov ax,dsshl eax,4add eax,PM_GDTmov dword [GdtPtr +2 ],eaxlgdt [GdtPtr];A20cliin al,92hor al,00000010bout 92h,al;切换到保护模式mov eax,cr0or eax,1mov cr0,eaxjmp dword SelectoerCode32:0[SECTION .s32] ;32位的代码段
[BITS 32]
PM_SEG_CODE32 :mov ax,SelectoerDATA ;通过数据段的选择子放入ds寄存器,就可以用段+偏移进行寻址mov ds,axmov ax,SelectoerTEST ;通过测试段的选择子放入es寄存器,就可以用段+偏移进行寻址mov es,axmov ax,SelectoerVideomov gs,axmov ax,SelectoerSTACKmov ss,axmov esp,TopOfStackmov ah,0Chxor esi,esixor edi,edimov esi,OffsetPMessagemov edi,(80*10 +0) *2cld.1:lodsbtest al,aljz .2mov [gs:edi],axadd edi,2jmp .1.2: ;显示完毕;Load LDTmov ax,SelectoerLDT ; SelectoerLDT=> GDTlldt axjmp SelectoerLDTCodeA:0SegCode32Len equ $ - PM_SEG_CODE32;LDT
[SECTION .ldt]
ALIGN 32
LABEL_LDT:
; 段基址,段界限, 属性
LABEL_LDT_DESC_CODEA: Descriptor 0, CodeALen-1, DA_C+DA_32LDTLen equ $ - LABEL_LDT
;选择子
SelectoerLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL[SECTION .la]
ALIGN 32
[BITS 32]
LABEL_CODE_A:mov ax,SelectoerVideomov gs,axmov edi, (80*5 +0) *2mov ah, 0Chmov al, 'D'mov [gs:edi],axjmp $
CodeALen equ $ - LABEL_CODE_A
;END of 任务段
ring0和ring3的由来:内核态和用户态的切换
CPL:当前权限级别
DPL :descriptor privilege level 段( 门)的特权级。 当当前的代码段去访问对应的真实地址,DPL会检查程序间的允许级别是否一致。低权限的访问高权限的数据直接程序崩溃。
RPL:请求权限级别
TSS Task State Segment:任务状态段。任务和进程
如果没有OS,那么任务就等价于进程。任务实际上是一段运行在处理器上的程序。分为系统程序和用户程序。所有的程序,在有OS,写的是一个半成品,我们只负责用户态下面的,内核部分的就是OS提供的。任务是在CPU上推进,权限的转化。
TSS维护一个栈的结构。TSS是CPU这种硬件原生的系统级别的数据结构。必须有TSS才能实现特权转换。
GDT:在内存里面,有GDTR寄存器加载
TSS:由TR寄存器加载。
这种硬件级别的数据结构,由软件填写内容,由硬件使用。
调用门与特权切换
通过调用门的方式实现两个程序的切换
DA_32 EQU 4000h;32位
DA_C EQU 98h; 只执行代码段的属性
DA_DRW EQU 92h;可读写的数据段
DA_DRWA EQU 93h;存在的已访问的可读写的
DA_LDT EQU 82h;省局SA_TIL EQU 4 ;具体的任务
SA_RPL3 EQU 3DA_DPL3 EQU 60hDA_386TSS EQU 89h%macro Descriptor 3dw %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
%endmacroorg 0100h ;因为我们dos下调试程序,那么0100是可用区域jmp PM_BEGIN ;跳入到标号为PM_BEGIN的代码段开始推进[SECTION .gdt]
;GDT
; 段基址,段界限,属性
PM_GDT: Descriptor 0, 0, 0
PM_DESC_CODE32: Descriptor 0, SegCode32Len -1,DA_C+DA_32
PM_DESC_DATA: Descriptor 0, DATALen-1, DA_DRW
PM_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32
PM_DESC_TEST: Descriptor 0200000h,0ffffh, DA_DRW
PM_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW + DA_DPL3LABEL_DESC_LDT: Descriptor 0, LDTLen -1, DA_LDTPM_DESC_CODE_DEST: Descriptor 0, SegCodeDestLen -1,DA_C+DA_32PM_DESC_CODE_RING3: Descriptor 0, SegCodeRing3Len-1,DA_C+DA_32 + DA_DPL3
PM_DESC_STACK3: Descriptor 0, TopOfStack3, DA_DRWA+DA_32+DA_DPL3
PM_DESC_TSS: Descriptor 0, TSSLen -1,DA_386TSSPM_CALL_GATE_TEST:
dw 00000h
dw SelectoerCodeDest
dw 0ec00h
dw 00000h
;end of definiton gdt
GdtLen equ $ - PM_GDT
GdtPtr dw GdtLen - 1
dd 0 ; GDT 基地址;GDT 选择子
SelectoerCode32 equ PM_DESC_CODE32 - PM_GDT
SelectoerDATA equ PM_DESC_DATA - PM_GDT
SelectoerSTACK equ PM_DESC_STACK - PM_GDT
SelectoerTEST equ PM_DESC_TEST - PM_GDT
SelectoerVideo equ PM_DESC_VIDEO - PM_GDT
SelectoerLDT equ LABEL_DESC_LDT - PM_GDT SelectoerCodeDest equ PM_DESC_CODE_DEST - PM_GDT
SelectorCallGateTest equ PM_CALL_GATE_TEST - PM_GDT + SA_RPL3SelctorCodeRing3 equ PM_DESC_CODE_RING3 - PM_GDT + SA_RPL3
SelctorStack3 equ PM_DESC_STACK3 - PM_GDT + SA_RPL3
SelctorTSS equ PM_DESC_TSS - PM_GDT;END of [SECTION .gdt][SECTION .data1]
ALIGN 32
[BITS 32]
PM_DATA:
PMMessage : db "Potect Mode", 0;
OffsetPMessage equ PMMessage - $$
DATALen equ $- PM_DATA
;END of [SECTION .data];全局的堆栈段
[SECTION .gs]
ALIGN 32
[BITS 32]
PM_STACK:times 512 db 0
TopOfStack equ $ - PM_STACK -1
;END of STACK ;ring3的堆栈段
[SECTION .s3]
ALIGN 32
[BITS 32]
PM_STACK3:times 512 db 0
TopOfStack3 equ $ - PM_STACK3 -1
;END of STACK ;全局的堆栈段
[SECTION .tss]
ALIGN 32
[BITS 32]
PM_TSS:DD 0 ; BackDD TopOfStack ; 0 级堆栈DD SelectoerSTACK ; DD 0 ; 1 级堆栈DD 0 ; DD 0 ; 2 级堆栈DD 0 ; DD 0 ; CR3DD 0 ; EIPDD 0 ; EFLAGSDD 0 ; EAXDD 0 ; ECXDD 0 ; EDXDD 0 ; EBXDD 0 ; ESPDD 0 ; EBPDD 0 ; ESIDD 0 ; EDIDD 0 ; ESDD 0 ; CSDD 0 ; SSDD 0 ; DSDD 0 ; FSDD 0 ; GSDD 0 ; LDTDW 0 ; 调试陷阱标志DW $- PM_TSS+2 ; I/O位图基址DB 0ffh ; I/O位图结束标志
TSSLen equ $ - PM_TSS -1
;END of STACK [SECTION .s16]
[BITS 16]
PM_BEGIN:mov ax,csmov ds,axmov es,axmov ss,axmov sp,0100h;初始化32位的代码段xor eax,eaxmov ax,csshl eax,4add eax,PM_SEG_CODE32mov word[PM_DESC_CODE32+2],axshr eax,16mov byte [PM_DESC_CODE32+4],almov byte [PM_DESC_CODE32+7],ah;初始化32位的数据段xor eax,eaxmov ax,dsshl eax,4add eax,PM_DATAmov word[PM_DESC_DATA+2],axshr eax,16mov byte [PM_DESC_DATA+4],almov byte [PM_DESC_DATA+7],ah;初始化32位的stack段xor eax,eaxmov ax,dsshl eax,4add eax,PM_STACKmov word[PM_DESC_STACK+2],axshr eax,16mov byte [PM_DESC_STACK+4],almov byte [PM_DESC_STACK+7],ah;初始化32位的LDT,得把省局注册到全国xor eax,eaxmov ax,dsshl eax,4add eax,LABEL_LDT ;//to do mov word[LABEL_DESC_LDT+2],axshr eax,16mov byte [LABEL_DESC_LDT+4],almov byte [LABEL_DESC_LDT+7],ah;根据GDT,把LDT管理的具体公司初始化,得把省局注册到全国xor eax,eaxmov ax,dsshl eax,4add eax, LABEL_CODE_A ;//to do mov word[LABEL_LDT_DESC_CODEA+2],axshr eax,16mov byte [LABEL_LDT_DESC_CODEA +4],almov byte [LABEL_LDT_DESC_CODEA +7],ah;为调用门的运行,我们将目标代码段跳转xor eax,eaxmov ax,csshl eax,4add eax, PM_SEG_CODE_DEST ;//to do mov word[PM_DESC_CODE_DEST+2],axshr eax,16mov byte [PM_DESC_CODE_DEST+4],almov byte [PM_DESC_CODE_DEST+7],ah;初始化Ring3xor eax,eaxmov ax,dsshl eax,4add eax, PM_CODE_RING3 ;//to do mov word[PM_DESC_CODE_RING3+2],axshr eax,16mov byte [PM_DESC_CODE_RING3+4],almov byte [PM_DESC_CODE_RING3+7],ah;初始化TSSxor eax,eaxmov ax,dsshl eax,4add eax, PM_TSS ;//to do mov word[PM_DESC_TSS+2],axshr eax,16mov byte [PM_DESC_TSS+4],almov byte [PM_DESC_TSS+7],ah;加载GDTRxor eax,eaxmov ax,dsshl eax,4add eax,PM_GDTmov dword [GdtPtr +2 ],eaxlgdt [GdtPtr];A20cliin al,92hor al,00000010bout 92h,al;切换到保护模式mov eax,cr0or eax,1mov cr0,eaxjmp dword SelectoerCode32:0[SECTION .s32] ;32位的代码段
[BITS 32]
PM_SEG_CODE32 :mov ax,SelectoerDATA ;通过数据段的选择子放入ds寄存器,就可以用段+偏移进行寻址mov ds,axmov ax,SelectoerTEST ;通过测试段的选择子放入es寄存器,就可以用段+偏移进行寻址mov es,axmov ax,SelectoerVideomov gs,axmov ax,SelectoerSTACKmov ss,axmov esp,TopOfStackmov ah,0Chxor esi,esixor edi,edimov esi,OffsetPMessagemov edi,(80*10 +0) *2cld.1:lodsbtest al,aljz .2mov [gs:edi],axadd edi,2jmp .1.2: ;显示完毕;Load LDT;mov ax,SelectoerLDT ; SelectoerLDT=> GDT;lldt ax;jmp SelectoerLDTCodeA:0;------------gate 1;call SelectorCallGateTest:0;jmp $;------------end of gate 1;beging gate 2:有级别转换;load TSSmov ax, SelctorTSSltr axpush SelctorStack3push TopOfStack3push SelctorCodeRing3push 0retfSegCode32Len equ $ - PM_SEG_CODE32;LDT
[SECTION .ldt]
ALIGN 32
LABEL_LDT:
; 段基址,段界限, 属性
LABEL_LDT_DESC_CODEA: Descriptor 0, CodeALen-1, DA_C+DA_32LDTLen equ $ - LABEL_LDT
;选择子
SelectoerLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL[SECTION .la]
ALIGN 32
[BITS 32]
LABEL_CODE_A:mov ax,SelectoerVideomov gs,axmov edi, (80*5 +0) *2mov ah, 0Chmov al, 'D'mov [gs:edi],axjmp $
CodeALen equ $ - LABEL_CODE_A
;END of 任务段[SECTION .sdest]
ALIGN 32
[BITS 32]
PM_SEG_CODE_DEST:mov ax,SelectoerVideomov gs,axmov edi, (80*18 +0) *2mov ah, 0Chmov al, 'G'mov [gs:edi],ax;Load LDTmov ax, SelectoerLDTlldt axjmp SelectoerLDTCodeA:0;retfSegCodeDestLen equ $ - PM_SEG_CODE_DEST
;END of 调用门;ring 3
[SECTION .ring3]
ALIGN 32
[BITS 32]
PM_CODE_RING3:mov ax,SelectoerVideomov gs,axmov edi, (80*12 +0) *2mov ah, 0Chmov al, '3'mov [gs:edi],axcall SelectorCallGateTest:0 ;用调用门完成特权级切换jmp $SegCodeRing3Len equ $ - PM_CODE_RING3
;END of 调用门
从ring0到ring3特权级切换实战
linux内核只用了ring0和riing3
时钟中断:进程时间片轮转的基础
任务门 陷阱门 调用门 中断门
学习1:如何操作硬件
学习2:保护模式下如何访问IO
这篇关于自制OS3-1到3-16==保护模式(GDT、选择子、寄存器)、多任务由来(LDT)、内核态和用户态ring0和ring3、特权级切换(TSS-CPL-DPL-RPL-门)、时钟中断、保护模式中断编程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!