一直以来,我们把所有的段描述符都放在GDT中,而不管它属于内核还是用户程序,为了有效地在任务之间实施隔离,处理器建议每个任务都应当具有自己的描述符表,称为局部描述符表LDT,并且把专属于自己的那些段放到LDT中。

和GDT一样,LDT也是用来存放描述符的。不同之处在于,LDT只属于某个任务。或者说,每个任务都有自己的LDT,每个任务私有的段,都应当在LDT中进行描述。另外,LDT的第1个描述符,也就是0号槽位,也是有效的、可以使用的。

[SECTION .gdt]
; GDT
; 段基址, 段界限 , 属性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32 ; 非一致代码段
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址
LABEL_DESC_LDT: Descriptor 0, LDTLen - 1, DA_LDT ; LDT
; GDT 结束 GdtLen equ $ - LABEL_GDT ; GDT长度
GdtPtr dw GdtLen - 1 ; GDT界限
dd 0 ; GDT基地址 ; GDT 选择子
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
SelectorLDT equ LABEL_DESC_LDT - LABEL_GDT [SECTION .s16]
[BITS 16]
LABEL_BEGIN:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0100h ; 初始化 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 ; 初始化 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 ; 为加载 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,
; 并跳转到 SelectorCode32:0 处
; END of [SECTION .s16]

GDTR全局描述符寄存器:48位,高32位存放GDT基址,低16为存放GDT限长。
LDTR局部描述符寄存器:16位,高13为存放LDT在GDT中的索引值。

LDTR寄存器只用于指向当前任务的LDT。每当发生任务切换时,LDTR的内容被更新以指向新任务的LDT。如果选择子的TI被置为1则系统将从当前LDT中寻找相应描述符。当用到SelectorLDTCodeA时,系统会从LDT中找到LABEL_LDT_DESC_CODEA描述符,并跳转到相应的段中。在用LDT前需要先用lldt指令加载ldtr,lldt的操作数是GDT中用来描述LDT的描述符。

; 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 选择子,SA_TIL将此选择子的TI位置为1.
SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL
; END of [SECTION .ldt]

使用方法如下:

LABEL_SEG_CODE32:
...
; 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], ax jmp $
CodeALen equ $ - LABEL_CODE_A
; END of [SECTION .la]

运行结果如下:

源码及软盘映像

操作系统开发系列—4.LDT的更多相关文章

  1. 操作系统开发系列—13.i.进程调度 ●

    上面的三个进程都是延迟相同的时间,让我们修改一下,尝试让它们延迟不同的时间. void TestA() { int i = 0; while (1) { disp_str("A." ...

  2. 操作系统开发系列—13.g.操作系统的系统调用 ●

    在我们的操作系统中,已经存在的3个进程是运行在ring1上的,它们已经不能任意地使用某些指令,不能访问某些权限更高的内存区域,但如果一项任务需要这些使用指令或者内存区域时,只能通过系统调用来实现,它是 ...

  3. 操作系统开发系列—13.d.多进程 ●

    进程此时不仅是在运行而已,它可以随时被中断,可以在中断处理程序完成之后被恢复.进程此时已经有了两种状态:运行和睡眠.我们已经具备了处理多个进程的能力,只需要让其中一个进程处在运行态,其余进程处在睡眠态 ...

  4. 操作系统开发系列—13.a.进程 ●

    进程的切换及调度等内容是和保护模式的相关技术紧密相连的,这些代码量可能并不多,但却至关重要. 我们需要一个数据结构记录一个进程的状态,在进程要被挂起的时候,进程信息就被写入这个数据结构,等到进程重新启 ...

  5. 操作系统开发系列—12.f.在内核中添加中断处理 ●

    因为CPU只有一个,同一时刻要么是客户进程在运行,要么是操作系统在运行,如果实现进程,需要一种控制权转换机制,这种机制便是中断. 要做的工作有两项:设置8259A和建立IDT. /*========= ...

  6. 操作系统开发系列—9.Loader

    一个操作系统从开机到开始运行,大致经历“引导—>加载内核入内存—>跳入保护模式—>开始执行内核”这样一个过程.也就是说,在内核开始执行之前不但要加载内核,而且还有准备保护模式等一系列 ...

  7. 操作系统开发系列—1.HelloWorld ●

    org 07c00h ;伪指令,告诉编译器程序会被加载到7c00处 mov ax, cs mov ds, ax mov es, ax call DispStr ;调用显示字符串例程 jmp $ ;无限 ...

  8. 操作系统开发系列—13.h.延时操作

    计数器的工作原理是这样的:它有一个输入频率,在PC上是1193180HZ.在每一个时钟周期(CLK cycle),计数器值会减1,当减到0时,就会触发一个输出.由于计数器是16位的,所以最大值是655 ...

  9. 操作系统开发系列—13.e.三进程

    我们再来添加一个任务,首先添加一个进程体: void TestC() { int i = 0x2000; while(1){ disp_str("C"); disp_int(i++ ...

随机推荐

  1. 编译Linux内核

    下面的实验以 debian7.5 64bit 为例. 获取源码 获取 debian7.5 本身的源码非常简单: sudo apt-get install linux-source https://ww ...

  2. javascript时间戳和日期字符串相互转换

    <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="C ...

  3. HT for Web列表和3D拓扑组件的拖拽应用

    很多可视化编辑器都或多或少有一些拖拽功能,比如从一个List列表中拖拽一个节点到拓扑组件上进行建模,并且在拖拽的过程中鼠标位置下会附带一个被拖拽节点的缩略图,那么今天我们就来实现这样的拖拽效果. 首先 ...

  4. 【Swift学习】Swift编程之旅---集合类型之字典(八)

    字典是一种存储相同类型多重数据的存储器.每个值(value)都关联独特的键(key),键作为字典中的这个值数据的标识符.和数组中的数据项不同,字典中的数据项并没有具体顺序. 字典写作Dictionar ...

  5. react路由深度解析

    先看一段代码能否秒懂很重要 这是app.js  全局js的入口 import React from 'react' import { render } from 'react-dom' import ...

  6. vue-resource 拦截器使用

    在vue项目使用vue-resource的过程中,临时增加了一个需求,需要在任何一个页面任何一次http请求,增加对token过期的判断,如果token已过期,需要跳转至登录页面.如果要在每个页面中的 ...

  7. ASP.NET MVC图片管理(删除)

    上星期有写了一篇<ASP.NET MVC图片管理(上传,预览与显示)>http://www.cnblogs.com/insus/p/4620420.html 它只实现了上传功能,即时预览以 ...

  8. HoverTree项目添加了查看留言列表功能

    HoverTree项目添加了查看留言列表功能 页面:HoverTreeWeb项目下hvtpanel/usermessage/messagelist.aspx 添加留言页面:addmessage.asx ...

  9. NanUI for Winform 使用示例【第二集】——做一个所见即所得的Markdown编辑器

    经过了这一个多星期的调整与修复,NanUI for .NET Winform的稳定版已经发布.应广大群友的要求,现已将NanUI的全部代码开源. GitHub: https://github.com/ ...

  10. windows下用eclipse+goclipse插件+gdb搭建go语言开发调试环境

    windows下用eclipse+goclipse插件+gdb搭建go语言开发调试环境   http://rongmayisheng.com/post/windows%E4%B8%8B%E7%94%A ...