xref: /qemu/bsd-user/qemu.h (revision 4e111653)
188dae46dSSean Bruno /*
288dae46dSSean Bruno  *  qemu bsd user mode definition
388dae46dSSean Bruno  *
488dae46dSSean Bruno  *  This program is free software; you can redistribute it and/or modify
588dae46dSSean Bruno  *  it under the terms of the GNU General Public License as published by
688dae46dSSean Bruno  *  the Free Software Foundation; either version 2 of the License, or
788dae46dSSean Bruno  *  (at your option) any later version.
888dae46dSSean Bruno  *
988dae46dSSean Bruno  *  This program is distributed in the hope that it will be useful,
1088dae46dSSean Bruno  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1188dae46dSSean Bruno  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1288dae46dSSean Bruno  *  GNU General Public License for more details.
1388dae46dSSean Bruno  *
1488dae46dSSean Bruno  *  You should have received a copy of the GNU General Public License
1588dae46dSSean Bruno  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
1688dae46dSSean Bruno  */
1784778508Sblueswir1 #ifndef QEMU_H
1884778508Sblueswir1 #define QEMU_H
1984778508Sblueswir1 
2084778508Sblueswir1 #include "cpu.h"
21e5e44263SWarner Losh #include "qemu/units.h"
22f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h"
23ab77bd84SWarner Losh #include "exec/exec-all.h"
2484778508Sblueswir1 
2522879b66SPhilippe Mathieu-Daudé #include "user/abitypes.h"
2684778508Sblueswir1 
274b599848SWarner Losh extern char **environ;
284b599848SWarner Losh 
29*4e111653SPhilippe Mathieu-Daudé #include "user/thunk.h"
30ab77bd84SWarner Losh #include "target_arch.h"
3184778508Sblueswir1 #include "syscall_defs.h"
320c6940d0SLluís Vilanova #include "target_syscall.h"
3382792244SWarner Losh #include "target_os_vmparam.h"
34790baaccSWarner Losh #include "target_os_signal.h"
35647afdf1SWarner Losh #include "target.h"
36022c62cbSPaolo Bonzini #include "exec/gdbstub.h"
37e022d9caSEmanuele Giuseppe Esposito #include "qemu/clang-tsa.h"
3884778508Sblueswir1 
399b4a902dSStacey Son #include "qemu-os.h"
40c2bdd9a1SWarner Losh /*
418c45039fSRichard Henderson  * TODO: Remove these and rely only on qemu_real_host_page_size().
428c45039fSRichard Henderson  */
438c45039fSRichard Henderson extern uintptr_t qemu_host_page_size;
448c45039fSRichard Henderson extern intptr_t qemu_host_page_mask;
458c45039fSRichard Henderson #define HOST_PAGE_ALIGN(addr) ROUND_UP((addr), qemu_host_page_size)
468c45039fSRichard Henderson 
478c45039fSRichard Henderson /*
48c2bdd9a1SWarner Losh  * This struct is used to hold certain information about the image.  Basically,
49c2bdd9a1SWarner Losh  * it replicates in user space what would be certain task_struct fields in the
50c2bdd9a1SWarner Losh  * kernel
5184778508Sblueswir1  */
5284778508Sblueswir1 struct image_info {
530475f8faSWarner Losh     abi_ulong load_bias;
5484778508Sblueswir1     abi_ulong load_addr;
5584778508Sblueswir1     abi_ulong start_code;
5684778508Sblueswir1     abi_ulong end_code;
5784778508Sblueswir1     abi_ulong start_data;
5884778508Sblueswir1     abi_ulong end_data;
5984778508Sblueswir1     abi_ulong brk;
6084778508Sblueswir1     abi_ulong rss;
6184778508Sblueswir1     abi_ulong start_stack;
6284778508Sblueswir1     abi_ulong entry;
6384778508Sblueswir1     abi_ulong code_offset;
6484778508Sblueswir1     abi_ulong data_offset;
650475f8faSWarner Losh     abi_ulong arg_start;
660475f8faSWarner Losh     abi_ulong arg_end;
670475f8faSWarner Losh     uint32_t  elf_flags;
6884778508Sblueswir1 };
6984778508Sblueswir1 
7084778508Sblueswir1 struct emulated_sigtable {
7184778508Sblueswir1     int pending; /* true if signal is pending */
72b46d4ad7SWarner Losh     target_siginfo_t info;
7384778508Sblueswir1 };
7484778508Sblueswir1 
75c2bdd9a1SWarner Losh /*
76c2bdd9a1SWarner Losh  * NOTE: we force a big alignment so that the stack stored after is aligned too
77c2bdd9a1SWarner Losh  */
7884778508Sblueswir1 typedef struct TaskState {
79bd88c780SAlex Bennée     pid_t ts_tid;     /* tid (or pid) of this task */
80bd88c780SAlex Bennée 
8184778508Sblueswir1     struct TaskState *next;
82031fe7afSWarner Losh     struct bsd_binprm *bprm;
8384778508Sblueswir1     struct image_info *info;
8484778508Sblueswir1 
8538be620cSWarner Losh     struct emulated_sigtable sync_signal;
8638be620cSWarner Losh     /*
8738be620cSWarner Losh      * TODO: Since we block all signals while returning to the main CPU
8838be620cSWarner Losh      * loop, this needn't be an array
8938be620cSWarner Losh      */
9084778508Sblueswir1     struct emulated_sigtable sigtab[TARGET_NSIG];
9148047225SWarner Losh     /*
9248047225SWarner Losh      * Nonzero if process_pending_signals() needs to do something (either
9348047225SWarner Losh      * handle a pending signal or unblock signals).
9448047225SWarner Losh      * This flag is written from a signal handler so should be accessed via
9548047225SWarner Losh      * the qatomic_read() and qatomic_set() functions. (It is not accessed
9648047225SWarner Losh      * from multiple threads.)
9748047225SWarner Losh      */
9848047225SWarner Losh     int signal_pending;
996c6d4b56SWarner Losh     /* True if we're leaving a sigsuspend and sigsuspend_mask is valid. */
1006c6d4b56SWarner Losh     bool in_sigsuspend;
101149076adSWarner Losh     /*
102149076adSWarner Losh      * This thread's signal mask, as requested by the guest program.
103149076adSWarner Losh      * The actual signal mask of this thread may differ:
104149076adSWarner Losh      *  + we don't let SIGSEGV and SIGBUS be blocked while running guest code
105149076adSWarner Losh      *  + sometimes we block all signals to avoid races
106149076adSWarner Losh      */
107149076adSWarner Losh     sigset_t signal_mask;
1086c6d4b56SWarner Losh     /*
1096c6d4b56SWarner Losh      * The signal mask imposed by a guest sigsuspend syscall, if we are
1106c6d4b56SWarner Losh      * currently in the middle of such a syscall
1116c6d4b56SWarner Losh      */
1126c6d4b56SWarner Losh     sigset_t sigsuspend_mask;
11384778508Sblueswir1 
11446f4f76dSWarner Losh     /* This thread's sigaltstack, if it has one */
11546f4f76dSWarner Losh     struct target_sigaltstack sigaltstack_used;
11684778508Sblueswir1 } __attribute__((aligned(16))) TaskState;
11784778508Sblueswir1 
get_task_state(CPUState * cs)118e4e5cb4aSIlya Leoshkevich static inline TaskState *get_task_state(CPUState *cs)
119e4e5cb4aSIlya Leoshkevich {
120e4e5cb4aSIlya Leoshkevich     return cs->opaque;
121e4e5cb4aSIlya Leoshkevich }
122e4e5cb4aSIlya Leoshkevich 
123653ccec2SWarner Losh void stop_all_tasks(void);
12486327290SStacey Son extern const char *interp_prefix;
12584778508Sblueswir1 extern const char *qemu_uname_release;
12684778508Sblueswir1 
12784778508Sblueswir1 /*
128e5e44263SWarner Losh  * TARGET_ARG_MAX defines the number of bytes allocated for arguments
129e5e44263SWarner Losh  * and envelope for the new program. 256k should suffice for a reasonable
130944399ffSMichael Tokarev  * maximum env+arg in 32-bit environments, bump it up to 512k for !ILP32
131e5e44263SWarner Losh  * platforms.
13284778508Sblueswir1  */
133e5e44263SWarner Losh #if TARGET_ABI_BITS > 32
134e5e44263SWarner Losh #define TARGET_ARG_MAX (512 * KiB)
135e5e44263SWarner Losh #else
136e5e44263SWarner Losh #define TARGET_ARG_MAX (256 * KiB)
137e5e44263SWarner Losh #endif
138e5e44263SWarner Losh #define MAX_ARG_PAGES (TARGET_ARG_MAX / TARGET_PAGE_SIZE)
13984778508Sblueswir1 
14084778508Sblueswir1 /*
14184778508Sblueswir1  * This structure is used to hold the arguments that are
14284778508Sblueswir1  * used when loading binaries.
14384778508Sblueswir1  */
144afcbcff8SWarner Losh struct bsd_binprm {
14584778508Sblueswir1         char buf[128];
14684778508Sblueswir1         void *page[MAX_ARG_PAGES];
14784778508Sblueswir1         abi_ulong p;
14898b34d35SWarner Losh         abi_ulong stringp;
14984778508Sblueswir1         int fd;
15084778508Sblueswir1         int e_uid, e_gid;
15184778508Sblueswir1         int argc, envc;
15284778508Sblueswir1         char **argv;
15384778508Sblueswir1         char **envp;
1541b50ff64SWarner Losh         char *filename;         /* (Given) Name of binary */
1551b50ff64SWarner Losh         char *fullpath;         /* Full path of binary */
1560475f8faSWarner Losh         int (*core_dump)(int, CPUArchState *);
15784778508Sblueswir1 };
15884778508Sblueswir1 
15984778508Sblueswir1 void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
16084778508Sblueswir1 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
161ffa03665SWarner Losh                               abi_ulong stringp);
16284778508Sblueswir1 int loader_exec(const char *filename, char **argv, char **envp,
163d37853f9SWarner Losh                 struct target_pt_regs *regs, struct image_info *infop,
164d37853f9SWarner Losh                 struct bsd_binprm *bprm);
16584778508Sblueswir1 
166afcbcff8SWarner Losh int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
16784778508Sblueswir1                     struct image_info *info);
168afcbcff8SWarner Losh int load_flt_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs,
16984778508Sblueswir1                     struct image_info *info);
1700475f8faSWarner Losh int is_target_elf_binary(int fd);
17184778508Sblueswir1 
17284778508Sblueswir1 abi_long memcpy_to_target(abi_ulong dest, const void *src,
17384778508Sblueswir1                           unsigned long len);
17484778508Sblueswir1 void target_set_brk(abi_ulong new_brk);
17584778508Sblueswir1 abi_long do_brk(abi_ulong new_brk);
17684778508Sblueswir1 void syscall_init(void);
17784778508Sblueswir1 abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
17884778508Sblueswir1                             abi_long arg2, abi_long arg3, abi_long arg4,
17978cfb07fSJuergen Lock                             abi_long arg5, abi_long arg6, abi_long arg7,
18078cfb07fSJuergen Lock                             abi_long arg8);
18184778508Sblueswir1 abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
18284778508Sblueswir1                            abi_long arg2, abi_long arg3, abi_long arg4,
18384778508Sblueswir1                            abi_long arg5, abi_long arg6);
18484778508Sblueswir1 abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
18584778508Sblueswir1                             abi_long arg2, abi_long arg3, abi_long arg4,
18684778508Sblueswir1                             abi_long arg5, abi_long arg6);
1879edc6313SMarc-André Lureau void gemu_log(const char *fmt, ...) G_GNUC_PRINTF(1, 2);
188d42df502SWarner Losh extern __thread CPUState *thread_cpu;
1899349b4f9SAndreas Färber void cpu_loop(CPUArchState *env);
19084778508Sblueswir1 char *target_strerror(int err);
19184778508Sblueswir1 int get_osversion(void);
19284778508Sblueswir1 void fork_start(void);
1934edc98fcSIlya Leoshkevich void fork_end(pid_t pid);
19484778508Sblueswir1 
1951de7afc9SPaolo Bonzini #include "qemu/log.h"
19684778508Sblueswir1 
19784778508Sblueswir1 /* strace.c */
19888dae46dSSean Bruno struct syscallname {
19988dae46dSSean Bruno     int nr;
20088dae46dSSean Bruno     const char *name;
20188dae46dSSean Bruno     const char *format;
20288dae46dSSean Bruno     void (*call)(const struct syscallname *,
20388dae46dSSean Bruno                  abi_long, abi_long, abi_long,
20488dae46dSSean Bruno                  abi_long, abi_long, abi_long);
20588dae46dSSean Bruno     void (*result)(const struct syscallname *, abi_long);
20688dae46dSSean Bruno };
20788dae46dSSean Bruno 
20884778508Sblueswir1 void
20984778508Sblueswir1 print_freebsd_syscall(int num,
21084778508Sblueswir1                       abi_long arg1, abi_long arg2, abi_long arg3,
21184778508Sblueswir1                       abi_long arg4, abi_long arg5, abi_long arg6);
21284778508Sblueswir1 void print_freebsd_syscall_ret(int num, abi_long ret);
21384778508Sblueswir1 void
21484778508Sblueswir1 print_netbsd_syscall(int num,
21584778508Sblueswir1                      abi_long arg1, abi_long arg2, abi_long arg3,
21684778508Sblueswir1                      abi_long arg4, abi_long arg5, abi_long arg6);
21784778508Sblueswir1 void print_netbsd_syscall_ret(int num, abi_long ret);
21884778508Sblueswir1 void
21984778508Sblueswir1 print_openbsd_syscall(int num,
22084778508Sblueswir1                       abi_long arg1, abi_long arg2, abi_long arg3,
22184778508Sblueswir1                       abi_long arg4, abi_long arg5, abi_long arg6);
22284778508Sblueswir1 void print_openbsd_syscall_ret(int num, abi_long ret);
223fd5bec9aSWarner Losh /**
224fd5bec9aSWarner Losh  * print_taken_signal:
225fd5bec9aSWarner Losh  * @target_signum: target signal being taken
226fd5bec9aSWarner Losh  * @tinfo: target_siginfo_t which will be passed to the guest for the signal
227fd5bec9aSWarner Losh  *
228fd5bec9aSWarner Losh  * Print strace output indicating that this signal is being taken by the guest,
229fd5bec9aSWarner Losh  * in a format similar to:
230fd5bec9aSWarner Losh  * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
231fd5bec9aSWarner Losh  */
232fd5bec9aSWarner Losh void print_taken_signal(int target_signum, const target_siginfo_t *tinfo);
23384778508Sblueswir1 extern int do_strace;
23484778508Sblueswir1 
23584778508Sblueswir1 /* mmap.c */
23684778508Sblueswir1 int target_mprotect(abi_ulong start, abi_ulong len, int prot);
23784778508Sblueswir1 abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
238be04f210SWarner Losh                      int flags, int fd, off_t offset);
23984778508Sblueswir1 int target_munmap(abi_ulong start, abi_ulong len);
24084778508Sblueswir1 abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
24184778508Sblueswir1                        abi_ulong new_size, unsigned long flags,
24284778508Sblueswir1                        abi_ulong new_addr);
24384778508Sblueswir1 int target_msync(abi_ulong start, abi_ulong len, int flags);
244be04f210SWarner Losh extern abi_ulong mmap_next_start;
245be04f210SWarner Losh abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size);
2464e00b7d8SStacey Son void mmap_reserve(abi_ulong start, abi_ulong size);
247e022d9caSEmanuele Giuseppe Esposito void TSA_NO_TSA mmap_fork_start(void);
248e022d9caSEmanuele Giuseppe Esposito void TSA_NO_TSA mmap_fork_end(int child);
24984778508Sblueswir1 
25028e738dcSBlue Swirl /* main.c */
25101a298a5SWarner Losh extern char qemu_proc_pathname[];
252312a0b1cSWarner Losh extern unsigned long target_maxtsiz;
253312a0b1cSWarner Losh extern unsigned long target_dfldsiz;
254312a0b1cSWarner Losh extern unsigned long target_maxdsiz;
255312a0b1cSWarner Losh extern unsigned long target_dflssiz;
256312a0b1cSWarner Losh extern unsigned long target_maxssiz;
257312a0b1cSWarner Losh extern unsigned long target_sgrowsiz;
25828e738dcSBlue Swirl 
259deeff83bSWarner Losh /* os-syscall.c */
260e5f674f0SWarner Losh abi_long get_errno(abi_long ret);
261e5f674f0SWarner Losh bool is_error(abi_long ret);
262deeff83bSWarner Losh int host_to_target_errno(int err);
263e5f674f0SWarner Losh 
264cc47390cSStacey Son /* os-proc.c */
265cc47390cSStacey Son abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
266cc47390cSStacey Son         abi_ulong guest_envp, int do_fexec);
267cc47390cSStacey Son abi_long do_freebsd_procctl(void *cpu_env, int idtype, abi_ulong arg2,
268cc47390cSStacey Son         abi_ulong arg3, abi_ulong arg4, abi_ulong arg5, abi_ulong arg6);
269cc47390cSStacey Son 
270da07e694SWarner Losh /* os-sys.c */
2717adda6deSKyle Evans abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
2727adda6deSKyle Evans         abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen);
2736da777e2SKyle Evans abi_long do_freebsd_sysctlbyname(CPUArchState *env, abi_ulong namep,
2746da777e2SKyle Evans         int32_t namelen, abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp,
2756da777e2SKyle Evans         abi_ulong newlen);
276da07e694SWarner Losh abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2);
277da07e694SWarner Losh 
27884778508Sblueswir1 /* user access */
27984778508Sblueswir1 
2801720751fSRichard Henderson #define VERIFY_READ  PAGE_READ
2811720751fSRichard Henderson #define VERIFY_WRITE (PAGE_READ | PAGE_WRITE)
28284778508Sblueswir1 
access_ok(int type,abi_ulong addr,abi_ulong size)2831720751fSRichard Henderson static inline bool access_ok(int type, abi_ulong addr, abi_ulong size)
28484778508Sblueswir1 {
285bef6f008SRichard Henderson     return page_check_range((target_ulong)addr, size, type);
28684778508Sblueswir1 }
28784778508Sblueswir1 
288c2bdd9a1SWarner Losh /*
289c2bdd9a1SWarner Losh  * NOTE __get_user and __put_user use host pointers and don't check access.
290c2bdd9a1SWarner Losh  *
291c2bdd9a1SWarner Losh  * These are usually used to access struct data members once the struct has been
292c2bdd9a1SWarner Losh  * locked - usually with lock_user_struct().
29384778508Sblueswir1  */
2948a45962bSWarner Losh 
2958a45962bSWarner Losh /*
2968a45962bSWarner Losh  * Tricky points:
2978a45962bSWarner Losh  * - Use __builtin_choose_expr to avoid type promotion from ?:,
2988a45962bSWarner Losh  * - Invalid sizes result in a compile time error stemming from
2998a45962bSWarner Losh  *   the fact that abort has no parameters.
3008a45962bSWarner Losh  * - It's easier to use the endian-specific unaligned load/store
3018a45962bSWarner Losh  *   functions than host-endian unaligned load/store plus tswapN.
3028a45962bSWarner Losh  * - The pragmas are necessary only to silence a clang false-positive
3038a45962bSWarner Losh  *   warning: see https://bugs.llvm.org/show_bug.cgi?id=39113 .
3048a45962bSWarner Losh  * - gcc has bugs in its _Pragma() support in some versions, eg
3058a45962bSWarner Losh  *   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83256 -- so we only
3068a45962bSWarner Losh  *   include the warning-suppression pragmas for clang
3078a45962bSWarner Losh  */
3088a45962bSWarner Losh #if defined(__clang__) && __has_warning("-Waddress-of-packed-member")
3098a45962bSWarner Losh #define PRAGMA_DISABLE_PACKED_WARNING                                   \
3108a45962bSWarner Losh     _Pragma("GCC diagnostic push");                                     \
3118a45962bSWarner Losh     _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"")
3128a45962bSWarner Losh 
3138a45962bSWarner Losh #define PRAGMA_REENABLE_PACKED_WARNING          \
3148a45962bSWarner Losh     _Pragma("GCC diagnostic pop")
3158a45962bSWarner Losh 
3168a45962bSWarner Losh #else
3178a45962bSWarner Losh #define PRAGMA_DISABLE_PACKED_WARNING
3188a45962bSWarner Losh #define PRAGMA_REENABLE_PACKED_WARNING
3198a45962bSWarner Losh #endif
3208a45962bSWarner Losh 
3216538c682SWarner Losh #define __put_user_e(x, hptr, e)                                            \
3226538c682SWarner Losh     do {                                                                    \
3236538c682SWarner Losh         PRAGMA_DISABLE_PACKED_WARNING;                                      \
3246538c682SWarner Losh         (__builtin_choose_expr(sizeof(*(hptr)) == 1, stb_p,                 \
3256538c682SWarner Losh         __builtin_choose_expr(sizeof(*(hptr)) == 2, stw_##e##_p,            \
3266538c682SWarner Losh         __builtin_choose_expr(sizeof(*(hptr)) == 4, stl_##e##_p,            \
3276538c682SWarner Losh         __builtin_choose_expr(sizeof(*(hptr)) == 8, stq_##e##_p, abort))))  \
3286538c682SWarner Losh             ((hptr), (x)), (void)0);                                        \
3296538c682SWarner Losh         PRAGMA_REENABLE_PACKED_WARNING;                                     \
3306538c682SWarner Losh     } while (0)
33184778508Sblueswir1 
3326538c682SWarner Losh #define __get_user_e(x, hptr, e)                                            \
3336538c682SWarner Losh     do {                                                                    \
3346538c682SWarner Losh         PRAGMA_DISABLE_PACKED_WARNING;                                      \
3356538c682SWarner Losh         ((x) = (typeof(*hptr))(                                             \
3366538c682SWarner Losh         __builtin_choose_expr(sizeof(*(hptr)) == 1, ldub_p,                 \
3376538c682SWarner Losh         __builtin_choose_expr(sizeof(*(hptr)) == 2, lduw_##e##_p,           \
3386538c682SWarner Losh         __builtin_choose_expr(sizeof(*(hptr)) == 4, ldl_##e##_p,            \
3396538c682SWarner Losh         __builtin_choose_expr(sizeof(*(hptr)) == 8, ldq_##e##_p, abort))))  \
3406538c682SWarner Losh             (hptr)), (void)0);                                              \
3416538c682SWarner Losh         PRAGMA_REENABLE_PACKED_WARNING;                                     \
3426538c682SWarner Losh     } while (0)
3436538c682SWarner Losh 
3446538c682SWarner Losh 
3456538c682SWarner Losh #if TARGET_BIG_ENDIAN
3466538c682SWarner Losh # define __put_user(x, hptr)  __put_user_e(x, hptr, be)
3476538c682SWarner Losh # define __get_user(x, hptr)  __get_user_e(x, hptr, be)
3486538c682SWarner Losh #else
3496538c682SWarner Losh # define __put_user(x, hptr)  __put_user_e(x, hptr, le)
3506538c682SWarner Losh # define __get_user(x, hptr)  __get_user_e(x, hptr, le)
3516538c682SWarner Losh #endif
35284778508Sblueswir1 
353c2bdd9a1SWarner Losh /*
354c2bdd9a1SWarner Losh  * put_user()/get_user() take a guest address and check access
355c2bdd9a1SWarner Losh  *
356c2bdd9a1SWarner Losh  * These are usually used to access an atomic data type, such as an int, that
357c2bdd9a1SWarner Losh  * has been passed by address.  These internally perform locking and unlocking
358c2bdd9a1SWarner Losh  * on the data type.
35984778508Sblueswir1  */
36084778508Sblueswir1 #define put_user(x, gaddr, target_type)                                 \
36184778508Sblueswir1 ({                                                                      \
36284778508Sblueswir1     abi_ulong __gaddr = (gaddr);                                        \
36384778508Sblueswir1     target_type *__hptr;                                                \
3646538c682SWarner Losh     abi_long __ret = 0;                                                 \
36533066934SWarner Losh     __hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0);  \
36633066934SWarner Losh     if (__hptr) {                                                       \
3676538c682SWarner Losh         __put_user((x), __hptr);                                        \
36884778508Sblueswir1         unlock_user(__hptr, __gaddr, sizeof(target_type));              \
36984778508Sblueswir1     } else                                                              \
37084778508Sblueswir1         __ret = -TARGET_EFAULT;                                         \
37184778508Sblueswir1     __ret;                                                              \
37284778508Sblueswir1 })
37384778508Sblueswir1 
37484778508Sblueswir1 #define get_user(x, gaddr, target_type)                                 \
37584778508Sblueswir1 ({                                                                      \
37684778508Sblueswir1     abi_ulong __gaddr = (gaddr);                                        \
37784778508Sblueswir1     target_type *__hptr;                                                \
3786538c682SWarner Losh     abi_long __ret = 0;                                                 \
37933066934SWarner Losh     __hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1);   \
38033066934SWarner Losh     if (__hptr) {                                                       \
3816538c682SWarner Losh         __get_user((x), __hptr);                                        \
38284778508Sblueswir1         unlock_user(__hptr, __gaddr, 0);                                \
38384778508Sblueswir1     } else {                                                            \
38484778508Sblueswir1         (x) = 0;                                                        \
38584778508Sblueswir1         __ret = -TARGET_EFAULT;                                         \
38684778508Sblueswir1     }                                                                   \
38784778508Sblueswir1     __ret;                                                              \
38884778508Sblueswir1 })
38984778508Sblueswir1 
39084778508Sblueswir1 #define put_user_ual(x, gaddr) put_user((x), (gaddr), abi_ulong)
39184778508Sblueswir1 #define put_user_sal(x, gaddr) put_user((x), (gaddr), abi_long)
39284778508Sblueswir1 #define put_user_u64(x, gaddr) put_user((x), (gaddr), uint64_t)
39384778508Sblueswir1 #define put_user_s64(x, gaddr) put_user((x), (gaddr), int64_t)
39484778508Sblueswir1 #define put_user_u32(x, gaddr) put_user((x), (gaddr), uint32_t)
39584778508Sblueswir1 #define put_user_s32(x, gaddr) put_user((x), (gaddr), int32_t)
39684778508Sblueswir1 #define put_user_u16(x, gaddr) put_user((x), (gaddr), uint16_t)
39784778508Sblueswir1 #define put_user_s16(x, gaddr) put_user((x), (gaddr), int16_t)
39884778508Sblueswir1 #define put_user_u8(x, gaddr)  put_user((x), (gaddr), uint8_t)
39984778508Sblueswir1 #define put_user_s8(x, gaddr)  put_user((x), (gaddr), int8_t)
40084778508Sblueswir1 
40184778508Sblueswir1 #define get_user_ual(x, gaddr) get_user((x), (gaddr), abi_ulong)
40284778508Sblueswir1 #define get_user_sal(x, gaddr) get_user((x), (gaddr), abi_long)
40384778508Sblueswir1 #define get_user_u64(x, gaddr) get_user((x), (gaddr), uint64_t)
40484778508Sblueswir1 #define get_user_s64(x, gaddr) get_user((x), (gaddr), int64_t)
40584778508Sblueswir1 #define get_user_u32(x, gaddr) get_user((x), (gaddr), uint32_t)
40684778508Sblueswir1 #define get_user_s32(x, gaddr) get_user((x), (gaddr), int32_t)
40784778508Sblueswir1 #define get_user_u16(x, gaddr) get_user((x), (gaddr), uint16_t)
40884778508Sblueswir1 #define get_user_s16(x, gaddr) get_user((x), (gaddr), int16_t)
40984778508Sblueswir1 #define get_user_u8(x, gaddr)  get_user((x), (gaddr), uint8_t)
41084778508Sblueswir1 #define get_user_s8(x, gaddr)  get_user((x), (gaddr), int8_t)
41184778508Sblueswir1 
412c2bdd9a1SWarner Losh /*
413c2bdd9a1SWarner Losh  * copy_from_user() and copy_to_user() are usually used to copy data
41484778508Sblueswir1  * buffers between the target and host.  These internally perform
41584778508Sblueswir1  * locking/unlocking of the memory.
41684778508Sblueswir1  */
41784778508Sblueswir1 abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
41884778508Sblueswir1 abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
41984778508Sblueswir1 
420c2bdd9a1SWarner Losh /*
421c2bdd9a1SWarner Losh  * Functions for accessing guest memory.  The tget and tput functions
422c2bdd9a1SWarner Losh  * read/write single values, byteswapping as necessary.  The lock_user function
423c2bdd9a1SWarner Losh  * gets a pointer to a contiguous area of guest memory, but does not perform
424c2bdd9a1SWarner Losh  * any byteswapping.  lock_user may return either a pointer to the guest
425c2bdd9a1SWarner Losh  * memory, or a temporary buffer.
426c2bdd9a1SWarner Losh  */
42784778508Sblueswir1 
428c2bdd9a1SWarner Losh /*
429c2bdd9a1SWarner Losh  * Lock an area of guest memory into the host.  If copy is true then the
430c2bdd9a1SWarner Losh  * host area will have the same contents as the guest.
431c2bdd9a1SWarner Losh  */
lock_user(int type,abi_ulong guest_addr,long len,int copy)432c2bdd9a1SWarner Losh static inline void *lock_user(int type, abi_ulong guest_addr, long len,
433c2bdd9a1SWarner Losh                               int copy)
43484778508Sblueswir1 {
435cb0ea019SWarner Losh     if (!access_ok(type, guest_addr, len)) {
43684778508Sblueswir1         return NULL;
437cb0ea019SWarner Losh     }
4381f2355f5SIlya Leoshkevich #ifdef CONFIG_DEBUG_REMAP
43984778508Sblueswir1     {
44084778508Sblueswir1         void *addr;
441fd9a3048SMd Haris Iqbal         addr = g_malloc(len);
442cb0ea019SWarner Losh         if (copy) {
4433e8f1628SRichard Henderson             memcpy(addr, g2h_untagged(guest_addr), len);
444cb0ea019SWarner Losh         } else {
44584778508Sblueswir1             memset(addr, 0, len);
446cb0ea019SWarner Losh         }
44784778508Sblueswir1         return addr;
44884778508Sblueswir1     }
44984778508Sblueswir1 #else
4503e8f1628SRichard Henderson     return g2h_untagged(guest_addr);
45184778508Sblueswir1 #endif
45284778508Sblueswir1 }
45384778508Sblueswir1 
454c2bdd9a1SWarner Losh /*
455c2bdd9a1SWarner Losh  * Unlock an area of guest memory.  The first LEN bytes must be flushed back to
456c2bdd9a1SWarner Losh  * guest memory. host_ptr = NULL is explicitly allowed and does nothing.
457c2bdd9a1SWarner Losh  */
unlock_user(void * host_ptr,abi_ulong guest_addr,long len)45884778508Sblueswir1 static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
45984778508Sblueswir1                                long len)
46084778508Sblueswir1 {
46184778508Sblueswir1 
4621f2355f5SIlya Leoshkevich #ifdef CONFIG_DEBUG_REMAP
463cb0ea019SWarner Losh     if (!host_ptr) {
46484778508Sblueswir1         return;
465cb0ea019SWarner Losh     }
466cb0ea019SWarner Losh     if (host_ptr == g2h_untagged(guest_addr)) {
46784778508Sblueswir1         return;
468cb0ea019SWarner Losh     }
469cb0ea019SWarner Losh     if (len > 0) {
4703e8f1628SRichard Henderson         memcpy(g2h_untagged(guest_addr), host_ptr, len);
471cb0ea019SWarner Losh     }
472fd9a3048SMd Haris Iqbal     g_free(host_ptr);
47384778508Sblueswir1 #endif
47484778508Sblueswir1 }
47584778508Sblueswir1 
476c2bdd9a1SWarner Losh /*
477c2bdd9a1SWarner Losh  * Return the length of a string in target memory or -TARGET_EFAULT if access
478c2bdd9a1SWarner Losh  * error.
479c2bdd9a1SWarner Losh  */
48084778508Sblueswir1 abi_long target_strlen(abi_ulong gaddr);
48184778508Sblueswir1 
48284778508Sblueswir1 /* Like lock_user but for null terminated strings.  */
lock_user_string(abi_ulong guest_addr)48384778508Sblueswir1 static inline void *lock_user_string(abi_ulong guest_addr)
48484778508Sblueswir1 {
48584778508Sblueswir1     abi_long len;
48684778508Sblueswir1     len = target_strlen(guest_addr);
487cb0ea019SWarner Losh     if (len < 0) {
48884778508Sblueswir1         return NULL;
489cb0ea019SWarner Losh     }
49084778508Sblueswir1     return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1);
49184778508Sblueswir1 }
49284778508Sblueswir1 
49341d1af4dSStefan Weil /* Helper macros for locking/unlocking a target struct.  */
49484778508Sblueswir1 #define lock_user_struct(type, host_ptr, guest_addr, copy)      \
49584778508Sblueswir1     (host_ptr = lock_user(type, guest_addr, sizeof(*host_ptr), copy))
49684778508Sblueswir1 #define unlock_user_struct(host_ptr, guest_addr, copy)          \
49784778508Sblueswir1     unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
49884778508Sblueswir1 
target_arg64(uint32_t word0,uint32_t word1)4990ff05082SWarner Losh static inline uint64_t target_arg64(uint32_t word0, uint32_t word1)
5000ff05082SWarner Losh {
5010ff05082SWarner Losh #if TARGET_ABI_BITS == 32
502ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
5030ff05082SWarner Losh     return ((uint64_t)word0 << 32) | word1;
5040ff05082SWarner Losh #else
5050ff05082SWarner Losh     return ((uint64_t)word1 << 32) | word0;
5060ff05082SWarner Losh #endif
5070ff05082SWarner Losh #else /* TARGET_ABI_BITS != 32 */
5080ff05082SWarner Losh     return word0;
5090ff05082SWarner Losh #endif /* TARGET_ABI_BITS != 32 */
5100ff05082SWarner Losh }
5110ff05082SWarner Losh 
51284778508Sblueswir1 #include <pthread.h>
51384778508Sblueswir1 
514aae57ac3SWarner Losh #include "user/safe-syscall.h"
515aae57ac3SWarner Losh 
51684778508Sblueswir1 #endif /* QEMU_H */
517