一个操作系统的实现-3_保护模式2
来源:互联网 发布:linux 组权限 设置 编辑:程序博客网 时间:2024/06/04 18:57
代码部分基本是自己根据书中自带的源码自己手敲了一遍,逐步加代码,把这一节需要的内容加了进去,另外还是把头文件和源文件分开了,前两节代码少也就没分开了.字符串显示这些代码自己看明白应该就可以了,没有注释,估计自己现在也写不出来,目前不怎么需要自己写汇编,我的态度是能看懂即可.
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 3dw %2 & 0FFFFhdw %1 & 0FFFFhdb (%1>>16) & 0FFhdw ((%2>>8) & 0F00h) | (%3 & 0F0FFh)db (%1>>24) & 0FFh%endmacroDA_32EQU 4000hDA_CEQU 98hDA_DRWEQU 92hDA_DRWAEQU 93h
源文件:pmtest2.asm
%include"pm.inc";org 07c00horg 0100hjmp LABEL_BEGIN[SECTION .gdt]LABEL_GDT:Descriptor 0, 0, 0LABEL_DESC_NORMAL:Descriptor 0, 0ffffh, DA_DRWLABEL_DESC_CODE32:Descriptor 0, SegCode32Len - 1, DA_C + DA_32LABEL_DESC_CODE16:Descriptor 0, 0ffffh, DA_CLABEL_DESC_DATA:Descriptor 0, DataLen-1, DA_DRWLABEL_DESC_STACK:Descriptor 0, TopOfStack, DA_DRWA+DA_32LABEL_DESC_TEST:Descriptor0500000h, 0ffffh, DA_DRWLABEL_DESC_VIDEO:Descriptor0B8000h, 0ffffh, DA_DRWGdtLen equ $ - LABEL_GDTGdtPtr dw GdtLen - 1 dd 0SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDTSelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDTSelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDTSelectorData equ LABEL_DESC_DATA - LABEL_GDTSelectorStack equ LABEL_DESC_STACK - LABEL_GDTSelectorTest equ LABEL_DESC_TEST - LABEL_GDTSelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT[SECTION .data1] ;数据段;ALIGN 32[BITS 32]LABEL_DATA:SPValueInRealModedw0PMMessage:db"In Protect Mode now. ^-^", 0OffsetPMMessageequPMMessage - $$StrTest:db"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0OffsetStrTestequStrTest - $$DataLenequ$ - LABEL_DATA[SECTION .gs] ;堆栈段;ALIGN 32[BITS 32]LABEL_STACK:times 512 db 0TopOfStackequ$ - LABEL_STACK - 1[SECTION .s16][BITS 16]LABEL_BEGIN:mov ax,csmov ds,axmov es,axmov ss,axmov sp,0100hmov [LABEL_GO_BACK_TO_REAL+3], axmov [SPValueInRealMode], spmov ax,cs ;初始化16位代码段描述符movzx eax,axshl eax,4add eax,LABEL_SEG_CODE16mov word [LABEL_DESC_CODE16 + 2],axshr eax,16mov byte [LABEL_DESC_CODE16 + 4],almov byte [LABEL_DESC_CODE16 + 7],ahxor eax,eax ;初始化32位段描述符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 xor eax,eax ;初始化数据段描述符mov ax,dsshl eax,4add eax,LABEL_DATAmov word [LABEL_DESC_DATA + 2],axshr eax,16mov byte [LABEL_DESC_DATA + 4],almov byte [LABEL_DESC_DATA + 7],ahxor eax,eaxmov ax,dsshl eax,4add eax,LABEL_STACKmov word [LABEL_DESC_STACK + 2],axshr eax,16mov byte [LABEL_DESC_STACK + 4],almov byte [LABEL_DESC_STACK + 7],ahxor eax,eaxmov ax,dsshl eax,4add eax,LABEL_GDTmov dword [GdtPtr + 2],eaxlgdt [GdtPtr]cliin al,92hor al,00000010bout 92h,almoveax,cr0or eax,1mov cr0,eaxjmp dword SelectorCode32:0LABEL_REAL_ENTRY:mov ax,csmov ds,axmov es,axmov ss,axmov sp,[SPValueInRealMode]in al,92hand al,11111101bout 92h,alstimov ax,4c00hint 21h[SECTION .s32][BITS 32]LABEL_SEG_CODE32:mov ax,SelectorDatamov ds,axmov ax,SelectorTestmov es,axmov ax,SelectorVideomov gs,axmov ax,SelectorStackmov ss,axmov esp,TopOfStackmov ah,0Chxor esi,esixor edi,edimov esi,OffsetPMMessagemov edi,(80 * 10 + 0) * 2cld.1:lodsbtest al,aljz .2mov [gs:edi],axadd edi,2jmp .1.2:call DispReturncall TestReadcall TestWritecall TestReadjmp SelectorCode16:0TestRead:xor esi,esimov ecx,8.loop:mov al,[es:esi]call DispALinc esiloop .loopcall DispReturnretTestWrite:push esipush edixor esi,esixor edi,edimov esi,OffsetStrTestcld.1:lodsbtest al,aljz .2mov [es:edi],alinc edijmp .1.2:pop edipop esiretDispAL:push ecxpush edxmov ah,0Chmov dl,alshr al,4mov ecx,2.begin:and al,01111bcmp al,9ja .1add al,'0'jmp .2.1:sub al,0Ahadd al,'A'.2:mov [gs:edi],axadd edi,2mov al,dlloop .beginadd edi,2pop edxpop ecxretDispReturn:push eaxpush ebxmov eax,edimov bl,160div bland eax,0FFhinc eaxmov bl,160mul blmov edi,eaxpop ebxpop eaxretSegCode32Lenequ$ - LABEL_SEG_CODE32[SECTION .s16code];ALIGN 32[BITS 16]LABEL_SEG_CODE16:mov ax,SelectorNormalmov ds,axmov es,axmov fs,axmov gs,axmov ss,axmov eax,cr0and al,11111110bmov cr0,eaxLABEL_GO_BACK_TO_REAL:jmp 0:LABEL_REAL_ENTRYCode16Lenequ $ - LABEL_SEG_CODE16
运行结果:
最后补充一点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
- 一个操作系统的实现-4_保护模式3
- 一个操作系统的实现-2_保护模式1
- 一个操作系统的实现-5_保护模式4
- 一个操作系统的实现-6_保护模式5
- 一个操作系统的实现:保护模式
- 一个操作系统的实现--保护模式
- 一个操作系统的实现(3)-保护模式进阶
- <<orange‘s :一个操作系统的实现>>读书笔记(2) 保护模式
- 一个操作系统的实现(2)-认识保护模式
- 《一个操作系统的实现》笔记(2)--保护模式
- 《Orange’s 一个操作系统的实现》3.保护模式3----保护模式进阶
- 《Orange’s 一个操作系统的实现》3.保护模式2----认识保护模式A
- 《Orange’s 一个操作系统的实现》3.保护模式2----认识保护模式B
- 一个操作系统的实现(11)-让操作系统进入保护模式
- 《Orange's 一个操作系统的实现》读书手记3(2)--- [ 保护模式(Protect Mode)]
- 一个操作系统的实现:第三章 保护模式 调试问题
- 《一个操作系统的实现》读书笔记--第三章--保护模式
- 集合
- Java多线程 start()和run()方法
- 简单的表白公式
- python mysql 查询事务异常------table doesnt exist
- LeetCode
- 一个操作系统的实现-3_保护模式2
- mysql添加列到指定位置
- IO和NIO的区别
- MYSQL经典题目
- Linux上Redis的安装
- 使用dagger2来做依赖注入(通俗易懂)
- NYOJ H : 没错,就让你做A+B
- Altium Designer PCB导出step 3D文件时遇到的问题
- LeetCode