一个操作系统的实现-3_保护模式2

很久没碰汇编,看这一节代码顺带复习了下汇编语言,以后看内核程序里的汇编心里也不会那么虚,挺好的.前面的几个知识点是这一节中需要用的的汇编知识,最后两个是这一节中主要内容,如何从保护模式返回实模式.
代码部分基本是自己根据书中自带的源码自己手敲了一遍,逐步加代码,把这一节需要的内容加了进去,另外还是把头文件和源文件分开了,前两节代码少也就没分开了.字符串显示这些代码自己看明白应该就可以了,没有注释,估计自己现在也写不出来,目前不怎么需要自己写汇编,我的态度是能看懂即可.
1:esi,edi区别:在串操作指令这类指令里(movs/cmps/stos/lods),esi和edi的使用是固定的,比如movs是由ds:[esi]复制到es:[edi]处,即指定源和目的.
2:CLD指令功能:将标志寄存器Flag的方向标志位DF清零,在字串操作中使变址寄存器SI或DI的地址指针自动增加
3:lodsb|lodsw|lodsd :用于将ds:[esi]指向的存储单元数据装入al|ax|eax中,stosb|stosw等则相反
4:test只是做与操作,结果只改变标志位寄存器
5:div SRC 无符号除法,16位被除数在ax,8位除数为源操作数,结果的8位商在AL中,8位余数在AH中.
6:mul SRC 如果SRC是字节操作数,则把AL中的无符号数与SRC相乘得到16位结果送入AX中,如果SRC是字操作数,则把AX中无符号数与SRC相乘得到32位结果送入DX和AX中,DX存高16位,AX存低16位.
7:汇编换行实现---((视频段偏移/160)&0xff+1)*160
8:ja 根据jmp结果进行判断,若前者大于后者则跳转 jump if above
9:loop label指令,根据cx寄存器计数循环次数
10:movzx  dst,src  将源操作数取出,置于目的操作数,目的操作数其余位用0填充.
11:jmp 0:LABEL_REAL_ENTRY为什么能实现jmp cs_real_mode:LABEL_REAL_ENTRY的效果?
首先要明白,这条语句是编译后是属于代码段的,存在与内存中,而在程序真正运行时,保护模式下不能更改代码段内容,但是在实模式下是可以改变代码段内容的,在程序开头的实模式初始化时,有mov [LABEL_GO_BACK_TO_REAL+3],ax,这句代码就更改了原来的jmp 0:LABEL_REAL_ENTRY语句了.+3的原因和长跳转指令的机器码有关,这个机器码的第四五字节表示段基址,书中已经画出指令示意图了.
12:关于Normal描述符,为什么需要存在这样一个描述符?

因为在实模式下不能改变段属性,我们预先设置一个Normal描述符,设置其属性,在返回实模式之前,将对应选择子SelectorNormal加载到ds,es,ss,使得返回实模式后段属性符合实模式要求.

头文件:pm.inc

%macro Descriptor 3
dw %2 & 0FFFFh
dw %1 & 0FFFFh
db (%1>>16) & 0FFh
dw ((%2>>8) & 0F00h) | (%3 & 0F0FFh)
db (%1>>24) & 0FFh
%endmacro

DA_32	EQU 4000h
DA_C	EQU 98h
DA_DRW	EQU 92h
DA_DRWA	EQU 93h

源文件:pmtest2.asm

%include	"pm.inc"


;org 07c00h
org 0100h
jmp LABEL_BEGIN

[SECTION .gdt]
LABEL_GDT:				Descriptor	 0,         0,	                  0
LABEL_DESC_NORMAL:			Descriptor       0,         0ffffh,              DA_DRW
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
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

GdtLen  equ $ - LABEL_GDT
GdtPtr dw GdtLen - 1 
dd 0

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
SelectorVideo	   equ		 LABEL_DESC_VIDEO    - LABEL_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



[SECTION .gs]  ;堆栈段
;ALIGN 32
[BITS  32]
LABEL_STACK:
	times 512 db 0

TopOfStack		equ	$ - LABEL_STACK - 1

