From patchwork Thu Sep 22 15:06:29 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aleksandar Markovic X-Patchwork-Id: 9345615 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 40588607D0 for ; Thu, 22 Sep 2016 15:35:36 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2E7C12AB0C for ; Thu, 22 Sep 2016 15:35:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 20CD32AB19; Thu, 22 Sep 2016 15:35:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id C21CA2AB0C for ; Thu, 22 Sep 2016 15:35:34 +0000 (UTC) Received: from localhost ([::1]:50855 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bn629-0003Hc-WD for patchwork-qemu-devel@patchwork.kernel.org; Thu, 22 Sep 2016 11:35:34 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50184) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bn5bI-000833-0s for qemu-devel@nongnu.org; Thu, 22 Sep 2016 11:07:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bn5bG-0004KI-48 for qemu-devel@nongnu.org; Thu, 22 Sep 2016 11:07:47 -0400 Received: from mx2.rt-rk.com ([89.216.37.149]:46179 helo=mail.rt-rk.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bn5bF-0004KB-Ox for qemu-devel@nongnu.org; Thu, 22 Sep 2016 11:07:46 -0400 Received: from localhost (localhost [127.0.0.1]) by mail.rt-rk.com (Postfix) with ESMTP id 0A0B21A463B; Thu, 22 Sep 2016 17:07:45 +0200 (CEST) X-Virus-Scanned: amavisd-new at rt-rk.com Received: from mcs19.domain.local (mcs19.domain.local [10.10.13.51]) by mail.rt-rk.com (Postfix) with ESMTPSA id A9B871A4618; Thu, 22 Sep 2016 17:07:44 +0200 (CEST) From: Aleksandar Markovic To: qemu-devel@nongnu.org, riku.voipio@iki.fi, laurent@vivier.eu, peter.maydell@linaro.org, petar.jovanovic@imgtec.com, miodrag.dinic@imgtec.com, aleksandar.rikalo@imgtec.com, aleksandar.markovic@imgtec.com Date: Thu, 22 Sep 2016 17:06:29 +0200 Message-Id: <20160922150646.78163-2-aleksandar.markovic@rt-rk.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20160922150646.78163-1-aleksandar.markovic@rt-rk.com> References: <20160922150646.78163-1-aleksandar.markovic@rt-rk.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 89.216.37.149 Subject: [Qemu-devel] [PATCH v6 01/10] linux-user: Add support for adjtimex() syscall X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Aleksandar Markovic This patch implements Qemu user mode adjtimex() syscall support. Syscall adjtimex() reads and optionally sets parameters for a clock adjustment algorithm used in network synchonization or similar scenarios. Its declaration is: int adjtimex(struct timex *buf); The correspondent source code in the Linux kernel is at kernel/time.c, line 206. The Qemu implementation is based on invocation of host's adjtimex(), and its key part is in the "TARGET_NR_adjtimex" case segment of the the main switch statement of the function do_syscall(), in linux-user/syscalls.c. All necessary conversions of the data structures from target to host and from host to target are covered. Two new functions, target_to_host_timex() and host_to_target_timex(), are provided for the purpose of such conversions. For that purpose, the support for related structure "timex" had tp be added to the file linux-user/syscall_defs.h, based on its definition in Linux kernel. Also, the relevant support for "-strace" Qemu option is included in files linux-user/strace.c and linux-user/strace.list. This patch also fixes failures of LTP tests adjtimex01 and adjtimex02, if executed in Qemu user mode. Signed-off-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic --- linux-user/strace.c | 46 +++++++++++++++++++++++++ linux-user/strace.list | 3 +- linux-user/syscall.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++- linux-user/syscall_defs.h | 28 +++++++++++++++ 4 files changed, 162 insertions(+), 2 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index cc10dc4..ff7fce9 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -483,6 +483,52 @@ print_syscall_ret_newselect(const struct syscallname *name, abi_long ret) } #endif +/* special meanings of adjtimex()' non-negative return values */ +#define TARGET_TIME_OK 0 /* clock synchronized, no leap second */ +#define TARGET_TIME_INS 1 /* insert leap second */ +#define TARGET_TIME_DEL 2 /* delete leap second */ +#define TARGET_TIME_OOP 3 /* leap second in progress */ +#define TARGET_TIME_WAIT 4 /* leap second has occurred */ +#define TARGET_TIME_ERROR 5 /* clock not synchronized */ +static void +print_syscall_ret_adjtimex(const struct syscallname *name, abi_long ret) +{ + const char *errstr = NULL; + + gemu_log(" = "); + if (ret < 0) { + gemu_log("-1 errno=%d", errno); + errstr = target_strerror(-ret); + if (errstr) { + gemu_log(" (%s)", errstr); + } + } else { + gemu_log(TARGET_ABI_FMT_ld, ret); + switch (ret) { + case TARGET_TIME_OK: + gemu_log(" TIME_OK (clock synchronized, no leap second)"); + break; + case TARGET_TIME_INS: + gemu_log(" TIME_INS (insert leap second)"); + break; + case TARGET_TIME_DEL: + gemu_log(" TIME_DEL (delete leap second)"); + break; + case TARGET_TIME_OOP: + gemu_log(" TIME_OOP (leap second in progress)"); + break; + case TARGET_TIME_WAIT: + gemu_log(" TIME_WAIT (leap second has occurred)"); + break; + case TARGET_TIME_ERROR: + gemu_log(" TIME_ERROR (clock not synchronized)"); + break; + } + } + + gemu_log("\n"); +} + UNUSED static struct flags access_flags[] = { FLAG_GENERIC(F_OK), FLAG_GENERIC(R_OK), diff --git a/linux-user/strace.list b/linux-user/strace.list index aa967a2..44e8322 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -16,7 +16,8 @@ { TARGET_NR_add_key, "add_key" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_adjtimex -{ TARGET_NR_adjtimex, "adjtimex" , NULL, NULL, NULL }, +{ TARGET_NR_adjtimex, "adjtimex" , "%s(%p)", NULL, + print_syscall_ret_adjtimex }, #endif #ifdef TARGET_NR_afs_syscall { TARGET_NR_afs_syscall, "afs_syscall" , NULL, NULL, NULL }, diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ca06943..d3fbaec 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef __ia64__ int __clone2(int (*fn)(void *), void *child_stack_base, size_t stack_size, int flags, void *arg, ...); @@ -6643,6 +6644,77 @@ static inline abi_long host_to_target_itimerspec(abi_ulong target_addr, return 0; } +static inline abi_long target_to_host_timex(struct timex *host_tx, + abi_long target_addr) +{ + struct target_timex *target_tx; + + if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) { + return -TARGET_EFAULT; + } + + __get_user(host_tx->modes, &target_tx->modes); + __get_user(host_tx->offset, &target_tx->offset); + __get_user(host_tx->freq, &target_tx->freq); + __get_user(host_tx->maxerror, &target_tx->maxerror); + __get_user(host_tx->esterror, &target_tx->esterror); + __get_user(host_tx->status, &target_tx->status); + __get_user(host_tx->constant, &target_tx->constant); + __get_user(host_tx->precision, &target_tx->precision); + __get_user(host_tx->tolerance, &target_tx->tolerance); + __get_user(host_tx->time.tv_sec, &target_tx->time.tv_sec); + __get_user(host_tx->time.tv_usec, &target_tx->time.tv_usec); + __get_user(host_tx->tick, &target_tx->tick); + __get_user(host_tx->ppsfreq, &target_tx->ppsfreq); + __get_user(host_tx->jitter, &target_tx->jitter); + __get_user(host_tx->shift, &target_tx->shift); + __get_user(host_tx->stabil, &target_tx->stabil); + __get_user(host_tx->jitcnt, &target_tx->jitcnt); + __get_user(host_tx->calcnt, &target_tx->calcnt); + __get_user(host_tx->errcnt, &target_tx->errcnt); + __get_user(host_tx->stbcnt, &target_tx->stbcnt); + __get_user(host_tx->tai, &target_tx->tai); + + unlock_user_struct(target_tx, target_addr, 0); + return 0; +} + +static inline abi_long host_to_target_timex(abi_long target_addr, + struct timex *host_tx) +{ + struct target_timex *target_tx; + + if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) { + return -TARGET_EFAULT; + } + + __put_user(host_tx->modes, &target_tx->modes); + __put_user(host_tx->offset, &target_tx->offset); + __put_user(host_tx->freq, &target_tx->freq); + __put_user(host_tx->maxerror, &target_tx->maxerror); + __put_user(host_tx->esterror, &target_tx->esterror); + __put_user(host_tx->status, &target_tx->status); + __put_user(host_tx->constant, &target_tx->constant); + __put_user(host_tx->precision, &target_tx->precision); + __put_user(host_tx->tolerance, &target_tx->tolerance); + __put_user(host_tx->time.tv_sec, &target_tx->time.tv_sec); + __put_user(host_tx->time.tv_usec, &target_tx->time.tv_usec); + __put_user(host_tx->tick, &target_tx->tick); + __put_user(host_tx->ppsfreq, &target_tx->ppsfreq); + __put_user(host_tx->jitter, &target_tx->jitter); + __put_user(host_tx->shift, &target_tx->shift); + __put_user(host_tx->stabil, &target_tx->stabil); + __put_user(host_tx->jitcnt, &target_tx->jitcnt); + __put_user(host_tx->calcnt, &target_tx->calcnt); + __put_user(host_tx->errcnt, &target_tx->errcnt); + __put_user(host_tx->stbcnt, &target_tx->stbcnt); + __put_user(host_tx->tai, &target_tx->tai); + + unlock_user_struct(target_tx, target_addr, 1); + return 0; +} + + static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp, abi_ulong target_addr) { @@ -9420,7 +9492,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #endif case TARGET_NR_adjtimex: - goto unimplemented; + { + struct timex host_buf; + + if (target_to_host_timex(&host_buf, arg1) != 0) { + goto efault; + } + ret = get_errno(adjtimex(&host_buf)); + if (!is_error(ret)) { + if (host_to_target_timex(arg1, &host_buf) != 0) { + goto efault; + } + } + } + break; #ifdef TARGET_NR_create_module case TARGET_NR_create_module: #endif diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index c0c9b58..4cb66ff 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -207,6 +207,34 @@ struct target_itimerspec { struct target_timespec it_value; }; +struct target_timex { + abi_uint modes; /* Mode selector */ + abi_long offset; /* Time offset */ + abi_long freq; /* Frequency offset */ + abi_long maxerror; /* Maximum error (microseconds) */ + abi_long esterror; /* Estimated error (microseconds) */ + abi_int status; /* Clock command/status */ + abi_long constant; /* PLL (phase-locked loop) time constant */ + abi_long precision; /* Clock precision (microseconds, ro) */ + abi_long tolerance; /* Clock freq. tolerance (ppm, ro) */ + struct target_timeval time; /* Current time */ + abi_long tick; /* Microseconds between clock ticks */ + abi_long ppsfreq; /* PPS (pulse per second) frequency */ + abi_long jitter; /* PPS jitter (ro); nanoseconds */ + abi_int shift; /* PPS interval duration (seconds) */ + abi_long stabil; /* PPS stability */ + abi_long jitcnt; /* PPS jitter limit exceeded (ro) */ + abi_long calcnt; /* PPS calibration intervals */ + abi_long errcnt; /* PPS calibration errors */ + abi_long stbcnt; /* PPS stability limit exceeded */ + abi_int tai; /* TAI offset */ + + /* Further padding bytes to allow for future expansion */ + abi_int:32; abi_int:32; abi_int:32; abi_int:32; + abi_int:32; abi_int:32; abi_int:32; abi_int:32; + abi_int:32; abi_int:32; abi_int:32; +}; + typedef abi_long target_clock_t; #define TARGET_HZ 100