如何使用内联汇编中的 LIDT 加载中断向量 table?

How to use LIDT from inline assembly to load an interrupt vector table?

我正在尝试使用 GCC 编写一个简单的操作系统,它允许我在显示器上显示我键入的文本。我在 C 中有一个中断 table,我需要加载它并希望能够使用内联汇编而不是外部汇编语言模块来加载它。

我正在寻找的是一种将 C 指针传递到内联汇编的方法。

我试图内联的需要内存操作数的指令是 LIDT:

Loads the values in the source operand into the global descriptor table register (GDTR) or the interrupt descriptor table register (IDTR). The source operand specifies a 6-byte memory location that contains the base address (a linear address) and the limit (size of table in bytes) of the global descriptor table (GDT) or the interrupt descriptor table (IDT). If operand-size attribute is 32 bits, a 16-bit limit (lower 2 bytes of the 6-byte data operand) and a 32-bit base address (upper 4 bytes of the data operand) are loaded into the register. If the operand-size attribute is 16 bits, a 16-bit limit (lower 2 bytes) and a 24-bit base address (third, fourth, and fifth byte) are loaded. Here, the high-order byte of the operand is not used and the high-order byte of the base address in the GDTR or IDTR is filled with zeros.

你没有提供任何代码,也没有说是哪个 C 编译器,但我会假设 GCC 和一个32 位内核。这是您可以执行的操作的示例:

#include <stdint.h>

struct idt_record
{
    uint16_t  limit;      /* Size of IDT array - 1 */
    uintptr_t base;       /* Pointer to IDT array  */
} __attribute__((packed));

void load_idt (struct idt_record *idt_r)
{
    __asm__ ("lidt %0" :: "m"(*idt_r));
}

此代码使用内联汇编并将 IDT 记录的地址传递到 LIDT instruction. We use the m constraint 使用的扩展内联模板中。如果约束的参数是 (idt_r) ,它会将内存引用传递给指针。我们想要一个对实际数据的内存引用,所以我们用 * 取消引用它,这就是我使用 "m"(*idt_r) 的原因。

您必须将 base 设置为指向您的实际 IDT 数组,并且 limit 将是 IDT 数组减 1。如果您向我们展示了您的数据结构,我就不必提供如此通用的响应。我不知道你是如何定义你的 IDT 记录结构的,所以我使用了一个快速简单的例子。

我可能会在包含文件中提供 load_idt 函数并将该函数标记为 static inline.


注意:如果您正在使用 IDT 记录的结构,请确保您 pack 结构类似于我对 __attribute__((packed)) 所做的。如果您不打包它,将在 limitbase 之间添加额外的 2 个字节,这将生成损坏的 IDT 记录。