简体   繁体   English

实现 IRQ 时出现无效的操作码异常

[英]Invalid Op Code Exception when implementing IRQs

I have been trying to loosely follow this tutorial on basic kernel dev.我一直试图在基本的 kernel 开发人员上松散地遵循本教程 Currently, the target architecture is i386.目前,目标架构是 i386。

The implementation of IRQs is causing me issues; IRQ 的实施给我带来了问题; my interrupt handler reports a cascade of Invalid Op Code exceptions whenever I try to pass registers (defined as a struct ) as an argument to a function.每当我尝试将寄存器(定义为struct )作为参数传递给 function 时,我的中断处理程序都会报告一系列Invalid Op Code异常。 Here is the code for the interrupt handler which raises the exception:这是引发异常的中断处理程序的代码:

void interrupt_handler(registers_t all_registers) {
    // Printing exception's name
    kprint("interrupt_handler.c (l. 53) : Exception raised was:", 0xB0);
    kprint(exception_messages[(int) all_registers.int_no], 0xB0);
    kprint("\n", 0xB0);

    // Celling test_handle to display the value of some registers
    // INVALID OP CODE ================>
    test_handle(all_registers); // works as expected if this line is commented out
   
}

void test_handle(registers_t all_registers) {
    kprint("interrupt_handler.c (l. 78) : Register DS contains", 0xD0);
    kprint("to be implemented", 0xD0);
}

The structure registers_t is defined as follows (copied from the tutorial):结构registers_t定义如下(从教程中复制):

typedef struct {
   u32int ds;                                      /* Data segment selector */
   u32int edi, esi, ebp, esp, ebx, edx, ecx, eax;  /* Pushed by pusha. */
   u32int int_no, err_code;                        /* Interrupt number and error code (if applicable) */
   u32int eip, cs, eflags, useresp, ss;            /* Pushed by the processor automatically */
} __attribute__((packed)) registers_t;

Trying function calling with other struct, I found that the number of variables in the struct matters;尝试使用其他结构调用 function ,我发现struct中的变量数量很重要; any struct that has between 5 and 16 u32int triggers the exception.任何具有 5 到 16 个 u32int 的struct都会触发异常。 For instance, the following structure, when initialized and passed empty to test_handle , does not raise exceptions:例如,以下结构在初始化并将空传递给test_handle时,不会引发异常:

// Same as registers_t with less arguments
typedef struct {
    u32int ds;
    u32int edi, esi;
}  __attribute__((packed))  test_t;

Disassembling the.o file reveals that the generated code uses the mov instruction to pass test_t structures and movsd to pass registers_t .反汇编 .o 文件显示生成的代码使用mov指令传递test_t结构, movsd传递registers_t So my suspicion is that the compilation process is at fault, since the compiler generates unrecognized instructions.所以我怀疑编译过程有问题,因为编译器会生成无法识别的指令。

Here are the relevant excerpts of my Makefile :以下是我的Makefile的相关摘录:

C_FLAGS=-ffreestanding -nostartfiles -nodefaultlibs -fno-builtin -Wall -Wextra -fno-exceptions -m32 -target i386-pc-elf  -fno-rtti

# Compiling C code
%.o: %.c
    clang $(C_FLAGS) -c $< -o $@ 

# Linking
kernel/kernel.bin: $(O_FILES)
    ld -o $@ -Ttext 0x1000 $^ --oformat binary -m elf_i386

Is there anything wrong about the compiling process?编译过程有什么问题吗? Or does the problem stem from elsewhere?还是问题出在其他地方?

@Ross Ridge figured it out (thanks to him.). @Ross Ridge 想通了(感谢他。)。 The details below are what I learned from the OSDev wiki下面的细节是我从OSDev wiki学到的

The Streaming SIMD Extension (SSE) expands the set of instructions recognized by the CPU with some 70 additional instructions and adds some more registers.流式 SIMD 扩展(SSE) 扩展了 CPU 识别的指令集,增加了大约 70 条指令,并添加了更多寄存器。 SSE needs to be enabled before its instructions and registers can be used.需要先启用 SSE,然后才能使用其指令和寄存器。 The compiler generates machine code which can include SSE instructions and therefore, SSE needs to be enabled.编译器生成可以包含 SSE 指令的机器代码,因此需要启用 SSE。

In the code above, the passing of struct to the function was compiled into machine code which involved the xmm0 register, which is part of the SSE.在上面的代码中,将struct传递给 function 被编译为涉及xmm0寄存器的机器代码,它是 SSE 的一部分。

The assembly code to enable SSE is given below (adapted from the OSDev wiki).下面给出了启用 SSE 的汇编代码(改编自 OSDev wiki)。 I added it to my bootloader, right after entering the 32-bit protected mode and before entering the kernel.在进入 32 位保护模式之后和进入 kernel 之前,我将它添加到我的引导加载程序中。 That fixed the problem!这解决了问题!

mov eax, cr0        ; cr0 cannot be manipulated directly, manipulate eax instead
and ax, 0xFFFB      ; clear coprocessor emulation CR0.EM
or ax, 0x2          ; set coprocessor monitoring  CR0.MP
mov cr0, eax
mov eax, cr4        ; cr4 too cannot be manipulated directly
or ax, 3 << 9       ; set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
mov cr4, eax

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM