八、x86cpu创建LDT表

局部描述符表(Local Descriptor Table,简称LDT)是保护模式下存储器寻址的一种数据表。跟GDT(Global Descriptor Table)表结构相对应,结构也类似,每个进程都可以创建自己的LDT表并调用。

LDT 提供了将一个任务的代码段、数据段与操作系统的其余部分相隔离的机制。其段描述符被放在 GDT 中。首先要从 GDT 中找到 LDT 描述符。

LDT 由寄存器 LDTR控制,当一个任务需要引用自身的 LDT 时,它需要通过 LLDT 指令将其 LDT 的段描述符装入 LDTR 寄存器。与 LGDT 指令不同的是,LGDT 指令的操作数是一个32位的内存地址,这个内存地址处存放的是一个32位 GDT 的入口地址以及16位的 GDT 界限。而 LLDT 指令的操作数是一个16位的选择子,这个选择子的主要内容是被装入的 LDT 的段描述符在 GDT 中的索引值。

 

LDT表为每个任务提供了一种隔离和管理私有内存段的机制。通过LDT,操作系统能够将一个任务的代码段、数据段、堆栈等与其他任务分隔开来,从而避免任务之间的相互干扰和错误访问。这有助于提高系统的稳定性和安全性。在多任务环境中,不同任务可能有各自特定的资源需求和访问权限,LDT能够为每个任务定制化地管理这些资源和权限。

下面进行LDT表的创建

参考文档在GDT表中配置LDT表并进行初始化

#define TASK0_LDT_SEL           (8 * 8)             // 任务0 LDT
#define TASK1_LDT_SEL           (9 * 8)             // 任务1 LDT

[TASK0_LDT_SEL / 8] = {sizeof(task0_ldt_table) - 1, (uint32_t)0, 0xe200, 0x00cf},
[TASK1_LDT_SEL / 8] = {sizeof(task0_ldt_table) - 1, (uint32_t)0, 0xe200, 0x00cf},

 配置LDT表的地址

 gdt_table[TASK0_LDT_SEL / 8].base_l = (uint32_t)task0_ldt_table;
 gdt_table[TASK1_LDT_SEL / 8].base_l = (uint32_t)task1_ldt_table;

定义LDT表中的数据段和代码段

//判断cs寄存器中的第二位,如果为0,从GDT表中加载,如果为1,从LDT表中加载所以或4,运行在特权级3的模式下,所以或3
#define TASK_CODE_SEG           (0*0 | 0x4 | 3)         // LDT, 任务代码段
#define TASK_DATA_SEG           (1*8 | 0x4 | 3)         // LDT, 任务代码段

参考文档初始化LDT表,可以看到LDT表和GDT表的结构基本完全一样,所以我们可以直接跟GDT表进行一样的初始化。

//LDT表跟GDT表结构类似,可以仿照初始化
struct {uint16_t limit_l, base_l, basehl_attr, base_limit;}task0_ldt_table[2] __attribute__((aligned(8))) = {
    // 0x00cffa000000ffff - 从0地址开始,P存在,DPL=3,Type=非系统段,32位代码段,界限4G
    [TASK_CODE_SEG/ 8] = {0xffff, 0x0000, 0xfa00, 0x00cf},
    // 0x00cff3000000ffff - 从0地址开始,P存在,DPL=3,Type=非系统段,数据段,界限4G,可读写
    [TASK_DATA_SEG/ 8] = {0xffff, 0x0000, 0xf300, 0x00cf},
};

struct {uint16_t limit_l, base_l, basehl_attr, base_limit;}task1_ldt_table[2] __attribute__((aligned(8))) = {
   // 0x00cffa000000ffff - 从0地址开始,P存在,DPL=3,Type=非系统段,32位代码段,界限4G
    [TASK_CODE_SEG/ 8] = {0xffff, 0x0000, 0xfa00, 0x00cf},
    // 0x00cff3000000ffff - 从0地址开始,P存在,DPL=3,Type=非系统段,数据段,界限4G,可读写
    [TASK_DATA_SEG/ 8] = {0xffff, 0x0000, 0xf300, 0x00cf},
};

  tss结构中保存的GDT表中的应用数据段和应用代码段改成LDT表中对应的值

// es, cs, ss, ds, fs, gs, ldt, iomap

//APP_DATA_SEG, APP_CODE_SEG, APP_DATA_SEG, APP_DATA_SEG, APP_DATA_SEG, APP_DATA_SEG, (uint32_t), 0x0,

//将GDT表中的应用代码段和应用数据段改成LDT表中相应的段

TASK_DATA_SEG, TASK_CODE_SEG, TASK_DATA_SEG, TASK_DATA_SEG, TASK_DATA_SEG, TASK_DATA_SEG, TASK0_LDT_SEL, 0x0,


// es, cs, ss, ds, fs, gs, ldt, iomap

//APP_DATA_SEG, APP_CODE_SEG, APP_DATA_SEG, APP_DATA_SEG, APP_DATA_SEG, APP_DATA_SEG, 0x0, 0x0,

TASK_DATA_SEG, TASK_CODE_SEG, TASK_DATA_SEG, TASK_DATA_SEG, TASK_DATA_SEG, TASK_DATA_SEG, TASK1_LDT_SEL, 0x0,

汇编指令lldt,加载ldtr寄存器,这个过程放在_start_32即保护模式开始运行之后,此时已经加载任务0

mov $TASK0_LDT_SE
lldt %ax

 在中断中把GDT表中的值改成LDT表的,参见上一章系统调用,要把数据段和代码段压到栈底,这样能被tss结构调用

push $TASK_DATA_SEG
push $TASK_CODE_SEG

 调试代码

可以看到LDT表已经创建,此时,在task0,task1中的程序不在调用GDT表中的应用代码段和应用数据段,而是调用保存在task0和task1中的LDT代码段和数据段

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值