chapter 1:
内存寻址
逻辑地址: 包含在机器语言指令中用来指定一个操作数或一条指令的地址。
逻辑地址的组成:
(1) 段(段选择符) 16位
(2) 偏移量 :指明了从段开始的地方到实际地址之间的距离。32位
线形地址:
32位无符号整数,表示高达4G的地址。用十六进制表示。
范围:0x00000000-0xffffffff
物理地址:
用于内存芯片级内存单元寻址。由32位或36位无符号整数表示。
内存控制单元(MMU)
逻辑地址通过分段单元硬件电路转换为线形地址。
线形地址通过分页单元硬件电路转换为物理地址。
硬件中的分段:
(1) 段选择符:16位:
0-1:RPL(请求者特权级)
2:Tl (表指示器) 0:GDT 1:LDT
3-15:索引号
(2) 段寄存器:
作用:为了快速方便的找到段选择符。
目的:存放段选择符。
种类:cs,ss,ds,es,fs,gs.
解释:cs:代码段寄存器。指向包含程序指令的段。
ss:栈段寄存器。 指向包含当前程序栈的段。
ds:数据段寄存器。指向包含静态数据或全局数据段。
其他3个段寄存器作一般用途,可以指向任意的数据段。
cs:0代表内核态。3代表用户态。
段描述符:
每个段由8个字节的段描述符表示。描述了段的特征。
位置:在全局描述符表中(GDT),或局部描述符表中。(LDT)
GDT的地址和大小的位置:放在gdtr控制寄存器中。
当前正被使用的局部描述符表(LDT)地址和大小放在ldtr控制寄存器中。
分段单元:
逻辑地址转换为相应的线形地址的操作:
1:先检查段选择符的TI字段。(0:GDT;1:LDT),以决定段描述符保存在哪一个描述符表中。
如果TI为0,也就是在GDT中,分段单元从gdtr寄存器中得到GDT的线形地址。
如果TI为1,也就是在LDT中,分段单元从ldtr寄存器中得到LDT的线形地址。
2:从段选择符的索引号字段计算段描述符的地址,index字段的值*8,+gdtr/ldtr寄存器中的内容
3:2的结果(段描述符BASE字段的值)+逻辑地址的偏移量=线形地址。
LINUX GDT:
在linux内核中的位置:arch/i386/kernel/head.s (linux-2.6.18)第476行
ENTRY(cpu_gdt_table)
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x0000000000000000 /* 0x0b reserved */
.quad 0x0000000000000000 /* 0x13 reserved */
.quad 0x0000000000000000 /* 0x1b reserved */
.quad 0x0000000000000000 /* 0x20 unused */
.quad 0x0000000000000000 /* 0x28 unused */
.quad 0x0000000000000000 /* 0x33 TLS entry 1 */
.quad 0x0000000000000000 /* 0x3b TLS entry 2 */
.quad 0x0000000000000000 /* 0x43 TLS entry 3 */
.quad 0x0000000000000000 /* 0x4b reserved */
.quad 0x0000000000000000 /* 0x53 reserved */
.quad 0x0000000000000000 /* 0x5b reserved */
.quad 0x00cf9a000000ffff /* 0x60 kernel 4GB code at 0x00000000 */
.quad 0x00cf92000000ffff /* 0x68 kernel 4GB data at 0x00000000 */
.quad 0x00cffa000000ffff /* 0x73 user 4GB code at 0x00000000 */
.quad 0x00cff2000000ffff /* 0x7b user 4GB data at 0x00000000 */
.quad 0x0000000000000000 /* 0x80 TSS descriptor */
.quad 0x0000000000000000 /* 0x88 LDT descriptor */
/*
* Segments used for calling PnP BIOS have byte granularity.
* They code segments and data segments have fixed 64k limits,
* the transfer segment sizes are set at run time.
*/
.quad 0x00409a000000ffff /* 0x90 32-bit code */
.quad 0x00009a000000ffff /* 0x98 16-bit code */
.quad 0x000092000000ffff /* 0xa0 16-bit data */
.quad 0x0000920000000000 /* 0xa8 16-bit data */
.quad 0x0000920000000000 /* 0xb0 16-bit data */
/*
* The APM segments have byte granularity and their bases
* are set at run time. All have 64k limits.
*/
.quad 0x00409a000000ffff /* 0xb8 APM CS code */
.quad 0x00009a000000ffff /* 0xc0 APM CS 16 code (16 bit) */
.quad 0x004092000000ffff /* 0xc8 APM DS data */
.quad 0x0000920000000000 /* 0xd0 - ESPFIX 16-bit SS */
.quad 0x0000000000000000 /* 0xd8 - unused */
.quad 0x0000000000000000 /* 0xe0 - unused */
.quad 0x0000000000000000 /* 0xe8 - unused */
.quad 0x0000000000000000 /* 0xf0 - unused */
.quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */
每个GDT包含18个段描述符和14个空的,未使用,或保留的项。具体请看以上代码!