qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] User mode: Handle x86_64 vsyscall
@ 2009-07-11 15:14 Laurent Desnogues
  2009-10-17 15:42 ` [Qemu-devel] " Laurent Desnogues
  2009-10-17 19:57 ` [Qemu-devel] " Edgar E. Iglesias
  0 siblings, 2 replies; 20+ messages in thread
From: Laurent Desnogues @ 2009-07-11 15:14 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 495 bytes --]

Hello,

the attached patch implements two of the three x86_64 vsyscall's.
Also attached is a test that demonstrates the issue and hopefully
the fix.

Note there is a trick in there:  since vsyscall functions are in high
memory, page_l1_map will return NULL resulting in an abort when
calling tb_link_phys in tb_gen_code.  Also perhaps not very nice
is the way a ret is simulated in cpu_loop.

I didn't implement vgetcpu.


Laurent

Signed-off-by: Laurent Desnogues <laurent.desnogues@gmail.com>

[-- Attachment #2: vsyscall.patch --]
[-- Type: application/octet-stream, Size: 6006 bytes --]

diff --git a/exec.c b/exec.c
index d6e5d3c..8b8bea5 100644
--- a/exec.c
+++ b/exec.c
@@ -41,6 +41,9 @@
 #include "kvm.h"
 #if defined(CONFIG_USER_ONLY)
 #include <qemu.h>
+#ifdef TARGET_X86_64
+#include "vsyscall.h"
+#endif
 #endif
 
 //#define DEBUG_TB_INVALIDATE
@@ -908,6 +911,13 @@ TranslationBlock *tb_gen_code(CPUState *env,
     cpu_gen_code(env, tb, &code_gen_size);
     code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
 
+#if defined(CONFIG_USER_ONLY) && defined(TARGET_X86_64)
+    /* if we are doing vsyscall don't link the page as it lies in high memory
+       and tb_alloc_page will abort due to page_l1_map returning NULL */
+    if (unlikely(phys_pc >= TARGET_VSYSCALL_START
+                 && phys_pc < TARGET_VSYSCALL_END))
+        return tb;
+#endif
     /* check next page if needed */
     virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
     phys_page2 = -1;
diff --git a/linux-user/main.c b/linux-user/main.c
index e331d65..761f1cc 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -30,6 +30,9 @@
 #include "qemu.h"
 #include "qemu-common.h"
 #include "cache-utils.h"
+#if defined(CONFIG_USER_ONLY) && defined(TARGET_X86_64)
+#include "vsyscall.h"
+#endif
 /* For tb_lock */
 #include "exec-all.h"
 
@@ -327,6 +330,9 @@ void cpu_loop(CPUX86State *env)
     int trapnr;
     abi_ulong pc;
     target_siginfo_t info;
+#ifdef TARGET_X86_64
+    int syscall_num;
+#endif
 
     for(;;) {
         trapnr = cpu_x86_exec(env);
@@ -356,6 +362,37 @@ void cpu_loop(CPUX86State *env)
             env->eip = env->exception_next_eip;
             break;
 #endif
+#ifdef TARGET_X86_64
+        case EXCP_VSYSCALL:
+            switch (env->eip) {
+            case TARGET_VSYSCALL_ADDR(__NR_vgettimeofday):
+                syscall_num = __NR_gettimeofday;
+                break;
+            case TARGET_VSYSCALL_ADDR(__NR_vtime):
+                syscall_num = __NR_time;
+                break;
+            case TARGET_VSYSCALL_ADDR(__NR_vgetcpu):
+                /* XXX: not yet implemented */
+                cpu_abort(env, "Unimplemented vsyscall vgetcpu");
+                break;
+            default:
+                cpu_abort(env,
+                          "Invalid vsyscall to address " TARGET_FMT_lx "\n",
+                          env->eip);
+            }
+            env->regs[R_EAX] = do_syscall(env,
+                                          syscall_num,
+                                          env->regs[R_EDI],
+                                          env->regs[R_ESI],
+                                          env->regs[R_EDX],
+                                          env->regs[10],
+                                          env->regs[8],
+                                          env->regs[9]);
+            /* simulate a ret */
+            env->eip = ldq(env->regs[R_ESP]);
+            env->regs[R_ESP] += 8;
+            break;
+#endif
         case EXCP0B_NOSEG:
         case EXCP0C_STACK:
             info.si_signo = SIGBUS;
diff --git a/linux-user/x86_64/vsyscall.h b/linux-user/x86_64/vsyscall.h
new file mode 100644
index 0000000..11dcc07
--- /dev/null
+++ b/linux-user/x86_64/vsyscall.h
@@ -0,0 +1,19 @@
+#ifndef VSYSCALL_H
+#define VSYSCALL_H
+
+/* This is based on asm/syscall.h in kernel 2.6.29. */
+
+enum vsyscall_num {
+    __NR_vgettimeofday,
+    __NR_vtime,
+    __NR_vgetcpu,
+};
+
+#define TARGET_VSYSCALL_START (-10UL << 20)
+#define TARGET_VSYSCALL_SIZE 1024
+#define TARGET_VSYSCALL_END (-2UL << 20)
+#define TARGET_VSYSCALL_MAPPED_PAGES 1
+#define TARGET_VSYSCALL_ADDR(vsyscall_nr) \
+    (TARGET_VSYSCALL_START+TARGET_VSYSCALL_SIZE*(vsyscall_nr))
+
+#endif /* !VSYSCALL_H */
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 6f7478a..a4281ae 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -437,6 +437,8 @@
 
 #define EXCP_SYSCALL    0x100 /* only happens in user only emulation
                                  for syscall instruction */
+#define EXCP_VSYSCALL   0x101 /* only happens in user only emulation
+                                 on x86_64 */
 
 enum {
     CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
diff --git a/target-i386/helper.h b/target-i386/helper.h
index 68d57b1..3d39d7b 100644
--- a/target-i386/helper.h
+++ b/target-i386/helper.h
@@ -57,6 +57,7 @@ DEF_HELPER_1(sysexit, void, int)
 #ifdef TARGET_X86_64
 DEF_HELPER_1(syscall, void, int)
 DEF_HELPER_1(sysret, void, int)
+DEF_HELPER_0(vsyscall, void)
 #endif
 DEF_HELPER_1(hlt, void, int)
 DEF_HELPER_1(monitor, void, tl)
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index ed22c7a..6b558bf 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -1004,6 +1004,12 @@ void helper_syscall(int next_eip_addend)
     env->exception_next_eip = env->eip + next_eip_addend;
     cpu_loop_exit();
 }
+
+void helper_vsyscall(void)
+{
+    env->exception_index = EXCP_VSYSCALL;
+    cpu_loop_exit();
+}
 #else
 void helper_syscall(int next_eip_addend)
 {
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 4726009..d6daef4 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -33,6 +33,10 @@
 #define GEN_HELPER 1
 #include "helper.h"
 
+#if defined(CONFIG_USER_ONLY) && defined(TARGET_X86_64)
+#include "vsyscall.h"
+#endif
+
 #define PREFIX_REPZ   0x01
 #define PREFIX_REPNZ  0x02
 #define PREFIX_LOCK   0x04
@@ -7688,6 +7692,15 @@ static inline void gen_intermediate_code_internal(CPUState *env,
 
     gen_icount_start();
     for(;;) {
+#if defined(CONFIG_USER_ONLY) && defined(TARGET_X86_64)
+        /* Detect vsyscall's */
+        if (unlikely(pc_ptr >= TARGET_VSYSCALL_START
+                     && pc_ptr < TARGET_VSYSCALL_END)) {
+            gen_helper_vsyscall();
+            break;
+        }
+#endif
+
         if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
             TAILQ_FOREACH(bp, &env->breakpoints, entry) {
                 if (bp->pc == pc_ptr &&

[-- Attachment #3: check-vsyscall.c --]
[-- Type: text/x-csrc, Size: 1877 bytes --]

#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>

static void print_tod(const struct timeval *tv, const struct timezone *tz)
{
  if (tv)
    printf(" tv=%10ld.%06ld us",
	   tv->tv_sec, tv->tv_usec);
  else
    fputs(" (tv null)", stdout);
  if (tz)
    printf(" tz=%d/%d",
	   tz->tz_minuteswest, tz->tz_dsttime);
  else
    fputs(" (tz null)", stdout);
  fputc('\n', stdout);
}

static time_t t1, t2;
static struct timeval tv1, tv2;
static struct timezone tz1, tz2;

int main(void)
{
  int ret;

  fputs("Checking vtime with NULL param\n", stdout);
  t1 = time(NULL);
  printf("  %ld\n", t1);
  sleep(1);
  t2 = time(NULL);
  printf("  %ld (should be t1 + 1)\n", t2);

  fputs("Checking vtime with non NULL param\n", stdout);
  time(&t1);
  printf("  %ld\n", t1);
  sleep(1);
  time(&t2);
  printf("  %ld (should be t1 + 1)\n", t2);
  fputc('\n', stdout);


  fputs("Checking gettimeofday\n", stdout);
  ret = gettimeofday(&tv1, &tz1);
  printf("  ret=%d", ret);
  print_tod(&tv1, &tz1);
  sleep(1);
  ret = gettimeofday(&tv2, &tz2);
  printf("  ret=%d", ret);
  print_tod(&tv2, &tz2);

  fputs("Checking gettimeofday (tv NULL)\n", stdout);
  ret = gettimeofday(NULL, &tz1);
  printf("  ret=%d", ret);
  print_tod(NULL, &tz1);
  sleep(1);
  ret = gettimeofday(NULL, &tz2);
  printf("  ret=%d", ret);
  print_tod(NULL, &tz2);

  fputs("Checking gettimeofday (tz NULL)\n", stdout);
  ret = gettimeofday(&tv1, NULL);
  printf("  ret=%d", ret);
  print_tod(&tv1, NULL);
  sleep(1);
  ret = gettimeofday(&tv2, NULL);
  printf("  ret=%d", ret);
  print_tod(&tv2, NULL);

  fputs("Checking gettimeofday (tv and tz NULL)\n", stdout);
  ret = gettimeofday(NULL, NULL);
  printf("  ret=%d", ret);
  print_tod(NULL, NULL);
  sleep(1);
  ret = gettimeofday(NULL, NULL);
  printf("  ret=%d", ret);
  print_tod(NULL, NULL);

  return 0;
}

^ permalink raw reply related	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2010-02-08 14:58 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-07-11 15:14 [Qemu-devel] [PATCH] User mode: Handle x86_64 vsyscall Laurent Desnogues
2009-10-17 15:42 ` [Qemu-devel] " Laurent Desnogues
2009-10-17 19:57 ` [Qemu-devel] " Edgar E. Iglesias
2009-10-18  0:16   ` Laurent Desnogues
2009-10-18  2:47     ` Jamie Lokier
2009-10-18 11:23       ` Laurent Desnogues
2009-10-18  3:09   ` Jamie Lokier
2009-10-18  7:17     ` Edgar E. Iglesias
2009-10-18 11:29     ` Laurent Desnogues
2010-02-04 22:15       ` Stefan Weil
2010-02-05 22:57       ` Stefan Weil
2010-02-06  1:37         ` Laurent Desnogues
2010-02-06  7:49           ` Stefan Weil
2010-02-06 23:50             ` Laurent Desnogues
2010-02-07  0:22               ` Jamie Lokier
2010-02-07  3:11                 ` malc
2010-02-07 10:06                 ` Laurent Desnogues
2010-02-07 23:18               ` Richard Henderson
2010-02-08 14:57                 ` Vince Weaver
2010-02-06 20:12         ` Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).