《自己动手写操作系统》第三章 pmtest5源码解析——特权级变换与堆栈切换实例详解
时间:2014-03-05 17:18:10
收藏:0
阅读:734
摘要:在pmtest4中,我们已经看到,对于非一致性代码,如何从低特权级转移向高特权级。但是我们该怎样从高特权级别,转移到低特权级别呢?本文,主要是为你解答这些疑问,展现实现这种特权级别转移的方法。另外,我们将在实践中探讨,为什么要设定RPL,是不是相对与DPL多此一举呢?在调试环节,我们将通过改动代码,排查相关错误来深入理解特权级检测机制。一、预备理论
1.关于堆栈 我们都知道,可以通过call和jmp实现长跳转或者短跳转(段内转移或者段间转移)。但是jmp和call毕竟是有分别的,其中call指令是会影响到堆栈的:对于短调用,call指令执行时,下一条指令的eip入栈,ret指令执行时候,这个eip就会从堆栈中弹出。 短调用call指令执行前后堆栈的变化如下图所示(注意带有参数的ret指令): 长调用的情况与此相似,不同的是call指令执行时,被压栈的还有cs。![]()
2.特权级变换 注意到:如果我们采用call指令进行长跳转,而且特权级别发生了变换,这个时候就发生了堆栈切换,比如从A切换到了B。但是我们的数据保存在A上面,如何从B中返回呢?原来,intel提供了一种机制,能够将A上的一些内容copy到B堆栈中。同时,A堆栈要切换到B堆栈,但是它怎么知道B堆栈在哪里呢?答案:原来这个内容保存在任务的TSS结构中,TSS是任务状态段。每个任务都最多有四个堆栈段,但是只有一个esp和ss,TSS就解决了堆栈切换方面的数据保存问题。TSS的相关介绍,可以参考:保护模式及其编程——任务切换http://blog.csdn.net/trochiluses/article/details/19768579。 比如,我们目前是ring 3,需要转移到ring 1,那时,堆栈将自动切换到ss1和esp1。(由于只是从外层到内层切换,才从TSS中取得堆栈信息,所以,TSS中没有ring 3相关的堆栈信息。那么从内层向外层切换,如何获得目的地的信息呢)。 切换过程中有关堆栈的处理,可以参考:保护模式及其编程——保护的详尽意义:通过调用门转移特权级http://blog.csdn.net/trochiluses/article/details/19573651 好了,我们已经知道call------ret分别实现特权级高低转化,可能我们平时一直先使用call,然后再使用ret,以至于你对它的印象好像if和else,实际上不是这样的,我们通过retf指令,单独使用就可以实现特权级别从0到3,从高到低。二、代码分析
pmtest5.a:我们需要增加一个ring 3的代码段,堆栈段,另外为了在rign 3下打印字符,需要将video段的DPL改成3.我们先来写一个测试版本a:程序执行流程和前面没有太大区别,在保护模式重打印字符串之后,我们让程序进入ring 3代码段,并且死循环,需要添加如下代码。
push SelectorStack3 push TopOfStack3 push SelecorCodeRing3 push 0
但是,如果我们去改动SelectorStack3和SelecorCodeRing3的描述符中RPL的字段,变成0,发现这个程序pmtest5.asm并没有像我们想象的那样,进入ring3.显然,retf的指令没有被正确执行。想一想,为什么?
pmtest5.b:在a的基础上,我们让程序在ring3代码段,进入死循环之前,调用调用门。在pmtest4的和a的基础上,我们需要做如下改动: 改动调用门的描述符和选择符到ring3;添加TSS以便能够从低特权级别转移到高特权级,并进行相关初始化。 最后,我们让程序在调用门的目标段,也就是ring 0中,跳入局部任务。 总结一下,pmtest5的执行流程:实模式---保护模式32b代码段ring 0---通过retf进入ring 3的代码段——通过调用门,进入ring 0的目标代码段——通过jmp,跳转到LDT局部任务。三、调试过程中发现的错误与分析
1)为什么要有RPL,我们都知道有“别名段”,那么别名段意味着什么呢?同一个段,可以对应着不同的selector,也就能够对应不同的RPL,这样就有利于实现自由的权限管理。 我们回忆,最开始的retf并没有生效,猜想到可能是权限的问题。我们从ring0 经过retf 到ring 3; call,从ring 3--->ring 0,要求:CPL<=DPL_G,RPL<=RPL_G,CPL>=DPL_B;变化以后CPL=DPL_B=0 retf是相反的过程,ring 0--->ring 3,要求:CPL<DPL_B,RPL<DPL_B!!!注意,retf只能用于不同特权级之间,所以没有等于,这也就是为什么开始转移失败了。
2)堆栈切换的特权级检查
更改TSS段中,将ss对应部分改成selectorstack3,然后就能在调试bochs的时候收到如下信息:
00082857633e[CPU0 ] call_protected: SS selector.rpl != CS descr.dpl 注明:开启出错信息的方法,在.bochsrc中添加对于log信息的注释#log
程序代码如下:
%include "head.inc" org 0100h jmp LABEL_BEGIN [SECTION .gdt] ;GDT base, length, attr LABEL_GDT: Descriptor 0, 0, 0 LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW LABEL_DESC_CODE16: Descriptor 0, 0FFFFH, DA_C LABEL_DESC_DATA: Descriptor 0, SegDataLen-1, DA_DRW LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32 LABEL_DESC_CODE32: Descriptor 0, SegCode32Len-1, DA_C+DA_32 LABEL_DESC_CODE_DEST: Descriptor 0, SegCodeDestLen-1,DA_C+DA_32 LABEL_DESC_LDT: Descriptor 0, LDTLen-1, DA_LDT LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW + DA_DPL3 LABEL_DESC_CODE_RING3: Descriptor 0, SegCodeRing3Len-1,DA_C + DA_32 + DA_DPL3 LABEL_DESC_STACK3: Descriptor 0, TopOfStack3,DA_DRWA + DA_32 + DA_DPL3 LABEL_DESC_TSS: Descriptor 0, TSSLen-1, DA_386TSS LABEL_CALL_GATE_TEST: Gate SelectorCodeDest,0,0,DA_386CGate + DA_DPL3 GdtLen equ $-LABEL_GDT GdtPtr dw GdtLen-1;注意,长度都是实际长度减1 dd 0 ;段基地址,注意,这里之所以没有直接制定,是因为还没有确定保护模式下gdt的基地址 ;选择子 SelectorData equ LABEL_DESC_DATA - LABEL_GDT SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT SelectorStack equ LABEL_DESC_STACK - LABEL_GDT SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT SelectorLDT equ LABEL_DESC_LDT - LABEL_GDT SelectorCodeDest equ LABEL_DESC_CODE_DEST - LABEL_GDT SelectorCallGateTest equ LABEL_CALL_GATE_TEST - LABEL_GDT +SA_RPL3 SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT SelectorCodeRing3 equ LABEL_DESC_CODE_RING3 - LABEL_GDT +SA_RPL3 SelectorStack3 equ LABEL_DESC_STACK3 - LABEL_GDT +SA_RPL3 SelectorTSS equ LABEL_DESC_TSS - LABEL_GDT ;end of section gdt ;-------------------------------------------------------------- [SECTION .data] [BITS 32] ALIGN 32 LABEL_SEG_DATA: SPValueInRealModel dw 0 PMMessage: db "Coming into protect mode now !",0 OffsetPMMessage equ PMMessage - $$ StrTest: db "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0 OffsetStrTest equ StrTest - $$ SegDataLen equ $ - LABEL_SEG_DATA ;end of section data ;-----------------------------section:global stack------------------ [SECTION .gs] ALIGN 32 [BITS 32] LABEL_SEG_STACK: times 512 db 0 TopOfStack equ $-LABEL_SEG_STACK-1 ;----------------------section:LDT---------------------------------- [SECTION .ldt] align 32 [bits 32] LABEL_SEG_LDT: LABEL_DESC_CODEA: Descriptor 0,CodeALen -1,DA_C+DA_32 LDTLen equ $- LABEL_SEG_LDT SelectorCodeA equ LABEL_DESC_CODEA - LABEL_SEG_LDT + SA_TIL ;end of ldt segment ;-------------------------------section:codeA------------------------ [section .codeA] align 32 [bits 32] LABEL_SEG_CODEA: mov ax,SelectorVideo mov gs,ax mov ah,0ch mov al,‘L‘ mov edi,(2*80+0)*2 mov [gs:edi],ax jmp SelectorCode16:0 CodeALen equ $-LABEL_SEG_CODEA ;end of secion codeA ;------------------------------section:s16 begin--------------------- [SECTION .s16] [BITS 16] LABEL_BEGIN: xchg bx,bx mov ax,cs mov ds,ax mov es,ax mov ss,ax mov sp,0100h mov [LABEL_GO_BACK_TO_REAL+3],ax mov [SPValueInRealModel],sp ;for segment code32 xor eax,eax mov eax,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 ;for segment code16 xor eax,eax mov ax,cs 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 ;for segment data xor eax,eax mov eax,ds shl eax,4 add eax,LABEL_SEG_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 ;for segment ldt xor eax,eax mov eax,ds shl eax,4 add eax,LABEL_SEG_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 ;for segment codeA xor eax,eax mov eax,ds shl eax,4 add eax,LABEL_SEG_CODEA; mov word [LABEL_DESC_CODEA +2],ax shr eax,16 mov byte [LABEL_DESC_CODEA + 4],al mov byte [LABEL_DESC_CODEA + 7],ah ;for segment stack xor eax,eax mov eax,ds shl eax,4 add eax,LABEL_SEG_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 ;no need for video base ;for segment dstcode xor eax,eax mov ax,cs shl eax,4 add eax,LABEL_SEG_CODE_DEST mov word [LABEL_DESC_CODE_DEST +2],ax shr eax,16 mov byte [LABEL_DESC_CODE_DEST +4],al mov byte [LABEL_DESC_CODE_DEST +7],ah ;for segment code ring 3 xor eax,eax mov ax,cs shl eax,4 add eax,LABEL_SEG_CODE_RING3 mov word [LABEL_DESC_CODE_RING3 +2],ax shr eax,16 mov byte [LABEL_DESC_CODE_RING3 +4],al mov byte [LABEL_DESC_CODE_RING3 +7],ah ;for segment code stack 3 xor eax,eax mov ax,cs shl eax,4 add eax,LABEL_SEG_STACK3 mov word [LABEL_DESC_STACK3 +2],ax shr eax,16 mov byte [LABEL_DESC_STACK3 +4],al mov byte [LABEL_DESC_STACK3 +7],ah ;for segment code stack 3 xor eax,eax mov ax,cs shl eax,4 add eax,LABEL_SEG_TSS mov word [LABEL_DESC_TSS +2],ax shr eax,16 mov byte [LABEL_DESC_TSS +4],al mov byte [LABEL_DESC_TSS +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,02h out 92h,al mov eax,cr0 or eax,1 mov cr0,eax jmp dword SelectorCode32:0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; LABEL_REAL_ENTRY: ;come here from protect model mov ax,cs mov ds,ax mov es,ax mov ss,ax mov sp,[SPValueInRealModel] in al,92h and al,11111101b out 92h,al sti mov ax,4c00h int 21h ;end of section .s16 ;------------------------section:code32,start of protect model-------- [SECTION .s32] [BITS 32] LABEL_SEG_CODE32: mov ax,SelectorVideo mov gs,ax mov ax,SelectorData mov ds,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*11+0)*2 cld .loopPmMessage: lodsb test al,al jz .end mov [gs:edi],ax add edi,2 jmp .loopPmMessage .end: ; call DispReturn mov ax,SelectorTSS ltr ax push SelectorStack3 push TopOfStack3 push SelectorCodeRing3 push 0 xchg bx,bx retf xchg bx,bx call SelectorCallGateTest:0 ;Load LDT mov ax,SelectorLDT lldt ax jmp SelectorCodeA:0 ;function: read and print 8 byte from es:0 TestRead: xor esi,esi mov ecx,8 .loopForEightBype: mov al,[es:esi] call DispAL inc esi loop .loopForEightBype call DispReturn ret; be sure of this ;funtion: ;write 8byte to es:OffsetStrTest ;input:es TestWrite: push esi push edi xor esi,esi xor edi,edi mov esi,OffsetStrTest cld .loopForEightBype: lodsb ;ds:si->al test al,al jz .end mov [es:edi],al inc edi jmp .loopForEightBype .end: pop edi pop esi ret ;funtion DispAL ; display the number in AL ;input: AL-the number ; edi-the position to display ;modified:ax,edi 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 .moreThanNine add al,‘0‘ jmp .end .moreThanNine: sub al,0ah add al,‘A‘ .end: mov [gs:edi],ax add edi,2 mov al,dl loop .begin add edi,2 pop edx pop ecx ret ;DispAL ;function DispReturn ;if edi=(a*80 + b)*2 ;then edi=(a*80 + 80)*2 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 ;end for function DispReturn SegCode32Len equ $-LABEL_SEG_CODE32 ;end of section .s32 ;---------------------section s16code,before return to real----------- [SECTION .s16code] ALIGN 32 [BITS 16] LABEL_SEG_CODE16: ;return to real model 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 ;end of section s16code ;---------------------section:sdest--------------------------------- [section .sdest] [bits 32] LABEL_SEG_CODE_DEST: mov ax,SelectorVideo mov gs,ax mov edi,(80*12+0)*2 mov ah,0ch mov al,‘C‘ mov [gs:edi],ax ;load LDT mov ax,SelectorLDT lldt ax jmp SelectorCodeA:0 SegCodeDestLen equ $-LABEL_SEG_CODE_DEST ;-------------------section stack ring3----------------------------- [section .s3] align 32 [bits 32] LABEL_SEG_STACK3: times 512 db 0 TopOfStack3 equ $-LABEL_SEG_STACK3 - 1 ;----------------------section CodeRing3----------------------------- [section .CodeRing3] [bits 32] LABEL_SEG_CODE_RING3: mov ax,SelectorVideo mov gs,ax mov edi,(80*14+0)*2 mov ah,0ch mov al,‘3‘ mov [gs:edi],ax call SelectorCallGateTest:0 jmp $ SegCodeRing3Len equ $ - LABEL_SEG_CODE_RING3 ;------------------------section TSS------------------------------- [section .tss] [bits 32] LABEL_SEG_TSS: dd 0 dd TopOfStack dd SelectorStack dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dd 0 dw 0 dw $ - LABEL_SEG_TSS +2 db 0ffh TSSLen equ $ - LABEL_SEG_TSS
《自己动手写操作系统》第三章 pmtest5源码解析——特权级变换与堆栈切换实例详解,布布扣,bubuko.com
原文:http://blog.csdn.net/trochiluses/article/details/20473941
评论(0)