【1】README

  • 1.0)由于实现进程的切换任务,其功能涉及到 LDT + TSS +GATE + INTERRUPT;下面我们对这些内容进行复习;
  • 1.1) source code from orange’s implemention of a os .

##**【2】知识复习(LDT+TSS+GATE +** INTERRUPT)
**2.1)LDT的复习**

  • (1)在GDT中定义 LDT 描述符;
  • (2)然后在实模式下,初始化 GDT中的LDT描述符;
  • (3)还要初始化 LDT中的段描述符(用局部任务代码去初始化 LDT 中 段描述符的基地址);
  • (4)加载GDT到GDTR;
  • (5)切换到保护模式;
  • (6)做完任务后,跳转到局部任务(jmp SelectorLDTCodeA:0),SelectorLDTCodeA作为LDT的选择子,用于索引LDT中段描述符,其初始化在实模式下完成;
  • (7)紧接着就跳转到该选择子对应的任务代码段去执行;

2.2)对于GDT和LDT的结构,我们再做个总结

LABEL_GDT:

LABEL_DESC_LDT : Descriptor 0, LDTLen - 1, DA_LDT ; LDT

SelectorLDT equ LABEL_DESC_LDT- LABEL_GDT

LABEL_LDT

LABEL_LDT_DESC_CODEA : Descriptor 0, CodeALen - 1, DA_C + DA_32 ; Code, 32 位

SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT: + SA_TIL



; 初始化 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



; Load LDT

mov ax, SelectorLDT

lldt ax

jmp SelectorLDTCodeA :0 ; 跳入局部任务



; CodeA (LDT, 32 位代码段)

[SECTION .la]

ALIGN 32

[BITS 32]

LABEL_CODE_A :

mov ax, SelectorVideo

mov gs, ax ; 视频段选择子(目的)

mov edi, (80 * 12 + 0) * 2 ; 屏幕第 10 行, 第 0 列。

mov ah, 0Ch ; 0000: 黑底 1100: 红字

mov al, 'L'

mov [gs:edi],

(Attention)显然,我们发现,加载到 ldt 寄存器 的 选择子是 GDT中 LDT段描述符 的选择子, 而调用局部描述符对应的目标代码时,我们用的是 LDT 中的该代码对应的选择子;(干货)


**2.2)TSS的复习**

  • 由于每个任务可能在4个特权级间转移,故每个任务实际上需要4个堆栈;
  • 问题是:我们只有一个ss 和 esp, 那么当发生堆栈切换,我们该从哪里获取其他堆栈的ss 和 esp 呢?

    我们引入TSS, 它可以解决这个问题。
  • 我们再总结一下就是:不同特权级的代码段间的转移(更具体点,是从低特权级->高特权级),会发生堆栈切换,使得调用者的入栈的堆栈是针对调用者本身的堆栈, 而出栈操作是针对被调用者的堆栈,即入栈和出栈的堆栈不一致,使得特权级间跳转出错,故引入了 TSS;

(Conclusion)我们再理一理 TSS 和 GDT 的结构关系

; 任务状态段描述符 LABEL_DESC_TSS + 选择子

LABEL_GDT:

...........

LABEL_DESC_TSS : Descriptor 0, TSSLen-1, DA_386TSS ; ( DA_386TSS == 89h )

SelectorTSS equ LABEL_DESC_TSS - LABEL_GDT

; TSS [add] (任务状态段的定义)

[SECTION .tss]

ALIGN 32

[BITS 32]

LABEL_TSS :

DD 0 ; Back

DD TopOfStack ; 0 级堆栈

DD SelectorStack ;

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_TSS+ 2 ; I/O位图基址

DB 0ffh ; I/O位图结束标志

TSSLen equ $ - LABEL_TSS

; 初始化 TSS 描述符,实模式

xor eax, eax

mov ax, ds

shl eax, 4

add eax, LABEL_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

; Load TSS, 在保护模式中,从ring3->ring0之前

; 因为是先通过retf实现 ring0->ring3,然后通过门实现ring3->ring0(门目标段的特权级为0),ring3->ring0会发生堆栈切换,所以在这之前需要加载TSS进入 tr-任务寄存器

mov ax, SelectorTSS

ltr ax ; 在任务内发生特权级变换时要切换堆栈,而内层堆栈的指针存放在当前任务的TSS中,所以要设置任务状态段寄存器 TR。

push SelectorStack3

push TopOfStack3

push SelectorCodeRing3 ; 打印 '3'

push 0

retf

(Attention) 从以上代码,初始化TSS的内存空间,创建 GDT中的 TSS 描述符 以及 在实模式下初始化TSS 的描述符, 最后跳转到 保护模式,在特权级切换之前,我们把 TSS段描述符在GDT 中的选择子加载到了 tr-任务寄存器中,这样方便 不同特权级代码间的切换 进行堆栈切换;


