gdt描述_全局描述符表GDT

写在前面

添油加醋系列第二弹——剖析GDT

话说C语言的话除了刷刷OJ外,就是用来实现操作系统这个大头了。C语言比C++少了很多很多臃肿的语法特性,写起来非常优美(至少写操作系统是这样的)。虽说C++有许多的奇技淫巧,一个算法有N种实现方法,但这会让选择恐惧症患者(比如我)难堪,比如说一个类要怎样写啊等等,,抛开其他不谈,假如一个语言的语法特性越少,学起来可能越简单(刚试过lua语法很简单)。OK废话不多说,进入本章主题(涉及OS的资料很杂很偏,如有错误望海涵)。

GDT的构成

首先,根据网上资料,GDT(全局描述符表)又叫段描述符表,暂且就这样认为吧,如有异议可以提出来。

在代码中它又是这样:

// 全局描述符表结构 http://www.cnblogs.com/hicjiajia/archive/2012/05/25/2518684.html

// base: 基址(注意,base的byte是分散开的)

// limit: 寻址最大范围 tells the maximum addressable unit

// flags: 标志位 见上面的AC_AC等

// access: 访问权限

struct gdt_entry {

uint16_t limit_low;

uint16_t base_low;

uint8_t base_middle;

uint8_t access;

unsigned limit_high: 4;

unsigned flags: 4;

uint8_t base_high;

} __attribute__((packed));

这时你的内心OS:

答案是——它们都是GDT。。

关于C语言的问题:首先,可能有些童鞋不知道struct里那些冒号是神马意思。(C语言 struct结构体的变量声明加冒号)这里叫作“位域”,就是占几个二进制位。同时,它又涉及内存对齐的概念(C语言 结构体的内存对齐问题与位域)。涉及__attribute__((packed))的概念(__attribute__ 你知多少?)它是手动设置对齐大小。

众所周知,一个字节byte是八个bit,那么结构体中有两个4bit的成员,不可能用16bit去容纳它们吧~让它们互相挤挤,节省空间,何乐而不为。

可能看到这里,已经花了好多时间了……没办法,OS的内容非常多,同时GCC的一些怪异偏僻用法又不得不去领会,所以只能一步步来,慢慢理解,急不得。

至于GDT为什么这样描述呢,我自创行不行?一个字——标准,你想改,可能你电脑里的硬件设施不答应……

GDT的存在意义全局描述符表GDT(Global Descriptor Table)在整个系统中,全局描述符表GDT只有一张(一个处理器对应一个GDT),GDT可以被放在内存的任何位置,但CPU必须知道GDT的入口,也就是基地址放在哪里,Intel的设计者门提供了一个寄存器GDTR用来存放GDT的入口地址,程序员将GDT设定在内存中某个位置之后,可以通过LGDT指令将GDT的入口地址装入此寄存器,从此以后,CPU就根据此寄存器中的内容作为GDT的入口来访问GDT了。GDTR中存放的是GDT在内存中的基地址和其表长界限。也就是说,GDT是全局的,存放在内存中的某个位置,而这个位置是由你来指定给CPU的,换句话说,你来钦定!

设置GDT

现在知道了GDT的struct构成(就是一个个数组元素),那么我们要给CPU的就是一个gdt_entry数组地址啦~

那么设置gdt_entry的方法如下:

void gdt_install(uint8_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags) {

/* Setup the descriptor base address */

gdt[num].base_low = (base & 0xffff);

gdt[num].base_middle = (base >> 16) & 0xff;

gdt[num].base_high = (base >> 24) & 0xff;

/* Setup the descriptor limits */

gdt[num].limit_low = (limit & 0xffff);

gdt[num].limit_high = ((limit >> 16) & 0x0f);

/* Finally, set up the granularity and access flags */

gdt[num].flags = flags;

access |= AC_RE; // 设置保留位为1

gdt[num].access = access;

}

通过实例认识它:

// 宏定义

#define AC_AC 0x1 // 可访问 access

#define AC_RW 0x2 // [代码]可读;[数据]可写 readable for code selector & writeable for data selector

#define AC_DC 0x4 // 方向位 direction

#define AC_EX 0x8 // 可执行 executable, code segment

#define AC_RE 0x10 // 保留位 reserve

#define AC_PR 0x80 // 有效位 persent in memory

// 特权位: 01100000b

#define AC_DPL_KERN 0x0 // RING 0 kernel level

#define AC_DPL_USER 0x60 // RING 3 user level

#define GDT_GR 0x8 // 页面粒度 page granularity, limit in 4k blocks

