专注于操作系统18之完整的特权级转换
来源:互联网 发布:淘宝童装图片素材 编辑:程序博客网 时间:2024/04/29 21:12
在上一篇文章中,我们已经能从ring0级进入到ring3级,在这里我们将再加上从ring3级到ring0级。从ring3级到ring0级这需要使用在第十四篇文章中提到的调用门来实现。即在进入ring3级后,在使用调用门来调用ring0级代码(注意当发生特权级转换时,堆栈是发生了变化的,上一篇文章已说明从ring0级到ring3级堆栈所发生的变化。当从ring3到ring0级时,ring0级堆栈信息要放在TSS中,转换时,会从中取得ring0级堆栈的信息,将ss和esp指向这个堆栈)。特权级在描述符中存储。
下面给出代码, 代码参考了《自己动手写操作系统》。
- ;;nasm 2.07
- ;;nasm changelv.asm -o changelv.com
- org 0100H
- %macro Descriptor 3 ;定义Descriptor结构体宏
- dw %2 & 0FFFFh ; 段界限 1 (2 字节)
- dw %1 & 0FFFFh ; 段基址 1 (2 字节)
- db (%1 >> 16) & 0FFh ; 段基址 2 (1 字节)
- dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ; 属性 1 + 段界限 2 + 属性 2 (2 字节)
- db (%1 >> 24) & 0FFh ; 段基址 3 (1 字节)
- %endmacro ; 共 8 字节
- ;定义Gate结构体宏
- %macro Gate 4
- dw (%2 & 0FFFFh) ; 偏移 1 (2 字节)
- dw %1 ; 选择子 (2 字节)
- dw (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 属性 (2 字节)
- dw ((%2 >> 16) & 0FFFFh) ; 偏移 2 (2 字节)
- %endmacro ; 共 8 字节
- DA_C EQU 98h ; 只读代码段的属性值
- DA_DRW EQU 92h ; 允许读写的数据段的属性值
- DA_DRWA EQU 93h ; 存在的已访问可读写数据段类型值
- DA_32 EQU 4000h ;32位段的属性值
- DA_LDT EQU 82h ; 局部描述符表段类型值
- SA_TIL EQU 4 ; 用于指明是LDT的描述符,即选择符中TI=1
- DA_386CGate EQU 8Ch ; 386 调用门类型值
- DA_386TSS EQU 89h ; 可用 386 任务状态段类型值
- DA_DPL0 EQU 00h ; DPL = 0
- DA_DPL1 EQU 20h ; DPL = 1
- DA_DPL2 EQU 40h ; DPL = 2
- DA_DPL3 EQU 60h ; DPL = 3
- SA_RPL0 EQU 0 ; ┓
- SA_RPL1 EQU 1 ; ┣ RPL
- SA_RPL2 EQU 2 ; ┃
- SA_RPL3 EQU 3 ; ┛
- jmp LABEL_BEGIN
- ;现在进行第一步:建立GDT表
- [SECTION .gdt] ;用于放GDT表的段
- ;GDT
- LABEL_GDT: Descriptor 0,0,0 ;空描述符,当一个任务没有LDT时,会把LDTR清空,这时,LDTR便指向空描述符。
- LABEL_CODE32: Descriptor 0,SegCode32Len-1,DA_C + DA_32 ; 代码段的描述符,特权级为0
- LABEL_VIDEO: Descriptor 0B8000h,0ffffh,DA_DRW +DA_DPL3 ;显存的描述符,0b8000h是显存的首地址,特权级为3
- ;GDT 结束
- LABEL_NORMAL: Descriptor 0,0ffffh,DA_DRW ;normal描述符,用于将段寄存器的属性规范化(即属性为读写,大小为0ffffh)
- LABEL_GOALCODE: Descriptor 0,GoalCodeLen -1 ,DA_C + DA_32 ;调用门目标段的描述符,特权级为0
- LABEL_LDT: Descriptor 0,LdtLen - 1,DA_LDT ;用于描述LDT表的描述符
- LABEL_CALL_GATE: Gate SelectorGoalCode,0,0,DA_386CGate + DA_DPL3 ;门描述符,特权级为3
- LABEL_CODERING3: Descriptor 0,CodeRing3Len -1 , DA_C + DA_32 + DA_DPL3 ;特权级为3的代码段的描述符
- LABEL_STACKRING3: Descriptor 0, StackRing3Len , DA_32 + DA_DRWA + DA_DPL3 ;特权级为3的代码段对应的堆栈段的描述符
- LABEL_GSTACK: Descriptor 0, GStackLen , DA_32 + DA_DRWA ;全局堆栈段的描述符
- LABEL_TSS: Descriptor 0, TssLen -1 ,DA_386TSS ;TSS段的描述符
- GdtLenth equ $ - LABEL_GDT ;计算GDT表的长度
- GdtPtr dw GdtLenth - 1 ; 准备存入GDTR的信息
- dd 0 ; 用于存放GDT表的物理地址,后面会计算
- ;GDT选择子
- SelectorLdt equ LABEL_LDT - LABEL_GDT ;ldt表的选择子
- SelectorCode32 equ LABEL_CODE32 - LABEL_GDT ;代码段的选择子
- SelectorVideo equ LABEL_VIDEO - LABEL_GDT ;显存所在段的选择子
- SelectorNormal equ LABEL_NORMAL - LABEL_GDT ;normal描述符的选择子
- SelectorGoalCode equ LABEL_GOALCODE - LABEL_GDT ;调用门所调用的目标段的描述符的选择子
- SelectorCallGate equ LABEL_CALL_GATE - LABEL_GDT ;调用门的描述符的选择子
- SelectorCodeRing3 equ LABEL_CODERING3 - LABEL_GDT + SA_RPL3 ;特权级为3的代码段的描述符的选择子
- SelectorStackRing3 equ LABEL_STACKRING3 - LABEL_GDT +SA_RPL3 ;堆栈段的描述符的选择子
- SelectorGStack equ LABEL_GSTACK - LABEL_GDT ;全局堆栈段的选择子
- SelectorTss equ LABEL_TSS - LABEL_GDT ;TSS描述符的选择子
- ;[SECTION .gdt]结束
- [SECTION .TSS]
- ALIGN 32
- [BITS 32]
- LABEL_SEG_TSS:
- DD 0 ; Back
- DD GStackLen ; 0 级堆栈
- DD SelectorGStack ;
- DD 0 ; 1 级堆栈
- DD 0 ;
- DD 0 ; 2 级堆栈
- DD 0 ;
- DD 0 ; CR3
- DD 0 ; EIP
- DD 0 ; EFLAGS
- DD 0 ; EAX
- DD 0 ; ECX
- DD 0 ; EDX
- DD 0 ; EBX
- DD 0 ; ESP
- DD 0 ; EBP
- DD 0 ; ESI
- DD 0 ; EDI
- DD 0 ; ES
- DD 0 ; CS
- DD 0 ; SS
- DD 0 ; DS
- DD 0 ; FS
- DD 0 ; GS
- DD 0 ; LDT
- DW 0 ; 调试陷阱标志
- DW $ - LABEL_SEG_TSS + 2 ; I/O位图基址
- DB 0ffh ; I/O位图结束标志
- TssLen equ $ - LABEL_SEG_TSS
- ;[SECTION .TSS]结束
- [SECTION .ldt] ;建立LDT表
- ;LDT
- ALIGN 32
- LABEL_TABLE_LDT:
- LABEL_CODEA: Descriptor 0,CodeALen - 1 ,DA_C + DA_32 ; ldt表中CODEA段的描述符
- LdtLen equ $ - LABEL_TABLE_LDT
- SelectorCodeA equ LABEL_CODEA - LABEL_TABLE_LDT + SA_TIL ;这里的SA_TIL表示是LDT中的选择符
- ;[SECTION .ldt]结束
- ;全局堆栈段
- [SECTION .gstack] ;ring0级的堆栈段
- ALIGN 32
- [BITS 32]
- LABEL_SEG_GSTACK:
- times 512 db 0
- GStackLen equ $ - LABEL_SEG_GSTACK - 1
- ;[SECTION .gstack]结束
- [SECTION .stackring3] ;ring3级的堆栈段
- ALIGN 32
- [BITS 32]
- LABEL_SEG_STACKRING3:
- times 512 db 0
- StackRing3Len equ $ - LABEL_SEG_STACKRING3 - 1
- ;[SECTION .stackring3]结束
- [SECTION .codering3] ;ring3级的代码段
- ALIGN 32
- [BITS 32]
- LABEL_SEG_CODERING3:
- mov ax,SelectorVideo ;视频选择子,用于找到显存段的描述符
- mov gs,ax
- mov edi,(80 * 10 + 3)*2 ;屏幕的第10行,第3列
- mov ah,0Ch
- mov al,'3'
- mov [gs:edi],ax ;将字符‘3’输出到屏幕,表示进入了ring3级
- call SelectorCallGate:0 ;在这里使用调用门,进入ring0级的代码,在这里是[SECTION .goalcode]段
- jmp $ ;最后程序停在这里
- CodeRing3Len equ $ - LABEL_SEG_CODERING3
- ;[SECTION .codering3]结束
- [SECTION .s16]
- [BITS 16] ;目标处理器模式
- LABEL_BEGIN:
- mov ax,cs
- mov ds,ax
- mov es,ax
- mov ss,ax
- mov sp,0100h
- ;初始化TSS段的描述符
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,LABEL_SEG_TSS
- mov word [LABEL_TSS + 2], ax
- shr eax, 16
- mov byte [LABEL_TSS + 4], al
- mov byte [LABEL_TSS + 7], ah
- ;初始化全区堆栈段的描述符
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,LABEL_SEG_GSTACK
- mov word [LABEL_GSTACK + 2], ax
- shr eax, 16
- mov byte [LABEL_GSTACK + 4], al
- mov byte [LABEL_GSTACK + 7], ah
- ;初始化特权级为3的代码段的描述符
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,LABEL_SEG_CODERING3
- mov word [LABEL_CODERING3 + 2], ax
- shr eax, 16
- mov byte [LABEL_CODERING3 + 4], al
- mov byte [LABEL_CODERING3 + 7], ah
- ;初始化堆栈段的描述符
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,LABEL_SEG_STACKRING3
- mov word [LABEL_STACKRING3 + 2], ax
- shr eax, 16
- mov byte [LABEL_STACKRING3 + 4], al
- mov byte [LABEL_STACKRING3 + 7], ah
- ;初始化调用门目标段的描述符
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,LABEL_SEG_GOALCODE
- mov word [LABEL_GOALCODE + 2], ax
- shr eax, 16
- mov byte [LABEL_GOALCODE + 4], al
- mov byte [LABEL_GOALCODE + 7], ah
- ;初始化LDT在GDT中的描述符
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,LABEL_TABLE_LDT
- mov word [LABEL_LDT + 2], ax
- shr eax, 16
- mov byte [LABEL_LDT + 4], al
- mov byte [LABEL_LDT + 7], ah
- ;初始化LDT中的描述符
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,LABEL_SEG_CODEA
- mov word [LABEL_CODEA + 2], ax
- shr eax, 16
- mov byte [LABEL_CODEA + 4], al
- mov byte [LABEL_CODEA + 7], ah
- ;初始化32位段的描述符
- xor eax,eax ; 同或运算,这里是将eax清零
- mov ax,cs
- shl eax,4 ;左移四位,相当于乘以16,实模式下计算物理地址
- add eax,LABEL_SEG_CODE32 ;eax中为32位段的物理地址
- mov word [LABEL_CODE32 + 2],ax ;将32位段的物理地址存入段的描述符中
- shr eax,16
- mov byte [LABEL_CODE32 + 4],al
- mov byte [LABEL_CODE32 + 7],ah
- ;计算GDT表的物理地址,将GDT表的物理地址信息存入GdtPtr中
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,LABEL_GDT
- mov dword [GdtPtr + 2],eax
- ;现在进行第二步:将GDT表的信息加载到GDTR中
- lgdt [GdtPtr] ;装载GDTR
- ;关中断
- cli
- ;现在进行第三步:打开地址线
- in al,92h
- or al,00000010b
- out 92h,al
- ;现在进行第四步:置PE为1,表示CPU处于保护模式下
- mov eax,cr0
- or eax,1
- mov cr0,eax
- ;现在进入第五步:跳到保护模式的代码
- jmp dword SelectorCode32:0 ;这里将SelectorCode32存入CS中作为选择子
- ;[SECTION .s16] 结束
- [SECTION .s32]
- [BITS 32]
- LABEL_SEG_CODE32:
- mov ax,SelectorVideo ;视频选择子,用于找到显存段的描述符
- mov gs,ax
- mov ax,SelectorGStack
- mov ss,ax
- mov esp,GStackLen
- mov edi,(80 * 10 + 0)*2 ;屏幕的第10行,第0列
- mov ah,0Ch
- mov al,'p'
- mov [gs:edi],ax ;将字符‘p’输出到屏幕
- mov ax,SelectorTss
- ltr ax
- push SelectorStackRing3 ;ring3级的堆栈段的选择子
- push StackRing3Len ;ring3级的堆栈段的栈顶指针
- push SelectorCodeRing3 ; ring3级的代码段的选择子
- push 0 ;ring3级的代码段的段内偏移
- retf ;从这跳到ring3级的代码段,ring3级堆栈段的栈底地址,栈顶指针, 代码段的选择子,偏移已由前面的三
- ;个push进入了ring0级的堆栈段
- mov ax,SelectorLdt
- lldt ax ;将描述ldt表的描述符的选择子装入LDTR寄存器
- ;call SelectorCallGate:0 ;通过调用门,调用代码段
- jmp SelectorCodeA:0 ;调到局部任务
- SegCode32Len equ $ - LABEL_SEG_CODE32 ;计算32位代码段的长度
- ;[SECTION .s32]结束
- ;ldt表中描述符所指向的CODEA代码段
- [SECTION .la]
- [BITS 32]
- LABEL_SEG_CODEA:
- mov ax,SelectorVideo ;视频选择子,用于找到显存段的描述符
- mov gs,ax
- mov edi,(80 * 11 + 0)*2 ;屏幕的第11行,第0列
- mov ah,0Ch
- mov al,'l'
- mov [gs:edi],ax ;将字符‘l’输出到屏幕
- jmp $
- CodeALen equ $ - LABEL_SEG_CODEA ;计算32位代码段的长度
- ;[SECTION .la]结束
- [SECTION .goalcode] ;调用门的目标段,这里输出‘g’表示调用了该段
- LABEL_SEG_GOALCODE:
- mov ax,SelectorVideo ;视频选择子,用于找到显存段的描述符
- mov gs,ax
- mov edi,(80 * 12 + 0)*2 ;屏幕的第12行,第0列
- mov ah,0Ch
- mov al,'g'
- mov [gs:edi],ax ;将字符‘g’输出到屏幕
- retf ;返回,调用该段的 代码段,这里是[SECTION .codering3]
- GoalCodeLen equ $ - LABEL_SEG_GOALCODE
- ;[SECTION .goalcode]结束
下面是运行结果图:
0 0
- 专注于操作系统18之完整的特权级转换
- 专注于操作系统18之完整的特权级转换
- 专注于操作系统15之特权级
- 专注于操作系统17之进入ring3特权级
- 专注于操作系统1之操作系统的从无到有a
- 专注于操作系统2之操作系统的从无到有b
- 专注于操作系统3之计算机的启动过程
- 专注于操作系统27之对GetFATEntry函数的理解
- 专注于操作系统4之引导程序
- 专注于操作系统5之引导程序代码
- 专注于操作系统13之LDT
- 专注于操作系统19之走进分页
- 专注于操作系统20之启动分页
- 专注于操作系统21之分页进阶
- 专注于操作系统22之中断
- 专注于操作系统23之中断进阶
- 专注于操作系统6之导入操作系统内核
- 专注于操作系统7之初识保护模式
- openstack vs docker
- jquery学习总结
- android 音乐播放器,带seekBar滑动
- 题目1208:10进制 VS 2进制
- 引用类型归纳
- 专注于操作系统18之完整的特权级转换
- 接口常见的两种实用方式
- 非洲小孩
- Nginx使用的php-fpm的两种进程管理方式及优化
- spark webui的展示
- LDT
- java web基础1Tomcat服务器基本知识
- 加权并查集—— uva12232 Exclusive-OR
- 最好的8个 Java RESTful 框架