irq6软盘控制器中断未触发



由于某些原因,irq6从未在我的Qemu, Bochs, VMWare或VirtualBox模拟器中命中。我需要虚拟软驱之类的东西吗?这是我的IRq6处理程序:

void  i86_flpy_irq (struct regs *r) {
    //! irq fired
    _FloppyDiskIRQ = 1;
    printf("IRQ 6 HIT");
}

它从来没有说"irq6 HIT",不仅如此,在我的irq6的安装函数中,我在内核中调用:

void flpydsk_install (int irq) {
    //! install irq handler
    install_handler_irq (irq, i86_flpy_irq);
    //! initialize the DMA for FDC
    flpydsk_initialize_dma ();
    //! reset the fdc
    flpydsk_reset ();
    //! set drive information
    //flpydsk_drive_data (13, 1, 0xf, true);
}

如您所见,我调用了一个函数来重置软驱控制器。让我们看看这个函数:

void flpydsk_reset () {
    uint32_t st0, cyl;
    _FloppyDiskIRQ = 0;
    //! reset the controller
    flpydsk_disable_controller ();
    flpydsk_enable_controller ();
    //flpydsk_wait_irq ();
    printf("STARTED WAITING");
    while(_FloppyDiskIRQ == 0);
        _FloppyDiskIRQ = 0;
    printf("ENDED WAITING FOR IRQ");
    //! send CHECK_INT/SENSE INTERRUPT command to all drives
    for (int i=0; i<4; i++)
        flpydsk_check_int (&st0,&cyl);
    //! transfer speed 500kb/s
    flpydsk_write_ccr (0);
    //! pass mechanical drive info. steprate=3ms, unload time=240ms, load time=16ms
    flpydsk_drive_data (3,16,240,true);
    //! calibrate the disk
    flpydsk_calibrate ( _CurrentDrive );
}

你可以在上面看到,我通过检查_FloppyDiskIRQ是否为1来等待IRQ结束,我在它到达时设置了这个值。我也注意到了这个常见的错误。代码从未通过while()循环,因为IRQ6从未触发。这有什么原因吗?我如何修复它,使irq6可以发射?我想我必须添加一些东西到我的模拟器(就像我为我的ATA控制器添加了一个虚拟硬盘驱动器)。

我还通过打印IRQ来测试,到目前为止只有0,1,12(没有6)…

extern "C" void irq_handler(struct regs *r)
{
     /* This is a blank function pointer */
    regs_func handler;
    /* Find out if we have a custom handler to run for this
    *  IRQ, and then finally, run it */
    handler = irq_routines[r->int_no];
    if (handler)
    {
        handler(r);
    }
    printf("%d,",r->int_no);
    //irq_taskmanager->Schedule((CPUState*)r);
    /* If the IDT entry that was invoked was greater than 40
    *  (meaning IRQ8 - 15), then we need to send an EOI to
    *  the slave controller */
    if (r->int_no >= 8)
    {
        p8b_irq.out(0x20,0xA0);
    }
    /* In either case, we need to send an EOI to the master
    *  interrupt controller too */
    p8b_irq.out(0x20, 0x20);
}

完整源代码:https://github.com/amanuel2/OS_MIRROR

这个问题与您所展示的代码无关。如果您使用QEMUGDB进行调试,或者使用BOCHS及其内部调试器并允许您的代码运行直到进入无限循环,那么您可能会发现问题的根本原因是什么。

主要问题不在于虚拟或真实硬件有bug。您的内核有错误。如果您正确地启用了硬件设备(本例中为软盘控制器)的irq,并且您没有得到预期的中断,则有以下几种可能性:

    你把错误的中断处理程序连接到IRQ
  • 你没有在PIC上启用你期望的IRQ
  • 你没有在CPU上启用中断。
  • 在设备(软盘控制器)上启用中断的代码不正确

调试器告诉您的关键信息是,到达flpydsk_reset时,EFLAGS中的中断启用标志已清除。这意味着CPU不接受外部中断。如果中断启用标志无意中被关闭,或者您从未打开过它们,就会发生这种情况。

