【0】写在前面

  • 0.1)本代码旨在演示 从 ring0 转移到 ring3(即,从高特权级 转移到 低特权级)
  • 0.2)本文 只对 与 门相关的 代码进行简要注释,言简意赅;
  • 0.3)文末的个人总结是干货,前面代码仅供参考的,且source code from orange’s implemention of a os.

; ==========================================
; pmtest5a.asm
; 编译方法:nasm pmtest5a.asm -o pmtest5a.com
; ========================================== %include "pm.inc" ; 常量, 宏, 以及一些说明 org 0100h
jmp LABEL_BEGIN

;[SECTION .gdt]

; GDT
; 段基址, 段界限 , 属性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ; Normal 描述符
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len-1, DA_C+DA_32; 非一致代码段,32
LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C ; 非一致代码段,16
LABEL_DESC_CODE_DEST: Descriptor 0, SegCodeDestLen-1, DA_C+DA_32; 非一致代码段,32

; ring3的代码段描述符的定义 [add]

LABEL_DESC_CODE_RING3: Descriptor 0,SegCodeRing3Len-1, DA_C+DA_32+DA_DPL3
LABEL_DESC_DATA: Descriptor 0, DataLen-1, DA_DRW ; Data
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32;Stack, 32 位

; ring3的堆栈段描述符的定义 [add]

LABEL_DESC_STACK3:     Descriptor 0,      TopOfStack3, DA_DRWA+DA_32+DA_DPL3
LABEL_DESC_LDT: Descriptor 0, LDTLen-1, DA_LDT ; LDT

; ring3的视频段描述符的DPL属性设置为 3 [add]

LABEL_DESC_VIDEO:      Descriptor 0B8000h,     0ffffh, DA_DRW+DA_DPL3

; 门                               目标选择子,偏移,DCount, 属性
LABEL_CALL_GATE_TEST: Gate SelectorCodeDest, 0, 0, DA_386CGate+DA_DPL0
; GDT 结束 GdtLen equ $ - LABEL_GDT ; GDT长度
GdtPtr dw GdtLen - 1 ; GDT界限
dd 0 ; GDT基地址 ; GDT 选择子
SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT
SelectorCodeDest equ LABEL_DESC_CODE_DEST - LABEL_GDT

; ring3的代码段描述符的选择子定义 [add]

SelectorCodeRing3   equ LABEL_DESC_CODE_RING3   - LABEL_GDT + SA_RPL3

SelectorData     equ    LABEL_DESC_DATA  - LABEL_GDT
SelectorStack equ LABEL_DESC_STACK - LABEL_GDT

; ring3的堆栈段描述符的选择子定义 [add]

SelectorStack3   equ    LABEL_DESC_STACK3   - LABEL_GDT + SA_RPL3

SelectorLDT  equ    LABEL_DESC_LDT   - LABEL_GDT

;ring3的视频段描述符(DPL==3)的选择子定义 [add]

SelectorVideo    equ    LABEL_DESC_VIDEO    - LABEL_GDT

SelectorCallGateTest    equ LABEL_CALL_GATE_TEST    - LABEL_GDT
; END of [SECTION .gdt]

[SECTION .data1] ; 数据段

ALIGN   32
[BITS 32]
LABEL_DATA:
SPValueInRealMode dw 0
; 字符串
PMMessage: db "In Protect Mode now. ^-^", 0 ; 进入保护模式后显示此字符串
OffsetPMMessage equ PMMessage - $$
StrTest: db "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0
OffsetStrTest equ StrTest - $$
DataLen equ $ - LABEL_DATA
; END of [SECTION .data1]

; 全局堆栈段

[SECTION .gs]

ALIGN   32
[BITS 32]
LABEL_STACK:
times 512 db 0 TopOfStack equ $ - LABEL_STACK - 1 ; END of [SECTION .gs]

; 堆栈段ring3的定义

[SECTION .s3]

ALIGN   32
[BITS 32]
LABEL_STACK3:
times 512 db 0
TopOfStack3 equ $ - LABEL_STACK3 - 1
; END of [SECTION .s3]

[SECTION .s16]

[BITS   16]
LABEL_BEGIN:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0100h mov [LABEL_GO_BACK_TO_REAL+3], ax
mov [SPValueInRealMode], sp ; 初始化 16 位代码段描述符
mov ax, cs
movzx eax, ax
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 ; 初始化 32 位代码段描述符
xor eax, eax
mov ax, 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 ; 初始化测试调用门的代码段描述符
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 ; 初始化数据段描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_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 ; 初始化堆栈段描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_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