#define GDT_SZ 0x4 // 大小位 size bt, 32 bit protect mode

// gdt selector 选择子

#define SEL_KCODE 0x1 // 内核代码段

#define SEL_KDATA 0x2 // 内核数据段

#define SEL_UCODE 0x3 // 用户代码段

#define SEL_UDATA 0x4 // 用户数据段

#define SEL_TSS 0x5 // 任务状态段 task state segment http://wiki.osdev.org/TSS

// RPL 请求特权等级 request privilege level

#define RPL_KERN 0x0

#define RPL_USER 0x3

// CPL 当前特权等级 current privilege level

#define CPL_KERN 0x0

#define CPL_USER 0x3

========================================================

/* Setup the GDT pointer and limit */

gp.limit = (sizeof(struct gdt_entry) * NGDT) - 1;

gp.base = (uint32_t)&gdt;

/* null descriptor */

gdt_install(0, 0, 0, 0, 0);

/* kernel code segment type: code addr: 0 limit: 4G gran: 4KB sz: 32bit */

gdt_install(SEL_KCODE, 0, 0xfffff, AC_RW|AC_EX|AC_DPL_KERN|AC_PR, GDT_GR|GDT_SZ);

/* kernel data segment type: data addr: 0 limit: 4G gran: 4KB sz: bit 32bit */

gdt_install(SEL_KDATA, 0, 0xfffff, AC_RW|AC_DPL_KERN|AC_PR, GDT_GR|GDT_SZ);

/* user code segment type: code addr: 0 limit: 4G gran: 4KB sz: 32bit */

gdt_install(SEL_UCODE, 0, 0xfffff, AC_RW|AC_EX|AC_DPL_USER|AC_PR, GDT_GR|GDT_SZ);

/* user code segment type: data addr: 0 limit: 4G gran: 4KB sz: 32bit */

gdt_install(SEL_UDATA, 0, 0xfffff, AC_RW|AC_DPL_USER|AC_PR, GDT_GR|GDT_SZ);

