4

I'm developing a microkernel. In my kernel, there is a function which enables external interrupts. But it doesn't work. Then I realized that the instruction causing the problem is a sti followed by ret. Intel Software Developer Manual says:

If IF = 0, maskable hardware interrupts remain inhibited on the instruction boundary following an execution of STI. (The delayed effect of this instruction is provided to allow interrupts to be enabled just before returning from a procedure or subroutine. For instance, if an STI instruction is followed by an RET instruction, the RET instruction is allowed to execute before external interrupts are recognized. No interrupts can be recognized if an execution of CLI immediately follow such an execution of STI.) The inhibition ends after delivery of another event (e.g., exception) or the execution of the next instruction.

So interrupts should be enabled after the ret instruction, but that doesn't happen. IF in eflags in set, but no external interrupts. If I put a nop instruction between sti and ret, everything works.

Minimal reproducible example:

        asm volatile ("call 1f;"
                      "jmp 2f;"
                      "1:"
                      "sti;"
//                      "nop;"
                      "ret;"
                      "2:");

Uncomment that nop, and interrupts would be enabled. Also, if I place one of the following line afters above, interrupts work:

        asm volatile ("jecxz 1f; 1:");
        asm volatile ("pushf; popf");

Note: I'm using QEMU to run my kernel.

Akib Azmain Turja
  • 1,142
  • 7
  • 27
  • 1
    How do you determine it doesn't happen? If you do a `pushf` after the return and output the flags that got pushed (or look at the flags in a debugger), is IF set? – CherryDT Jun 25 '21 at 17:59
  • 3
    You're sure it is a `ret` and not an `iret`? – Nate Eldredge Jun 25 '21 at 18:23
  • 2
    Is your `ret` causing a fault? (e.g. by returning to an unmapped address? Or even a non-canonical address? Or a far ret with a bad segment selector?) But you're expecting an external interrupt to be taken before the fault from the `ret` happens? An [mcve] would be good if you can make one that's small enough to be useful, but definitely a more detailed description of your test case is needed. – Peter Cordes Jun 25 '21 at 18:23
  • Is this reproducible in other emulators or real hardware? Also, what mode / privilege level are you in at this point (real, protected, long, etc)? – Nate Eldredge Jun 25 '21 at 18:24
  • @CherryDT GDB says IF is set in eflags. – Akib Azmain Turja Jun 26 '21 at 03:16
  • @NateEldredge I'm sure it's a **`ret`**, not `iret`. I'm in supervisor mode, ring 0. I don't have other emulators, and I can't run it on my PC, as it requires VGA to print texts. – Akib Azmain Turja Jun 26 '21 at 03:23
  • @PeterCordes No, `ret` is doing its job very well. It returns and caller continues. But interrupts are not enabled. I'm trying to provide a minimal working example. – Akib Azmain Turja Jun 26 '21 at 03:26
  • 2
    If IF is set in EFLAGS, then interrupts *are* enabled. Are you sure you didn't somehow block most interrupts another way? Like possibly interrupt priority filter of the APIC/LAPIC? [How is CR8 register used to prioritize interrupts in an x86-64 CPU?](https://stackoverflow.com/q/51490552) talks about how x86-64 can access that via CR8, but it's also accessible through MMIO or an IO port on the APIC, or something like that. Have you tried single-stepping in BOCHS's built-in debugger to see if pending interrupts are serviced? – Peter Cordes Jun 26 '21 at 03:36
  • @PeterCordes No, I don't have bochs. Bochs in the repo doesn't have debugging facilities, and I failed to compile bochs myself. I have given a minimal working example, please see that. – Akib Azmain Turja Jun 26 '21 at 03:51
  • 2
    Sounds like a possible QEMU bug, then. I don't think it's plausible for real hardware to have IF set (if you read it with popf) but to behave as if it's not. Unless there's a bug in the rest of your kernel somewhere. – Peter Cordes Jun 26 '21 at 03:54
  • 1
    @PeterCordes Yes, It looks like a QEMU bug. After 4 hours of trials (as my GNU/Linux distribtution (Guix) is not much popular, it doesn't have much tutorials), I was finally able compile Bochs without SMP support (it only took 2-3 minutes!). Then I started Bochs and saw that interrupts were working. However, I need to implement serial ports so that I can read output easily, to be sure it's a bug. – Akib Azmain Turja Jun 26 '21 at 09:46

0 Answers0