; 初始化堆栈段描述符(Ring3) [add]

 xor    eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_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 ; 初始化 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

; 初始化Ring3描述符 [add]

 xor    eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_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 ; 为加载 GDTR 作准备
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_GDT ; eax <- gdt 基地址
mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址 ; 加载 GDTR
lgdt [GdtPtr] ; 关中断
cli ; 打开地址线A20
in al, 92h
or al, 00000010b
out 92h, al ; 准备切换到保护模式
mov eax, cr0
or eax, 1
mov cr0, eax ; 真正进入保护模式
jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0 处 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; LABEL_REAL_ENTRY: ; 从保护模式跳回到实模式就到了这里
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax mov sp, [SPValueInRealMode] in al, 92h ; ┓
and al, 11111101b ; ┣ 关闭 A20 地址线
out 92h, al ; ┛ sti ; 开中断 mov ax, 4c00h ; ┓
int 21h ; ┛回到 DOS
; END of [SECTION .s16]

[SECTION .s32]; 32 位代码段. 由实模式跳入.

[BITS   32]

LABEL_SEG_CODE32:
mov ax, SelectorData
mov ds, ax ; 数据段选择子
mov ax, SelectorVideo
mov gs, ax ; 视频段选择子 mov ax, SelectorStack
mov ss, ax ; 堆栈段选择子 mov esp, TopOfStack ; 下面显示一个字符串
mov ah, 0Ch ; 0000: 黑底 1100: 红字
xor esi, esi
xor edi, edi
mov esi, OffsetPMMessage ; 源数据偏移
mov edi, (80 * 10 + 0) * 2 ; 目的数据偏移。屏幕第 10 行, 第 0 列。
cld
.1:
lodsb
test al, al
jz .2
mov [gs:edi], ax
add edi, 2
jmp .1
.2: ; 显示完毕 call DispReturn

; ; 以下代码分步骤演示了如何将A的堆栈拷贝到B的堆栈(A==调用者,B=被调用者)

; 1.将ring3的堆栈段描述符的选择子压栈 [add]

 push   SelectorStack3

; 2.将ring3的堆栈压栈 [add]

 push   TopOfStack3

; 3.将ring3的堆栈值 压栈 [add]

 push   SelectorCodeRing3
push 0

; 4.retf 弹出ip + 弹出cs;此时ip==0, cs==SelectorCodeRing3,然后CPU自动解析出SelectorCodeRing3 索引(定位)的段描述符, 该描述符存储有

; 4.ring3下代码段LABEL_CODE_RING3 的基地址, 让我们转向 代码末尾的 LABEL_CODE_RING3 代码段吧;

 retf

 ; 测试调用门(无特权级变换),将打印字母 'C'
call SelectorCallGateTest:0
;call SelectorCodeDest:0 ; Load LDT
mov ax, SelectorLDT
lldt ax jmp SelectorLDTCodeA:0 ; 跳入局部任务,将打印字母 'L'。 ; ------------------------------------------------------------------------
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
; DispReturn 结束--------------------------------------------------------- SegCode32Len equ $ - LABEL_SEG_CODE32
; END of [SECTION .s32]

[SECTION .sdest]; 调用门目标段

[BITS   32]

LABEL_SEG_CODE_DEST:
mov ax, SelectorVideo
mov gs, ax ; 视频段选择子(目的) mov edi, (80 * 12 + 0) * 2 ; 屏幕第 12 行, 第 0 列。
mov ah, 0Ch ; 0000: 黑底 1100: 红字
mov al, 'C'
mov [gs:edi], ax retf SegCodeDestLen equ $ - LABEL_SEG_CODE_DEST
; END of [SECTION .sdest]

; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式

[SECTION .s16code]

ALIGN   32
[BITS 16]
LABEL_SEG_CODE16:
; 跳回实模式:
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]

; LDT

[SECTION .ldt]

ALIGN   32
LABEL_LDT:
; 段基址 段界限 , 属性
LABEL_LDT_DESC_CODEA: Descriptor 0, CodeALen - 1, DA_C + DA_32 ; Code, 32 位 LDTLen equ $ - LABEL_LDT ; LDT 选择子
SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL
; END of [SECTION .ldt]

; CodeA (LDT, 32 位代码段)

