zoukankan      html  css  js  c++  java
  • 《Orange’s》保护模式

    保护模式

    完整代码

    ; ==========================================
    ; pmtest1.asm
    ; 编译方法:nasm pmtest1.asm -o pmtest1.bin
    ; ==========================================
    
    
    
    ;
    ;
    ;
    ;
    %include	"pm.inc"	; 常量, 宏, 以及一些说明
    
    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; 非一致代码段
    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 ; [SECTION .s32]这个段的物理地址
    	;分成三个部分赋值给描述符 DESC_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 作准备
    	;把GDT的物理地址填充到了GdtPtr这个6字节的数据结构
    	xor	eax, eax
    	mov	ax, ds
    	shl	eax, 4
    	add	eax, LABEL_GDT		; eax <- gdt 基地址
    	mov	dword [GdtPtr + 2], eax	; [GdtPtr + 2] <- gdt 基地址
    
    	; 加载 GDTR 将GdtPtr指示的6字节加载到寄存器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 * 11 + 79) * 2	; 屏幕第 11 行, 第 79 列。
    	mov	ah, 0Ch			; 0000: 黑底    1100: 红字
    	mov	al, 'P'
    	mov	[gs:edi], ax
    
    	; 到此停止
    	jmp	$
    
    SegCode32Len	equ	$ - LABEL_SEG_CODE32
    ; END of [SECTION .s32]
    
    

    分析

    [SECTION .gdt]
    ; GDT
    ;                              段基址,       段界限     , 属性
    LABEL_GDT:	   Descriptor       0,                0, 0           ; 空描述符
    LABEL_DESC_CODE32: Descriptor       0, SegCode32Len - 1, DA_C + DA_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]
    

    这一段定义了3个Descriptor,至于Descriptor,是作者于pm.inc中定义的一个宏,类似于一个结构体:

    %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 字节
    

    这个结构体实际就是全局描述符表(GDT)中描述符的定义。

    这个宏接受3个参数,分别是段基址,段界限和属性。然后将这三个参数加以转换成图中描述符对应的格式。
    至于如何转换,以及为什么段描述符格式这么奇怪请参考这里。

    [SECTION .gdt]中定义了3个描述符。处理器规定,GDT中的第一个描述符必须是空描述符,或者叫哑描述符或NULL描述符。所以LABEL_GDT就被定义为一个空的描述符。LABEL_DESC_CODE32为代码段描述符,LABEL_DESC_VIDEO为图形显示段的描述符。属性这里暂且不探讨。

    接着定义了对应的选择子,直观上看来,它好像就是描述符相对于GDT基址的偏移。但实际上它是如图所示的结构:

    所以,当TI和RPL都为0时,选择子就变成了对应描述符相对于GDT基址的偏移。而描述符的大小为8字节,所以选择子为8的倍数,因此最后三位必然为0。

    总之,整个寻址方式如下:

    接着把GDT的物理地址填充到了GdtPtr这个6字节的数据结构中

    ; 为加载 GDTR 作准备
    	;把GDT的物理地址填充到了GdtPtr这个6字节的数据结构
    	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]
    

    这一句的作用是将GdtPtr指示的6字节加载到寄存器gdtr。gdtr的结构如图:

    关掉中断:

    cli
    

    保护模式下的中断机制和实模式不同,因此,原有的中断向量表不再适用。而且在保护模式下,BIOS中断都不能再用,因为它们是实模式下的代码。在重新设置保护模式下的中断环境之前,必须关中断。

    打开地址线A20:

    	in	al, 92h
    	or	al, 00000010b
    	out	92h, al
    

    原因是:实模式下的程序只能寻址1MB内存,因为它依赖16位的段地址左移4位,加上16位的偏移地址来访问内存。当逻辑段地址达到最大值0xFFFF时,再加一,结果为0x100000.但因为它只能维持20位的地址,进位自然丢失,地址又绕回最低地址0x00000。但后来,到了80286时代,处理器有24根地址线,因此地址在达到0xffff时不应回0。为了能在80286机器上运行8086程序且不出现问题,便有了强制第21根线A20为0的做法。上述代码则是打开A20,使其可以为1。

    切换到保护模式:

    	mov	eax, cr0
    	or	eax, 1
    	mov	cr0, eax
    

    CR0为处理器内部的控制寄存器,结构如图所示:

    当把第0位置为1时,系统就运行于保护模式之下了。

    跳转,正式进入保护模式:

    jmp	dword SelectorCode32:0
    



    ps:最后,书中的代码在我这里是无法在bochs上正常运行的。需要把类似[SECTION ...]的语句去掉,在代码最后加上:

    times 510-($-$$) db 0
    dw 0xaa55
    
  • 相关阅读:
    maven 依赖排除
    SpringMvc自动装配@Controller无效
    SpringMvc笔记-对RESTFUL风格的配置
    Shiro报错-[org.apache.shiro.mgt.AbstractRememberMeManager]
    According to TLD or attribute directive in tag file, attribute value does not accept any expressions报错解决办法
    shiro笔记-AuthenticatingRealm和AuthorizingRealm关系
    Shiro笔记--shiroFilter权限过滤
    maven使用jstl表达式和The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application解决
    mysql window版本下载
    linux中/bin和/sbin和/usr/bin和/usr/sbin
  • 原文地址:https://www.cnblogs.com/cknightx/p/7867457.html
Copyright © 2011-2022 走看看