逻辑地址--------------》线性地址------------》 物理地址

      分段          分页

GDT是[gobal (segment) descriptor table]的缩写,它保存所有segment的信息

内存管理时,不让多进程的程序出现内存冲突的一解决方案是Segmentation。4GB的内存可以任何分割,每块的初始地址都是0。另外还有一种复杂的内存管理方案,既Paging,目前主流的操作系统都是采用这种方式。本文的OS为了实现简单,只采用Segmentation方案。

我们规定1个Segmentation的信息有:

l         Size

l         初始地址

l         属性(读写权限等)。

每个Segementation信息占8Byte,既64bit。我们把所有的Segment编号,并把编号保存在CPU内的16位segment register里。Segment register可以处理0到8191个segment,本来16位的register应该可以处理0到65535个segment,但是因为register的低3为不能使用,所以最多只到8191。为了保存8192个segment(每个8bytes),需要64KB的容量,CPU是无法保存这么多数据的,因此需要内存的帮助。GDT是[gobal (segment) descriptor table]的缩写,它保存所有segment的信息。Segment的初始地址和有效设定个数保存在CPU的GDTR寄存器内。另外一个IDT是[interrupt descriptor table]的缩写,用来处理一些内部或外部的中断。例如键盘,鼠标,软驱,硬盘,CDROM,网卡等。IDT可以处理0到255编号的中断,例如当123号中断发生时,调用XXX函数。IDT的信息和GDT相似,也是每个8bytes。本系统的GDT分配在内存的0x27000到0x27ffff。IDT是0x26f800到0x26ffff,占2KB。

我们将Segment定义为:

struct SEGMENT_DESCRIPTOR {

short limit_low, base_low;

char base_mid, access_right;

char limit_high, base_high;

};

Segment信息的初始地址由32bit组成,成为Base地址,分为3个部分,low(2byte),mid(1byte),high(1byte),如此分割是为了兼容80286 CPU。

Segment信息的大小成为Limit,Limit最大可以为4GB,当然是在32位机。这样就需要4Byte,和Base地址一共需要8个byte,但这样就没有保存属性的位置。为了留给属性空间,只能给Limit 20bit,最大能表示1MB,当然这样是不能满足目前主流的32bit机的。Intel为了解决这个问题,规定了在属性里留有1位称为G bit(G表示granularity,粒度),limit的单位不是Byte,而是Page,PC的CPU的1个Page表示4KB。这样4KB*1MB=4GB。为了能表示20bit的Limit,我们使用2个Byte。其中多出的4bit用来表示属性。

Segment的属性由Limit多出的4bit加上剩下的8个bit表示,也称访问权限。访问权限的构成:

XXXX0000XXXXXXXX(X代表0或1)

上4bit是386以后使用的扩张访问属性,由[GD00]构成,G表示上面提到的粒度,D表示Segment mode,1表示32位机,0表示16位机。下8bit继承80286时代的Segement属性。8bit的属性内容非常多,在这里,我们常用的有如下几个:

00000000(0x00):未使用的Descriptor table

10010010(0x92):系统专用,可读写,不能执行

10011010(0x9a):系统专用,可执行,可读,不可写

11110010(0xf2):应用程序使用,可读写,不可执行。

11111010(0xfa):应用程序可用,可执行,可读,不可写。

属性规定了系统和应用程序使用的读写执行权限。系统模式称为Ring0,应用程序模式称为Ring3,中间的Ring1和Ring2模式是系统服务。Ring0管理Ring3,例如,Ring3的应用程序在请求Load LGDT时,操作系统将否决该请求,以保证系统的安全性。下面是新增加的源代码文件。

http://www.kissthink.com/archive/An-operating-system-of-personal-development-and-IDT-GDT-Initialization.html

