专注于操作系统18之完整的特权级转换

来源:互联网 发布:淘宝童装图片素材 编辑:程序博客网 时间:2024/04/29 21:12

     在上一篇文章中,我们已经能从ring0级进入到ring3级,在这里我们将再加上从ring3级到ring0级。从ring3级到ring0级这需要使用在第十四篇文章中提到的调用门来实现。即在进入ring3级后,在使用调用门来调用ring0级代码(注意当发生特权级转换时,堆栈是发生了变化的,上一篇文章已说明从ring0级到ring3级堆栈所发生的变化。当从ring3到ring0级时,ring0级堆栈信息要放在TSS中,转换时,会从中取得ring0级堆栈的信息,将ss和esp指向这个堆栈)。特权级在描述符中存储。


      下面给出代码, 代码参考了《自己动手写操作系统》。



[html] view plain copy
  1. ;;nasm 2.07  
  2. ;;nasm changelv.asm -o changelv.com  
  3. org 0100H  
  4.   
  5. %macro Descriptor 3             ;定义Descriptor结构体宏  
  6.     dw  %2 & 0FFFFh             ; 段界限 1             (2 字节)  
  7.     dw  %1 & 0FFFFh             ; 段基址 1             (2 字节)  
  8.     db  (%1 >> 16) & 0FFh         ; 段基址 2             (1 字节)  
  9.     dw  ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)   ; 属性 1 + 段界限 2 + 属性 2       (2 字节)  
  10.     db  (%1 >> 24) & 0FFh         ; 段基址 3             (1 字节)  
  11. %endmacro ; 共 8 字节  
  12.                                  ;定义Gate结构体宏  
  13. %macro Gate 4  
  14.     dw  (%2 & 0FFFFh)               ; 偏移 1              (2 字节)  
  15.     dw  %1                  ; 选择子               (2 字节)  
  16.     dw  (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 属性                    (2 字节)  
  17.     dw  ((%2 >> 16) & 0FFFFh)         ; 偏移 2              (2 字节)  
  18. %endmacro ; 共 8 字节  
  19.   
  20.   
  21. DA_C        EQU 98h ; 只读代码段的属性值  
  22. DA_DRW      EQU 92h ; 允许读写的数据段的属性值  
  23. DA_DRWA     EQU 93h ; 存在的已访问可读写数据段类型值  
  24. DA_32       EQU 4000h   ;32位段的属性值  
  25. DA_LDT      EQU   82h   ; 局部描述符表段类型值  
  26. SA_TIL      EQU 4   ;  用于指明是LDT的描述符,即选择符中TI=1  
  27. DA_386CGate EQU   8Ch   ; 386 调用门类型值  
  28. DA_386TSS   EQU   89h   ; 可用 386 任务状态段类型值  
  29. DA_DPL0     EQU   00h   ; DPL = 0  
  30. DA_DPL1     EQU   20h   ; DPL = 1  
  31. DA_DPL2     EQU   40h   ; DPL = 2  
  32. DA_DPL3     EQU   60h   ; DPL = 3  
  33. SA_RPL0     EQU 0   ; ┓  
  34. SA_RPL1     EQU 1   ; ┣ RPL  
  35. SA_RPL2     EQU 2   ; ┃  
  36. SA_RPL3     EQU 3   ; ┛  
  37.   
  38.   
  39.     jmp LABEL_BEGIN           
  40.                    ;现在进行第一步:建立GDT表  
  41. [SECTION .gdt]     ;用于放GDT表的段  
  42. ;GDT  
  43. LABEL_GDT: Descriptor 0,0,0 ;空描述符,当一个任务没有LDT时,会把LDTR清空,这时,LDTR便指向空描述符。  
  44.   
  45. LABEL_CODE32: Descriptor 0,SegCode32Len-1,DA_C + DA_32 ; 代码段的描述符,特权级为0  
  46.   
  47. LABEL_VIDEO: Descriptor 0B8000h,0ffffh,DA_DRW  +DA_DPL3  ;显存的描述符,0b8000h是显存的首地址,特权级为3  
  48. ;GDT 结束  
  49. LABEL_NORMAL: Descriptor 0,0ffffh,DA_DRW      ;normal描述符,用于将段寄存器的属性规范化(即属性为读写,大小为0ffffh)  
  50.   
  51. LABEL_GOALCODE: Descriptor 0,GoalCodeLen -1 ,DA_C + DA_32  ;调用门目标段的描述符,特权级为0  
  52.   
  53. LABEL_LDT:   Descriptor 0,LdtLen - 1,DA_LDT     ;用于描述LDT表的描述符  
  54.   
  55. LABEL_CALL_GATE: Gate SelectorGoalCode,0,0,DA_386CGate + DA_DPL3      ;门描述符,特权级为3  
  56. LABEL_CODERING3: Descriptor 0,CodeRing3Len -1 , DA_C + DA_32 + DA_DPL3   ;特权级为3的代码段的描述符  
  57. LABEL_STACKRING3: Descriptor 0, StackRing3Len , DA_32 + DA_DRWA  + DA_DPL3  ;特权级为3的代码段对应的堆栈段的描述符  
  58. LABEL_GSTACK: Descriptor 0, GStackLen , DA_32 + DA_DRWA      ;全局堆栈段的描述符  
  59. LABEL_TSS:    Descriptor 0, TssLen -1 ,DA_386TSS    ;TSS段的描述符  
  60. GdtLenth equ $ - LABEL_GDT   ;计算GDT表的长度  
  61.   
  62. GdtPtr dw GdtLenth - 1 ; 准备存入GDTR的信息  
  63.        dd 0    ;    用于存放GDT表的物理地址,后面会计算  
  64.   
  65.   
  66. ;GDT选择子  
  67. SelectorLdt equ LABEL_LDT - LABEL_GDT     ;ldt表的选择子  
  68. SelectorCode32 equ LABEL_CODE32 - LABEL_GDT ;代码段的选择子  
  69. SelectorVideo  equ LABEL_VIDEO - LABEL_GDT  ;显存所在段的选择子  
  70. SelectorNormal equ LABEL_NORMAL - LABEL_GDT  ;normal描述符的选择子  
  71.   
  72. SelectorGoalCode equ LABEL_GOALCODE - LABEL_GDT   ;调用门所调用的目标段的描述符的选择子  
  73. SelectorCallGate  equ LABEL_CALL_GATE - LABEL_GDT   ;调用门的描述符的选择子  
  74. SelectorCodeRing3  equ LABEL_CODERING3 - LABEL_GDT   + SA_RPL3  ;特权级为3的代码段的描述符的选择子  
  75. SelectorStackRing3 equ LABEL_STACKRING3 - LABEL_GDT +SA_RPL3   ;堆栈段的描述符的选择子  
  76. SelectorGStack equ  LABEL_GSTACK - LABEL_GDT       ;全局堆栈段的选择子  
  77. SelectorTss   equ   LABEL_TSS - LABEL_GDT    ;TSS描述符的选择子  
  78.   
  79. ;[SECTION .gdt]结束  
  80.   
  81. [SECTION .TSS]  
  82. ALIGN 32  
  83. [BITS 32]  
  84. LABEL_SEG_TSS:  
  85.         DD  0           ; Back  
  86.         DD  GStackLen   ; 0 级堆栈  
  87.         DD  SelectorGStack      ;   
  88.         DD  0           ; 1 级堆栈  
  89.         DD  0           ;   
  90.         DD  0           ; 2 级堆栈  
  91.         DD  0           ;   
  92.         DD  0           ; CR3  
  93.         DD  0           ; EIP  
  94.         DD  0           ; EFLAGS  
  95.         DD  0           ; EAX  
  96.         DD  0           ; ECX  
  97.         DD  0           ; EDX  
  98.         DD  0           ; EBX  
  99.         DD  0           ; ESP  
  100.         DD  0           ; EBP  
  101.         DD  0           ; ESI  
  102.         DD  0           ; EDI  
  103.         DD  0           ; ES  
  104.         DD  0           ; CS  
  105.         DD  0           ; SS  
  106.         DD  0           ; DS  
  107.         DD  0           ; FS  
  108.         DD  0           ; GS  
  109.         DD  0           ; LDT  
  110.         DW  0           ; 调试陷阱标志  
  111.         DW  $ - LABEL_SEG_TSS + 2   ; I/O位图基址  
  112.         DB  0ffh            ; I/O位图结束标志  
  113.   
  114.   
  115. TssLen equ $ - LABEL_SEG_TSS  
  116. ;[SECTION .TSS]结束  
  117.   
  118.   
  119. [SECTION .ldt] ;建立LDT表  
  120. ;LDT  
  121. ALIGN 32  
  122. LABEL_TABLE_LDT:  
  123. LABEL_CODEA: Descriptor 0,CodeALen - 1 ,DA_C + DA_32  ; ldt表中CODEA段的描述符  
  124.   
  125. LdtLen equ $ - LABEL_TABLE_LDT   
  126.   
  127. SelectorCodeA equ LABEL_CODEA - LABEL_TABLE_LDT + SA_TIL ;这里的SA_TIL表示是LDT中的选择符  
  128.   
  129. ;[SECTION .ldt]结束  
  130.   
  131. ;全局堆栈段  
  132. [SECTION .gstack] ;ring0级的堆栈段  
  133. ALIGN   32  
  134. [BITS   32]  
  135. LABEL_SEG_GSTACK:  
  136. times 512  db 0  
  137. GStackLen equ $ - LABEL_SEG_GSTACK - 1  
  138. ;[SECTION .gstack]结束  
  139.   
  140.   
  141. [SECTION .stackring3]  ;ring3级的堆栈段  
  142. ALIGN   32  
  143. [BITS   32]  
  144. LABEL_SEG_STACKRING3:  
  145. times 512 db 0  
  146.   
  147. StackRing3Len equ $ - LABEL_SEG_STACKRING3 - 1  
  148.   
  149. ;[SECTION .stackring3]结束  
  150.   
  151.   
  152.   
  153. [SECTION .codering3]  ;ring3级的代码段  
  154. ALIGN   32  
  155. [BITS   32]  
  156. LABEL_SEG_CODERING3:  
  157.   
  158. mov ax,SelectorVideo ;视频选择子,用于找到显存段的描述符  
  159. mov gs,ax   
  160.   
  161. mov edi,(80 * 10 + 3)*2  ;屏幕的第10行,第3列  
  162. mov ah,0Ch  
  163. mov al,'3'  
  164. mov [gs:edi],ax ;将字符‘3’输出到屏幕,表示进入了ring3级  
  165.   
  166. call SelectorCallGate:0        ;在这里使用调用门,进入ring0级的代码,在这里是[SECTION .goalcode]段  
  167.    
  168. jmp $                          ;最后程序停在这里  
  169.   
  170. CodeRing3Len equ $ - LABEL_SEG_CODERING3  
  171.   
  172. ;[SECTION .codering3]结束  
  173.   
  174.   
  175.   
  176. [SECTION .s16]  
  177. [BITS 16]   ;目标处理器模式  
  178. LABEL_BEGIN:  
  179. mov ax,cs  
  180. mov ds,ax  
  181. mov es,ax  
  182. mov ss,ax  
  183. mov sp,0100h  
  184.   
  185.   
  186. ;初始化TSS段的描述符  
  187. xor eax,eax  
  188. mov ax,cs  
  189. shl eax,4  
  190. add eax,LABEL_SEG_TSS  
  191. mov word [LABEL_TSS + 2], ax  
  192. shr eax, 16  
  193. mov byte [LABEL_TSS + 4], al  
  194. mov byte [LABEL_TSS + 7], ah  
  195.   
  196.   
  197. ;初始化全区堆栈段的描述符  
  198. xor eax,eax  
  199. mov ax,cs  
  200. shl eax,4  
  201. add eax,LABEL_SEG_GSTACK  
  202. mov word [LABEL_GSTACK + 2], ax  
  203. shr eax, 16  
  204. mov byte [LABEL_GSTACK + 4], al  
  205. mov byte [LABEL_GSTACK + 7], ah  
  206.   
  207. ;初始化特权级为3的代码段的描述符  
  208. xor eax,eax  
  209. mov ax,cs  
  210. shl eax,4  
  211. add eax,LABEL_SEG_CODERING3  
  212. mov word [LABEL_CODERING3 + 2], ax  
  213. shr eax, 16  
  214. mov byte [LABEL_CODERING3 + 4], al  
  215. mov byte [LABEL_CODERING3 + 7], ah  
  216.   
  217. ;初始化堆栈段的描述符  
  218. xor eax,eax  
  219. mov ax,cs  
  220. shl eax,4  
  221. add eax,LABEL_SEG_STACKRING3  
  222. mov word [LABEL_STACKRING3 + 2], ax  
  223. shr eax, 16  
  224. mov byte [LABEL_STACKRING3 + 4], al  
  225. mov byte [LABEL_STACKRING3 + 7], ah  
  226.   
  227.   
  228.   
  229. ;初始化调用门目标段的描述符  
  230. xor eax,eax  
  231. mov ax,cs  
  232. shl eax,4  
  233. add eax,LABEL_SEG_GOALCODE  
  234. mov word [LABEL_GOALCODE + 2], ax  
  235. shr eax, 16  
  236. mov byte [LABEL_GOALCODE + 4], al  
  237. mov byte [LABEL_GOALCODE + 7], ah  
  238.   
  239.   
  240.   
  241. ;初始化LDT在GDT中的描述符  
  242. xor eax,eax  
  243. mov ax,cs  
  244. shl eax,4  
  245. add eax,LABEL_TABLE_LDT  
  246. mov word [LABEL_LDT + 2], ax  
  247. shr eax, 16  
  248. mov byte [LABEL_LDT + 4], al  
  249. mov byte [LABEL_LDT + 7], ah  
  250.   
  251.   
  252. ;初始化LDT中的描述符  
  253. xor eax,eax  
  254. mov ax,cs  
  255. shl eax,4  
  256. add eax,LABEL_SEG_CODEA  
  257. mov word [LABEL_CODEA + 2], ax  
  258. shr eax, 16  
  259. mov byte [LABEL_CODEA + 4], al  
  260. mov byte [LABEL_CODEA + 7], ah  
  261.   
  262.   
  263.   
  264.   
  265.   
  266.   
  267. ;初始化32位段的描述符  
  268.   
  269. xor eax,eax   ; 同或运算,这里是将eax清零  
  270.   
  271. mov ax,cs  
  272. shl eax,4     ;左移四位,相当于乘以16,实模式下计算物理地址  
  273. add eax,LABEL_SEG_CODE32    ;eax中为32位段的物理地址  
  274.   
  275. mov word [LABEL_CODE32 + 2],ax   ;将32位段的物理地址存入段的描述符中  
  276.   
  277. shr eax,16  
  278. mov byte [LABEL_CODE32 + 4],al  
  279. mov byte [LABEL_CODE32 + 7],ah  
  280.   
  281. ;计算GDT表的物理地址,将GDT表的物理地址信息存入GdtPtr中  
  282. xor eax,eax  
  283. mov ax,cs  
  284. shl eax,4  
  285. add eax,LABEL_GDT  
  286. mov dword [GdtPtr + 2],eax  
  287.   
  288. ;现在进行第二步:将GDT表的信息加载到GDTR中  
  289. lgdt [GdtPtr]  ;装载GDTR  
  290.   
  291. ;关中断  
  292. cli  
  293.   
  294. ;现在进行第三步:打开地址线  
  295. in al,92h  
  296. or al,00000010b  
  297. out 92h,al  
  298.   
  299. ;现在进行第四步:置PE为1,表示CPU处于保护模式下  
  300. mov eax,cr0  
  301. or eax,1  
  302. mov cr0,eax  
  303. ;现在进入第五步:跳到保护模式的代码  
  304.   
  305. jmp dword SelectorCode32:0  ;这里将SelectorCode32存入CS中作为选择子  
  306. ;[SECTION .s16] 结束  
  307.   
  308. [SECTION .s32]  
  309. [BITS 32]    
  310.   
  311. LABEL_SEG_CODE32:  
  312. mov ax,SelectorVideo ;视频选择子,用于找到显存段的描述符  
  313. mov gs,ax   
  314.   
  315. mov ax,SelectorGStack  
  316. mov ss,ax  
  317. mov esp,GStackLen  
  318.   
  319.   
  320. mov edi,(80 * 10 + 0)*2  ;屏幕的第10行,第0列  
  321. mov ah,0Ch  
  322. mov al,'p'  
  323. mov [gs:edi],ax ;将字符‘p’输出到屏幕  
  324.    
  325. mov ax,SelectorTss  
  326. ltr ax  
  327.   
  328.    
  329. push SelectorStackRing3    ;ring3级的堆栈段的选择子  
  330.                        
  331. push StackRing3Len         ;ring3级的堆栈段的栈顶指针   
  332. push SelectorCodeRing3    ; ring3级的代码段的选择子  
  333. push 0                      ;ring3级的代码段的段内偏移  
  334.   
  335. retf                 ;从这跳到ring3级的代码段,ring3级堆栈段的栈底地址,栈顶指针, 代码段的选择子,偏移已由前面的三  
  336.                      ;个push进入了ring0级的堆栈段  
  337.   
  338.   
  339.   
  340.  mov ax,SelectorLdt  
  341.  lldt ax            ;将描述ldt表的描述符的选择子装入LDTR寄存器  
  342.   
  343. ;call SelectorCallGate:0   ;通过调用门,调用代码段  
  344.   
  345. jmp SelectorCodeA:0    ;调到局部任务  
  346.   
  347. SegCode32Len equ $ - LABEL_SEG_CODE32  ;计算32位代码段的长度  
  348.   
  349.   
  350. ;[SECTION .s32]结束  
  351.   
  352.   
  353. ;ldt表中描述符所指向的CODEA代码段  
  354. [SECTION .la]  
  355. [BITS 32]    
  356.   
  357. LABEL_SEG_CODEA:  
  358. mov ax,SelectorVideo ;视频选择子,用于找到显存段的描述符  
  359. mov gs,ax   
  360.   
  361. mov edi,(80 * 11 + 0)*2  ;屏幕的第11行,第0列  
  362. mov ah,0Ch  
  363. mov al,'l'  
  364. mov [gs:edi],ax ;将字符‘l’输出到屏幕  
  365.   
  366. jmp $  
  367.   
  368. CodeALen equ $ - LABEL_SEG_CODEA  ;计算32位代码段的长度  
  369. ;[SECTION .la]结束  
  370.   
  371. [SECTION .goalcode]   ;调用门的目标段,这里输出‘g’表示调用了该段  
  372. LABEL_SEG_GOALCODE:  
  373. mov ax,SelectorVideo ;视频选择子,用于找到显存段的描述符  
  374. mov gs,ax   
  375.   
  376. mov edi,(80 * 12 + 0)*2  ;屏幕的第12行,第0列  
  377. mov ah,0Ch  
  378. mov al,'g'  
  379. mov [gs:edi],ax ;将字符‘g’输出到屏幕  
  380. retf                         ;返回,调用该段的 代码段,这里是[SECTION .codering3]   
  381. GoalCodeLen equ $ - LABEL_SEG_GOALCODE    
  382. ;[SECTION .goalcode]结束  

下面是运行结果图:
0 0
原创粉丝点击