From: Laurent Desnogues <laurent.desnogues@gmail.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] User mode: Handle x86_64 vsyscall
Date: Sat, 11 Jul 2009 17:14:47 +0200 [thread overview]
Message-ID: <761ea48b0907110814t12c644b6mf733d3b5e28e152@mail.gmail.com> (raw)
[-- 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;
}
next reply other threads:[~2009-07-11 15:14 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-07-11 15:14 Laurent Desnogues [this message]
2009-10-17 15:42 ` [Qemu-devel] Re: [PATCH] User mode: Handle x86_64 vsyscall 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=761ea48b0907110814t12c644b6mf733d3b5e28e152@mail.gmail.com \
--to=laurent.desnogues@gmail.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).