1. What is GDT
在Protected Mode下,一个重要的必不可少的数据结构就是GDT(Global Descriptor Table)。
为什么要有GDT?我们首先考虑一下在Real Mode下的编程模型:
在Real Mode下,我们对一个内存地址的访问是通过Segment:Offset的方式来进行的,其中Segment是一个段的Base Address,一个Segment的最大长度是64 KB,这是16-bit系统所能表示的最大长度。而Offset则是相对于此Segment Base Address的偏移量。Base Address+Offset就是一个内存绝对地址。由此,我们可以看出,一个段具备两个因素:Base Address和Limit(段的最大长度),而对一个内存地址的访问,则是需要指出:使用哪个段?以及相对于这个段Base Address的Offset,这个Offset应该小于此段的Limit。当然对于16-bit系统,Limit不要指定,默认为最大长度64KB,而 16-bit的Offset也永远不可能大于此Limit。我们在实际编程的时候,使用16-bit段寄存器CS(Code Segment),DS(Data Segment),SS(Stack Segment)来指定Segment,CPU将段积存器中的数值向左偏移4-bit,放到20-bit的地址线上就成为20-bit的Base Address。
到了Protected Mode,内存的管理模式分为两种,段模式和页模式,其中页模式也是基于段模式的。也就是说,Protected Mode的内存管理模式事实上是:纯段模式和段页式。进一步说,段模式是必不可少的,而页模式则是可选的——如果使用页模式,则是段页式;否则这是纯段模式。
既然是这样,我们就先不去考虑页模式。对于段模式来讲,访问一个内存地址仍然使用Segment:Offset的方式,这是很自然的。由于 Protected Mode运行在32-bit系统上,那么Segment的两个因素:Base Address和Limit也都是32位的。IA-32允许将一个段的Base Address设为32-bit所能表示的任何值(Limit则可以被设为32-bit所能表示的,以2^12为倍数的任何指),而不象Real Mode下,一个段的Base Address只能是16的倍数(因为其低4-bit是通过左移运算得来的,只能为0,从而达到使用16-bit段寄存器表示20-bit Base Address的目的),而一个段的Limit只能为固定值64 KB。另外,Protected Mode,顾名思义,又为段模式提供了保护机制,也就说一个段的描述符需要规定对自身的访问权限(Access)。所以,在Protected Mode下,对一个段的描述则包括3方面因素:[Base Address, Limit, Access],它们加在一起被放在一个64-bit长的数据结构中,被称为段描述符。这种情况下,如果我们直接通过一个64-bit段描述符来引用一个段的时候,就必须使用一个64-bit长的段积存器装入这个段描述符。但Intel为了保持向后兼容,将段积存器仍然规定为16-bit(尽管每个段积存器事实上有一个64-bit长的不可见部分,但对于程序员来说,段积存器就是16-bit的),那么很明显,我们无法通过16-bit长度的段积存器来直接引用64-bit的段描述符。
怎么办?解决的方法就是把这些长度为64-bit的段描述符放入一个数组中,而将段寄存器中的值作为下标索引来间接引用(事实上,是将段寄存器中的高13 -bit的内容作为索引)。这个全局的数组就是GDT。事实上,在GDT中存放的不仅仅是段描述符,还有其它描述符,它们都是64-bit长,我们随后再讨论。
GDT可以被放在内存的任何位置,那么当程序员通过段寄存器来引用一个段描述符时,CPU必须知道GDT的入口,也就是基地址放在哪里,所以Intel的设计者门提供了一个寄存器GDTR用来存放GDT的入口地址,程序员将GDT设定在内存中某个位置之后,可以通过LGDT指令将GDT的入口地址装入此积存器,从此以后,CPU就根据此积存器中的内容作为GDT的入口来访问GDT了。
GDT是Protected Mode所必须的数据结构,也是唯一的——不应该,也不可能有多个。另外,正象它的名字(Global Descriptor Table)所揭示的,它是全局可见的,对任何一个任务而言都是这样。
除了GDT之外,IA-32还允许程序员构建与GDT类似的数据结构,它们被称作LDT(Local Descriptor Table),但与GDT不同的是,LDT在系统中可以存在多个,并且从LDT的名字可以得知,LDT不是全局可见的,它们只对引用它们的任务可见,每个任务最多可以拥有一个LDT。另外,每一个LDT自身作为一个段存在,它们的段描述符被放在GDT中。
IA-32为LDT的入口地址也提供了一个寄存器LDTR,因为在任何时刻只能有一个任务在运行,所以LDT寄存器全局也只需要有一个。如果一个任务拥有自身的LDT,那么当它需要引用自身的LDT时,它需要通过LLDT将其LDT的段描述符装入此寄存器。LLDT指令与LGDT指令不同的时,LGDT指令的操作数是一个32-bit的内存地址,这个内存地址处存放的是一个32-bit GDT的入口地址,以及16-bit的GDT Limit。而LLDT指令的操作数是一个16-bit的选择子,这个选择子主要内容是:被装入的LDT的段描述符在GDT中的索引值——这一点和刚才所讨论的通过段积存器引用段的模式是一样的。

