阅读Intel和AMD之间的文档并查看代码有时会使您难以理解如何创建没有IO端口位图(IOPB)的正确任务状态段(TSS)。在使用IOPB创建TSS方面似乎也有些困惑,因为在IO位图(IOPB)是否需要尾随0xff
字节方面似乎模棱两可。
我知道TSS和TSS描述符(在GDT中)之间存在依赖关系。 TSS描述符控制TSS的基地址以及限制。描述符中的限制比结构的实际大小小一(本质上类似于GDT和IDT记录中指定的大小)。 TSS限制将发挥作用,以确定IOPB大小。
我知道:
TSS描述符限制比整个TSS结构的大小小1
16位TSS没有IOPB,结构是固定大小
基本的32位和64位TSS结构大小相似(数据含义不同)
通过在基本结构中添加额外的DWORD,32位TSS可以支持控制流执行。
TSS中的IOPB偏移量(字)指向相对于任务段开头的偏移量。
IOPB偏移量指向IOPB结构的开始,并且启用Virtual Mode Enhancements (VME)可使IOPB之前的32个字节成为中断重定向表。
如果未启用VME,则内核可以在基本TSS结构的末尾与IOPB偏移量之间放置额外的每个任务实例数据
如果启用了VME,则内核可以在基本TSS结构的末尾与IOPB下方的偏移量32个字节之间放置额外的每个任务实例数据。
如果存在IOPB,则每个0位为端口访问权限,而1位为拒绝权限。
32-bit TSS structure can be visualized这样:
该链接还包含16位TSS和64位TSS结构的布局。
问题:
如果我想要一个没有IOPB的TSS,我应该为+ 66h处的IOPB偏移量填写什么值?
如果我想要带有IOPB的TSS,是否必须在IOPB的末尾添加0xff
字节?
在上图中,为什么末尾的额外字节表示为xxxxx111
。如果最后一个字节是0xff
,那不是11111111
吗?
最佳答案
这是一个非常公平的问题。尽管乍看之下,带有或不带有IO端口位图(IOPB)的TSS似乎微不足道,但它一直是激烈讨论的重点;辩论;不正确的文件;含糊的文件;以及来自CPU设计师的信息,这些信息有时会使水变得浑浊。在OS/2 Museum中可以找到有关此主题的很好的阅读。尽管名称,但信息不限于OS / 2。从这篇文章中总结出来的一句话是:
显然,正确使用IOPB并非易事。另外,错误设置的IOPB不太可能引起明显的问题,但是可能会禁止访问所需的端口,或者(更糟糕的是,从安全角度而言)允许访问不需要的端口。
TSS和IOPB与386BSD,NetBSD,OpenBSD中的安全漏洞和错误有关的历史悠久,值得一读。如果您希望避免引入错误,那么应该提出的问题是合理的。
问题答案
如果您不希望使用IOPB,则可以简单地用整个TSS结构的长度填充IOPB偏移字段(不要减去1)。您的TSS结构中不应包含结尾的0xff
字节。 TSS描述符中的TSS限制(如您所知)将比该值小1。英特尔手册说,如果IOPB偏移值中的值大于TSS限制,则没有IOPB。如果IOPB偏移字段中的值始终大于限制1,则满足此条件。这就是现代Microsoft Windows处理它的方式。
如果使用IOPB,则根据英特尔文档在末尾将另一个字节设置为0xff
。通过为所有0xff
设置一个额外的字节,可以防止任何多端口访问(INW / OUTW / INL / OUTL)从最后8个端口开始或结束。这样可以避免多端口读/写可能跨越IOPB的末端,从而导致访问超出IOPB范围的端口的情况。它还会拒绝多端口访问,该访问始于最后8个端口之前的端口,该端口与随后的8个端口交叉。如果多端口访问的任何端口的许可权位设置为1,则整个端口访问将被拒绝(根据Intel文档)
目前尚不清楚x
在图的上下文中代表什么,但是如果将这些位设置为0,它们将显示为允许的端口,这不是您想要的。同样,请遵守英特尔文档,并在0xff
处设置一个额外的尾随字节(所有位均设置为拒绝访问)。
从Intel386 DX Microprocessor Data Sheet:
I / O权限位图中的每个位对应一个单个字节宽的I / O端口,如图4-15a所示。如果某个位为0,则可以在不生成异常的情况下对相应的字节宽端口进行I / O。否则,I / O指令将导致异常13错误。由于每个字节宽的I / O端口都必须是
可以保护的是,与字宽或dword宽端口相对应的所有位都必须为0,以允许字宽或dword宽的I / O。如果全部引用
位为0,将允许I / O。如果任何引用的位为1,则尝试的I / O将导致异常13故障。
和
**重要的实现注意:“ I / O权限位图”中I / O映射信息的最后一个字节必须是一个包含全1的字节。全1的字节必须在Intel386 DX TSS段的限制内(请参见图4-15a)。
在NASM程序集中,您可以创建如下结构:
tss_entry:
.back_link: dd 0
.esp0: dd 0 ; Kernel stack pointer used on ring transitions
.ss0: dd 0 ; Kernel stack segment used on ring transitions
.esp1: dd 0
.ss1: dd 0
.esp2: dd 0
.ss2: 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: dd 0
.trap: dw 0
.iomap_base:dw TSS_SIZE ; IOPB offset
;.cetssp: dd 0 ; Need this if CET is enabled
; Insert any kernel defined task instance data here
; ...
; If using VME (Virtual Mode extensions) there need to bean additional 32 bytes
; available immediately preceding iomap. If using VME uncomment next 2 lines
;.vmeintmap: ; If VME enabled uncomment this line and the next
;TIMES 32 db 0 ; 32*8 bits = 256 bits (one bit for each interrupt)
.iomap:
TIMES TSS_IO_BITMAP_SIZE db 0x0
; IO bitmap (IOPB) size 8192 (8*8192=65536) representing
; all ports. An IO bitmap size of 0 would fault all IO
; port access if IOPL < CPL (CPL=3 with v8086)
%if TSS_IO_BITMAP_SIZE > 0
.iomap_pad: db 0xff ; Padding byte that has to be filled with 0xff
; To deal with issues on some CPUs when using an IOPB
%endif
TSS_SIZE EQU $-tss_entry
特别说明:
如果您正在使用高级语言并创建TSS结构,请确保使用打包结构(即:使用GCC的
__attribute__((packed))
或MSVC的#pragma pack
)。查看您的编译器文档以获取更多详细信息。如果不注意此建议,可能会导致将额外的字节添加到TSS结构的末尾,如果您具有IOPB,可能会导致问题。如果TSS中存在IOPB并添加了额外的填充字节,则这些字节将成为IO位图的一部分,并且可能授予/拒绝您不希望使用的权限。这是在BSD内核中产生错误的故障之一。创建带有或不带有IOPB的TSS时,用于64位TSS的规则相同。即使在长模式(64位和兼容模式)下,仍使用64位TSS,并通过
LTR
指令在传统保护模式下将其加载到任务寄存器中。