将 ISR 链接到向量中断 80x86 32 位 AT&T 程序集
Posted
技术标签:
【中文标题】将 ISR 链接到向量中断 80x86 32 位 AT&T 程序集【英文标题】:Link ISR to vector interrupt 80x86 32bit AT&T assembly 【发布时间】:2011-11-27 04:59:30 【问题描述】:我从事 Intel-Atom 32 位(Assembly AT&T)的工作。
我想将我的 ISR 链接到向量中断 0x33:
push %ebp //save the context to swith back
movl %esp,%ebp
movl $OSTickISR, %eax //address of int 0x33 = address of OSTickISR
movl $0x33*4, %ebx
movl %eax, (%ebx)
pop %ebp //Return to the calling function
ret
当我尝试使用我的 int $0x33 时,什么都没有发生!!!
怎么了?
【问题讨论】:
【参考方案1】:在 x86 32 位中,ISR 信息存储在 IDT 中。 IDT 不是简单的地址列表,也不一定存储在地址 0。有关 IDT 格式的说明,请参阅OSDev Wiki page。 IDT 的位置由操作系统确定,用户模式软件可能无法访问它。假设您确实有权修改它,您可以使用 sidt
指令获取 IDT 的位置。
sidt -6(%esp)
在 32 位模式下,sidt
将在指定位置存储 6 个字节的数据。我在示例中使用了-6(%esp)
,它将数据存储在当前堆栈的正下方。低两个字节是 IDT 的长度,以字节为单位,接下来的 4 个(在 32 位模式下)是 IDT 的地址。由于每个 IDT 条目的长度为 8 个字节,因此您想要的条目的位置将是 IDT 开始之后的0x33*8
字节。在修改条目之前,您应该确保 IDT 确实包含该条目(它至少有 0x34*8
字节长)。
这是一个找到 IDT、确保它足够长并设置中断 0x33 的条目的示例。
sidt -6(%esp) // Get the location and size of the IDT
cmpw $0x34*8, -6(%esp) // Make sure the IDT is long enough
jb IDT_too_short // and handle the error if it isn't
mov -4(%esp), %ebx // Get the IDT's address
add $0x33*8, %ebx // and move to the entry for 0x33
mov $OSTickISR, %eax // Get the ISR's address
mov %ax, (%ebx) // Store the low 16 bits of the ISR's address
movw $ISR_CS, 2(%ebx) // Store the code segment which should be used with this ISR
movb $0, 4(%ebx) // This has to be 0
movb $0xEE, 5(%ebx) // See the OSDev link for information on this byte.
// 0xEE is most common for interrupts available from user mode
shr $16, %eax
mov %ax, 6(%ebx) // Store the high 16 bits of the ISR's address
【讨论】:
+1 很好的答案,除了IA Software Developers Manuals 的强制性链接外,我没有什么要补充的。 (哦,为了完整起见,可能会在顶部添加sub $8, %esp
:)
@user786653 感谢您的链接。至于sub $8, %esp
,我的回答取决于你的推理。如果 1)您正在为函数对齐堆栈,这不是必需的,因为没有函数调用,或者 2)您想要使用 %esp
的正偏移量,我更喜欢在红色区域工作这么小的尽可能多的数据。
我想在堆栈上分配空间,因为我不记得在 32 位 x86 上使用了带有红色区域的调用约定?无论哪种方式,任何能够理解和使用上述代码的人都应该能够轻松地对其调用约定进行适当的调整:)
谢谢,当我测试这段代码时,它总是在 IDT_too_short 宏中!!!,在使用此代码进行调查后: sidt -6(%esp) movb -1(%esp),%ah movb -2(%esp),%al movb -3(%esp),%bh movb -4(%esp),%bl movb -5(%esp),%ch movb -6(%esp),%cl %ah = 00 %al = 00 %bh = 03 %bl = 06 %ch = 00 %cl = 00 因为我在 32 位,所以解释应该是:DEST[0:15] ← IDTR(Limit) = 0x00 DEST[ 16:47] ← IDTR(基地); FI; (* 存储完整的 32 位基地址 *) = 0x00603 我觉得我迷路了?????
@mustapha 你的bh
和bl
的顺序错误,指定的地址是0x306
。但它的长度似乎是 0,所以位置无关紧要。您可以通过分配内存并使用lidt
自己创建 IDT,只需确保使用 0 填充未使用的中断。【参考方案2】:
x86 上的地址由段和偏移量组成。在实模式下,它是段*16 + 偏移量。在保护模式下有一点间接性:段寄存器它实际上是一个指向段描述符的选择器,它包含段基数和限制,以及其他段属性。访问内存的指令可以采用显式段说明符(例如:DS:BX
),否则它们采用取决于所用寄存器的隐式段(例如:如果您使用 SP,则隐式段为 SS)。
实模式下的IVT在地址0000:0000,保护模式下的IDT在地址IDT:0000,可以通过LIDT/SIDT指令访问IDT。
您还应该考虑到,如果您在虚拟内存操作系统上运行,则无法直接访问物理内存,程序中的地址是虚拟地址,在分段和分页后会转换为物理地址.
【讨论】:
【参考方案3】:已解决 :),由于有 Bios,它已经构建了 GDT/IDT,所以我使用 sidt 和 sgdt 指令找到了 IDT 的地址,并将我的 ISR 添加到 sidt
【讨论】:
以上是关于将 ISR 链接到向量中断 80x86 32 位 AT&T 程序集的主要内容,如果未能解决你的问题,请参考以下文章
将弱 ISR 处理程序从 Assembly 覆盖到 C++ 不会编译任何代码