Public bug reported:

Reporting this as present in QEMU 3.1.0, although I don't see any commit
in current git master (a6ae23831b05a11880b40f7d58e332c45a6b04f7) that
would suggest this issue is fixed.

    $ uname -a
    Linux boole 4.19.0-4-686-pae #1 SMP Debian 4.19.28-2 (2019-03-15) i686 
GNU/Linux
    $ qemu -version
    QEMU emulator version 3.1.0 (Debian 1:3.1+dfsg-7)
    Copyright (c) 2003-2018 Fabrice Bellard and the QEMU Project developers

Here's an excerpt from the code which handles reboot requests in SeaBIOS
1.12, located in src/fw/shadow.c:

    // Request a QEMU system reset.  Do the reset in this function as
    // the BIOS code was overwritten above and not all BIOS
    // functionality may be available.

    // Attempt PCI style reset
    outb(0x02, PORT_PCI_REBOOT);
    outb(0x06, PORT_PCI_REBOOT);

    // Next try triple faulting the CPU to force a reset
    asm volatile("int3");

This compiles to the following:

    (qemu) x/10i 0xf1993
    0x000f1993:  b0 02                    movb     $2, %al
    0x000f1995:  ee                       outb     %al, %dx
    0x000f1996:  b0 06                    movb     $6, %al
    0x000f1998:  ee                       outb     %al, %dx
    0x000f1999:  cc                       int3     
    0x000f199a:  80 3d 0d 53 0f 00 08     cmpb     $8, 0xf530d
    0x000f19a1:  75 52                    jne      0xf19f5
    0x000f19a3:  a1 10 53 0f 00           movl     0xf5310, %eax
    0x000f19a8:  8b 15 14 53 0f 00        movl     0xf5314, %edx
    0x000f19ae:  89 c3                    movl     %eax, %ebx

Now, with the TCG backend, upon reaching the second outb instruction,
the thread executing JIT-ed opcodes invokes
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET). This signals
another thread to reset the guest CPU registers to their initial state.
However, the execution thread is *not* stopped, which means it will keep
executing already-translated instructions in the TCG buffer. In
particular, the bootstrap value of the EIP register will be overwritten.
On my machine, this usually results in the guest CPU finding itself in
real mode, CS base 0xffff0000, EIP 0x0000199e, which in real mode
disassembles to this:

    (qemu) xp/1i 0xf199e
    0x000f199e:  0f 00 08                 strw     0(%bx, %si)

This instruction triggers a #UD exception, and given that SeaBIOS
handles #UD by immediately returning, it manifests as the guest locking
up with 100% CPU usage every other reboot.

** Affects: qemu
     Importance: Undecided
         Status: New


** Tags: freeze reboot tcg

** Tags removed: lockup
** Tags added: freeze

-- 
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1827871

Title:
  Race condition when rebooting with the TCG backend

Status in QEMU:
  New

Bug description:
  Reporting this as present in QEMU 3.1.0, although I don't see any
  commit in current git master
  (a6ae23831b05a11880b40f7d58e332c45a6b04f7) that would suggest this
  issue is fixed.

      $ uname -a
      Linux boole 4.19.0-4-686-pae #1 SMP Debian 4.19.28-2 (2019-03-15) i686 
GNU/Linux
      $ qemu -version
      QEMU emulator version 3.1.0 (Debian 1:3.1+dfsg-7)
      Copyright (c) 2003-2018 Fabrice Bellard and the QEMU Project developers

  Here's an excerpt from the code which handles reboot requests in
  SeaBIOS 1.12, located in src/fw/shadow.c:

      // Request a QEMU system reset.  Do the reset in this function as
      // the BIOS code was overwritten above and not all BIOS
      // functionality may be available.

      // Attempt PCI style reset
      outb(0x02, PORT_PCI_REBOOT);
      outb(0x06, PORT_PCI_REBOOT);

      // Next try triple faulting the CPU to force a reset
      asm volatile("int3");

  This compiles to the following:

      (qemu) x/10i 0xf1993
      0x000f1993:  b0 02                    movb     $2, %al
      0x000f1995:  ee                       outb     %al, %dx
      0x000f1996:  b0 06                    movb     $6, %al
      0x000f1998:  ee                       outb     %al, %dx
      0x000f1999:  cc                       int3     
      0x000f199a:  80 3d 0d 53 0f 00 08     cmpb     $8, 0xf530d
      0x000f19a1:  75 52                    jne      0xf19f5
      0x000f19a3:  a1 10 53 0f 00           movl     0xf5310, %eax
      0x000f19a8:  8b 15 14 53 0f 00        movl     0xf5314, %edx
      0x000f19ae:  89 c3                    movl     %eax, %ebx

  Now, with the TCG backend, upon reaching the second outb instruction,
  the thread executing JIT-ed opcodes invokes
  qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET). This signals
  another thread to reset the guest CPU registers to their initial
  state. However, the execution thread is *not* stopped, which means it
  will keep executing already-translated instructions in the TCG buffer.
  In particular, the bootstrap value of the EIP register will be
  overwritten. On my machine, this usually results in the guest CPU
  finding itself in real mode, CS base 0xffff0000, EIP 0x0000199e, which
  in real mode disassembles to this:

      (qemu) xp/1i 0xf199e
      0x000f199e:  0f 00 08                 strw     0(%bx, %si)

  This instruction triggers a #UD exception, and given that SeaBIOS
  handles #UD by immediately returning, it manifests as the guest
  locking up with 100% CPU usage every other reboot.

To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1827871/+subscriptions

Reply via email to