qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] Incorrect x86[_64] RMW emulation


From: malc
Subject: [Qemu-devel] Incorrect x86[_64] RMW emulation
Date: Thu, 19 Aug 2010 08:20:51 +0400 (MSD)
User-agent: Alpine 2.00 (LNX 1167 2008-08-23)

Alexander Graf kindly shared with the wolrd the link[1] to an
informative article which among other things the article highlights
the fact that QEMU's emulation of exception handling on x86[_64] is
incorrect when the faulting instruction is RMW.

Here's small test case (__i386__ case is untested):

#define _GNU_SOURCE
#include <err.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ucontext.h>
#include <unistd.h>

#define UNUSED __attribute ((unused))

/* http://fixunix.com/linux/7635-sigsegv-signal-handler.html */
static void handler (int signo, siginfo_t *info, void *context)
{
    int iswrite;
#ifdef __i386__
    (void) context;
    iswrite = info.err & 2;
#elif __x86_64__
    struct ucontext *uc = context;
    (void) info;
    mcontext_t *mc = &uc->uc_mcontext;
    iswrite = mc->gregs[REG_ERR] & 2;
#else
#error shrug
#endif
    if (iswrite) write (2, "write\n", 6);
    else write (2, "read\n", 5);
    _Exit (EXIT_FAILURE);
}

int main (int argc, char **argv)
{
    int ret;
    enum {R,W,RMW} n = R;
    struct sigaction act;

    if (argc == 2) {
        if (!strcmp (argv[1], "read")) n = R;
        else if (!strcmp (argv[1], "write")) n = W;
        else if (!strcmp (argv[1], "rmw")) n = RMW;
        else errx (EXIT_FAILURE, "argument should be one of [read|write|rmw]");
    }
    else {
        if (argc > 2) errx (EXIT_FAILURE, "need only one argument");
    }

    act.sa_sigaction = handler;
    sigemptyset (&act.sa_mask);
    act.sa_flags = SA_SIGINFO;

    ret = sigaction (SIGSEGV, &act, NULL);
    if (ret) err (EXIT_FAILURE, "sigaction");

    switch (n) {
    case W: asm ("mov %eax, 0"); break;
    case R: asm ("mov 0, %eax"); break;
    case RMW: asm ("incl 0"); break;
    }
    abort ();
}

Here's the output obtained on an x86_64 machine:

rmw$ gcc rmw.c
rmw$ ./a.out read
read
rmw$ ./a.out write
write
rmw$ ./a.out rmw
write

Since the last one is translated to more or less following TCG:

movi rN, $0
ld32 rM, rN
movi rL, $1
add rO, rM, rL
st32 rO, rN

and will incorrectly produce a read trap for both user and softmmu.

[1] http://emulators.com/docs/nx33_qemu_0125.htm

-- 
mailto:address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]