汇编程序&x2B;C或我可以';不能让中断工作

汇编程序&x2B;C或我可以';不能让中断工作,c,assembly,operating-system,interrupt,C,Assembly,Operating System,Interrupt,救命,我运行操作系统,它崩溃了!IDT加载正常。我做错了什么?真的很难!我需要在保护模式下写操作系统 #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 \

救命,我运行操作系统,它崩溃了!IDT加载正常。我做错了什么?真的很难!我需要在保护模式下写操作系统

    #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"); 
    }
    ...
#定义它0x000000
#定义IR 0x000800
#定义SCS 0x8
#定义IRQ_处理程序(func)void func(void)\
{asm(#func:pusha\n调用"#func“\n movb$0x20,%al\n outb%al,$0x20\n popa\n iret\n”);}\
void 35;##func(void)
void init_中断(){
int i=0;
无符号短*ir=ir;
对于(i=0;i>16;
*(ir+4)=(IT&0x0000FFFF);
set_int_handler(0x20,timer_int_handler,0x8E);
//设置整型处理器(0x21,打印c,0x8E);
asm(“LIDT0(,%0,)”:“a”(IR));
opb(0x21,0xfd);
opb(0xa1,0xff);
opb(0x20,0x20);opb(0xa0,0x20);
asm(“sti”);
}
void set\u int\u处理程序(字符索引,void*处理程序,字符类型){
asm(“pushf\n cli”);
char*ad=IT;
*(ad+索引*8)=(字符)(处理程序)&0x000000FF;
*(ad+索引*8+1)=((字符)(处理程序)和0x0000FF00)>>8;
*(ad+索引*8+2)=0x8;
*(ad+指数*8+3)=0;
*(ad+指数*8+4)=0;
*(ad+索引*8+5)=类型;
*(ad+索引*8+6)=((字符)(处理程序)和0x00FF0000)>>16;
*(ad+索引*8+7)=((字符)(处理程序)&0xFF000000)>>24;
asm(“popf”);
}
...


我不知道该怎么办!

首先,大多数编译器都允许您这样或那样做

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

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


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

大多数32位x86编译器不允许您直接创建ISR,因为保护模式中断处理通常太复杂,无法由通用中断函数prologue和epilogue.GCC和clangdo来处理,如do Borland和Watcom IIRC(已经很多年了…)。GNU风格的语法:
\uuuuuu attibute\uuuuu((中断))
,大多数其他编译器
\u中断
或类似编译器,签名要求各不相同。如果目标不是16位实模式,我更喜欢同时使用QEMU监视器和GDB的QEMU/GDB。尽管GDB在32位到64位代码的交叉点无法正常工作(假设有人想要编写64位内核),可以通过使用具有不同体系结构的QEMU重新启动调试会话来解决该问题。可以调试16位实模式代码,但前提是您使用的段都为零且代码位于前64kb。使用GDB,如果您还生成ELF文件,则至少可以使用符号调试信息。@MichaelPetch我尝试过的所有调试器都坏了,一个解决办法是修补QEMU以将
%eip
报告为
%cs*16+%eip
当处于16位模式时,我大部分时间都使用了它:---它在转换中仍然不起作用。你不能像那样使用内联汇编。编译器不能保证使堆栈保持与以前相同的状态在您的
pushf\n cli
执行
popf
之后。在答案和注释之上。我看到您执行
opb(0x21,0xfd);opb(0xa1,0xff)
这表明您屏蔽了除IRQ1(键盘中断)之外的所有16个中断,但随后您为计时器设置了中断处理程序IRQ0。您的意思是这样做的吗?0xfd=二进制111111 01,这是您设置的主PIC,它将是IRQ1。也许您的意思是0xfe?