任务是动态的概念,程序的执行状态。程序给的解释就是静态的,例如桌面上放了个五子棋的程序。
为了保存任务的状态,并在下次重新执行程序的时候恢复它们,每个任务都应当拥有一个额外的内存区域记录相关的信息,这叫做任务状态段(TSS)。
这个地方写这个与点不合适,因为么有完全看懂。
下面简单在串一下。
在前面简单介绍过,保护模式的寻址http://my.oschina.net/u/1185580/blog/182241
这里详细啰嗦下。
1.保护模式下的段是找的上图这种的描述符 每个描述符的大小是8个字节=2个双字
2.描述符有 全局描述符表、局部描述符秒、任务描述符表、中断、门;描述符都在全局描述符中定义
3.上图中的s=0 系统 type=1100(门);权限间的切换
0010(ldt 也就是局部描述符);
1001(任务ltr不忙);
1011(任务ltr忙)
=1 代码、数据段(type(第一位也就是11位)=0数据段;=1代码段)
下面是一个简单的描述符的定义
;创建1#描述符,这是一个数据段,对应0~4GB的线性地址空间 mov dword [ebx+0x08],0x0000ffff ;基地址为0,段界限为0xFFFFF mov dword [ebx+0x0c],0x00cf9200 ;粒度为4KB,存储器段描述符
4.进入保护模式后,根据选择子得到 基地址+偏移量 然后检查权限、检查界限=安全的检查
5.暂且看的是,代码数据段立即加载过去了;
如果是局部描述表要先得到局部描述符的,lldt中,然后得到局部描述符表信息;(<64KB大小)
如果是任务描述符则就应该是后面的偏移量是没有用的
这些是记录任务当前运行的状态
这里说明下调用门的格式:
31--------------------16-15----------------------------0
选择子 偏移量15-0
31--------------------16-15-14-13-12-11----8-7-4----0
偏移量 P |DPL| 0 |TYPE| 0 参数个数
调用门实施特权级的控制转移,可以使用jmp far指令,也可以使用 call far 指令
使用jmp far指令可以将控制通过门转移到比当前特权级别高的代码段,但不改变当前的特权级别;
如果使用call会改变当前特权级的CPL。1.堆栈的请求要求是必须与当前的特权级请求一致,哪意味着堆栈的切换
2.数据段的请求权限》=当前的权限
3.代码段的请求权限 同级别或者依从【(权限《=当前)才可以使用】
type 11-8 10位是C位
系统不允许高的权限转移到底的权限中。
call 段内转移 esp入栈
call 段间转移 cs、esp依次入栈
当没有特权级变化的时候,cal,jmp都可以进入任务门。
*这样的处理权限的转换问题
当特权级切换的时候哪?
LABEL_TSS: DD 0 ; Back DD 0 ; 0 级堆栈,现处于0级 esp的值 DD 0x00000020 ;堆栈选择子 DD 0 ; 1 级堆栈 DD 0 ; DD 0 ; 2 级堆栈 DD 0 ; DD 0 ; CR3 DD 0 ; EIP DD 0 ; EFLAGS DD 0 ; EAX DD 0 ; ECX DD 0 ; EDX DD 0 ; EBX DD 0 ; ESP DD 0 ; EBP DD 0 ; ESI DD 0 ; EDI DD 0 ; ES DD 0 ; CS DD 0 ; SS DD 0 ; DS DD 0 ; FS DD 0 ; GS DD 0 ; LDT 就是0 DW 0 ; 调试陷阱标志 DW $ - LABEL_TSS + 2 ; I/O位图基址 截取后16位 DB 0ffh ; I/O位图结束标志 TSSLen equ $ - LABEL_TSS
;目的是分页的练习 ;时间 2013-12-14 下午 周六 [org 0x7c00] [bits 16] ldt_description equ 0x00007F00 mov ax,cs mov ds,ax call show_style ;设置显示模式 主要是清屏 ;计算GDT所在的逻辑段地址 mov eax,[pgdt+0x02] ;得到描述符的基地址 xor edx,edx mov ebx,16 div ebx mov ds,eax ;令DS指向该段以进行操作 mov ebx,edx ;段内起始偏移地址 ;创建0#描述符,它是空描述符,这是处理器的要求 ;创建1#描述符,这是一个数据段,对应0~4GB的线性地址空间 mov dword [ebx+0x08],0x0000ffff ;基地址为0,段界限为0xFFFFF mov dword [ebx+0x0c],0x00cf9200 ;粒度为4KB,存储器段描述符 ;创建保护模式下初始代码段描述符 mov dword [ebx+0x10],0x7c0001ff ;基地址为0x00007c00,界限0x1FF mov dword [ebx+0x14],0x00409800 ;粒度为1个字节,代码段描述符 ;建立保护模式下的堆栈段描述符 ;基地址为0x00007C00,界限0xFFFFE mov dword [ebx+0x18],0x7c00fffe ;粒度为4KB mov dword [ebx+0x1c],0x00cf9600 ;建立保护模式下的显示缓冲区描述符 mov dword [ebx+0x20],0x80007fff ;基地址为0x000B8000,界限0x07FFF mov dword [ebx+0x24],0x0040920b ;粒度为字节 ;为了测试句不断选择子,大小就8个字节也就是一个ldt mov eax,ldt_description shl eax,16 or eax,0x00000007 mov dword [ebx+0x28],eax ;基地址为0,段界限为8 mov dword [ebx+0x2c],0x00408200 ;粒度为4KB,存储器段描述符 mov eax, LABEL_TSS ;TSS段基地址 shl eax,16 or eax,TSSLen-1 mov dword [ebx+0x28],eax mov dword [ebx+0x2c],0x00408900 ;========================================================= ;初始化描述符表寄存器GDTR ;因为上面吧数据段地址改了所以这利用代码段 mov word [cs:pgdt],55 ;描述符表的界限(总字节数减一) n*8-1; lgdt [cs:pgdt] in al,0x92 ;南桥芯片内的端口 or al,0000_0010B out 0x92,al ;打开A20 cli ;保护模式下中断机制尚未建立,应 ;禁止中断 mov eax,cr0 or eax,1 mov cr0,eax ;设置PE位 ;以下进入保护模式... ... jmp dword 0x0010:protect_loader-0x7C00;16位的描述符选择子:32位偏移 ;hlt ;程序终止 ;===================showStyle============================= show_style: ;设置显示方式 mov ah,0x00 mov al,0x03 int 10h ret ;========================================================= [bits 32] protect_loader: xor eax,eax mov eax,0000_0000_00100_000B ;#4 显示段 mov es,eax mov byte[es:0x00],'H' mov byte[es:0x02],'E' mov byte[es:0x04],'L' mov byte[es:0x06],'L' mov byte[es:0x08],'O' mov byte[es:0x0a],',' mov byte[es:0x0c],'O' mov byte[es:0x0e],'S' mov eax,0000_0000_00001_000B ;#1数据段 4G mov es,eax xor ebx,ebx mov ebx,ldt_description; 得到偏移地址 mov dword [es:ebx+0x00],0x7c0001ff mov dword [es:ebx+0x04],0x00409800 ;拼凑一个lldt的选择子 xor eax,eax mov ax,0000_0000_00101_000B ;第五个描述符的位置 lldt ax ;加载lldt ;hlt ;jmp dword 0x0004:ldt_loader-0x7c00 mov eax,0000_0000_00110_000B ;#6 TSS段 ltr ax xor esp,esp ;esp设置为0 jmp dword ax:0 hlt ;程序终止 ;---------------------------------------------------------------- ldt_loader: ;这里是局部全局变量的加载 xor eax,eax mov eax,0000_0000_00100_000B ;#4 显示段 mov es,eax mov byte[es:0x00+0xa0],'L' mov byte[es:0x02+0xa0],'L' mov byte[es:0x04+0xa0],'D' mov byte[es:0x06+0xa0],'T' hlt; LABEL_TSS: DD 0 ; Back DD 0 ; 0 级堆栈,现处于0级 esp的值 DD 0x00000020 ;堆栈选择子 DD 0 ; 1 级堆栈 DD 0 ; DD 0 ; 2 级堆栈 DD 0 ; DD 0 ; CR3 DD 0 ; EIP DD 0 ; EFLAGS DD 0 ; EAX DD 0 ; ECX DD 0 ; EDX DD 0 ; EBX DD 0 ; ESP DD 0 ; EBP DD 0 ; ESI DD 0 ; EDI DD 0 ; ES DD 0 ; CS DD 0 ; SS DD 0 ; DS DD 0 ; FS DD 0 ; GS DD 0 ; LDT 就是0 DW 0 ; 调试陷阱标志 DW $ - LABEL_TSS + 2 ; I/O位图基址 截取后16位 DB 0ffh ; I/O位图结束标志 TSSLen equ $ - LABEL_TSS ;--------------数据段-------------------------------------------- pgdt dw 0 dd 0x00007e00 ;GDT的物理地? times 510-($-$$) db 0 db 0x55 ;引导识别标示 db 0xaa
上面 首先实例化了 1.全局段描述符表GDT;lgdt
2.然后跳转进入了保护模式
3.实例化了LDT的描述符表 通过4G的数据段
4.加载lldt、加载了ltr
5.最后根据ltr的这个选择子进入了,lldt中的选择子 0 (当然也可以直接跳转加载lldt的选择子)
效果如下