Project

General

Profile

Actions

Bug #14489

open

bhyve should emulate imul

Added by Andy Fiddaman 5 months ago. Updated 4 months ago.

Status:
In Progress
Priority:
Normal
Assignee:
Category:
bhyve
Start date:
Due date:
% Done:

0%

Estimated time:
Difficulty:
Medium
Tags:
Gerrit CR:

Description

Using the same test case as in #14483 (but with that emulation added), I also see:

Failed to emulate instruction sequence [0f, af, 4a, 3c, 48, 01, d1, 48, 39, d9, 76, 1c, 8d, 78, ff] @ rip = 7bae07d
0x7bae07d:      imull  0x3c(%rdx),%ecx
[0]> 0x7bae07d/I
0x7bae07d:      7bae07d 3c4aaf0f: imull  0x3c(%rdx),%ecx

Files

imul32.c (1.42 KB) imul32.c imul fuzz test program (32-bit case) Andy Fiddaman, 2022-02-27 12:14 PM

Related issues

Related to illumos gate - Bug #14483: bhyve should emulate testb imm8,r/m8ClosedAndy Fiddaman

Actions
Actions #1

Updated by Andy Fiddaman 5 months ago

  • Description updated (diff)
  • Category set to bhyve
  • Status changed from New to In Progress
  • Assignee set to Andy Fiddaman
Actions #2

Updated by Andy Fiddaman 5 months ago

  • Description updated (diff)
Actions #3

Updated by Electric Monk 5 months ago

  • Gerrit CR set to 2022
Actions #4

Updated by Andy Fiddaman 4 months ago

The particular instruction which triggers the emulation is the first of these (in the bootrom), but both would trigger.

./X64/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe/OUTPUT/Reclaim.obj

    GetLbaAndOffsetByAddress+0x7d: 0f af 4a 3c        imull  0x3c(%rdx),%ecx
    GetLbaAndOffsetByAddress+0x96: 0f af 42 3c        imull  0x3c(%rdx),%eax
      if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {
        //
        // Found the (Lba, Offset).
        //
        *Lba    = LbaIndex - 1;
        *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
Actions #5

Updated by Andy Fiddaman 4 months ago

  • Related to Bug #14483: bhyve should emulate testb imm8,r/m8 added
Actions #6

Updated by Andy Fiddaman 4 months ago

I tested the generic emulation using a C program that compared the results of the emulation with the results of executing a real imul call - for the 64, 32, and 16-bit cases. In addition to some specific test cases, I also generated both positive and negative random numbers (using random()) and ran this in a loop.

I also used this dtrace script to observe the behaviour when booting the VM that triggered the emulation failure:

vie_emulate_mul:entry { self->t++; }
vie_emulate_mul:return { self->t--; }

vm_get_register:entry/self->t/ {
        self->reg = arg2;
        self->valp = args[3];
}

vm_get_register:return/self->t/ {
        printf("Reg %x = %x", self->reg, *(self->valp));
}

vie_mmio_read:entry/self->t/ {
        self->mmvalp = args[4];
}

vie_mmio_read:return/self->t && arg1 == 0/ {
        printf("MMIO = %x", *(self->mmvalp));
}

vie_mmio_read:return/self->t && arg1 != 0/ {
        printf("MMIO return %x", arg1);
}

vie_update_register:entry/self->t/ {
        printf("Result = %x", arg3);
}

getimulflags:return/self->t/ {
        printf("RFLAGS = %x", arg1);
}

which resulted in the following output:

dtrace: script './imul.d' matched 9 probes
CPU     ID                    FUNCTION:NAME
  4  89576           vm_get_register:return Reg 2 = 1
  4  89855             vie_mmio_read:return MMIO = 1000
  4  89808        vie_update_register:entry Result = 1000
  4  89839              getimulflags:return RFLAGS = 206
  4  89576           vm_get_register:return Reg 15 = 10212
  4  89808        vie_update_register:entry Result = 10206

  4  89576           vm_get_register:return Reg 0 = 0
  4  89855             vie_mmio_read:return MMIO = 1000
  4  89808        vie_update_register:entry Result = 0
  4  89839              getimulflags:return RFLAGS = 206
  4  89576           vm_get_register:return Reg 15 = 10206
  4  89808        vie_update_register:entry Result = 10206

These correspond to the multiplications in the two lines in the original C source.

Actions #7

Updated by Andy Fiddaman 4 months ago

Actions #8

Updated by Andy Fiddaman 4 months ago

Then I went back and added an SDT probe, which yields the same information, in a much more straightforward fashion:

nemesis# dtrace -n 'vie-imul { printf("(%s) %x * %x = %x", stringof(arg0), arg1, arg2, arg3); }' -n 'vie-imul-rflags { printf("%x (%x)", arg1, arg0)}'
dtrace: description 'vie-imul ' matched 1 probe
dtrace: description 'vie-imul-rflags ' matched 1 probe

nemesis# bhyve -k x.cfg
CPU     ID                    FUNCTION:NAME
  3   4348         vie_emulate_mul:vie-imul (ecx) 1 * 1000 = 1000
  3   4347  vie_emulate_mul:vie-imul-rflags 206 (10206)
  3   4348         vie_emulate_mul:vie-imul (eax) 0 * 1000 = 0
  3   4347  vie_emulate_mul:vie-imul-rflags 206 (10206)
Actions

Also available in: Atom PDF