x86/x86_64处理器提供了4个内存管理寄存器(Memory Management Registers):GDTR、LDTR、IDTR和TR。如下图所示。
Global Descriptor Table Register(GDTR)
GDTR寄存器保存GDT的基址和表限(table limit)。基址是GDT的第一个字节的地址,表限(table limit)给出表的大小。
指令LGDT和SGDT是分别用来设置和保存GDTR寄存器的值。上电或重启处理器后,基址默认的值为0,表限(table limit)的值为0FFFFH。在保护模式运行前,作为处理器初始化的一部分,必须在GDTR寄存器中设置新的基址。
在Linux地址映射过程中,会用到GDTR寄存器。在此稍微详细介绍一下指令SGDT,即获取GDTR寄存器的值。SGDT指令的操作如下:
Operation
IF instruction is SGDT
IF OperandSize = 16
THEN
DEST[0:15] ← GDTR(Limit);
DEST[16:39] ← GDTR(Base); (* 24 bits of base address stored *)
DEST[40:47] ← 0;
ELSE IF (32-bit Operand Size)
DEST[0:15] ← GDTR(Limit);
DEST[16:47] ← GDTR(Base); (* Full 32-bit base address stored *)
FI;
ELSE (* 64-bit Operand Size *)
DEST[0:15] ← GDTR(Limit);
DEST[16:79] ← GDTR(Base); (* Full 64-bit base address stored *)
FI;
FI;
Local Descriptor Table Register(LDTR)
LDTR寄存器的值包括:16位的段选择码、基址、段限(segment limit)和LDT描述符属性。基址是LDT段的起始地址,段限是段的大小。
指令LLDT和SLDT是分别用来设置和保存LDTR寄存器的值。
Interrupt Descriptor Table Register(IDTR)
IDTR寄存器的内容是:IDT的基址和大小。
指令LIDT和SIDT是分别用来设置和保存IDTR寄存器的值。
Task Register(TR)
TR寄存器的内容包括:16位的段选择码、基址、段限(segment limit)和描述符的属性。由于Linux中没有使用TR寄存器,这里不作详细介绍。
看到这里,大家心里难免有一个疑问,这4个内存管理寄存器的用途是什么?Linux内核何时会用到?