《自己动手写操作系统》是本很有意思的书。不过于渊前辈对某些内容没有给出更多的解释,让我们这些新米很难上手。 书中第3章介绍保护模式的时候,题到了GDT这个东东。在这里给出一个更浅显的介绍。 在介绍GDT这个概念前,现介绍一下segmentation这个概念。 大家还记得ORG这个汇编命令吧。书的开篇,给出的boot.asm代码的第一行就是:     ORG 0x7c00 这个ORG就是告诉CPU,程序被载入内存的0x7c00这个地方了。也就是说CPU从这个内存地址开始读取指令就OK了。 但是,现在的CPU同时执行好几个程序是很正常的事情。那么不同的程序使用的内存就有可能重叠,这样载入程序的话就会发生冲突。解决方法之一就是把把内存分成若干个段(segmentation)。每段放一个程序,这样每个程序都可以声明ORG 0了。很方便。 (另一个解决方法是paging,这个以后有机会在谈。) 为了能使用segmentation, 每个段(segment)都需要清楚的表明以下信息: - 段(segment)的大小。 - 段在内存中的开始位置。 - 段的管理属性。比如只读,系统专用等等 CPU用8bytes(=64bits)来表示这些信息(叫做descriptor)。但是,CPU用来指定段的register只有16bits。就算是32bit的CPU,这个register也是16bits的。那怎么办呢? 方法就是每个segment给一个"编号"(正式叫做segment selector),然后在把这个编号放在register里就好了。剩下的工作就是让编号和segment一一对应起来。 大概的感觉是这样的: 1号segment的大小是4GB,从内存的0000开始。(也就是指整个内存了。) 2号segment的大小是xxKB,从内存的xxxx开始。。。。 segment的编号为0~8191。 刚才说了,segment register是16bits,按理说应该可以存放2**16 = 65536个编号。但是由于CPU设计式样的问题,最低3bits不能用,也就是只有13bits可用,刚好是2**13=8192个。 每个segment的描述需要8bytes,一共就需要8192*8=64KB。CPU里可没有这么大的空间。所以就放在内存里好了。这个64KB(可以小于这个值),记录了分段信息的数据结构就叫做GDT -- Global (segment) Descriptor Table. 我不知道这个东东的正式翻译是什么,直译过来就是一个存放了描述分段信息的表。 这次介绍了GDT的概念和这个东东是怎么来的,干什么用的。 下次介绍segment descriptor的数据结构,和如何使用

