一个操作系统的实现-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

程序运行结果如下:


阅读全文
1 0