x86 - 使用和不使用 IO 位图创建适当的任务状态段 (TSS) 结构?

标签 x86 x86-64 intel osdev amd-processor

阅读 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结构大小差不多(数据意义不同)
  • 32 位 TSS 可以通过向基本结构添加一个额外的 DWORD 来支持控制流执行。
  • 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这样:

enter image description here

该链接还包含 16 位 TSS 和 64 位 TSS 结构的布局。


问题:

  • 如果我想要一个没有 IOPB 的 TSS,我应该为 +66h 处的 IOPB 偏移量填写什么值?
  • 如果我想要一个带 IOPB 的 TSS,我是否必须在 IOPB 的末尾添加一个 0xff 字节?
  • 在上图中,为什么末尾的额外字节表示为 xxxxx111。如果最后一个字节假设为 0xff,那不就是 11111111 吗?

最佳答案

这是一个非常公平的问题。尽管乍一看带有或不带有 IO 端口位图 (IOPB) 的 TSS 本质上似乎相当微不足道,但它一直是激烈讨论的焦点;辩论;文件不正确;模棱两可的文件;以及来自 CPU 设计者的信息,这些信息有时会混淆水域。关于这个主题的很好的读物可以在 OS/2 Museum 中找到。 .尽管名称如此,但信息并不限于 OS/2。摘自那篇总结它的文章:

It is obviously not trivial to use the IOPB correctly. In addition, an incorrectly set up IOPB is unlikely to cause obvious problems, but may disallow access to desired ports or (much worse, security-wise) allow access to undesired ports.

TSS 和 IOPB 的肮脏历史,因为它与 386BSD、NetBSD、OpenBSD 中的安全漏洞和错误有关,值得一读,如果您希望避免引入错误,应该表明您提出的问题是合理的。


问题的答案

如果您不需要 IOPB,您可以简单地用整个 TSS 结构的长度填充 IOPB 偏移字段(不要减去 1)。您的 TSS 结构中不应有尾随 0xff 字节。 TSS 描述符中的 TSS 限制(如您所知)将比该值小 1。 Intel手册上说如果IOPB偏移值中的值大于TSS限制就没有IOPB。如果 IOPB 偏移字段中的值始终比限制大 1,则满足此条件。这就是现代 Microsoft Windows 处理它的方式。

如果使用 IOPB,请根据 Intel 文档在末尾设置一个附加字节到 0xff。通过为所有 0xff 设置一个额外的字节,可以防止在最后 8 个端口开始或结束的任何多端口访问(INW/OUTW/INL/OUTL)。这将避免多端口读/写可能跨越 IOPB 的末端导致访问超出 IOPB 范围的端口的情况。它还会拒绝从最后 8 个端口之前的端口开始并进入后面 8 个端口的多端口访问。如果多端口访问的任何端口的权限位设置为 1,则拒绝整个端口访问(根据 Intel 文档)

不清楚 x 在图表的上下文中代表什么,但如果这些位设置为 0,它们将显示为允许的端口,这不是您想要的。同样,坚持使用 Intel 文档并将额外的尾随字节设置为 0xff(所有位都设置为拒绝访问)。

来自Intel386 DX Microprocessor Data Sheet :

Each bit in the I/O Permission Bitmap corresponds to a single byte-wide I/O port, as illustrated in Figure 4-15a. If a bit is 0, I/O to the corresponding byte-wide port can occur without generating an exception. Otherwise the I/O instruction causes an exception 13 fault. Since every byte-wide I/O port must be protectable, all bits corresponding to a word-wide or dword-wide port must be 0 for the word-wide or dword-wide I/O to be permitted. If all the referenced bits are 0, the I/O will be allowed. If any referenced bits are 1, the attempted I/O will cause an exception 13 fault.

**IMPORTANT IMPLEMENTATION NOTE: Beyond the last byte of I/O mapping information in the I/O Permission Bitmap must be a byte containing all 1’s. The byte of all 1’s must be within the limit of the Intel386 DX TSS segment (see Figure 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,这可能会导致问题。如果 IOPB 存在于 TSS 中并且添加了额外的填充字节,那么这些字节将成为 IO 位图的一部分,并且可能会授予/拒绝您不想要的权限。这是在 BSD 内核中产生错误的失败之一。
  • 在创建带或不带 IOPB 的 TSS 时,64 位 TSS 的规则是相同的。即使在长模式(64 位和兼容模式)下,64 位 TSS 仍在使用,并通过 LTR 加载到任务寄存器中,方式与在传统保护模式下完成的方式相同。指导。

关于x86 - 使用和不使用 IO 位图创建适当的任务状态段 (TSS) 结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54876039/

相关文章:

c - 基于英特尔的 DCT 硬件加速?

assembly - 链接汇编程序 : error "undefined reference to ` printf'"

assembly - 无符号 64 位到 double 转换 : why this algorithm from g++

performance - 现代 x86 成本模型

x86 - 在 x86-64 中加载和存储长 double

python - 在 OSX 10.14.5 上安装 clickhouse-cityhash 时缺少指令 `_mm_crc32_u64`

debugging - 英特尔AT&T汇编程序的分步执行?

c++ - 使用 GDB 调试英特尔 C++ 编译代码

windows - 在 x64 位版本中获取 windows 目录的变量?

assembly - 将16位实模式代码链接到兼容Multiboot的ELF可执行文件时出现LD错误