[SECTION .la]

ALIGN   32
[BITS 32]
LABEL_CODE_A:
mov ax, SelectorVideo
mov gs, ax ; 视频段选择子(目的) mov edi, (80 * 13 + 0) * 2 ; 屏幕第 13 行, 第 0 列。
mov ah, 0Ch ; 0000: 黑底 1100: 红字
mov al, 'L'
mov [gs:edi], ax ; 准备经由16位代码段跳回实模式
jmp SelectorCode16:0
CodeALen equ $ - LABEL_CODE_A
; END of [SECTION .la]

; CodeRing3的定义(ring3下的代码段)

; 显然, ring3 中的任务执行完后, jmp $ 这句代码使得程序 就会 永久停留在该处;

[SECTION .ring3]
ALIGN 32
[BITS 32]
LABEL_CODE_RING3:
mov ax, SelectorVideo
mov gs, ax mov edi, (80 * 14 + 0) * 2
mov ah, 0Ch
mov al, '3'
mov [gs:edi], ax jmp $
SegCodeRing3Len equ $ - LABEL_CODE_RING3
; END of [SECTION .ring3]



【总结-Conclusion】

  • C1)实现ring0 jmp 到ring3, 使用的是ret 指令,代码如下:(核心代码)

    ; 以下代码分步骤演示了如何将A的堆栈拷贝到B的堆栈(A==调用者,B=被调用者)

    ; 1.将ring3的堆栈段描述符的选择子压栈 [add](堆栈段描述符 存储有新堆栈的基地址ss)

    push    SelectorStack3

    ; 2.将ring3的堆栈压栈[add](新栈顶指针esp压栈)

    push    TopOfStack3

    ; 3.将ring3的堆栈值 压栈 [add] (将ring3 下的任务代码段基地址cs 压栈)

    push    SelectorCodeRing3
    ; (偏移量ip == 0 压栈)
    push 0

; 4.retf 弹出ip + 弹出cs;此时ip==0, cs==SelectorCodeRing3,然后CPU自动解析出SelectorCodeRing3 索引(定位)的段描述符, 该描述符存储有

; 4.ring3下代码段LABEL_CODE_RING3 的基地址;

 retf

要知道: retf == [ pop cs, pop ip ] , ret == pop ip

  • C2)指令ret 用于执行近返回、同特权级远返回和不同特权级的远返回;
  • C2.1)近返回仅在当前代码段中转移程序控制权, 因此CPU 仅仅进行界限检查;
  • C2.2)对于同特权级远返回, CPU同时从堆栈中弹出返回代码段的选择子和返回指令指针;
  • C2.3)会发生特权级改变的远返回仅允许返回到低特权级程序中, 即返回到的代码段DPL要大于CPL;

  • 当执行远返回时, CPU执行以下步骤(也即是上述过程的第4步——指令retf):

  • 1)检查保存的cs 中的RPL 以判断返回时是否要变换特权级;
  • 2)加载被调用者堆栈上的cs 和eip;
  • 3)如果ret 指令含有参数,则增加esp 跳过参数,然后esp 将指向被保存过的调用者ss 和 esp ;ret的参数个数对应 调用门中的 Param Count的值;
  • 4)加载ss 和 esp , 切换到调用者堆栈,被调用者的ss 和 esp 被丢弃;
  • 5)如果ret 指令含有参数, 增加esp 的值以跳过参数;
  • 6)检查ds、es、fs、gs的值,如果其中哪一个寄存器指向的段的DPL 小于CPL(此规则不适用于一致代码段),那么一个空描述符会被加载到该寄存器;




