windows中 GDTR和GDT关于快速调用的实现1
windows中 GDTR和GDT关于快速调用的实现1
windows中 GDTR和GDT关于快速调用的实现1
文章目录
- windows中 GDTR和GDT关于快速调用的实现1
- 一、全局表述表
- 二、选择子
一、全局表述表
为进一步理解上面我们讲的两条指令(sysenter,sysexit).,我在解释一个”全局段描述符表(Global Descriptor Table)“即GDT及其段寄存器之间的关系,CPU中的系统寄存器GDTR指向内存中的GDT,这是一个结构数组。数组中的每一个表象都是一个64位的KGDTENTRY数据结构,里面描述了段的起点和大小,保护模式,访问权限等信息。合在一起就是一个64位的段描述块。数组的大小位NUM_GDT,定义为28
GDT的定义
//
// GDT Entry Definition
//
typedef struct _KGDTENTRY
{USHORT LimitLow;USHORT BaseLow;union{struct{UCHAR BaseMid;UCHAR Flags1;UCHAR Flags2;UCHAR BaseHi;} Bytes;struct{ULONG BaseMid:8;ULONG Type:5;ULONG Dpl:2;ULONG Pres:1;ULONG LimitHi:4;ULONG Sys:1;ULONG Reserved_0:1;ULONG Default_Big:1;ULONG Granularity:1;ULONG BaseHi:8;} Bits;} HighWord;
} KGDTENTRY, *PK
NUM_GDT的定义
// Descriptors
#define NUM_GDT 28 //15. The kernel wants 0xD8 as a last GDT entry offset
#define NUM_IDT 0x100 // only 16 are used though
二、选择子
在32位保护模式下,段寄存器的内容成为“选择项(Selector)",其主题部分即高13位就是用于GDT或者“局部描述段描述表(Local Descriptor Table)即LDT的下标。剩下的3位,bit2位LDT/GDT的选择位,位0表示选择GDT,为1表示选择LDT,最低两位则为RPL即运行权限,0表示0环系统态,
然而段寄存器所指向的段究竟在哪里,有多大,属于R0还是R3,则有具体的断描述符决定。下面是几个下标的定义
代码如下(示例):
//
// Selector Names
//
#ifdef __ASM__
#define RPL_MASK 0x0003
#define MODE_MASK 0x0001
#define KGDT_R0_CODE (0x8)
#define KGDT_R0_DATA (0x10)
#define KGDT_R3_CODE (0x18)
#define KGDT_R3_DATA (0x20)
#define KGDT_TSS (0x28)
#define KGDT_R0_PCR (0x30)
#define KGDT_R3_TEB (0x38)
#define KGDT_LDT (0x48)
#define KGDT_DF_TSS (0x50)
#define KGDT_NMI_TSS (0x58)
#endif
不要忘记了选择项的高13位才是下表,所以KGDT_R3_CODE 定义为0x18,去掉低三位对应的下表是3.
由于是用户空间的段选择项,其最低两位值应该是3,所以用户空间的空间段选择项实际上是1b,即(KGDT_R3_CODE | RPL_MASK).这里的RPL_MASK 定义为0x0003,但是,KGDT_R0_CODE所对应的下标是1.段选择值是0x8.因为这是系统空间的代码段。最低两位为0,至于下标0,则是禁用
由此可见,对于这样选择值的数值上的安排,实际上是各种段选择快在GDT中的位置,必须遵循某种规则。我们前面看到SYSENTER_CS_MSR的内容是KGDT_R0_CODE.所以指令sysenter置入CS的KGDT_R0_CODE,加上0就是KGDT_R0_DATA;
而sysexit置入CS的是KGDT_R3_CODE,置入SS的KGDT_R0_DATA.(注意sysexit会自动把cs,ss的RPL段设置为3)正因为这样。在R0空间堆栈中就无需保存用户空寂的那的堆栈段选择项SS
未完。。。