其次,你有没有注意到,在等待软盘中断时,你的鼠标指针没有移动,计时器也没有更新?这和没有触发软盘中断(IRQ 6)的原因是一样的。

快速浏览您的kernel.c++文件将揭示问题:

   isr.install_isrs();
   irq.install_irqs();
   Timer timer;
   timer.install_timer();
   KBD kbd;
   kbd.install_kbd_driver();
   MOUSE mouse;
   mouse.install_mouse_driver();
   flpydsk_install(6);
   __asm__ __volatile__ ("sti");

您安装了许多驱动程序(键盘/鼠标等),但是在到达这段代码之前,您开始处于CPU被发出CLI指令的状态。flpydisk_install函数最终需要启用中断,但是在调用flpydisk_install之后,您发出STI指令。直到你在flpydsk_reset之前发出STI,你将保持在一个无限循环中等待一个不会发生的中断。

一个快速修复方法是在调用flpydsk_install之前执行__asm__ __volatile__ ("sti");。我可能已经编码了一些东西来启用8259A PIC上的中断,因为每个需要中断的设备都需要中断。

修改后的快速修复代码看起来像这样:

   isr.install_isrs();
   irq.install_irqs();
   Timer timer;
   timer.install_timer();
   KBD kbd;
   kbd.install_kbd_driver();
   MOUSE mouse;
   mouse.install_mouse_driver();
   __asm__ __volatile__ ("sti");
   flpydsk_install(6);

现在STI使中断到CPU, IRQ6和它的中断处理程序应该被触发,允许flpydsk_reset退出循环。


Virtual Box软盘控制器

一旦使用STI启用对CPU的中断,VirtualBox将要求您向虚拟机添加软盘控制器。您不一定需要一个虚拟软盘,至少需要一个软盘控制器。如果没有虚拟软盘控制器,通过端口向不存在的硬件发送命令将无法启用IRQ6。

我相信默认情况下BOCHSQEMU将模拟存在的软盘控制器,即使没有虚拟软盘挂载到虚拟机中。


在内核中设置QEMU调试

由于您的文件BoneOS.bin是作为ELF可执行文件构建的,并且由于您的代码不能在模式(实模式或64位长模式)之间切换,因此设置调试相当容易。你的Makefile有一个QEMU的start-debug配方。我将其修改如下:

start-debug:
        qemu-system-i386 -S -s -kernel BoneOS.bin -m 1G -serial file:qemu-serial.log 
            -serial stdio -usb -device usb-host,hostbus=2,hostaddr=1 -no-reboot &
        gdb BoneOS.bin 
            -ex 'target remote localhost:1234' 
            -ex 'break kernelMain' 
            -ex 'layout src' 
            -ex 'layout reg' 
            -ex 'continue'

第一个QEMU命令设置QEMU在启动时停止,并等待与GDB的远程连接。第二个命令将GDB连接到QEMU,在kernelMain上中断(主要的 c++ 进入点到您的代码),显示源代码和寄存器。用于调试的符号来自BoneOS.bin

您可以从这里查找实际使用GDB调试器的通用教程。

如果您安装了DDD包,您可以使用图形化调试器。它可以这样启动:

start-debug:
        qemu-system-i386 -S -s -kernel BoneOS.bin -m 1G -serial file:qemu-serial.log 
            -serial stdio -usb -device usb-host,hostbus=2,hostaddr=1 -no-reboot &
        ddd BoneOS.bin 
            --eval-command="target remote localhost:1234" 
            --eval-command="break kernelMain"

通过调整Codeblocks项目的调试器选项,可以使用Codeblocks进行远程QEMU调试。

我也面临着同样的问题。我设法通过在每个中断服务执行后重新映射/重新初始化pic来解决它。我认为这是一个糟糕的解决方案,但就目前而言,它是有效的。在我的情况下,问题是我在键盘中断后调用软盘读取例程,而没有向PIC发送EOI(中断结束)命令。因此,在调用软盘读取例程之前发送EOI解决了这个问题。你找到更好的解决办法了吗?

相关内容

  • 没有找到相关文章

最新更新