80x86保护模式(3)

前面的两节里面仅仅简单的实现了从实模式进入到保护模式然后又返回实模式,而且特权等级都是在Ring0层的。保护模式之所以有保护作用,除了前面的分段机制,保证段不会越界之外。特权等级机制,也是起了很关键的作用。

关于特权等级的知识,在《一个操作系统的实现》读书笔记--第三章---不同特权级代码段之间的跳转 一文中有比较详细的解释。关于RPL、CPL、DPL的区分也做了比较详细的区分。

现在先看结果再来分析,代码如下:

;/*
;nasm boot.asm -o boot.com
;*/
;
; 描述符
; 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
	dw	%1 & 0FFFFh							; 段基址1
	db	(%1 >> 16) & 0FFh					; 段基址2
	dw	((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)	; 属性1 + 段界限2 + 属性2
	db	(%1 >> 24) & 0FFh					; 段基址3
%endmacro ; 共 8 字节
;
; 门
; usage: Gate Selector, Offset, DCount, Attr
;        Selector:  dw
;        Offset:    dd
;        DCount:    db
;        Attr:      db
%macro Gate 4
	dw	(%2 & 0FFFFh)						; 偏移1
	dw	%1									; 选择子
	dw	(%3 & 1Fh) | ((%4 << 8) & 0FF00h)	; 属性
	dw	((%2 >> 16) & 0FFFFh)				; 偏移2
%endmacro ; 共 8 字节
DA_DRW		EQU	92h	; 存在的可读写数据段属性值
; 描述符类型
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_C		EQU	98h	; 存在的只执行代码段属性值
; 系统段描述符类型
DA_LDT		EQU	  82h	; 局部描述符表段类型值
SA_TIG		EQU	0	; ┓TI
SA_TIL		EQU	4	; ┛
DA_386TSS	EQU	  89h	; 可用 386 任务状态段类型值
DA_386CGate	EQU	  8Ch	; 386 调用门类型值
SA_RPL3		EQU	3	; 

org 0x0100
				jmp 	LABEL_BEGIN
[section .gdt]
;GDT									段基址,      段界限,     段属性
LABEL_GDT_NULL:				Descriptor 		    0,		    0,		0	;空描述符
LABEL_DESC_NORMAL:			Descriptor			0,		0FFFFh,     DA_DRW
LABEL_DSCPTR_CODE16:		Descriptor			0, 		0FFFFh,		DA_C ;16位非一致代码段;为什么段界限为0FFFFh程序才没错
LABEL_DSCPTR_STACK:			Descriptor			0,		TopOfStack-1,		DA_DRW + DA_32;32位堆栈
LABEL_DESCPTR_DATA:			Descriptor			0,		DataLen-1,	DA_DRW +DA_DPL3
LABEL_DESCPTR_TEST:			Descriptor	 0500000h,		0FFFFh,		DA_DRW
LABEL_CODE_DESC:			Descriptor	        0,	Code32Len-1,		DA_C + DA_32	;非一致代码段
LABEL_VEDIO_DESC:			Descriptor	  0B8000H,       0FFFFH,	     DA_DRW +DA_DPL3;显存
LABEL_DESCPTR_LDT			Descriptor			0,		 LDTLen-1,		 DA_LDT
LABEL_DESCPTR_CODE_GATE		Descriptor			0,		CodeGateLen-1,	DA_C + DA_32 

LABEL_DESCPTR_TSS			Descriptor			0,		TSSLen-1,			DA_386TSS
;;;;;=================  Ring3  ===================
LABEL_DESCPTR_RING3_CODE32:  Descriptor			0,		 Ring3Code32Len-1, DA_C + DA_32 + DA_DPL3
LABEL_DESCPTR_RING3_STACK32: Descriptor			0,		 TopOfStackRing3-1, DA_DRW + DA_DPL3
; 门                                            目标选择子,       偏移, DCount, 属性
LABEL_CALL_GATE:			Gate		  SelectorCodeGate,          0,      0, DA_386CGate + DA_DPL3

;GDT end
Gdtlen						equ 			$ - LABEL_GDT_NULL
Gdtptr						dw				Gdtlen; GDTR段界限
							dd				0		;GDTR段基址
;GDT选择子
SelectorNormal				equ				LABEL_DESC_NORMAL - LABEL_GDT_NULL
SelectorCode32				equ				LABEL_CODE_DESC - LABEL_GDT_NULL
SelectorCode16				equ				LABEL_DSCPTR_CODE16 - LABEL_GDT_NULL
SelectorStack				equ				LABEL_DSCPTR_STACK - LABEL_GDT_NULL
SelectorData				equ				LABEL_DESCPTR_DATA - LABEL_GDT_NULL
SelectorTest				equ				LABEL_DESCPTR_TEST - LABEL_GDT_NULL
SelectorVideo				equ				LABEL_VEDIO_DESC - LABEL_GDT_NULL
SelectorLDT					equ				LABEL_DESCPTR_LDT - LABEL_GDT_NULL

SelectorCodeGate			equ				LABEL_DESCPTR_CODE_GATE - LABEL_GDT_NULL
SelectorGate				equ				LABEL_CALL_GATE - LABEL_GDT_NULL

SelectorTSS					equ				LABEL_DESCPTR_TSS - LABEL_GDT_NULL
;;Ring3 Selector
SelectorRing3Stack32		equ				LABEL_DESCPTR_RING3_STACK32 - LABEL_GDT_NULL + SA_RPL3
SelectorRing3Code32			equ				LABEL_DESCPTR_RING3_CODE32 - LABEL_GDT_NULL + SA_RPL3
;end section .gdt

[section .code16]
[BITS 16]
LABEL_BEGIN:
		mov ax,	cs
		mov es, ax
		mov ds, ax
		mov ss, ax
		mov sp, 0100h
		
		mov [LABEL_GOBACK_REAL+3] , ax ;;为跳转回实模式做准备
		mov	[SPValueInRealMode], sp
		;初始化32位代码段描述符
		xor	eax, eax
		mov ax, cs
		shl eax, 4
		add eax, LABEL_CODE32
		mov word [LABEL_CODE_DESC + 2], ax
		shr	eax, 16
		mov	byte [LABEL_CODE_DESC + 4], al
		mov byte [LABEL_CODE_DESC + 7], ah
		;初始化数据段描述符
		xor	eax, eax
		mov ax, cs
		shl eax, 4
		add eax, LABEL_DATA
		mov word [LABEL_DESCPTR_DATA + 2], ax
		shr	eax, 16
		mov	byte [LABEL_DESCPTR_DATA + 4], al
		mov byte [LABEL_DESCPTR_DATA + 7], ah
		
		;;初始化堆栈段描述符
		xor	eax, eax
		mov ax, cs
		shl eax, 4
		add eax, LABEL_STACK
		mov word [LABEL_DSCPTR_STACK + 2], ax
		shr	eax, 16
		mov	byte [LABEL_DSCPTR_STACK + 4], al
		mov byte [LABEL_DSCPTR_STACK + 7], ah
		

		;;初始化16位代码段描述符
		xor	eax, eax
		mov ax, cs
		shl eax, 4
		add eax, LABEL_CODE16
		mov word [LABEL_DSCPTR_CODE16 + 2], ax
		shr	eax, 16
		mov	byte [LABEL_DSCPTR_CODE16 + 4], al
		mov byte [LABEL_DSCPTR_CODE16 + 7], ah	
		
		;;初始化Ring3代码段描述符
		xor	eax, eax
		mov ax, cs
		shl eax, 4
		add eax, LABEL_CODE32_RING3
		mov word [LABEL_DESCPTR_RING3_CODE32 + 2], ax
		shr	eax, 16
		mov	byte [LABEL_DESCPTR_RING3_CODE32 + 4], al
		mov byte [LABEL_DESCPTR_RING3_CODE32 + 7], ah	
		
		;;初始化Ring3堆栈段描述符
		xor	eax, eax
		mov ax, cs
		shl eax, 4
		add eax, LABEL_STACK32_RING3
		mov word [LABEL_DESCPTR_RING3_STACK32 + 2], ax
		shr	eax, 16
		mov	byte [LABEL_DESCPTR_RING3_STACK32 + 4], al
		mov byte [LABEL_DESCPTR_RING3_STACK32 + 7], ah
		
		;;初始化TSS描述符
		xor	eax, eax
		mov ax, cs
		shl eax, 4
		add eax, LABEL_TSS
		mov word [LABEL_DESCPTR_TSS + 2], ax
		shr	eax, 16
		mov	byte [LABEL_DESCPTR_TSS + 4], al
		mov byte [LABEL_DESCPTR_TSS + 7], ah
		
		;;初始化LDT 在GDT中的描述符		
		xor	eax, eax
		mov ax, cs
		shl eax, 4
		add eax, LABEL_LDT
		mov word [LABEL_DESCPTR_LDT + 2], ax
		shr	eax, 16
		mov	byte [LABEL_DESCPTR_LDT + 4], al
		mov byte [LABEL_DESCPTR_LDT + 7], ah	
		; 初始化 LDT 中的描述符
		xor	eax, eax
		mov	ax, ds
		shl	eax, 4
		add	eax, LABEL_LDT_Code32
		mov	word [LABEL_LDT_DESCPTR_CODE32 + 2], ax
		shr	eax, 16
		mov	byte [LABEL_LDT_DESCPTR_CODE32 + 4], al
		
		; 初始化 门描述符
		xor	eax, eax
		mov	ax, ds
		shl	eax, 4
		add	eax, LABEL_SEG_CODE_GATE
		mov	word [LABEL_DESCPTR_CODE_GATE + 2], ax
		shr	eax, 16
		mov	byte [LABEL_DESCPTR_CODE_GATE + 4], al
		
		;为加载GDTR做准备
		xor eax, eax
		mov ax, ds
		shl eax, 4
		add eax, LABEL_GDT_NULL
		mov dword[Gdtptr + 2], eax
		;加载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

		;;============跳转回实模式执行代码 down================
LABEL_REAL_ENTRY:

		mov ax, cs
		mov ds, ax
		mov ss, ax
		mov es, ax
		
		
		mov sp, [SPValueInRealMode]
		;;关闭A20地址线
		in  al, 92h
		and al, 11111101b
		out 92h, al
		;;开中断
		sti
		;;返回dos
		
		mov ax, 4c00h
		int 21h
		
		;;============^up^跳转回实模式执行代码================
; end of section .code16
;;========== 跳回实模式准备代码=====================
[section .code16]
ALIGN 32
[BITS 16]
LABEL_CODE16:
		mov ax, SelectorNormal
		mov ds, ax
		mov ss, ax
		mov es, ax
		mov gs, ax
		mov fs, ax
		;;cr0 PE位清零
		mov eax, cr0
		and al, 11111110B
		mov cr0, eax
		
LABEL_GOBACK_REAL:
		jmp 0:LABEL_REAL_ENTRY	;跳转回实模式 段地址会在程序开始处被设置成正确的值
		
Code16Len		equ				$ - LABEL_CODE16
;;end of code16
;;=============================================================

[section .tss]
ALIGN 32
[BITS 32]
LABEL_TSS:
		DD	0			; Back
		DD	TopOfStack		; 0 级堆栈
		DD	SelectorStack		; 
		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	$ - LABEL_TSS + 2	; I/O位图基址
		DB	0ffh			; I/O位图结束标志
TSSLen 			equ 			$ - LABEL_TSS
;;===================== 数据段==========================
[section .data32]
ALIGN 32
[BITS 32]
LABEL_DATA:
SPValueInRealMode		dw 			0
;字符串
Message: 		db 			"In Protect Mode Now ^-^", 0
OffsetMessage	equ			Message - $$
TestStr			db			"Now I am In Ring3",0
OffsetRing3Message	equ			TestStr - $$
GateMessage		db			"by gate into Ring0",0
OffsetGateMessage	equ		GateMessage - $$
LDTMessage		db			"I am using LDT",0
OffsetLdtMessage equ        LDTMessage -$$
DataLen			equ			$ - LABEL_DATA
;;end of .data32
;;===========================================================

;;===========堆栈段 =================
[section .stack32_ring0]
ALIGN 32
[BITS 32]
LABEL_STACK:
times	512  	db			0
TopOfStack		equ			 $ - LABEL_STACK

[section .stack32_ring3]
ALIGN 32
[BITS 32]
LABEL_STACK32_RING3:
times	512  	db			0
TopOfStackRing3		equ			 $ - LABEL_STACK32_RING3
;;end of .stack32
;;=====================================================

;;====================== 保护模式 全局代码段 ========================
[section .code32]
[BITS 32]
LABEL_CODE32:
		mov	ax, SelectorVideo
		mov	gs, ax
		mov	ax, SelectorStack
		mov	ss, ax
		mov ax, SelectorData
		mov ds, ax
		mov ax, SelectorTest
		mov es, ax 
		mov esp, TopOfStack-1
		
		
		;;显示一个字符串
		mov ah, 0ch
		xor esi, esi
		xor edi, edi
		mov esi, OffsetMessage
		mov	edi, (80*10 + 10)*2
		cld
		
.1:
		lodsb
		test al, al
		jz .2
		mov [gs:edi], ax
		add edi, 2
		jmp .1
.2:		;字符串显示完毕
			
		; Load TSS
		mov	ax, SelectorTSS
		ltr	ax	; 在任务内发生特权级变换时要切换堆栈,而内层堆栈的指针存放在当前任务的TSS中,所以要设置任务状态段寄存器 TR。		
		push	SelectorRing3Stack32
		push	TopOfStackRing3-1
		push	SelectorRing3Code32
		push    0
		retf		;;ring0 --> ring3
		;jmp		SelectorCode16:0
		;;加载ldt
		;mov  ax, SelectorLDT
		;lldt ax
		;;跳转到局部代码段
		
		;jmp			LDT_Code32Selector:0
Code32Len		equ 		$ - LABEL_CODE32
;end of .code32


[SECTION .GateCode32]; 调用门目标段
ALIGN 32
[BITS	32]
LABEL_SEG_CODE_GATE:
		mov	ax, SelectorVideo
		mov	gs, ax			; 视频段选择子(目的)

		;;显示一个字符串
		mov ah, 0ch
		xor esi, esi
		xor edi, edi
		mov esi, OffsetGateMessage
		add edi, (80*12 + 10)*2
		cld
		
.1:
		lodsb
		test al, al
		jz .2
		mov [gs:edi], ax
		add edi, 2
		jmp .1
.2:		;字符串显示完毕

	;;加载ldt
		mov  ax, SelectorLDT
		lldt ax
		;;跳转到局部代码段		
		jmp			LDT_Code32Selector:0

	;retf

CodeGateLen     	equ	$ - LABEL_SEG_CODE_GATE
; END of [SECTION .sdest]
;;------------------< Ring3 >-----------------
[section .code32_ring3]
ALIGN 32
[BITS 32]
LABEL_CODE32_RING3:
		mov ax, SelectorVideo
		mov gs, ax
		mov ax, SelectorData
		mov ds, ax
				
		;;显示一个字符串
		mov ah, 0ch
		xor esi, esi
		xor edi, edi
		mov esi, OffsetRing3Message
		add edi, (80*11 + 10)*2
		cld
		
.1:
		lodsb
		test al, al
		jz .2
		mov [gs:edi], ax
		add edi, 2
		jmp .1
.2:		;字符串显示完毕
		
		;;call ring0 by callgate
		call 	SelectorGate:0
		jmp $
Ring3Code32Len         equ 				$ - LABEL_CODE32_RING3	
;;=================================================================

;;===================== ldt =====================

[section .ldt]
ALIGN 32
LABEL_LDT:
LABEL_LDT_DESCPTR_CODE32:		Descriptor		0,			LDT_Code32Len,     	 DA_C + DA_32

LDTLen					equ				$ - LABEL_LDT
;LDT Descriptor
LDT_Code32Selector		equ				LABEL_LDT_DESCPTR_CODE32 - LABEL_LDT + SA_TIL
;end of section .ldt
;;===================== 局部代码段 =====================
[section .ldtcode32]
ALIGN 32
[BITS 32]
LABEL_LDT_Code32:
		mov ax, SelectorVideo
		mov gs, ax
		mov ax, SelectorData
		mov ds, ax
		mov ax, SelectorStack
		mov ss, ax
		
		;;显示一个字符串
		mov ah, 0ch
		xor esi, esi
		xor edi, edi
		mov esi, OffsetLdtMessage
		add edi, (80*13 + 10)*2
		cld
		
.1:
		lodsb
		test al, al
		jz .2
		mov [gs:edi], ax
		add edi, 2
		jmp .1
.2:		;字符串显示完毕
; 准备经由16位代码段跳回实模式
		jmp		SelectorCode16:0
LDT_Code32Len			equ			$ - LABEL_LDT_Code32
;end of .ldtcode32
;==========================================================================

上述代码主要实现:

1、从实模式进入保护模式("In Protect Mode Now ^-^")

2、在保护模式中由Ring0特权级到Ring3特权级的转换("Now I am in Ring3")

3、在Ring3特权级通过call调用门,访问Ring0级别的代码段("by gate into Ring0")

4、在Ring0级别的代码段中,通过ldt访问局部代码段("i am using LDT")

5、在局部代码段中返回实模式(返回dos)

没图说JB奋斗:


在编程中注意的问题:

1、各个段描述符的特权级别不能搞错,在Ring3级别的代码段中,只能访问Ring3级别的调用门,但可以通过调用门访问Ring0级别的代码段,虽然比较绕,但我觉得这是特权级别转换的一个关键点。

2、在Ring0和Ring3特权级别的转换中,涉及到不同特权级别堆栈的切换,以及TSS的应用,也算是特权级别转换时注意的一个关键点。

3、要想把程序写的更好,最基本的要求是正确的理解编程中用到的各种定义,和编程中的一些硬性要求,才会举一反三。例如:为什么TSS只有Ring0~Ring2的堆栈信息保留项。若每个进程都有个TSS,他们是如何切换的,又是如何保存TSS信息的。


参考  《一个操作系统的实现》 于渊

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值