#ifndef QEMU_H
#define QEMU_H
-
-#include "qemu/osdep.h"
#include "cpu.h"
#include "qemu/units.h"
#include "exec/cpu_ldst.h"
extern char **environ;
-enum BSDType {
- target_freebsd,
- target_netbsd,
- target_openbsd,
-};
-extern enum BSDType bsd_type;
-
#include "exec/user/thunk.h"
#include "target_arch.h"
#include "syscall_defs.h"
#include "target_syscall.h"
#include "target_os_vmparam.h"
#include "target_os_signal.h"
+#include "target.h"
#include "exec/gdbstub.h"
+#include "qemu/clang-tsa.h"
+#include "qemu-os.h"
/*
* This struct is used to hold certain information about the image. Basically,
* it replicates in user space what would be certain task_struct fields in the
abi_ulong end_code;
abi_ulong start_data;
abi_ulong end_data;
- abi_ulong start_brk;
abi_ulong brk;
- abi_ulong start_mmap;
- abi_ulong mmap;
abi_ulong rss;
abi_ulong start_stack;
abi_ulong entry;
uint32_t elf_flags;
};
-#define MAX_SIGQUEUE_SIZE 1024
-
-struct sigqueue {
- struct sigqueue *next;
-};
-
struct emulated_sigtable {
int pending; /* true if signal is pending */
- struct sigqueue *first;
- /* in order to always have memory for the first signal, we put it here */
- struct sigqueue info;
+ target_siginfo_t info;
};
/*
struct bsd_binprm *bprm;
struct image_info *info;
+ struct emulated_sigtable sync_signal;
+ /*
+ * TODO: Since we block all signals while returning to the main CPU
+ * loop, this needn't be an array
+ */
struct emulated_sigtable sigtab[TARGET_NSIG];
- struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
- struct sigqueue *first_free; /* first free siginfo queue entry */
- int signal_pending; /* non zero if a signal may be pending */
-
- uint8_t stack[];
+ /*
+ * Nonzero if process_pending_signals() needs to do something (either
+ * handle a pending signal or unblock signals).
+ * This flag is written from a signal handler so should be accessed via
+ * the qatomic_read() and qatomic_set() functions. (It is not accessed
+ * from multiple threads.)
+ */
+ int signal_pending;
+ /* True if we're leaving a sigsuspend and sigsuspend_mask is valid. */
+ bool in_sigsuspend;
+ /*
+ * This thread's signal mask, as requested by the guest program.
+ * The actual signal mask of this thread may differ:
+ * + we don't let SIGSEGV and SIGBUS be blocked while running guest code
+ * + sometimes we block all signals to avoid races
+ */
+ sigset_t signal_mask;
+ /*
+ * The signal mask imposed by a guest sigsuspend syscall, if we are
+ * currently in the middle of such a syscall
+ */
+ sigset_t sigsuspend_mask;
+
+ /* This thread's sigaltstack, if it has one */
+ struct target_sigaltstack sigaltstack_used;
} __attribute__((aligned(16))) TaskState;
-void init_task_state(TaskState *ts);
void stop_all_tasks(void);
+extern const char *interp_prefix;
extern const char *qemu_uname_release;
/*
* TARGET_ARG_MAX defines the number of bytes allocated for arguments
* and envelope for the new program. 256k should suffice for a reasonable
- * maxiumum env+arg in 32-bit environments, bump it up to 512k for !ILP32
+ * maximum env+arg in 32-bit environments, bump it up to 512k for !ILP32
* platforms.
*/
#if TARGET_ABI_BITS > 32
abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5, abi_long arg6);
-void gemu_log(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+void gemu_log(const char *fmt, ...) G_GNUC_PRINTF(1, 2);
extern __thread CPUState *thread_cpu;
void cpu_loop(CPUArchState *env);
char *target_strerror(int err);
abi_long arg1, abi_long arg2, abi_long arg3,
abi_long arg4, abi_long arg5, abi_long arg6);
void print_openbsd_syscall_ret(int num, abi_long ret);
+/**
+ * print_taken_signal:
+ * @target_signum: target signal being taken
+ * @tinfo: target_siginfo_t which will be passed to the guest for the signal
+ *
+ * Print strace output indicating that this signal is being taken by the guest,
+ * in a format similar to:
+ * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
+ */
+void print_taken_signal(int target_signum, const target_siginfo_t *tinfo);
extern int do_strace;
-/* signal.c */
-void process_pending_signals(CPUArchState *cpu_env);
-void signal_init(void);
-long do_sigreturn(CPUArchState *env);
-long do_rt_sigreturn(CPUArchState *env);
-abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
-
/* mmap.c */
int target_mprotect(abi_ulong start, abi_ulong len, int prot);
abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
abi_ulong new_size, unsigned long flags,
abi_ulong new_addr);
int target_msync(abi_ulong start, abi_ulong len, int flags);
-extern unsigned long last_brk;
extern abi_ulong mmap_next_start;
abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size);
-void mmap_fork_start(void);
-void mmap_fork_end(int child);
+void TSA_NO_TSA mmap_fork_start(void);
+void TSA_NO_TSA mmap_fork_end(int child);
/* main.c */
extern char qemu_proc_pathname[];
extern unsigned long target_maxssiz;
extern unsigned long target_sgrowsiz;
-/* syscall.c */
+/* os-syscall.c */
abi_long get_errno(abi_long ret);
bool is_error(abi_long ret);
+int host_to_target_errno(int err);
+
+/* os-proc.c */
+abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
+ abi_ulong guest_envp, int do_fexec);
+abi_long do_freebsd_procctl(void *cpu_env, int idtype, abi_ulong arg2,
+ abi_ulong arg3, abi_ulong arg4, abi_ulong arg5, abi_ulong arg6);
/* os-sys.c */
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+ abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen);
+abi_long do_freebsd_sysctlbyname(CPUArchState *env, abi_ulong namep,
+ int32_t namelen, abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp,
+ abi_ulong newlen);
abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2);
/* user access */
static inline bool access_ok(int type, abi_ulong addr, abi_ulong size)
{
- return page_check_range((target_ulong)addr, size, type) == 0;
+ return page_check_range((target_ulong)addr, size, type);
}
/*
* 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:\
- x = 0;\
- abort();\
- } \
- 0;\
-})
+/*
+ * 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.
+ * - The pragmas are necessary only to silence a clang false-positive
+ * warning: see https://bugs.llvm.org/show_bug.cgi?id=39113 .
+ * - gcc has bugs in its _Pragma() support in some versions, eg
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83256 -- so we only
+ * include the warning-suppression pragmas for clang
+ */
+#if defined(__clang__) && __has_warning("-Waddress-of-packed-member")
+#define PRAGMA_DISABLE_PACKED_WARNING \
+ _Pragma("GCC diagnostic push"); \
+ _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"")
+
+#define PRAGMA_REENABLE_PACKED_WARNING \
+ _Pragma("GCC diagnostic pop")
+
+#else
+#define PRAGMA_DISABLE_PACKED_WARNING
+#define PRAGMA_REENABLE_PACKED_WARNING
+#endif
+
+#define __put_user_e(x, hptr, e) \
+ do { \
+ PRAGMA_DISABLE_PACKED_WARNING; \
+ (__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); \
+ PRAGMA_REENABLE_PACKED_WARNING; \
+ } while (0)
+
+#define __get_user_e(x, hptr, e) \
+ do { \
+ PRAGMA_DISABLE_PACKED_WARNING; \
+ ((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); \
+ PRAGMA_REENABLE_PACKED_WARNING; \
+ } while (0)
+
+
+#if TARGET_BIG_ENDIAN
+# 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
({ \
abi_ulong __gaddr = (gaddr); \
target_type *__hptr; \
- abi_long __ret; \
+ abi_long __ret = 0; \
__hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0); \
if (__hptr) { \
- __ret = __put_user((x), __hptr); \
+ __put_user((x), __hptr); \
unlock_user(__hptr, __gaddr, sizeof(target_type)); \
} else \
__ret = -TARGET_EFAULT; \
({ \
abi_ulong __gaddr = (gaddr); \
target_type *__hptr; \
- abi_long __ret; \
+ abi_long __ret = 0; \
__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1); \
if (__hptr) { \
- __ret = __get_user((x), __hptr); \
+ __get_user((x), __hptr); \
unlock_user(__hptr, __gaddr, 0); \
} else { \
(x) = 0; \
#define unlock_user_struct(host_ptr, guest_addr, copy) \
unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
+static inline uint64_t target_arg64(uint32_t word0, uint32_t word1)
+{
+#if TARGET_ABI_BITS == 32
+#if TARGET_BIG_ENDIAN
+ return ((uint64_t)word0 << 32) | word1;
+#else
+ return ((uint64_t)word1 << 32) | word0;
+#endif
+#else /* TARGET_ABI_BITS != 32 */
+ return word0;
+#endif /* TARGET_ABI_BITS != 32 */
+}
+
#include <pthread.h>
+#include "user/safe-syscall.h"
+
#endif /* QEMU_H */