IA-32 Manual
Architecture
IA-32处理器在加电或者复位后首先进入实地址模式,而后由软件完成到保护模式下的切换。
寄存器与数据结构:
全局和局部描述符表
保护模式下,所有内存访问通过:
- 全局描述符表(GDT)
- 局部描述符表(LDT)
描述符表里的项为段描述符(riscv: PTE),段描述符包含
- 一个段的基地址
- 访问权限
- 类型和用法信息
每个段描述符都有一个与之相关的段选择子(riscv: satp)。段选择子包含:
- 一个对GDT或LDT的索引
- 一个全局/局部标志
- 访问权限信息
访问段中的一个字节,必须同时提供一个段选择子和一个偏移,段选择子提供对段描述符的访问,处理器从段描述符中获取段在线性地址空间里的地址,而后加上偏移。根据处理器当前特权级(CPL)决定能否访问段。
系统段、段描述符和门
进程运行环境:
- 代码
- 数据
- 堆栈段
- 任务状态段(TSS)
- LDT
GDT不通过段选择子和段描述符访问
IA-32门:特殊描述符(意思是入口)
- 调用门:访问与当前代码段特权级更高或相同的代码段,若调用需要切换特权级,处理器就切换到对应特权级的堆栈(新堆栈的段选择子从当前任务的TSS中获得)
- 中断门
- 陷阱门
- 任务门
提供高于用户特权级的系统过程/处理程序来进行保护性访问
任务状态段和任务门
TSS(riscv: Context)定义任务执行环境的状态,包含:
- 通用寄存器
- 段寄存器
- EFLAGS
- EIP
- 段选择子
- 三个堆栈段(三个特全级各一个)指针
- LDT选择子
- 页表基地址
中断和异常处理
外部、软件中断和异常通过中断描述符表(IDT)处理,包含访问中断和异常处理程序门描述符的集合
IDT和GDT不是段,IDT线性基地址包含在IDT寄存器(IDTR)中
IDT中描述符可以是中断门、陷阱门或任务门,处理器从int/bound指令收到一个中断向量,才去访问中断或异常处理程序。中断向量是IDT中门描述符的索引。任务门:任务切换访问处理程序
内存管理
支持物理寻址也支持虚拟分页
页目录基地址保存在CR3
分页只有2级:页目录$\rightarrow$页表$\rightarrow$
系统寄存器
- EFLAGS寄存器:
- 系统标志和IOPL域控制任务和模式的切换、中断处理、指令跟踪和访问权限
- 控制寄存器
- 调试寄存器
- (G/L/I)DTR寄存器包含表的线性地址和限长
- 任务寄存器包含当前任务TSS的线性地址和大小
- 模型相关寄存器
运行模式
- 保护模式
- 实模式
- 系统管理态(SMM)
- 虚拟8086模式
上电后位于实模式,由控制寄存器CR0中的PE标志决定
EFLAGS
内存管理寄存器
限长以字节为单位
lgdt
与sgdt
分别装载和保存GDTR寄存器
控制寄存器
- CR0: 包含系统控制标志
- CR2: 包含页故障线性地址
- CR3: 页目录基地址寄存器(PDBR),包含页目录表的物理基址和两个标志(PCD和PWT)
- CR4: 包含一组标志,控制扩展启用
CR0:
- PG (page): CR0[31],分页
- CD (cache disable): CR0[30],为1 disable cache
- NW (no-direct write): CR0[29],写操作写回/写穿透
- AM (align mask): CR0[18],对齐屏蔽
- WP (write protection): CR0[16],管理程序能否写用户级的只读页;fork时COW依赖
- NE (number error):CR0[5],浮点错误
- PE (protection enable): CR0[0],启用保护模式,启用段级保护
CR3:
- PCD (page cache disable): CR3[4],禁用页级高速缓存
- PWD (page write transparent): CR3[3],控制页目录表的写回/写穿透
CR4:
- VME
- PVI (protection-mode virtual interrupt)
- TSD (timestamp disable): RDTSC指令
- DE (debug extension)
- PSE (page size extension): 4K->4M
- PAE (physical address extension): 32->36位物理寻址
- MCE (machine check enable)
- PGE (page global enable)
- PCE (performance counter enable)
CR4的位能够通过CPUID指令获取
保护模式内存管理
分段隔离每个进程,分段功能不可关闭
只有逻辑地址(远指针)确定字节在特定段中的位置
逻辑地址:段选择子+偏移
保护模式,物理地址空间4GB:0~0xffffffff
逻辑地址中段选择子在段寄存器中,一个程序内所有访存共享;用户只提供偏移
段选择子
段选择子16位,为段的标识码,并不直接指示段,而是指向定义段的段描述符
- 索引[3:15]:选择GDT或LDT中8192个描述符中的某个,处理器将索引值*8 + GDT/LDT base
- 表指示标记(TI)[2]:确定使用哪个描述符表,0 - GDT,1 - LDT
- 请求的特权级(RPL)[0:1]:确定选择子的特权级,0~3
GDT第一项无效,为空段选择子,装载至段寄存器时无异常,但用来访存时产生异常,但装载CS或SS产生一般保护异常(#GP)
段寄存器
- CS: 代码
- DS, ES, FS, GS: 数据
- SS: 堆栈
段寄存器有可见、不可见部分,段选择子可见,不可见称为描述符高速缓存/影子寄存器
段描述符
64位
- 段界限域:20位,根据段是向上扩展段/向下扩展段,偏移从0或段界限开始,到段界限或
0xffffffff
/0xffff
结束;根据G(粒度)设置不同,解释方式不同:- 若G为0,则段大小从1字节到1M字节,增量单位为字节
- 若G为1,则断大小从4K字节到4G字节,增量单位为4K字节
- S(描述符类型标志):0 - 系统描述符,1 - 代码、数据段描述符
- DPL(描述符特权级):0~3
- P(present):是否在内存中,为0时装在段选择子则返回段不存在异常#NP,MM可通过改标志控制哪些段真正载入物理内存。
- D/B(默认操作数大小/默认栈指针大小/上限):根据段类型,作用不同(32位代码和数据段,始终为1,16位为0):
- 可执行代码段:为D标志,指明指令的有效地址和操作符的默认位数,1 - 32位地址,32/8位操作符;0 - 16位地址,16/8位操作符
- 堆栈段(SS所知数据段):为B标志,为栈操作确定栈指针大小,1 - 32位栈指针,位于esp寄存器;0 - 16位栈指针,位于sp寄存器
- 向下扩展的数据段:B标志,确定段地址上界,1 -
0xffffffff
,0 -0xffff
type
: [[3:1], Accessed], [3:0]- S位为0时:
000
: RO data001
: R/W data010
: RO stack011
: R/W stack100
: XO code101
: X/R code100
: XO code, confirming101
: X/R code, confirming
- S位为0时:
代码段一致性/非一致性,转入特权级更高的一致性代码段的进程能够以当前特权级继续执行;转入不同特权级的非一致性段会产生一般保护异常。不能被特权级更低程序访问的程序应该被载入非一致性代码段
进程不能够因为call
或者jump
转入一个特权级较低的代码段执行,否则会产生一般保护异常#GP
所有数据段都是非一致性的,数据段不能被更低特权级的进程访问;数据段可以被更高优先级的程序或过程访问,不需要使用特别的访问门
系统描述符类型
S位0时为系统描述符
- LDT
- TSS
- 调用门
- 中断门
- 陷阱门
- 任务门
分两类:
- 系统段描述符
- 门描述符
中断门描述符为IDT表项
段描述符表
长度可变,最多包涵8192($2^{13}$)个8字节描述符
系统必须定义一个GDT,以备所有进程或任务使用,也可以定义一个/多个可共享的LDT
GDT本身不是一个段,而是线性地址空间的一个数据结构,线性基地址和界限必须装入GDTR寄存器,基地址8字节对齐,界限应该总是8的整数倍-1
LDT位于类型为LDT的系统段内,GDT必须包含一个指向LDT段的描述符
当保存GDTR寄存器时,48位伪描述符存入内存,应该放入一个奇字地址上(地址对4取模为2)
分页
由处理器控制寄存器的3个标志控制:
- PG(分页)
- PSE(页尺寸)
- PAE(物理地址扩展)
需要4个数据结构:
- 页目录指针表(启用扩展时)
- 页目录表
- 页表
- 页
格式:
任务管理
任务结构
任务由两部分构成:任务执行空间和任务状态段
任务执行空间由代码段、栈段、一个或多个数据段组成,为每个特权级提供独立的栈
任务状态
- 任务的当前执行空间,由段寄存器(CS、DS、SS、ES、FS和GS)中的段选择子指定
- 通用寄存器的状态
- EFLAGS寄存器的状态
- EIP寄存器的状态
- 控制寄存器CR3的状态
- 任务寄存器的状态
- LDTR寄存器的状态(段选择子)
- I/O位图基地址和I/O位图(位于TSS中)
- 特权级0、特权级1和特权级2的栈指针(位于TSS中)
- 指向前一个执行过的任务的链接(位于TSS中)
任务调度之前,除任务寄存器状态外都要在TSS中设置
执行任务
调度任务执行:
- call
- jmp
- 隐式中断/异常处理程序
- iret
用指向任务门或TSS的段选择子来识别被调度任务,调度任务处理中断异常时,相应中断/异常IDT项必须包含一个任务门,门中含有指向中断或异常处理程序任务的TSS选择子
任务调度:当前任务执行环境(context)被保存进TSS,而后挂起,而后处理器加载新任务context到寄存器,跳转到eip执行新任务
如果是由当前任务(调用任务)调用了被调度的任务(被调任务)而发生了任务切换,则把调用任务的TSS的选择子保存到被调任务的TSS 中,以提供返回调用任务的链接
不允许任务递归,任务不能调用或跳转到自身
可通过切换任务到处理程序任务来处理中断和异常,处理中断嵌套,允许每个任务拥有一个不同的基于LDT段的从逻辑到物理地址的映射机制。任务切换重新装在CR3
任务管理数据结构
- 任务状态段(TSS)
- 任务门描述符
- TSS描述符
- 任务寄存器
- EFLAGS NT bit
TSS:
TSS描述符:
TSS段也是通过段描述符定义,只能放在GDT中
任务寄存器:
保存16位段选择子和当前任务的TSS描述符,分为软件可见/不可见部分,可见部分段选择子指向GDT中TSS描述符,不可见部分为缓存
任务门描述符:
门描述符提供对任务的间接访问
只可通过任务门描述符或者TSS描述符来访问一个任务,满足以下需求:
- 任务只有一个忙标志,每个任务只有一个TSS描述符,但可能有很多任务门指向同一个TSS描述符
- 提供对任务选择性访问
- 通过一个独立任务处理中断或异常,任务门在IDT中
任务切换
发生方式:
- 进程、任务或例程执行了一个
jmp
或者call
指令到GDT中的一个TSS描述符 - ~GDT中的一个任务门描述符
- 一个中断或者异常向量,指向IDT中的一个任务门描述符
- 当前任务执行
iret
,EFLAGS NT标志置位
处理器动作:
- 从
jmp
或call
指令操作数、任务门、前一个任务链接域中获取新任务TSS段选择子 - 检验老任务是否允许切换,数据访问特权
- 检验新任务TSS描述符有存在标志且界限合法
- 检验新任务是可用或者忙的
- 检验老TSS、新TSS和所有用于任务切换的段描述符都被分页到系统内存中
- 如果是由
jmp
或iret
指令发动的任务切换,则处理器清除老任务TSS描述符B标志 - 如果是由
iret
指令发动的任务切换,处理器清除临时保存EFLAGS寄存器镜像的NT标志 - 保存老任务状态到TSS中,从任务寄存器中找出当前TSS基地址,复制寄存器到TSS中(GPR,段寄存器中的段选择子、临时保存的EFLAGS寄存器映像、EIP)
- 如果是由
call
指令、异常或中断发动的任务切换,处理器将设置新任务EFLAGS NT标志 - ~新任务TSS描述符B标志
- 用段选择子和新任务TSS描述符加载任务寄存器
- TSS状态加载到处理器,包括:LDTR寄存器、PDBR(CR3)、EFLAGS、EIP、GRP、段选择子
- 与段选择子相关的描述符加载、验证
- 执行新任务
新任务不继承挂起任务的特权级,新任务在CS寄存器CPL域指定的特权级上运行
任务切换发生时,CR0中TS(task switch)标志被置位
任务链接
TSS前一个任务链接域和EFLAGS NT标志用于返回前一个执行的任务
NT标志表明当前TSS的前一个任务链接域已经加载了已保存的TSS段选择子
标志或域 | JMP | CALL | IRET |
---|---|---|---|
新任务的忙标志 | set,之前必须已经被清除 | set,之前必须已经被清除 | 不变,必须已经置位 |
老任务的忙标志 | clear | 不变,之前必须已经被清除 | set |
新任务NT标志 | 置为新任务TSS中值 | set | 置为新任务TSS中值 |
老任务NT标志 | 不变 | 不变 | clear |
新任务中前一个任务链接域 | 不变 | 加载老任务TSS选择子 | 不变 |
CR0 TS | set | set | set |
使用忙标志可防止递归任务切换,一个TSS智能保存一个任务context
忙标志管理:
- 当调度一个任务时,set新任务忙标志
- 任务切换期间,当前任务置于嵌套链中,忙标志保持置位
- 切换到新任务时,若新任务忙标志置位,则产生异常(
iret
除外) - 当任务由于跳转到新任务(
jmp
)或发出iret
指令结束,则处理器清除忙标志
在需要从连接的任务链中提出一个任务时,按以下步骤:
- 关中断
- 改变后一个新任务TSS的前一个任务链接域,指向当前任务前一个更老任务
- 清除TSS忙标志
- 开中断
任务地址空间
任务地址空间由可访问的段构成,包括TSS引用的代码、数据、栈、系统等段
TSS的LDT段域可以给每个任务自己的LDT,可以做到把每个任务相关的段都放置在自己任务的LDT中,以便把自己的地址空间与其他任务隔绝
几个任务也可能使用同一个LDT,允许任务通讯和控制的方法
所有任务都访问GDT,也可以创建通过这个表中的段描述符访问的共享数据段
CR3页表集也可以被共享