1

出于某种原因,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 );
}

您可以在上面看到,我通过检查是否为 1 来等待 IRQ 完成_FloppyDiskIRQ,这是我在它命中时设置的。我也注意到了这个常见的错误。代码永远不会通过该while()循环,因为 IRQ6 永远不会触发。是否有一个原因?如何修复它以便 IRQ 6 可以触发?我想我必须在我的模拟器中添加一些东西(比如我为我的 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

4

2 回答 2

2

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

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

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

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

其次,您是否注意到在等待软盘中断时您的鼠标指针没有移动并且计时器没有更新?这与未触发软盘中断(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您将一直处于无限循环中,等待不会发生的中断。

一种快速的肮脏修复是__asm__ __volatile__ ("sti");在调用flpydsk_install. 我可能会编写一些代码来启用 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 位长模式)之间切换,因此设置调试相当容易。你Makefilestart-debugQEMU 的配方。我已将其修改为以下内容:

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

于 2016-09-18T17:51:10.677 回答
0

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

于 2021-06-05T04:46:04.147 回答