为什么要有GDT的更多相关文章

  1. 操作系统篇-分段机制与GDT|LDT

    || 版权声明:本文为博主原创文章,未经博主允许不得转载. 一.前言     在<操作系统篇-浅谈实模式与保护模式>中提到了两种模式,我们说在操作系统中,其实大部分时间是待在保护模式中的. ...

  2. Eclipse下使用GDT插件无法登陆GAE & GDT无法上传JAVA代码

    今天更新github主页的过程中,想使用GAE部署一个Java Web服务来更好的支持网站动态性(关键是利用了免费的GAE资源),结果遇到了2个大问题. 1.GDT插件无法登陆GAE账户 错误1:登陆 ...

  3. GDT 学习笔记逻辑地址和线性地址计算,因为是自学,所以这只是我的个人理解,不对的请大家指导。

    在 bochs 刚开始的时候 gdt 是未知的,需要通过实模式的16位代码段初始化 gdt 信息, 在 lgdt 指令之后,即可以使用程序自定义的 GDT 表了. 假如:gdt 初始地址为 0x7c7 ...

  4. GDT,LDT,GDTR,LDTR 详解,包你理解透彻(转)

    引自:http://www.techbulo.com/708.html 一.引入 保护模式下的段寄存器 由 16位的选择器 与 64位的段描述符寄存器 构成 段描述符寄存器: 存储段描述符 选择器:存 ...

  5. [自制简单操作系统] 2、鼠标及键盘中断处理事件[PIC\GDT\IDT\FIFO]

    1.大致介绍: >_<" 大致执行顺序是:ipl10.nas->asmhead.nas->bootpack.c PS: 这里bootpack.c要调用graphic. ...

  6. EPROCESS 进程/线程优先级 句柄表 GDT LDT 页表 《寒江独钓》内核学习笔记(2)

    在学习笔记(1)中,我们学习了IRP的数据结构的相关知识,接下来我们继续来学习内核中很重要的另一批数据结构: EPROCESS/KPROCESS/PEB.把它们放到一起是因为这三个数据结构及其外延和w ...

  7. 非常好!!!【从头开始写操作系统系列】实现一个-GDT(1)【转】

    转自:http://blog.csdn.net/luoyhang003/article/details/47338019 权声明:本文为博主原创文章,未经博主允许不得转载.(文章来源:http://b ...

  8. 段描述符表(GDT+LDT)的有感

    [0]写在前面 要知道,在汇编中,代码的装入顺序决定了在内存中的地址位置.所有的代码或者数据都在硬盘上,当调试或者启动的时候,加载到内存:当需要对数据进行处理的时候,我们通过将数据从内存载入到regi ...

  9. Windows xp下IDT Hook和GDT的学习

    一.前言   对于IDT第一次的认知是int 2e ,在系统调用的时候原来R3进入R0的方式就是通过int 2e自陷进入内核,然后进入KiSystemService函数,在根据系统服务调用号调用系统服 ...

  10. (转)GDT与LDT

    网址:http://blog.csdn.net/billpig/article/details/5833980 保护模式下的段寄存器 由 16位的选择器 与 64位的段描述符寄存器 构成段描述符寄存器 ...

随机推荐

  1. Latex Error cannot determine the size of graphic 报错的解决的方法

    Latex Error cannot determine the size of graphic 报错的解决的方法 插入jpg文件老是会报错... 追究了半天,原来是编译的命令又问题,不应该使用 la ...

  2. 1、Cocos2dx 3.0游戏开发找小三之前言篇

    尊重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27094663 前言 Cocos2d-x 是一个通用 ...

  3. rocketmq技术架构图

    NameServer.Broker.Producer.Consumer之间如何进行通信,如何工作: NameServer和Broker: NameServer主要做两件事情,第一就是管理Broker, ...

  4. 浅用block 转

    block是一门有用的大后期学问.现在我只是列出一点基本用法. 1.快速枚举(Enumeration) 通常是和NSArray, NSDictionary, NSSet, NSIndexSet放在一起 ...

  5. Rete算法

    RETE算法介绍一. rete概述Rete算法是一种前向规则快速匹配算法,其匹配速度与规则数目无关.Rete是拉丁文,对应英文是net,也就是网络.Rete算法通过形成一个rete网络进行模式匹配,利 ...

  6. 常用的快速Web原型图设计工具

    做产品原型是非常重要的一个环节,做产品原型就会用使用各式各样的工具.在PM朋友们的推荐下使用了很多各种各样的软件,当然选择一款真正适合自己的工具也是很重要,在这里就把我使用过的工具都介绍一下. 主要有 ...

  7. Lucene TFIDF打分公式

    还没读TFIDFSimilarity的代码,读了一下lucene的文档,没有特复杂,感觉还是非常严谨的. 对于查询q和文档d,如果查询为纯token查询,套用向量空间模型(VSM),相似度度量使用余弦 ...

  8. 使用HTML5画饼图

    在进行数据的统计分析时, 饼图也是比较经常用到的一类统计图. 需求分析:   一个饼图一般包含以下几部分:   1.标题   2.扇形   3.份额(百分比)   4.标识器      设计:     ...

  9. Objective-C:动态绑定

    // Complex.h // 03-动态绑定 // // Created by ma c on 15/8/11. // Copyright (c) 2015年. All rights reserve ...

  10. Java实现对Mysql的图片存取操作

    1.MySQL中的BLOB类型 Mysql中可以存储大文件数据,一般使用的BLOB对象.如图片,视频等等. BLOB是一个二进制大对象,可以容纳可变数量的数据.因为是二进制对象,所以与编码方式无关.有 ...