【问题标题】:IRQ 6 floppy disk controller interrupt not triggeredIRQ 6 软盘控制器中断未触发
【发布时间】:2017-01-25 22:16:16
【问题描述】:

由于某种原因,IRQ 6 从未在我的 Qemu、Bochs、VMWare 或 VirtualBox 仿真器中运行。我需要某种类型的虚拟软盘驱动器或其他东西吗?这是我的 IRq6 处理程序:

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

它从不说“IRQ 6 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 完成,这是我在它命中时设置的。我还注意到this 常见错误。代码永远不会通过 while() 循环,因为 IRQ6 永远不会触发。是否有一个原因?如何修复它以便 IRQ 6 可以触发?我想我必须在我的模拟器中添加一些东西(比如我为我的 ATA 控制器添加了一个虚拟硬盘)。

我还通过打印截至目前只有 0、1、12 的 IRQ 进行测试(第 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

【问题讨论】:

  • 对于否定这个问题并将其关闭为不清楚的人?这怎么不清楚?我显然在问为什么IRQ6 Never Fire , and How can i fix? 怎么能比这更清楚?
  • Stackoverflow 不是我之前试图指出的调试服务。
  • @MichaelPetch 我从来没有要求调试..我只是问我需要在我的 VM 中启用什么才能触发 IRQ 6..如果这不是一个有效的问题,为什么还要有 osdev先贴标签?对我来说,这是一个 100% 的好问题。
  • @MichaelPetch 我已经看了一百万次了
  • @MichaelPetch 哦,是的,我忘了接受 anwser .. 我做了谢谢。我现在正在做文件管理..完全是我自己的计划。大部分时间我都在chat.stackoverflow.com/rooms/85048/teenage-territory聊天室,如果你想在那里聊天,请随意;)

标签: x86 g++ osdev irq floppy


【解决方案1】:

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

主要问题不在于虚拟或真实硬件有问题。你的内核有一个错误。如果您为硬件设备(在这种情况下为软盘控制器)正确启用了 IRQ,并且您没有得到预期的中断,则有一些可能性:

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

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

其次,您是否注意到在等待软盘中断时鼠标指针没有移动并且计时器没有更新?这与未触发软盘中断 (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 函数最终需要启用中断,但您发出STI 指令AFTER 调用flpydisk_install。在您在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 有一个start-debug QEMU 配方。我已将其修改为以下内容:

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 调试。

【讨论】:

  • 对不起,我刚来......看到你回答......感谢您终于意识到这是一个好问题。稍后我会回到这个答案与您交谈.. 我有考试要参加
  • Michael 是否有关于 Bochs 的调试教程或任何适合 osdev 的调试器? (请不要将我链接到 wiki.osdev.org..)
  • @amanuel2 :我不打算写一篇关于使用 GDB 的教程,但我已经用 Makefile 配方修改了我的答案,它取代了你当前的 start-debugrule。足以让您进入连接到 GDB 和内核的文本模式调试器。您可以找到任何有关 GDB 调试的教程以正确使用它。
  • Michael : 好吧,如果我问你,我希望你不会结束一个问题,为什么我只能发出 READ 命令(ATA Pio 模式 28 位中的 0x20)?
【解决方案2】:

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

【讨论】:

猜你喜欢
  • 2016-04-25
  • 1970-01-01
  • 2011-01-13
  • 1970-01-01
  • 2015-11-25
  • 2013-02-27
  • 2018-11-18
  • 2016-10-11
  • 1970-01-01
相关资源
最近更新 更多