首页 > 解决方案 > 为什么我收到错误:中断服务例程应该将“unsigned long int”作为第二个参数?

问题描述

我收到一个简单的错误,因为我阅读了一份文档(https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#x86-Function-Attributes)并且想要正确地做事。在本文件中指出:

必须使用强制指针参数声明中断处理程序:

struct interrupt_frame;

__attribute__ ((interrupt))
void
f (struct interrupt_frame *frame)
{
}

并且您必须按照处理器手册中的说明定义 struct interrupt_frame。

异常处理程序与中断处理程序不同,因为系统将错误代码压入堆栈。异常处理程序声明类似于中断处理程序,但具有不同的强制函数签名。编译器安排在 IRET 指令之前将错误代码从堆栈中弹出。

#ifdef __x86_64__
typedef unsigned long long int uword_t;
#else
typedef unsigned int uword_t;
#endif

struct interrupt_frame;

__attribute__ ((interrupt))
void
f (struct interrupt_frame *frame, uword_t error_code)
{
 ...
}

异常处理程序应该只用于推送错误代码的异常;在其他情况下,您应该使用中断处理程序。如果使用了错误类型的处理程序,系统将崩溃。

因此,推送错误代码的异常应具有 64 位长作为第二个参数。其他应该只有用户定义的 interrupt_frame 结构。因此,我尝试使用以下代码来做到这一点:

struct InterruptFrame{
    UINT64 rsp;
};

//Divide by zero error
__attribute__((interrupt)) void IDT::isr0(InterruptFrame* frame) {
    asm volatile("hlt");
}

//Page fault
__attribute__((interrupt)) void IDT::isr14(InterruptFrame* frame, unsigned long long int errorCode) {
    asm volatile("hlt");
}

这些只是示例,因为我有更多独立的 ISR。当我编译时

g++ -static -ffreestanding -nostdlib -mgeneral-regs-only -mno-red-zone -c -m64 Kernel/Source/IDT.cpp -oKernel/Object/IDT.o

我收到一条错误消息

error: interrupt service routine should have ‘unsigned long int’ as the second argument

即使我完全按照文档中的说明做了。即使对于当前具有 unsigned long long int 作为第二个参数的页面错误处理程序,我也会收到每个 ISR 的错误。我在网上没有找到太多关于错误的搜索,所以我想在这里问。

怎么了?此外,对于 x86-64,InterruptFrame 结构应该包含哪些成员?

标签: c++kernelx86-64interruptosdev

解决方案


最后,这个问题是我的一个小错误。我__attribute__((interrupt))在 C++ IDT 成员函数的声明上而不是在原型上声明了。您可以使用以下内容重现该问题:

struct InterruptFrame{
    unsigned long rsp;
};

class IDT{
public:
    static void isr0(InterruptFrame* frame);
    static void isr14(InterruptFrame* frame, unsigned long errorCode);
};

__attribute__((interrupt)) void IDT::isr0(InterruptFrame* frame) {
    asm volatile("hlt");
}

__attribute__((interrupt)) void IDT::isr14(InterruptFrame* frame, unsigned long errorCode) {
    asm volatile("hlt");
}

此文件产生错误。而以下文件不会产生任何错误。

struct InterruptFrame{
    unsigned long rsp;
};

class IDT{
public:
    __attribute__((interrupt)) static void isr0(InterruptFrame* frame);
    __attribute__((interrupt)) static void isr14(InterruptFrame* frame, unsigned long errorCode);
};

void IDT::isr0(InterruptFrame* frame) {
    asm volatile("hlt");
}

void IDT::isr14(InterruptFrame* frame, unsigned long errorCode) {
    asm volatile("hlt");
}

我可以反汇编代码,看看中断代码似乎是正确的:

user@user-System-Product-Name:~$ objdump -d test.o

test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <_ZN3IDT4isr0EP14InterruptFrame>:
   0:   f3 0f 1e fa             endbr64 
   4:   55                      push   %rbp
   5:   48 89 e5                mov    %rsp,%rbp
   8:   50                      push   %rax
   9:   48 83 ec 08             sub    $0x8,%rsp
   d:   48 8d 45 08             lea    0x8(%rbp),%rax
  11:   48 89 45 f0             mov    %rax,-0x10(%rbp)
  15:   f4                      hlt    
  16:   90                      nop
  17:   48 83 c4 08             add    $0x8,%rsp
  1b:   58                      pop    %rax
  1c:   5d                      pop    %rbp
  1d:   48 cf                   iretq  
  1f:   90                      nop

0000000000000020 <_ZN3IDT5isr14EP14InterruptFramem>:
  20:   f3 0f 1e fa             endbr64 
  24:   55                      push   %rbp
  25:   48 89 e5                mov    %rsp,%rbp
  28:   50                      push   %rax
  29:   48 83 ec 10             sub    $0x10,%rsp
  2d:   48 8d 45 10             lea    0x10(%rbp),%rax
  31:   48 89 45 f0             mov    %rax,-0x10(%rbp)
  35:   48 8b 45 08             mov    0x8(%rbp),%rax
  39:   48 89 45 e8             mov    %rax,-0x18(%rbp)
  3d:   f4                      hlt    
  3e:   90                      nop
  3f:   48 83 c4 10             add    $0x10,%rsp
  43:   58                      pop    %rax
  44:   5d                      pop    %rbp
  45:   48 83 c4 08             add    $0x8,%rsp
  49:   48 cf                   iretq

我仍然想知道为什么中断代码不推送所有寄存器?


推荐阅读