高特权级代码段转向低特权级代码段(利用 ret(retf) 指令实现 jmp from ring0 to ring3)的更多相关文章

  1. JavaScript 执行环境(执行上下文) 变量对象 作用域链 上下文 块级作用域 私有变量和特权方法

    总结自<高程三>第四章  理解Javascript_12_执行模型浅析   JS的执行环境与作用域  javascript高级程序第三版学习笔记[执行环境.作用域] 在javascript ...

  2. C/C++学习笔记---高地址、低地址、大段字节序、小段字节序

    字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端.大端两种字节顺序. 小端字节序指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处: 大端字节序是高字节数据存放在低地址 ...

  3. 一段显示隐藏列表HTML代码

    一段显示隐藏列表HTML代码, 技巧在于把页面上的元素(“返回首页”)和控制显示/隐藏的元素(id=navs-menu)放在一个共同的div上,并在该div上绑定onmouseover和onmouse ...

  4. SqlServer高版本数据库数据备份到低版本数据库上

    想要将Sqlserver2014高版本备份的数据还原到低版本SqlServer2012上去,但是这在SqlServer中是没法直接还原数据库的,通过以下方法可以顺利还原. 通过高版本生成sql脚本在低 ...

  5. 21 段实用便捷的 PHP 代码

    PHP 是目前使用最广泛的基于 Web 的编程语言,驱动着数以百万计的网站,其中也包括如 Facebook 等一些大型站点.这里收集了 21 段实用便捷的 PHP 代码摘录,对每种类型的 PHP 开发 ...

  6. linux驱动由浅入深系列:高通sensor架构实例分析之二(驱动代码结构)【转】

    本文转载自:https://blog.csdn.net/radianceblau/article/details/73498303 本系列导航: linux驱动由浅入深系列:高通sensor架构实例分 ...

  7. “段寄存器”的故事[转](彻底搞清内存段/elf段/实模式保护模式以及段寄存器)

    http://blog.csdn.net/michael2012zhao/article/details/5554023 一. 段寄存器的产生 段寄存器的产生源于Intel 8086 CPU体系结构中 ...

  8. VS开发中的代码编写小技巧——避免重复代码编写的几种方法

    上一篇文章中程序员的幸福生活--有你的日子,每天都是情人节,收到了大家的很多好评.鼓励和祝福,非常感动,真诚的谢谢大家.也希望每个朋友都能保持一个积极向上的心态,去迎接丰富多彩的人生. 在开发过程中, ...

  9. Java中静态代码块、构造代码块、构造函数、普通代码块

    在Java中,静态代码块.构造代码块.构造函数.普通代码块的执行顺序是一个笔试的考点,通过这篇文章希望大家能彻底了解它们之间的执行顺序. 1.静态代码块 ①.格式 在java类中(方法中不能存在静态代 ...

随机推荐

  1. Codeforces 475D CGCDSSQ 区间gcd值

    题目链接 题意 给定一个长度为 \(n\) 的数列 \(a_1,...,a_n\) 与 \(q\) 个询问 \(x_1,...,x_q\),对于每个 \(x_i\) 回答有多少对 \((l,r)\) ...

  2. [CF665F]Four Divisors

    题目大意: 给定$n(n\leq10^{11})$,求$\displaystyle\sum_{i=1}^n[\tau(i)=4]$. 思路: 设$p,q$为不相等的质数,则满足$\tau(i)=4$的 ...

  3. Ruby Time And DateTime之Time in Core

    今天遇到一个问题,就是在Ruby中对于Time和DateTime的使用,不是很明了,现在研究一下: 先说Time: 在Ruby2.0中关于Time有两处定义一个是在Core中,http://www.r ...

  4. 串口调试利器--Minicom配置及使用详解.md

    因为现在电脑基本不配备串行接口,所以,usb转串口成为硬件调试时的必然选择.目前知道的,PL2303的驱动是有的,在dev下的名称是ttyUSB*. Minicom,是Linux下应用比较广泛的串口软 ...

  5. 聊聊、Zookeeper Linux 启动

    Zookeeper 在 windows 下安装比较简单,属于无脑式安装,下载下来双击脚本就可以了.前面的文章中也有介绍,今天我来写写 Linux 下的安装,以及所碰到的坑. 首先,登陆 Linux 系 ...

  6. Displaying Tabbed and Stacked Canvas Using Show_View In Oracle Forms

    Displays the indicated canvas at the coordinates specified by the canvas's X Position and Y Position ...

  7. java编程思想第四版第9章

    练习3: public class MainTest { public static void main(String args[]){ Bcycle b=new Bcycle(); b.print( ...

  8. context:exclude-filter spring事宜【经典-转】

    context:exclude-filter spring事务 如果带上事务,那么用annotation方式的事务注解和bean配置,事务会失效,要将service bean配置到xml文件中才行. ...

  9. ElasticSearch命令增加字段总结

    1.建立一个String类型的字段 curl -XPUT http://192.168.46.163:9200/t_risk_case/_mapping/t_risk_case?pretty -d ' ...

  10. TensorFlow笔记二:线性回归预测(Linear Regression)

    代码: import tensorflow as tf import numpy as np import xlrd import matplotlib.pyplot as plt DATA_FILE ...