【问题标题】:Assembler + C or I Can't Get Interrupts Working汇编程序 + C 或我无法让中断工作
【发布时间】:2017-02-01 21:56:37
【问题描述】:

求助,我运行操作系统但它崩溃了! IDT Loadet 正常。我做错了什么?真的很难!我需要在保护模式下编写操作系统!

    #define IT 0x000000
    #define IR 0x000800
    #define SCS 0x8
    #define IRQ_HANDLER(func) void func (void)\
     {asm(#func ": pusha \n call _" #func " \n movb $0x20, %al \n outb %al, $0x20 \n popa \n iret \n");}\
     void _ ## func(void)
        void init_interrupts() {
            int i=0;
            unsigned short *ir=IR;
            for(i=0;i<256*8;i++){
                *(ir+i)=0;
            }
            *(ir)=256*8-1;
            *(ir+2)=(IT &0xFFFF0000)>>16;
            *(ir+4)=(IT&0x0000FFFF);
            set_int_handler(0x20, timer_int_handler, 0x8E);
            //set_int_handler(0x21, print_c, 0x8E);
            asm("lidt 0(,%0,)"::"a"(IR));
            opb(0x21,0xfd);
           opb(0xa1,0xff);
            opb(0x20,0x20); opb(0xa0,0x20);
            asm("sti");
        }

        void set_int_handler(char index, void *handler, char type) {
        asm("pushf \n cli");
        char *ad=IT;
        *(ad+index*8)=(char)(handler)&0x000000FF;
        *(ad+index*8+1)=((char)(handler)&0x0000FF00)>>8;
        *(ad+index*8+2)=0x8;
        *(ad+index*8+3)=0;
        *(ad+index*8+4)=0;
        *(ad+index*8+5)=type;
        *(ad+index*8+6)=((char)(handler)&0x00FF0000)>>16;
        *(ad+index*8+7)=((char)(handler)&0xFF000000)>>24;   
        asm("popf"); 
    }
    ...


我不知道该怎么办!

【问题讨论】:

  • 你不能这样使用内联汇编。编译器不承诺在执行popf 时将堆栈保持在与pushf \n cli 之后相同的状态。
  • 已经在答案和 cmets 之上。我看到你这样做了opb(0x21,0xfd); opb(0xa1,0xff);,这表明你屏蔽了所有 16 个中断除了 IRQ1,它是键盘中断,但是你为定时器设置了中断处理程序,即 IRQ0。你是故意的吗? 0xfd = 二进制 11111101,这是您将主 PIC 设置为 IRQ1 的值。也许你的意思是 0xfe?

标签: c assembly operating-system interrupt


【解决方案1】:

首先,无论如何,大多数编译器都允许您使用create an ISR directly

其次,您应该从一开始就捕获所有内容,除非您希望系统在第一个未处理或虚假中断(乍一看似乎正在发生的情况)时崩溃。

适当的中断处理子系统将使代码更加简洁和可移植,允许您探测哑总线(如 ISA)的 IRQ 并干净地路由共享 IRQ。

大多数仿真器都支持 GDB 协议,并允许您轻松调试此类故障。例如,您可以使用-d int-no-reboot 启动QEMU 来调试此类问题,一旦发生故障,您可以从调试器中检查它。您可以在QEMU Wikibook 中找到一些入门说明。您可能还想尝试 BOCHS,它带有一个内部调试器,可以更好地处理低级别的东西,而且仿真有时更准确。

【讨论】:

  • 大多数 32 位 x86 编译器不允许您直接创建 ISR,因为保护模式中断处理通常过于复杂,无法由通用中断函数序言和结尾处理。
  • GCC 和 Clang 一样,Borland 和 Watcom IIRC 也是如此(已经很多年了......)。
  • GNU 风格的语法:__attibute__((interrupt)),大多数其他编译器 __interrupt 或类似的,签名要求各不相同。
  • 我更喜欢同时使用 QEMU 监视器和 GDB 的 QEMU/GDB IF 目标不是 16 位实模式。尽管 GDB 在从 32 位代码转换到 64 位代码时无法正常工作(假设有人想编写 64 位内核),但可以通过使用 QEMU 重新启动调试会话来解决该问题不同的架构。可以调试 16 位实模式代码,但前提是您使用的段全为零并且代码在前 64kb 中。使用 GDB,如果您还生成 ELF 文件,您至少可以使用符号调试信息。
  • @MichaelPetch 我试过的所有调试器都坏了,解决方法是修补 QEMU 以在 16 位模式下将 %eip 报告为 %cs * 16 + %eip,我已经使用了大部分时间:iodev.co.uk/… --- 在转换中仍然不起作用。
猜你喜欢
  • 2014-05-03
  • 2016-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多