[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

	mov ax,cs   ;初始化16位代码段描述符
	movzx eax,ax
	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
	

	xor eax,eax   ;初始化32位段描述符
	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


	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax,LABEL_GDT
	mov dword [GdtPtr + 2],eax

	lgdt  [GdtPtr]

	cli

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

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

	jmp dword SelectorCode32:0


LABEL_REAL_ENTRY:
	mov ax,cs
	mov ds,ax
	mov es,ax
	mov ss,ax

	mov sp,[SPValueInRealMode]
	in al,92h
	and al,11111101b
	out 92h,al

	sti

	mov ax,4c00h
	int 21h


[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
	xor esi,esi
	xor edi,edi
	mov esi,OffsetPMMessage
	mov edi,(80 * 10 + 0) * 2
	cld

.1:
	lodsb
	test al,al
	jz .2
	mov [gs:edi],ax
	add edi,2
	jmp .1

.2:
	call  DispReturn
	call  TestRead
	call  TestWrite
	call  TestRead

	jmp SelectorCode16:0


TestRead:
	xor esi,esi
	mov ecx,8

.loop:
	mov al,[es:esi]
	call DispAL
	inc esi
	loop .loop
	call DispReturn
	ret


TestWrite:
	push esi
	push edi
	xor esi,esi
	xor edi,edi
	mov esi,OffsetStrTest
	cld

.1:
	lodsb
	test al,al
	jz .2
	mov [es:edi],al
	inc edi
	jmp .1

.2:
	pop edi
	pop esi

	ret



DispAL:
	push ecx
	push edx

	mov ah,0Ch
	mov dl,al
	shr al,4
	mov ecx,2

.begin:
	and al,01111b
	cmp al,9
	ja .1
	add al,'0'
	jmp .2

.1:
	sub al,0Ah
	add al,'A'

.2:
	mov [gs:edi],ax
	add edi,2

	mov al,dl
	loop .begin
	add edi,2

	pop edx
	pop ecx
	ret


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

SegCode32Len	equ	$ - LABEL_SEG_CODE32

[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





运行结果:

一个操作系统的实现-3_保护模式2_第1张图片


最后补充一点LDT方面的知识:

1:LDT:本地描述符表,与全局描述符表的区别是在selector选择子结构中,需要设置TI位为1,即在设置选择子时加上SA_TIL属性. 另外需要注意,类似gdtr寄存器,对于ldt也有相应的ldtr寄存器,但存放的是选择子,gdtr存放的是gdt的基地址.LABEL_GDT需要有全0的描述符描述,但LABEL_LDT不需要描述.
mov ax,SelectorLDT
lldt ax
我们可以把一个单独的任务所用到的所有东西封装在一个LDT中,这种思想是以后章节中的多任务处理的一个雏形.

[SECTION .gdt]
LABEL_GDT:                    Descriptor     0,                    0,     0
LABEL_DESC_NORMAL:            Descriptor   0,            0ffffh,  DA_DRW
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
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

SelectorLDT        equ         LABEL_DESC_LDT      - LABEL_GDT
    
;初始化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

在保护模式中装载ldtr寄存器,跳转到自己的代码去运行
    call  DispReturn

    mov ax,SelectorLDT
    lldt ax

    jmp SelectorLDTCodeA:0

初始化本地描述符表以及本地描述符表项对应的代码,即CODE_A
[SECTION  .ldt]
LABEL_LDT:
LABEL_LDT_DESC_CODEA:    Descriptor    0,    CodeALen-1,    DA_C + DA_32
LDTLen    equ    $ - LABEL_LDT

SelectorLDTCodeA    equ    LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL

[SECTION  .la]
[BITS 32]
LABEL_CODE_A:
    mov ax,SelectorVideo
    mov gs,ax

    mov edi,(80*12 + 0) *2
    mov ah,0Ch
    mov al,'L'
    mov [gs:edi],ax

    jmp SelectorCode16:0

CodeALen    equ    $ - LABEL_CODE_A

程序运行结果如下:

一个操作系统的实现-3_保护模式2_第2张图片

你可能感兴趣的:(一个操作系统的实现)