**2.3)GATE的复习**

  • (1)在GDT中定义门描述符+门选择子 + 该门对应的代码段描述符及其选择子,从以下 门和门对应的代码段描述符 的定义可以看到,门描述符存储着该代码段描述符的选择子以建立它们间的联系;

    LABEL_DESC_CODE_DEST: Descriptor 0,SegCodeDestLen-1, DA_C+DA_32; 非一致代码段,32

    SelectorCodeDest equ LABEL_DESC_CODE_DEST- LABEL_GDT

    ; 门 目标选择子,偏移,DCount, 属性

    LABEL_CALL_GATE_TEST : Gate SelectorCodeDest, 0, 0, DA_386CGate+DA_DPL0

    SelectorCallGateTest equ LABEL_CALL_GATE_TEST - LABEL_GDT

  • (2)在实模式中初始化测试调用门的代码段描述符;(门对应的代码段,我们称其为调用门目标段)

      ; 初始化测试调用门的代码段描述符
    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
  • (3)加载GDT到GDTR,并进入保护模式;

  • (4)做完任务后,测试调用门(call SelectorCallGateTest:0),注意,它这里的调用地址用的是 调用门选择子,通过调用门选择子->调用门描述符->门目标段选择子->门目标段描述符->门目标段基地址,即通过调用门选择子寻址到门目标段基地址去运行;

    ; 测试调用门(无特权级变换),将打印字母 'C'

    call SelectorCallGateTest:0


**2.4)中断复习**

  • step0)构建中断处理程序函数(在32位代码段的保护模式中):

      _UserIntHandler:
    UserIntHandler equ _UserIntHandler - $$
    mov ah, 0Ch ; 0000: 黑底 1100: 红字
    mov al, 'I'
    mov [gs:((80 * 0 + 70) * 2)], ax ; 屏幕第 0 行, 第 70 列。
    iretd _SpuriousHandler:
    SpuriousHandler equ _SpuriousHandler - $$
    mov ah, 0Ch ; 0000: 黑底 1100: 红字
    mov al, '!'
    mov [gs:((80 * 0 + 75) * 2)], ax ; 屏幕第 0 行, 第 75 列。
    jmp $
    iretd
  • step1)构建IDT,IDT表项也就是门(中断门+陷阱门),主要是为中断向量号(依据表项索引)绑定中断处理程序,(为演示方便,特别为向量号 80h 绑定了中断处理程序),要知道,中断向量号 把中断异常的处理程序 与 中断异常类型联系了起来;

      [SECTION .idt]
    ALIGN 32
    [BITS 32]
    LABEL_IDT:
    ; 门 目标选择子, 偏移, DCount, 属性
    %rep 128
    Gate SelectorCode32, SpuriousHandler, 0, DA_386IGate
    %endrep
    .080h: Gate SelectorCode32, UserIntHandler, 0, DA_386IGate
    IdtLen equ $ - LABEL_IDT
    IdtPtr dw IdtLen - 1 ; 段界限
    dd 0 ; 基地址
  • step2)实模式下,为加载IDTR做准备, 并将IDT(基地址+段界限)加载到 IDTR;

      ; 为加载 IDTR 作准备
    xor eax, eax
    mov ax, ds
    shl eax, 4
    add eax, LABEL_IDT ; eax <- idt 基地址
    mov dword [IdtPtr + 2], eax ; [IdtPtr + 2] <- idt 基地址
    ; 加载 GDTR
    lgdt [GdtPtr]
    ; 关中断
    cli
    ; 加载 IDTR
    lidt [IdtPtr]
  • step4)向主8259A写入OCW1,以开启定时器中断, 然后向从8259A写入OCW1 以屏蔽从8259A所有中断;

      ; start Init8259A
    Init8259A:
    mov al, 011h
    out 020h, al ; 主8259, ICW1.
    call io_delay out 0A0h, al ; 从8259, ICW1.
    call io_delay mov al, 020h ; IRQ0 对应中断向量 0x20
    out 021h, al ; 主8259, ICW2.
    call io_delay mov al, 028h ; IRQ8 对应中断向量 0x28
    out 0A1h, al ; 从8259, ICW2.
    call io_delay mov al, 004h ; IR2 对应从8259
    out 021h, al ; 主8259, ICW3.
    call io_delay mov al, 002h ; 对应主8259的 IR2
    out 0A1h, al ; 从8259, ICW3.
    call io_delay mov al, 001h
    out 021h, al ; 主8259, ICW4.
    call io_delay out 0A1h, al ; 从8259, ICW4.
    call io_delay mov al, 11111110b ; 仅仅开启定时器中断
    ;mov al, 11111111b ; 屏蔽主8259所有中断
    out 021h, al ; 主8259, OCW1.
    call io_delay mov al, 11111111b ; 屏蔽从8259所有中断
    out 0A1h, al ; 从8259, OCW1.
    call io_delay ret
    ; over Init8259A
  • step5)触发中断 int 080h;

