Warm tip: This article is reproduced from serverfault.com, please click

Why BIOS interrupt 8 (timer) not working on qemu-system-x86_64

发布于 2021-01-06 08:59:00

I suppose BIOS interrupt 8 (timer) should come 18.2 times per second, but it doesn't on qemu. See the following example:

$ cat c.asm

init:
    .segments:
        mov ax, 0x07C0
        mov ds, ax
        mov ax, 0
        mov fs, ax
    .interrupt:
        mov [fs:0x08*4], word timer
        mov [fs:0x08*4+2], ds

main:
    hlt
    jmp main

timer:
    mov ah, 0x0e
    mov al, 0x41
    int 0x10
    iret

times 510-($-$$) db 0
dw 0xaa55
$ nasm -f bin c.asm -o c.bin && qemu-system-x86_64 c.bin

Qemu window appears, and only one 'A' displayed, not continuously.

What's wrong with my code, if I hope interrupt 8 comings again and again.

I use nasm 1.14.02, qemu 4.2.1 and ubuntu 20.04.

Questioner
L. Ouyang
Viewed
0
ecm 2021-01-06 22:19:06

The crucial change to make it display 'A' repeatedly is sending an End Of Interrupt signal to the PIC on port 20h. If you use interrupt 1Ch or chain to another interrupt 08h handler this is not needed in your code. If you replace the interrupt 08h handler entirely though, it is. The PIC won't send another IRQ #0 until the prior one gets an EOI. Because of this I was able to reproduce your problem.

The other changes I did were to insure that the interrupt flag is set before entering the main loop (with a sti instruction), and preserving all registers across the interrupt 08h handler (this is optional if your code is the only thing running on the machine).

init:
    .segments:
        mov ax, 0x07C0
        mov ds, ax
        mov ax, 0
        mov fs, ax
    .interrupt:
        mov [fs:0x08*4], word timer
        mov [fs:0x08*4+2], ds

        sti
main:
    hlt
    jmp main

timer:
        push ax
        push bx
        push bp
    mov ah, 0x0e
    mov al, 0x41
    int 0x10
        mov al, 20h
        out 20h, al
        pop bp
        pop bx
        pop ax
    iret

times 510-($-$$) db 0
dw 0xaa55

Run like so:

$ nasm test.asm
$ timeout 10 qemu-system-x86_64 test -curses