自制OS3-1到3-16==保护模式(GDT、选择子、寄存器)、多任务由来(LDT)、内核态和用户态ring0和ring3、特权级切换(TSS-CPL-DPL-RPL-门)、时钟中断、保护模式中断编程

本文详细介绍了保护模式下的内存管理和寻址机制,包括全局描述符表(GDT)、段描述符、特权级(Ring0和Ring3)以及如何通过调用门实现不同权限级别的切换。代码示例展示了如何在32位保护模式下初始化GDT、LDT,并通过调用门进行任务切换。此外,还探讨了多任务环境下局部描述符表(LDT)和任务状态段(TSS)的作用。
摘要由CSDN通过智能技术生成

保护模式

前面我们可以任意的访问内存,寄存器在段式内存中,其实没有界限,操作系统和用户程序实际上做不到内存的隔离。

用户程序所访问的逻辑地址,实际上就是物理地址。

用户程序可以随意修改段基址(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 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 ;

org 07c00h
	jmp	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, cs
	mov	ds, ax
	mov	es, ax
	mov	ss, ax
	mov	sp, 0100h

	; 初始化 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

	; 为加载 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, 并跳转到 Code32Selector:0  处
; END of [SECTION .s16]


[SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS	32]

LABEL_SEG_CODE32:
	mov	ax, SelectorVideo
	mov	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 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
%endmacro


org 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,cs
	mov ds,ax
	mov es,ax
	mov ss,ax
	mov sp,0100h
	
	;初始化32位的代码段
	xor eax,eax
	mov ax,cs
	shl eax,4
	add eax,PM_SEG_CODE32
	mov word[PM_DESC_CODE32+2],ax
	shr eax,16
	mov byte [PM_DESC_CODE32+4],al
	mov byte [PM_DESC_CODE32+7],ah
	
	
	;初始化32位的数据段
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax,PM_DATA
	mov word[PM_DESC_DATA+2],ax
	shr eax,16
	mov byte [PM_DESC_DATA+4],al
	mov byte [PM_DESC_DATA+7],ah
	
	;初始化32位的stack段
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax,PM_STACK
	mov word[PM_DESC_STACK+2],ax
	shr eax,16
	mov byte [PM_DESC_STACK+4],al
	mov byte [PM_DESC_STACK+7],ah
	
	;加载GDTR
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax,PM_GDT
	mov dword [GdtPtr +2 ],eax
	lgdt [GdtPtr]
	
	;A20
	cli
	
	in al,92h
	or al,00000010b
	out 92h,al
	
	;切换到保护模式
	mov eax,cr0
	or eax,1
	mov cr0,eax
	
	jmp dword SelectoerCode32:0



[SECTION .s32]	;32位的代码段
[BITS 32]
PM_SEG_CODE32 :
	mov ax,SelectoerDATA	;通过数据段的选择子放入ds寄存器,就可以用段+偏移进行寻址
	mov ds,ax
	
	mov ax,SelectoerTEST	;通过测试段的选择子放入es寄存器,就可以用段+偏移进行寻址
	mov es,ax
	
	mov ax,SelectoerVideo
	mov gs,ax
	
	mov ax,SelectoerSTACK
	mov ss,ax
	mov esp,TopOfStack
	
	mov ah,0Ch
	xor esi,esi
	xor edi,edi
	mov esi,OffsetPMessage
	mov edi,(80*10 +0) *2
	cld
	
.1:
	lodsb
	test al,al
	jz .2
	mov [gs:edi],ax
	add edi,2
	jmp .1
	
.2: ;显示完毕

	;测试段的寻址
	mov ax, 'A'
	mov [es:0],ax
	mov ax,SelectoerVideo
	mov gs,ax 
	mov edi,(80*15 +0) *2
	mov ah,0Ch
	mov al,[es:0]
	mov [gs:edi],ax

	jmp $
	

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 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
%endmacro


org 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

LABEL_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,cs
	mov ds,ax
	mov es,ax
	mov ss,ax
	mov sp,0100h
	
	;初始化32位的代码段
	xor eax,eax
	mov ax,cs
	shl eax,4
	add eax,PM_SEG_CODE32
	mov word[PM_DESC_CODE32+2],ax
	shr eax,16
	mov byte [PM_DESC_CODE32+4],al
	mov byte [PM_DESC_CODE32+7],ah
	
	
	;初始化32位的数据段
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax,PM_DATA
	mov word[PM_DESC_DATA+2],ax
	shr eax,16
	mov byte [PM_DESC_DATA+4],al
	mov byte [PM_DESC_DATA+7],ah
	
	;初始化32位的stack段
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax,PM_STACK
	mov word[PM_DESC_STACK+2],ax
	shr eax,16
	mov byte [PM_DESC_STACK+4],al
	mov byte [PM_DESC_STACK+7],ah
	
	;初始化32位的LDT,得把省局注册到全国
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax,LABEL_LDT					;//to do 
	mov word[LABEL_DESC_LDT+2],ax
	shr eax,16
	mov byte [LABEL_DESC_LDT+4],al
	mov byte [LABEL_DESC_LDT+7],ah
	
	
	
	;根据GDT,把LDT管理的具体公司初始化,得把省局注册到全国
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax, LABEL_CODE_A					;//to do 
	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,PM_GDT
	mov dword [GdtPtr +2 ],eax
	lgdt [GdtPtr]
	
	;A20
	cli
	
	in al,92h
	or al,00000010b
	out 92h,al
	
	;切换到保护模式
	mov eax,cr0
	or eax,1
	mov cr0,eax
	
	jmp dword SelectoerCode32:0



[SECTION .s32]	;32位的代码段
[BITS 32]
PM_SEG_CODE32 :
	mov ax,SelectoerDATA	;通过数据段的选择子放入ds寄存器,就可以用段+偏移进行寻址
	mov ds,ax
	
	mov ax,SelectoerTEST	;通过测试段的选择子放入es寄存器,就可以用段+偏移进行寻址
	mov es,ax
	
	mov ax,SelectoerVideo
	mov gs,ax
	
	mov ax,SelectoerSTACK
	mov ss,ax
	mov esp,TopOfStack
	
	mov ah,0Ch
	xor esi,esi
	xor edi,edi
	mov esi,OffsetPMessage
	mov edi,(80*10 +0) *2
	cld
	
.1:
	lodsb
	test al,al
	jz .2
	mov [gs:edi],ax
	add edi,2
	jmp .1
	
.2: ;显示完毕

	;Load LDT
	
	mov ax,SelectoerLDT	;	SelectoerLDT=> GDT
	lldt ax
	jmp SelectoerLDTCodeA:0
	

SegCode32Len equ $ - PM_SEG_CODE32


;LDT
[SECTION .ldt]
ALIGN 32
LABEL_LDT:
;									段基址,段界限,		属性
LABEL_LDT_DESC_CODEA:	Descriptor		0,		CodeALen-1,		DA_C+DA_32

LDTLen	equ $ - LABEL_LDT
;选择子
SelectoerLDTCodeA	equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL

[SECTION .la]
ALIGN 32
[BITS 32]
LABEL_CODE_A:
	
	mov  ax,SelectoerVideo
	mov gs,ax
	mov edi, (80*5 +0) *2
	mov ah, 0Ch
	mov al, 'D'
	mov [gs:edi],ax
	
	
	jmp $
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 3

DA_DPL3 EQU 60h

DA_386TSS EQU 89h

%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
%endmacro


org 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_DPL3

LABEL_DESC_LDT:		Descriptor		0,	LDTLen -1, DA_LDT

PM_DESC_CODE_DEST:	Descriptor		0,	SegCodeDestLen -1,DA_C+DA_32

PM_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_386TSS


PM_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_RPL3
		
SelctorCodeRing3 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			; Back
		DD	TopOfStack 		; 0 级堆栈
		DD	SelectoerSTACK		; 
		DD	0			; 1 级堆栈
		DD	0			; 
		DD	0			; 2 级堆栈
		DD	0			; 
		DD	0			; CR3
		DD	0			; EIP
		DD	0			; EFLAGS
		DD	0			; EAX
		DD	0			; ECX
		DD	0			; EDX
		DD	0			; EBX
		DD	0			; ESP
		DD	0			; EBP
		DD	0			; ESI
		DD	0			; EDI
		DD	0			; ES
		DD	0			; CS
		DD	0			; SS
		DD	0			; DS
		DD	0			; FS
		DD	0			; GS
		DD	0			; LDT
		DW	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,cs
	mov ds,ax
	mov es,ax
	mov ss,ax
	mov sp,0100h
	
	;初始化32位的代码段
	xor eax,eax
	mov ax,cs
	shl eax,4
	add eax,PM_SEG_CODE32
	mov word[PM_DESC_CODE32+2],ax
	shr eax,16
	mov byte [PM_DESC_CODE32+4],al
	mov byte [PM_DESC_CODE32+7],ah
	
	
	;初始化32位的数据段
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax,PM_DATA
	mov word[PM_DESC_DATA+2],ax
	shr eax,16
	mov byte [PM_DESC_DATA+4],al
	mov byte [PM_DESC_DATA+7],ah
	
	;初始化32位的stack段
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax,PM_STACK
	mov word[PM_DESC_STACK+2],ax
	shr eax,16
	mov byte [PM_DESC_STACK+4],al
	mov byte [PM_DESC_STACK+7],ah
	
	;初始化32位的LDT,得把省局注册到全国
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax,LABEL_LDT					;//to do 
	mov word[LABEL_DESC_LDT+2],ax
	shr eax,16
	mov byte [LABEL_DESC_LDT+4],al
	mov byte [LABEL_DESC_LDT+7],ah
	
	
	
	;根据GDT,把LDT管理的具体公司初始化,得把省局注册到全国
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax, LABEL_CODE_A					;//to do 
	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
	
	
	;为调用门的运行,我们将目标代码段跳转
	xor eax,eax
	mov ax,cs
	shl eax,4
	add eax, PM_SEG_CODE_DEST					;//to do 
	mov word[PM_DESC_CODE_DEST+2],ax
	shr eax,16
	mov byte [PM_DESC_CODE_DEST+4],al
	mov byte [PM_DESC_CODE_DEST+7],ah
	
	
	;初始化Ring3
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax, PM_CODE_RING3				;//to do 
	mov word[PM_DESC_CODE_RING3+2],ax
	shr eax,16
	mov byte [PM_DESC_CODE_RING3+4],al
	mov byte [PM_DESC_CODE_RING3+7],ah
	
	;初始化TSS
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax, PM_TSS			;//to do 
	mov word[PM_DESC_TSS+2],ax
	shr eax,16
	mov byte [PM_DESC_TSS+4],al
	mov byte [PM_DESC_TSS+7],ah
	
	
	
	
	;加载GDTR
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax,PM_GDT
	mov dword [GdtPtr +2 ],eax
	lgdt [GdtPtr]
	
	;A20
	cli
	
	in al,92h
	or al,00000010b
	out 92h,al
	
	;切换到保护模式
	mov eax,cr0
	or eax,1
	mov cr0,eax
	
	jmp dword SelectoerCode32:0



[SECTION .s32]	;32位的代码段
[BITS 32]
PM_SEG_CODE32 :
	mov ax,SelectoerDATA	;通过数据段的选择子放入ds寄存器,就可以用段+偏移进行寻址
	mov ds,ax
	
	mov ax,SelectoerTEST	;通过测试段的选择子放入es寄存器,就可以用段+偏移进行寻址
	mov es,ax
	
	mov ax,SelectoerVideo
	mov gs,ax
	
	mov ax,SelectoerSTACK
	mov ss,ax
	mov esp,TopOfStack
	
	mov ah,0Ch
	xor esi,esi
	xor edi,edi
	mov esi,OffsetPMessage
	mov edi,(80*10 +0) *2
	cld
	
.1:
	lodsb
	test al,al
	jz .2
	mov [gs:edi],ax
	add edi,2
	jmp .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 TSS
	mov ax, SelctorTSS
	ltr ax
	
	push SelctorStack3
	push TopOfStack3
	push SelctorCodeRing3
	push 0
	retf
	

SegCode32Len equ $ - PM_SEG_CODE32


;LDT
[SECTION .ldt]
ALIGN 32
LABEL_LDT:
;									段基址,段界限,		属性
LABEL_LDT_DESC_CODEA:	Descriptor		0,		CodeALen-1,		DA_C+DA_32

LDTLen	equ $ - LABEL_LDT
;选择子
SelectoerLDTCodeA	equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL

[SECTION .la]
ALIGN 32
[BITS 32]
LABEL_CODE_A:
	
	mov  ax,SelectoerVideo
	mov gs,ax
	mov edi, (80*5 +0) *2
	mov ah, 0Ch
	mov al, 'D'
	mov [gs:edi],ax
	
	
	jmp $
CodeALen  equ $ - LABEL_CODE_A
;END of 任务段

[SECTION .sdest]
ALIGN 32
[BITS 32]
PM_SEG_CODE_DEST:
	mov  ax,SelectoerVideo
	mov gs,ax
	mov edi, (80*18 +0) *2
	mov ah, 0Ch
	mov al, 'G'
	mov [gs:edi],ax
	
	;Load LDT
	mov ax, SelectoerLDT
	lldt ax
	jmp SelectoerLDTCodeA:0
	
	;retf
	
SegCodeDestLen equ $ - PM_SEG_CODE_DEST
;END of 调用门

;ring 3
[SECTION .ring3]
ALIGN 32
[BITS 32]
PM_CODE_RING3:
	mov  ax,SelectoerVideo
	mov gs,ax
	mov edi, (80*12 +0) *2
	mov ah, 0Ch
	mov al, '3'
	mov [gs:edi],ax
	
	call SelectorCallGateTest:0 ;用调用门完成特权级切换
	jmp $
	
SegCodeRing3Len equ $ - PM_CODE_RING3
;END of 调用门



 从ring0到ring3特权级切换实战

linux内核只用了ring0和riing3

时钟中断:进程时间片轮转的基础

任务门 陷阱门 调用门 中断门

学习1:如何操作硬件

学习2:保护模式下如何访问IO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值