x86gdbx86-64dosqemu

MS-DOS in QEMU breaks after running while loop in GDB


Running MS-DOS 3.20 with qemu with the command qemu-system-i386 -fda ./images/disk01.img seems to work fine. Attaching GDB (with the command qemu-system-i386 -fda ./images/disk01.img -S -s for qemu and target remote localhost:1234 and just continuing the program also seems to work fine and as intended (MS-DOS boots up properly and everything). However, when I do the following while loop in GDB:

while 1
si
end

After a while of going through instructions, it prints out "Disk Boot Failure" on MS-DOS for some reason. This just doesn't make sense to me (after all the instructions in memory are supposed to the same, why would there be different behavior) and I have no idea what could be causing this, is there maybe something in GDB that could be causing this interference with QEMU?


Solution

  • This is almost certainly something within DOS timing out because single-stepping instructions via the gdbstub means that the CPU executes very slowly.

    QEMU (when used in non-icount mode) makes guest timer devices work on the host "wall clock" time, so if the guest says "this attempt to read the floppy disk should time out after 10 seconds" then it will time out after 10 real-world seconds. The emulated CPU, meanwhile, executes as fast as QEMU can make it go. Usually that's fine, but if you're slowing down the guest CPU by making every instruction executed round-trip via a gdb singlestep, the guest might not be able to execute as much of the BIOS or DOS code as it ought to before the timeout fires.

    If you want instead to tie the simulation time to how many guest instructions have been executed (effectively setting the guest CPU speed and saying "when N instructions have been executed that's 1 second for the guest"), you can look at the -icount option. But the more usual approach is "don't do a lot of single-stepping in gdb, use breakpoints instead".