知识复习(LDT+TSS+GATE+INTERRUPT)的更多相关文章

  1. 前端知识复习: JS选中变色

    前端知识复习:JS选中变色 上篇文章 :前端知识复习:Html DIV 图文混排(文字放在图片下边) Js选中图片效果 <!DOCTYPE html> <html xmlns=&qu ...

  2. 前端知识复习:Html DIV 图文混排(文字放在图片下边)

    Html知识复习之图文混排 练习练习基础 先上效果图: 废话不多说,直接贴代码: <!DOCTYPE html> <html xmlns="http://www.w3.or ...

  3. PE知识复习之PE的绑定导入表

    PE知识复习之PE的绑定导入表 一丶简介 根据前几讲,我们已经熟悉了导入表结构.但是如果大家尝试过打印导入表的结构. INT IAT的时候. 会出现问题. PE在加载前 INT IAT表都指向一个名称 ...

  4. PE知识复习之PE的重定位表

    PE知识复习之PE的重定位表 一丶何为重定位 重定位的意思就是修正偏移的意思.  如一个地址位 0x401234 ,Imagebase = 0x400000 . 那么RVA就是 1234.  如果Im ...

  5. PE知识复习之PE的导入表

    PE知识复习之PE的导入表 一丶简介 上一讲讲解了导出表. 也就是一个PE文件给别人使用的时候.导出的函数  函数的地址 函数名称 序号 等等. 一个进程是一组PE文件构成的.  PE文件需要依赖那些 ...

  6. PE知识复习之PE的导出表

    PE知识复习之PE的导出表 一丶简介 在说明PE导出表之前.我们要理解.一个PE可执行程序.是由一个文件组成的吗. 答案: 不是.是由很多PE文件组成.DLL也是PE文件.如果我们PE文件运行.那么就 ...

  7. PE知识复习之PE合并节

    PE知识复习之PE合并节 一丶简介 根据上一讲.我们为PE新增了一个节. 并且属性了各个成员中的相互配合. 例如文件头记录节个数.我们新增节就要修改这个个数. 那么现在我们要合并一个节.以上一讲我们例 ...

  8. PE知识复习之PE新增节

    PE知识复习之PE新增节 一丶为什么新增节.以及新增节的步骤 例如前几讲.我们的PE文件在空白区可以添加代码.但是这样是由一个弊端的.因为你的空白区节属性可能是只读的不能执行.如果你修改了属性.那么程 ...

  9. PE知识复习之PE扩大节

    PE知识复习之PE扩大节 一丶为什么扩大节 上面我们讲了,空白区添加我们的代码.但是有的时候.我们的空白区不够了怎么办.所以需要进行扩大节. 扩大节其实很简单.修改节数据对齐后的大小即可. 并且在PE ...

随机推荐

  1. linux下的程序调试方法汇总

    搞电子都知道,电路不是焊接出来的,是调试出来的.程序员也一定认同,程序不是写出来的,是调试出来的.那么调试工具就显得尤为重要,linux作为笔者重要的开发平台,在linux中讨论调试工具主要是为那些入 ...

  2. AI创投的冰与火之歌:泡沫、跟风、短板和有钱花不出去的沮丧【转】

    转自:http://36kr.com/p/5071386.html 国内的AI行业仍处于野蛮生长阶段.热钱不少,优质项目却不多.创业者拿钱难,投资者有钱却花不出去. 编者按:本文来自微信公众号“刺猬公 ...

  3. Python 多核 多线程 调度

    参考: http://www.oschina.net/translate/pythons-hardest-problem https://news.ycombinator.com/item?id=58 ...

  4. LeetCode OJ-- Container With Most Water

    https://oj.leetcode.com/problems/container-with-most-water/ 不同高度的柱子排一列,两个柱子可以组成一个容器,求最大容积. 最直观的方法就是暴 ...

  5. Cryptography I 学习笔记 --- 认证加密

    1. 认证加密,Alice与Bob共享一个密钥k,Alice可以发送密文E给Bob,Bob可以确定接收到的E一定是拥有密钥k的Alice产生的.而不是攻击者随便产生的. 2. 认证加密必须能抵挡住选择 ...

  6. fs寄存器相关,PEB,TEB

    ---恢复内容开始--- FS寄存器指向:偏移 说明000 指向SEH链指针004 线程堆栈顶部008 线程堆栈底部00C SubSystemTib010 FiberData014 Arbitrary ...

  7. Maven错误:“No goals have been specified for this build...”问题解决

    如图出现如下错误: 解决方法如下: 1.(未测试)在pom.xml添加如下配置: <build> <defaultGoal>compile</defaultGoal> ...

  8. HDU1421

    提交啦n次一直WA,这个bug找啦几个小时,最终才发现数组开小啦,真是遗憾.这是一个典型的DP问题,题目要求从n个中选出k对使得最终疲劳度最小.首先对物品质量a[n]进行一次排序,用dp[i][j]表 ...

  9. 关于Web应用和容器的指纹收集以及自动化软件的制作

    一次对Web应用的渗透,九成都是从信息收集开始,所以信息收集就显得尤为重要.关键信息的收集可以使你在后期渗透的时候更加的得心应手,把渗透比喻成走黑暗迷宫的话,那信息收集可以帮你点亮迷宫的大部分地图. ...

  10. kali渗透测试基础

    一侦查 研究如何收集有关目标的情报,比如开发那些端口用来通信,托管在哪里,提供给客户的服务类型等. 交付内容应该包括需要攻击的所有目标资产清单,与那些资产关联的应用,使用的服务以及可能的资产所有者. ...