From patchwork Tue Jan 24 10:10:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 9534933 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 1DA196042D for ; Tue, 24 Jan 2017 11:04:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0E56023F88 for ; Tue, 24 Jan 2017 11:04:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0336426D05; Tue, 24 Jan 2017 11:04:52 +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.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID 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 619D323F88 for ; Tue, 24 Jan 2017 11:04:50 +0000 (UTC) Received: from localhost ([::1]:47729 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cVyu9-0004I4-8P for patchwork-qemu-devel@patchwork.kernel.org; Tue, 24 Jan 2017 06:04:49 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49638) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cVy3U-00078h-QF for qemu-devel@nongnu.org; Tue, 24 Jan 2017 05:10:29 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cVy3Q-0001e2-1x for qemu-devel@nongnu.org; Tue, 24 Jan 2017 05:10:24 -0500 Received: from mail-yb0-x243.google.com ([2607:f8b0:4002:c09::243]:36126) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cVy3P-0001dx-Pe for qemu-devel@nongnu.org; Tue, 24 Jan 2017 05:10:19 -0500 Received: by mail-yb0-x243.google.com with SMTP id l23so12876445ybj.3 for ; Tue, 24 Jan 2017 02:10:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to; bh=pVyhXLb8qs7U3bz5Fsvv8J+rKRpvzzBYyhA4LWJwsAM=; b=Tjl7iV4DGd6NUbmL3SZLtU0s1haLTZIpe2ClWbqbCPnGCA1MS++Eh4LB6GvcxnKAUH uSH7xjwm0phv9kV1ey15syhR/PL8lU1GH7kFWoRMQuFit5GO2no9sBnz0i3RpDo7FHeY JQrw52yYZ2SNJhqEfzAz5inJXu6RrAcyyg5TAMTF7puMU/4tfJ5U9KlIzbRRhFP1XuWR DousXRMI/BoncQsOWttSX8izeQeVzamfjbeB45jtIPxuURb+aRupuLFF6dIUqLoNAWqj +rttUlZ5cZy/n3IzB7dmb170tTWj3Zw8rWqafk2g8roYszUZ59mKry9NrDFCxazro7Al HoMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to; bh=pVyhXLb8qs7U3bz5Fsvv8J+rKRpvzzBYyhA4LWJwsAM=; b=jP/mmilstulmznsR7uDWOT/0VZrB+eMi2iBWusVmHksTjUEyLrbZvrmYYtmSCG0BYB dBEWCtjJ2net5O7tZ9088XhDR5fb4K08V2zk56E4izNnHTghVH2PDG+tdhSBNJ8XTR4J LR0OQe2Duy8BQ6p1Ck+hpgS/4QwSdCBdK50E2lN8asHqwlIIv/muiw/LjuzUDZTCJzY3 N/QdpU4yws239SlQzdpTyXP4QVXVRe4gSkALMlPtaQVfyJZ97d1SQNb4o76P/7Ek9d2e Yj5gF59TdHehv3tDFEmbewtpxE+3Tf7hHOGOQZHDsON82tSVA3gkXVqoIJStRK5Nu+xp l5vw== X-Gm-Message-State: AIkVDXLscJ0JfZ0TpNmoL9mXMgtO21yCHSw2t0vjgOSCBzfSVYlbtz8jCkTnEtDzldpXLuQX3ehZq+SFSchl7w== X-Received: by 10.37.74.2 with SMTP id x2mr24977612yba.76.1485252619083; Tue, 24 Jan 2017 02:10:19 -0800 (PST) MIME-Version: 1.0 References: <20170121084600.5860-1-ale+qemu@clearmind.me> <20170121084600.5860-2-ale+qemu@clearmind.me> In-Reply-To: <20170121084600.5860-2-ale+qemu@clearmind.me> From: =?UTF-8?B?TWFyYy1BbmRyw6kgTHVyZWF1?= Date: Tue, 24 Jan 2017 10:10:08 +0000 Message-ID: To: Alessandro Di Federico , qemu-devel@nongnu.org X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4002:c09::243 X-Content-Filtered-By: Mailman/MimeDel 2.1.21 Subject: Re: [Qemu-devel] [RFC PATCH 1/3] Factor out {linux, bsd}-user/qemu.h 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 Hi On Sat, Jan 21, 2017 at 12:46 PM Alessandro Di Federico < ale+qemu@clearmind.me> wrote: A quite large part of {linux,bsd}-user/qemu.h is shared, this patch introduces qemu-user-common.h which factors it out. This shared part is also the bare minimum required to build a linux-user-like target, and, in particular, it will be useful for the libtcg targets. Looks good. Probably worth to mention that the main difference is in commit 658f2dc970996d547a641b5685e384ebe6f2648e not being applied to bsd-user. --- bsd-user/qemu.h | 193 +---------------------------------------------------- linux-user/qemu.h | 176 +----------------------------------------------- qemu-user-common.h | 180 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+), 367 deletions(-) create mode 100644 qemu-user-common.h + if (len < 0) + return NULL; + return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1); +} + +/* Helper macros for locking/unlocking a target struct. */ +#define lock_user_struct(type, host_ptr, guest_addr, copy) \ + (host_ptr = lock_user(type, guest_addr, sizeof(*host_ptr), copy)) +#define unlock_user_struct(host_ptr, guest_addr, copy) \ + unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) + +#endif /* QEMU_USER_COMMON_H */ -- 2.11.0 diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 2b2b9184e0..b51319caf0 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -17,10 +17,8 @@ #ifndef QEMU_H #define QEMU_H - -#include "cpu.h" +#include "qemu-user-common.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" #undef DEBUG_REMAP #ifdef DEBUG_REMAP @@ -217,195 +215,6 @@ void mmap_fork_end(int child); /* main.c */ extern unsigned long x86_stack_size; -/* user access */ - -#define VERIFY_READ 0 -#define VERIFY_WRITE 1 /* implies read access */ - -static inline int access_ok(int type, abi_ulong addr, abi_ulong size) -{ - return page_check_range((target_ulong)addr, size, - (type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0; -} - -/* NOTE __get_user and __put_user use host pointers and don't check access. */ -/* These are usually used to access struct data members once the - * struct has been locked - usually with lock_user_struct(). - */ -#define __put_user(x, hptr)\ -({\ - int size = sizeof(*hptr);\ - switch(size) {\ - case 1:\ - *(uint8_t *)(hptr) = (uint8_t)(typeof(*hptr))(x);\ - break;\ - case 2:\ - *(uint16_t *)(hptr) = tswap16((typeof(*hptr))(x));\ - break;\ - case 4:\ - *(uint32_t *)(hptr) = tswap32((typeof(*hptr))(x));\ - break;\ - case 8:\ - *(uint64_t *)(hptr) = tswap64((typeof(*hptr))(x));\ - break;\ - default:\ - abort();\ - }\ - 0;\ -}) - -#define __get_user(x, hptr) \ -({\ - int size = sizeof(*hptr);\ - switch(size) {\ - case 1:\ - x = (typeof(*hptr))*(uint8_t *)(hptr);\ - break;\ - case 2:\ - x = (typeof(*hptr))tswap16(*(uint16_t *)(hptr));\ - break;\ - case 4:\ - x = (typeof(*hptr))tswap32(*(uint32_t *)(hptr));\ - break;\ - case 8:\ - x = (typeof(*hptr))tswap64(*(uint64_t *)(hptr));\ - break;\ - default:\ - /* avoid warning */\ - x = 0;\ - abort();\ - }\ - 0;\ -}) - -/* put_user()/get_user() take a guest address and check access */ -/* These are usually used to access an atomic data type, such as an int, - * that has been passed by address. These internally perform locking - * and unlocking on the data type. - */ -#define put_user(x, gaddr, target_type) \ -({ \ - abi_ulong __gaddr = (gaddr); \ - target_type *__hptr; \ - abi_long __ret; \ - if ((__hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0))) { \ - __ret = __put_user((x), __hptr); \ - unlock_user(__hptr, __gaddr, sizeof(target_type)); \ - } else \ - __ret = -TARGET_EFAULT; \ - __ret; \ -}) - -#define get_user(x, gaddr, target_type) \ -({ \ - abi_ulong __gaddr = (gaddr); \ - target_type *__hptr; \ - abi_long __ret; \ - if ((__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1))) { \ - __ret = __get_user((x), __hptr); \ - unlock_user(__hptr, __gaddr, 0); \ - } else { \ - /* avoid warning */ \ - (x) = 0; \ - __ret = -TARGET_EFAULT; \ - } \ - __ret; \ -}) - -#define put_user_ual(x, gaddr) put_user((x), (gaddr), abi_ulong) -#define put_user_sal(x, gaddr) put_user((x), (gaddr), abi_long) -#define put_user_u64(x, gaddr) put_user((x), (gaddr), uint64_t) -#define put_user_s64(x, gaddr) put_user((x), (gaddr), int64_t) -#define put_user_u32(x, gaddr) put_user((x), (gaddr), uint32_t) -#define put_user_s32(x, gaddr) put_user((x), (gaddr), int32_t) -#define put_user_u16(x, gaddr) put_user((x), (gaddr), uint16_t) -#define put_user_s16(x, gaddr) put_user((x), (gaddr), int16_t) -#define put_user_u8(x, gaddr) put_user((x), (gaddr), uint8_t) -#define put_user_s8(x, gaddr) put_user((x), (gaddr), int8_t) - -#define get_user_ual(x, gaddr) get_user((x), (gaddr), abi_ulong) -#define get_user_sal(x, gaddr) get_user((x), (gaddr), abi_long) -#define get_user_u64(x, gaddr) get_user((x), (gaddr), uint64_t) -#define get_user_s64(x, gaddr) get_user((x), (gaddr), int64_t) -#define get_user_u32(x, gaddr) get_user((x), (gaddr), uint32_t) -#define get_user_s32(x, gaddr) get_user((x), (gaddr), int32_t) -#define get_user_u16(x, gaddr) get_user((x), (gaddr), uint16_t) -#define get_user_s16(x, gaddr) get_user((x), (gaddr), int16_t) -#define get_user_u8(x, gaddr) get_user((x), (gaddr), uint8_t) -#define get_user_s8(x, gaddr) get_user((x), (gaddr), int8_t) - -/* copy_from_user() and copy_to_user() are usually used to copy data - * buffers between the target and host. These internally perform - * locking/unlocking of the memory. - */ -abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len); -abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len); - -/* Functions for accessing guest memory. The tget and tput functions - read/write single values, byteswapping as necessary. The lock_user function - gets a pointer to a contiguous area of guest memory, but does not perform - any byteswapping. lock_user may return either a pointer to the guest - memory, or a temporary buffer. */ - -/* Lock an area of guest memory into the host. If copy is true then the - host area will have the same contents as the guest. */ -static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy) -{ - if (!access_ok(type, guest_addr, len)) - return NULL; -#ifdef DEBUG_REMAP - { - void *addr; - addr = g_malloc(len); - if (copy) - memcpy(addr, g2h(guest_addr), len); - else - memset(addr, 0, len); - return addr; - } -#else - return g2h(guest_addr); -#endif -} - -/* Unlock an area of guest memory. The first LEN bytes must be - flushed back to guest memory. host_ptr = NULL is explicitly - allowed and does nothing. */ -static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, - long len) -{ - -#ifdef DEBUG_REMAP - if (!host_ptr) - return; - if (host_ptr == g2h(guest_addr)) - return; - if (len > 0) - memcpy(g2h(guest_addr), host_ptr, len); - g_free(host_ptr); -#endif -} - -/* Return the length of a string in target memory or -TARGET_EFAULT if - access error. */ -abi_long target_strlen(abi_ulong gaddr); - -/* Like lock_user but for null terminated strings. */ -static inline void *lock_user_string(abi_ulong guest_addr) -{ - abi_long len; - len = target_strlen(guest_addr); - if (len < 0) - return NULL; - return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1); -} - -/* Helper macros for locking/unlocking a target struct. */ -#define lock_user_struct(type, host_ptr, guest_addr, copy) \ - (host_ptr = lock_user(type, guest_addr, sizeof(*host_ptr), copy)) -#define unlock_user_struct(host_ptr, guest_addr, copy) \ - unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) - #if defined(CONFIG_USE_NPTL) #include #endif diff --git a/linux-user/qemu.h b/linux-user/qemu.h index da73a01106..b56abb5942 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -2,9 +2,8 @@ #define QEMU_H #include "hostdep.h" -#include "cpu.h" +#include "qemu-user-common.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" #undef DEBUG_REMAP #ifdef DEBUG_REMAP @@ -436,179 +435,6 @@ void mmap_fork_end(int child); /* main.c */ extern unsigned long guest_stack_size; -/* user access */ - -#define VERIFY_READ 0 -#define VERIFY_WRITE 1 /* implies read access */ - -static inline int access_ok(int type, abi_ulong addr, abi_ulong size) -{ - return page_check_range((target_ulong)addr, size, - (type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0; -} - -/* NOTE __get_user and __put_user use host pointers and don't check access. - These are usually used to access struct data members once the struct has - been locked - usually with lock_user_struct. */ - -/* Tricky points: - - Use __builtin_choose_expr to avoid type promotion from ?:, - - Invalid sizes result in a compile time error stemming from - the fact that abort has no parameters. - - It's easier to use the endian-specific unaligned load/store - functions than host-endian unaligned load/store plus tswapN. */ - -#define __put_user_e(x, hptr, e) \ - (__builtin_choose_expr(sizeof(*(hptr)) == 1, stb_p, \ - __builtin_choose_expr(sizeof(*(hptr)) == 2, stw_##e##_p, \ - __builtin_choose_expr(sizeof(*(hptr)) == 4, stl_##e##_p, \ - __builtin_choose_expr(sizeof(*(hptr)) == 8, stq_##e##_p, abort)))) \ - ((hptr), (x)), (void)0) - -#define __get_user_e(x, hptr, e) \ - ((x) = (typeof(*hptr))( \ - __builtin_choose_expr(sizeof(*(hptr)) == 1, ldub_p, \ - __builtin_choose_expr(sizeof(*(hptr)) == 2, lduw_##e##_p, \ - __builtin_choose_expr(sizeof(*(hptr)) == 4, ldl_##e##_p, \ - __builtin_choose_expr(sizeof(*(hptr)) == 8, ldq_##e##_p, abort)))) \ - (hptr)), (void)0) - -#ifdef TARGET_WORDS_BIGENDIAN -# define __put_user(x, hptr) __put_user_e(x, hptr, be) -# define __get_user(x, hptr) __get_user_e(x, hptr, be) -#else -# define __put_user(x, hptr) __put_user_e(x, hptr, le) -# define __get_user(x, hptr) __get_user_e(x, hptr, le) -#endif - -/* put_user()/get_user() take a guest address and check access */ -/* These are usually used to access an atomic data type, such as an int, - * that has been passed by address. These internally perform locking - * and unlocking on the data type. - */ -#define put_user(x, gaddr, target_type) \ -({ \ - abi_ulong __gaddr = (gaddr); \ - target_type *__hptr; \ - abi_long __ret = 0; \ - if ((__hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0))) { \ - __put_user((x), __hptr); \ - unlock_user(__hptr, __gaddr, sizeof(target_type)); \ - } else \ - __ret = -TARGET_EFAULT; \ - __ret; \ -}) - -#define get_user(x, gaddr, target_type) \ -({ \ - abi_ulong __gaddr = (gaddr); \ - target_type *__hptr; \ - abi_long __ret = 0; \ - if ((__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1))) { \ - __get_user((x), __hptr); \ - unlock_user(__hptr, __gaddr, 0); \ - } else { \ - /* avoid warning */ \ - (x) = 0; \ - __ret = -TARGET_EFAULT; \ - } \ - __ret; \ -}) - -#define put_user_ual(x, gaddr) put_user((x), (gaddr), abi_ulong) -#define put_user_sal(x, gaddr) put_user((x), (gaddr), abi_long) -#define put_user_u64(x, gaddr) put_user((x), (gaddr), uint64_t) -#define put_user_s64(x, gaddr) put_user((x), (gaddr), int64_t) -#define put_user_u32(x, gaddr) put_user((x), (gaddr), uint32_t) -#define put_user_s32(x, gaddr) put_user((x), (gaddr), int32_t) -#define put_user_u16(x, gaddr) put_user((x), (gaddr), uint16_t) -#define put_user_s16(x, gaddr) put_user((x), (gaddr), int16_t) -#define put_user_u8(x, gaddr) put_user((x), (gaddr), uint8_t) -#define put_user_s8(x, gaddr) put_user((x), (gaddr), int8_t) - -#define get_user_ual(x, gaddr) get_user((x), (gaddr), abi_ulong) -#define get_user_sal(x, gaddr) get_user((x), (gaddr), abi_long) -#define get_user_u64(x, gaddr) get_user((x), (gaddr), uint64_t) -#define get_user_s64(x, gaddr) get_user((x), (gaddr), int64_t) -#define get_user_u32(x, gaddr) get_user((x), (gaddr), uint32_t) -#define get_user_s32(x, gaddr) get_user((x), (gaddr), int32_t) -#define get_user_u16(x, gaddr) get_user((x), (gaddr), uint16_t) -#define get_user_s16(x, gaddr) get_user((x), (gaddr), int16_t) -#define get_user_u8(x, gaddr) get_user((x), (gaddr), uint8_t) -#define get_user_s8(x, gaddr) get_user((x), (gaddr), int8_t) - -/* copy_from_user() and copy_to_user() are usually used to copy data - * buffers between the target and host. These internally perform - * locking/unlocking of the memory. - */ -abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len); -abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len); - -/* Functions for accessing guest memory. The tget and tput functions - read/write single values, byteswapping as necessary. The lock_user function - gets a pointer to a contiguous area of guest memory, but does not perform - any byteswapping. lock_user may return either a pointer to the guest - memory, or a temporary buffer. */ - -/* Lock an area of guest memory into the host. If copy is true then the - host area will have the same contents as the guest. */ -static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy) -{ - if (!access_ok(type, guest_addr, len)) - return NULL; -#ifdef DEBUG_REMAP - { - void *addr; - addr = g_malloc(len); - if (copy) - memcpy(addr, g2h(guest_addr), len); - else - memset(addr, 0, len); - return addr; - } -#else - return g2h(guest_addr); -#endif -} - -/* Unlock an area of guest memory. The first LEN bytes must be - flushed back to guest memory. host_ptr = NULL is explicitly - allowed and does nothing. */ -static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, - long len) -{ - -#ifdef DEBUG_REMAP - if (!host_ptr) - return; - if (host_ptr == g2h(guest_addr)) - return; - if (len > 0) - memcpy(g2h(guest_addr), host_ptr, len); - g_free(host_ptr); -#endif -} - -/* Return the length of a string in target memory or -TARGET_EFAULT if - access error. */ -abi_long target_strlen(abi_ulong gaddr); - -/* Like lock_user but for null terminated strings. */ -static inline void *lock_user_string(abi_ulong guest_addr) -{ - abi_long len; - len = target_strlen(guest_addr); - if (len < 0) - return NULL; - return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1); -} - -/* Helper macros for locking/unlocking a target struct. */ -#define lock_user_struct(type, host_ptr, guest_addr, copy) \ - (host_ptr = lock_user(type, guest_addr, sizeof(*host_ptr), copy)) -#define unlock_user_struct(host_ptr, guest_addr, copy) \ - unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) - #include /* Include target-specific struct and function definitions; diff --git a/qemu-user-common.h b/qemu-user-common.h new file mode 100644 index 0000000000..349dd72fff --- /dev/null +++ b/qemu-user-common.h @@ -0,0 +1,180 @@ +#ifndef QEMU_USER_COMMON_H +#define QEMU_USER_COMMON_H + +#include "cpu.h" +#include "exec/cpu_ldst.h" + +/* user access */ + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 /* implies read access */ + +static inline int access_ok(int type, abi_ulong addr, abi_ulong size) +{ + return page_check_range((target_ulong)addr, size, + (type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0; +} + +/* NOTE __get_user and __put_user use host pointers and don't check access. + These are usually used to access struct data members once the struct has + been locked - usually with lock_user_struct. */ + +/* Tricky points: + - Use __builtin_choose_expr to avoid type promotion from ?:, + - Invalid sizes result in a compile time error stemming from + the fact that abort has no parameters. + - It's easier to use the endian-specific unaligned load/store + functions than host-endian unaligned load/store plus tswapN. */ + +#define __put_user_e(x, hptr, e) \ + (__builtin_choose_expr(sizeof(*(hptr)) == 1, stb_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 2, stw_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 4, stl_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 8, stq_##e##_p, abort)))) \ + ((hptr), (x)), (void)0) + +#define __get_user_e(x, hptr, e) \ + ((x) = (typeof(*hptr))( \ + __builtin_choose_expr(sizeof(*(hptr)) == 1, ldub_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 2, lduw_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 4, ldl_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 8, ldq_##e##_p, abort)))) \ + (hptr)), (void)0) + +#ifdef TARGET_WORDS_BIGENDIAN +# define __put_user(x, hptr) __put_user_e(x, hptr, be) +# define __get_user(x, hptr) __get_user_e(x, hptr, be) +#else +# define __put_user(x, hptr) __put_user_e(x, hptr, le) +# define __get_user(x, hptr) __get_user_e(x, hptr, le) +#endif + +/* put_user()/get_user() take a guest address and check access */ +/* These are usually used to access an atomic data type, such as an int, + * that has been passed by address. These internally perform locking + * and unlocking on the data type. + */ +#define put_user(x, gaddr, target_type) \ +({ \ + abi_ulong __gaddr = (gaddr); \ + target_type *__hptr; \ + abi_long __ret = 0; \ + if ((__hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0))) { \ + __put_user((x), __hptr); \ + unlock_user(__hptr, __gaddr, sizeof(target_type)); \ + } else \ + __ret = -TARGET_EFAULT; \ + __ret; \ +}) + +#define get_user(x, gaddr, target_type) \ +({ \ + abi_ulong __gaddr = (gaddr); \ + target_type *__hptr; \ + abi_long __ret = 0; \ + if ((__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1))) { \ + __get_user((x), __hptr); \ + unlock_user(__hptr, __gaddr, 0); \ + } else { \ + /* avoid warning */ \ + (x) = 0; \ + __ret = -TARGET_EFAULT; \ + } \ + __ret; \ +}) + +#define put_user_ual(x, gaddr) put_user((x), (gaddr), abi_ulong) +#define put_user_sal(x, gaddr) put_user((x), (gaddr), abi_long) +#define put_user_u64(x, gaddr) put_user((x), (gaddr), uint64_t) +#define put_user_s64(x, gaddr) put_user((x), (gaddr), int64_t) +#define put_user_u32(x, gaddr) put_user((x), (gaddr), uint32_t) +#define put_user_s32(x, gaddr) put_user((x), (gaddr), int32_t) +#define put_user_u16(x, gaddr) put_user((x), (gaddr), uint16_t) +#define put_user_s16(x, gaddr) put_user((x), (gaddr), int16_t) +#define put_user_u8(x, gaddr) put_user((x), (gaddr), uint8_t) +#define put_user_s8(x, gaddr) put_user((x), (gaddr), int8_t) + +#define get_user_ual(x, gaddr) get_user((x), (gaddr), abi_ulong) +#define get_user_sal(x, gaddr) get_user((x), (gaddr), abi_long) +#define get_user_u64(x, gaddr) get_user((x), (gaddr), uint64_t) +#define get_user_s64(x, gaddr) get_user((x), (gaddr), int64_t) +#define get_user_u32(x, gaddr) get_user((x), (gaddr), uint32_t) +#define get_user_s32(x, gaddr) get_user((x), (gaddr), int32_t) +#define get_user_u16(x, gaddr) get_user((x), (gaddr), uint16_t) +#define get_user_s16(x, gaddr) get_user((x), (gaddr), int16_t) +#define get_user_u8(x, gaddr) get_user((x), (gaddr), uint8_t) +#define get_user_s8(x, gaddr) get_user((x), (gaddr), int8_t) + +/* copy_from_user() and copy_to_user() are usually used to copy data + * buffers between the target and host. These internally perform + * locking/unlocking of the memory. + */ +abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len); +abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len); + +/* Functions for accessing guest memory. The tget and tput functions + read/write single values, byteswapping as necessary. The lock_user function + gets a pointer to a contiguous area of guest memory, but does not perform + any byteswapping. lock_user may return either a pointer to the guest + memory, or a temporary buffer. */ + +/* Lock an area of guest memory into the host. If copy is true then the + host area will have the same contents as the guest. */ +static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy) +{ + if (!access_ok(type, guest_addr, len)) + return NULL; +#ifdef DEBUG_REMAP + { + void *addr; + addr = g_malloc(len); + if (copy) + memcpy(addr, g2h(guest_addr), len); + else + memset(addr, 0, len); + return addr; + } +#else + return g2h(guest_addr); +#endif +} + +/* Unlock an area of guest memory. The first LEN bytes must be + flushed back to guest memory. host_ptr = NULL is explicitly + allowed and does nothing. */ +static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, + long len) +{ + +#ifdef DEBUG_REMAP + if (!host_ptr) + return; + if (host_ptr == g2h(guest_addr)) + return; + if (len > 0) + memcpy(g2h(guest_addr), host_ptr, len); + g_free(host_ptr); +#endif +} + +/* Return the length of a string in target memory or -TARGET_EFAULT if + access error. */ +abi_long target_strlen(abi_ulong gaddr); + +/* Like lock_user but for null terminated strings. */ +static inline void *lock_user_string(abi_ulong guest_addr) +{ + abi_long len; + len = target_strlen(guest_addr);