我的理解是,gdt_install的参数:(段选择子索引号/见题图,基址起始,长度,访问权限,GDT flags)。虽然上述例子中基址起始地址和长度都是一样的(原项目https://github.com/SilverRainZ/OS677是这样写的,可能有点问题),但是访问权限中有AC_EX和AC_DPL_KERN(ring0)/AC_DPL_USER(ring3)的变化,说明每个段的权限是不同的。这些段管理的是同一片内存,只是由于当前索引号的不同,访问/修改内存的权限也不同。分段管理可以把虚拟地址转换成线性地址,而分页管理可以进一步将线性地址转换成物理地址。

(根据段选择子找到)段基指 + 偏移地址 => 线性地址

线性地址 (通过页表) => 物理地址

通过将GDT告诉给CPU后,CPU就知道了操作系统中段的设置,从而可以通过段选择子得到线性地址,在后面实现分页管理后,可进一步将线性地址转换为物理地址(不过当前连物理 址有多大都没法知道呢,在后面会解决)。

段选择子

段选择子包括三部分:描述符索引(index)、TI(指示从GDT还是LDT中找)、请求特权级(RPL)。index部分表示所需要的段的描述符在描述符表的位置,由这个位置再根据在GDTR中存储的描述符表基址就可以找到相应的描述符gdt_entry。然后用描述符gdt_entry中的段基址SEL加上逻辑地址OFFSET就可以转换成线性地址SEL:OFFSET(看下面给的例子应该就是它们的和SEL+OFFSET)

段选择子中的TI值只有一位0或1,0代表选择子是在GDT选择,1代表选择子是在LDT选择。

请求特权级(RPL)则代表选择子的特权级,共有4个特权级(0级、1级、2级、3级),0级最高。关于特权级的说明:任务中的每一个段都有一个特定的级别。每当一个程序试图访问某一个段时,就将该程序所拥有的特权级与要访问的特权级进行比较,以决定能否访问该段。系统约定,CPU只能访问同一特权级或级别较低特权级的段。

例如:给出逻辑地址:21h:12345678h,需要将其转换为线性地址

a. 选择子SEL=21h=0000000000100 0 01b,他代表的意思是:选择子的index=4即100b,选择GDT中的第4个描述符;TI=0代表选择子是在GDT选择;左后的01b代表特权级RPL=1(因此有SEL=n<<3,n是索引号)

b. OFFSET=12345678h,若此时GDT第四个描述符中描述的段基址(Base)为11111111h,则线性地址=11111111h+12345678h=23456789h

任务状态段TSS任务寄存器(TR)用于寻址一个特殊的任务状态段(Task State Segment,TSS)。TSS中包含着当前执行任务的重要信息。

TR寄存器用于存放当前任务TSS段的16位段选择符、32位基地址、16位段长度和描述符属性值。它引用GDT表中的一个TSS类型的描述符。指令LTR和STR分别用于加载和保存TR寄存器的段选择符部分。当使用LTR指令把选择符加载进任务寄存器时,TSS描述符中的段基地址、段限长度以及描述符属性会被自动加载到任务寄存器中。当执行任务切换时,处理器会把新任务的TSS的段选择符和段描述符自动加载进任务寄存器TR中。

它的初始化和设置:

void tss_init() {

gdt_install(SEL_TSS, (uint32_t)&tss, sizeof(tss),AC_PR|AC_AC|AC_EX, GDT_GR);

/* for tss, access_reverse bit is 1 */

gdt[5].access &= ~AC_RE;

}

// 装载TSS

void tss_install() {

__asm__ volatile("ltr %%ax" : : "a"((SEL_TSS << 3)));

}

// 设置TSS

void tss_set(uint16_t ss0, uint32_t esp0) {

// 清空TSS

memset((void *)&tss, 0, sizeof(tss));

tss.ss0 = ss0;

tss.esp0 = esp0;

tss.iopb_off = sizeof(tss);

}

跟GDT也差不了多少,只是GDT_SZ没有了,也指定了tss的地址,并设置gdt_entry的保留位为1(至于为啥我没有仔细查)。至于__asm__ volatile的GCC在C语言中内嵌汇编 asm __volatile__我也没全部搞明白怎么用。SEL_TSS << 3的话要参考选择子的构成,它高13位是索引,所以要乘8。在任务内发生特权级变换时堆栈也随着自动切换,外层堆栈指针保存在内层堆栈中,而内层堆栈指针存放在当前任务的TSS中。所以,在从外层向内层变换时,要访问TSS(从内层向外层转移时不需要访问TSS,而只需访问内层栈中保存的栈指针)。

LTR指令是专门用于装载任务状态段寄存器TR的指令。该指令的操作数是对应TSS段描述符的选择子。LTR指令从GDT中取出相应的TSS段描述符,把TSS段描述符的基地址和界限等信息装入TR的高速缓冲寄存器中。

// 任务状态段 task state segment http://wiki.osdev.org/TSS

// The only interesting fields are SS0 and ESP0.

// SS0 gets the kernel datasegment descriptor (e.g. 0x10 if the third entry in your GDT describes your kernel's data)

// ESP0 gets the value the stack-pointer shall get at a system call

// IOPB may get the value sizeof(TSS) (which is 104) if you don't plan to use this io-bitmap further (according to mystran in http://forum.osdev.org/viewtopic.php?t=13678)

// http://blog.csdn.net/huybin_wang/article/details/2161886

// TSS的使用是为了解决调用门中特权级变换时堆栈发生的变化

// http://www.kancloud.cn/wizardforcel/intel-80386-ref-manual/123838

/*

TSS 状态段由两部分组成:

1、 动态部分(处理器在每次任务切换时会设置这些字段值)

通用寄存器(EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI)

段寄存器(ES,CS,SS,DS,FS,GS)

状态寄存器(EFLAGS)

指令指针(EIP)

前一个执行的任务的TSS段的选择子(只有当要返回时才更新)

2、 静态字段(处理器读取,但从不更改)

任务的LDT选择子

页目录基址寄存器(PDBR)(当启用分页时,只读)

内层堆栈指针,特权级0-2

T-位,指示了处理器在任务切换时是否引发一个调试异常

I/O 位图基址

*/

struct tss_entry {

uint32_t link;

uint32_t esp0;

uint32_t ss0;

uint32_t esp1;

uint32_t ss1;

uint32_t esp2;

uint32_t ss2;

uint32_t cr3;

uint32_t eip;

uint32_t eflags;

uint32_t eax;

uint32_t ecx;

uint32_t edx;

uint32_t ebx;

uint32_t esp;

uint32_t ebp;

uint32_t esi;

uint32_t edi;

uint32_t es;

uint32_t cs;

uint32_t ss;

uint32_t ds;

uint32_t fs;

uint32_t gs;

uint32_t ldtr;

uint16_t padding1;

uint16_t iopb_off;

} __attribute__ ((packed));

阶段性总结

涉及OS的内容真是庞大,单单一个GDT就涉及巨量的知识,包括结构体定义、汇编指令、GCC黑魔法、参数的使用等,还涉及了TSS,目标仅仅是实现分段管理。而后面还有中断管理、物理内存管理、虚拟内存管理等一系列内容,篇幅绝对不比本文少,真令人望洋兴叹。

原始项目OS67中也存在着一些错误,有些错误像是单词拼写等我已经纠正了,还有些如软盘访问我去参考了网上的资料,与OS67的不一致,但我没采用OS67的。毕竟OS67也是其作者自己摸索出来的,让我跳过了许多坑。。不过我想后面的进程管理还是得自己写才能体会更深。

既然OS的内容很杂很多,所以也只能挑一些重点的讲讲了,不可能面面俱到,在后面的编写/借鉴中,还是要以查资料为主,给源码附上参考文章的地址,方便阅读。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/488182.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

咸阳高考成绩查询2021,2021咸阳市地区高考成绩排名查询,咸阳市高考各高中成绩喜报榜单...

距离2018年高考还有不到一个月的时间了&#xff0c;很多人在准备最后冲刺的同时&#xff0c;也在关心高考成绩。2018各地区高考成绩排名查询,高考各高中成绩喜报榜单尚未公布&#xff0c;下面是往年各地区高考成绩排名查询,高考各高中成绩喜报榜单&#xff0c;想要了解同学可以…

云计算与人工智能

来自&#xff1a;cnblogs.com/popsuper1982/p/8505203.html我今天要讲这三个话题&#xff0c;一个是云计算&#xff0c;一个大数据&#xff0c;一个人工智能&#xff0c;我为什么要讲这三个东西呢&#xff1f;因为这三个东西现在非常非常的火&#xff0c;它们之间好像互相有关系…

泸西一中2021高考成绩查询,云南红河州四所好高中,红河州一中一本率领先,建水一中不容小觑...

红河州地处我国西南&#xff0c;是一个常住人口超过467万的多民族聚居边疆自治州(地级行政区划)&#xff0c;下辖4市(县级)、9县(其中3个自治县)&#xff0c;经济总量在全省仅次于昆明与曲靖&#xff0c;是一个综合实力较强的自治州。红河州的基础教育实力相当不错&#xff0c;…

Date类

Date&#xff1a;是时间对象&#xff0c;它也是对象数据类型的一个细分 获取的是当前自己电脑的时间&#xff08;获取客户端的时间&#xff09; var nowTime new Date(); GMT&#xff1a;格林尼治时间&#xff08;经纬度都是0&#xff09; 中国是 GMT0800 东八区 美国是 UTC-0…

python 遍历list_Python列表遍历知多少

遍历列表中的所有元素是常用的一种操作&#xff0c;在遍历的过程中可以完成查询、处理等功能。在生活中&#xff0c;如果想要去商场买一件衣服&#xff0c;就需要在商场中逛一圈&#xff0c;看是否有想要买的衣服。逛商场的过程相当于列表的遍历操作。在Python中遍历列表的方法…

【JavaWeb】Maven(学习笔记)

一、Maven概述 1、Maven Maven 是一个项目管理工具 2、Maven解决的问题 jar 包问题编译测试运行打包 3、Maven的组成 项目对象模型 &#xff1a;pom.xml标准集合&#xff1a;目录结构标准一个项目生命周期(Project Lifecycle)依赖管理系统&#xff1a;通过配置文件管理用…

高中计算机学考操作ppt,高中信息技术基础学考专题复习(共25张PPT)

ID:11883433资源大小&#xff1a;308KB资料简介:信息的加工与管理 信息资源管理 计算机的功能与特征 文字处理:WORD 图表处理:EXCEL 多媒体信息处理:图像、音频、视频基本概念 算法及其实现 信息资源管理基本概念 网上数据的管理 数据库系统及简单应用:ACCESS 信息的表达 信息的…

自我监督学习:AI技术的未来发展方向

尽管深度学习已经在人工智能领域做出重大贡献&#xff0c;但这项技术本身仍存在一项致命缺陷&#xff1a;需要大量数据的加持。来源丨The Next Web尽管深度学习已经在人工智能领域做出重大贡献&#xff0c;但这项技术本身仍存在一项致命缺陷&#xff1a;需要大量数据的加持。深…

vue8 生命周期

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>智能社——http://www.zhinengshe.com</title><meta name"viewport" content"widthdevice-width, initial-scale1.0, maximum…

简述css属性选择器的几种定义方式_CSS简介,语法,选择器分类使用,属性设置

1.CSS简介CSS(Cascading Style Sheets)通常称为CSS样式表或层叠样式表(级联样式表)&#xff0c;主要用于设置HTML页面中的文本内容(字体、大小、对齐方式等)、图片的外形(宽高、边框样式、边距等)以及版面的布局等外观显示样式。CSS以HTML为基础&#xff0c;提供了丰富的功能&a…

AI无间道!清华AI团队推出AI安全平台,欺骗顶尖人脸算法后又强势修复漏洞

随着人工智能技术的发展&#xff0c;人工智能在很多场景里正逐渐替代或协作着人类的各种劳动&#xff0c;它们可以成为人类的眼睛、耳朵、手臂甚至大脑。其中&#xff0c;机器视觉作为AI时代的基础技术&#xff0c;其背后的AI算法一直是各科技巨头和创业公司共同追逐的热点。然…

计算机组装与维护预实验报告,计算机组装与维护实验报告.doc

计算机组装与维护实验报告计算机组装与维护实验报告江西公安专科学校实 验 报 告课程名称年级专业学 号姓 名\实 验 报 告 说 明1.实验项目名称&#xff1a;要用最简练的语言反映实验的内容。要求与实验教学大纲或实验指导书相一致。2.实验类型&#xff1a;一般需说明是验证型实…

[数位dp] bzoj 3209 花神的数论题

[数位dp] bzoj 3209 花神的数论题 题意&#xff1a;中文题。 思路&#xff1a;和普通数位dp一样&#xff0c;这里转换成二进制&#xff0c;然后记录有几个一。 统计的时候乘起来就好了。 代码&#xff1a; #include"cstdlib" #include"cstdio" #include&qu…

高数七重积分的总结_高等数学重积分总结

【本章学习目标】⒈理解二重积分的概念与性质&#xff0c;了解二重积分的几何意义以及二重积分与定积分之间的联系&#xff0c;会用性质比较二重积分的大小&#xff0c;估计二重积分的取值范围。⒉领会将二重积分化为二次积分时如何确定积分次序和积分限&#xff0c;如何改换二…

神经拟态芯片拉近AI与人脑距离

来源&#xff1a;科技日报除了会看会听&#xff0c;还会“闻”。近日&#xff0c;一直致力于模仿人类五感的人工智能又有新突破&#xff0c;通过神经拟态芯片&#xff0c;人工智能已经掌握了丙酮、氨和甲烷等10种气味的神经表征&#xff0c;强烈的环境干扰也不会影响它对气味的…

单片机与微型计算机在结构上的区别和联系,AT89S52单片机片内硬件组成结构,与一般单片机和微机组成结构比较,显著区别有?...

满意答案a52245122020.09.19采纳率&#xff1a;49% 等级&#xff1a;8已帮助&#xff1a;159人以下内容讲诉了AT89S51/52单片机与AT89C51单片机的区别&#xff0c;资源来自网络转帖于此&#xff0c;请核实后采用。它们之间主要区别在于以下几点&#xff1a;1.引脚功能:管脚几…

Python基础教程之第3章 使用字符串

Python 2.7.5 (default, May 15 2013, 22:43:36) [MSC v.1500 32 bit (Intel)] on win32 Type "copyright", "credits" or "license()" for more information. #3.1基本字符串操作 >>> website http://www.python.org >>> we…

linux 拼音输出繁体_解决rime仓颉拼音反查为繁体的问题

和昆明IT没关系, 不过困扰我好几年的事解决了, 占地发一下:rime 有个很强的地方: 仓颉输入的时候, 想不起来, 可以输入拼音, 能提示对应字的仓颉的输入法. 也就是能用拼音反查对应的仓颉输入码.这样太方便学习了, 可是... 切到简体输入后, 输拼音反查时, 有时提示的是对应字的繁…

蒲慕明院士:脑机融合技术或许会成为未来人工智能的一个热门方向

来源&#xff1a;中国经济大讲堂【导读】当前&#xff0c;以人工智能为代表的新技术&#xff0c;成为推动第四次工业革命走向深入的重要力量&#xff0c;会给经济、社会、文化等多领域的发展带来深刻变革。但是&#xff0c;因为对大脑工作方式的了解有限&#xff0c;人工智能的…

html 两个图片并排,HTML – 两个图像并排和响应

使用显示表并排放置并保持并排并响应.显示&#xff1a;表;表格布局&#xff1a;固定;将使用display&#xff1a;table-cell为子元素创建流畅的布局;这不仅可以使它们保持相同的宽度,还可以使容器保持相同的高度.vertical-align&#xff1a;top;将它们与顶部对齐,或者您可以将垂…