diff options
-rwxr-xr-x | configure | 8 | ||||
-rw-r--r-- | include/elf.h | 1 | ||||
-rw-r--r-- | linux-user/Makefile.objs | 2 | ||||
-rw-r--r-- | linux-user/cpu-uname.h | 1 | ||||
-rw-r--r-- | linux-user/elfload.c | 147 | ||||
-rw-r--r-- | linux-user/main.c | 2 | ||||
-rw-r--r-- | linux-user/signal.c | 3 | ||||
-rw-r--r-- | linux-user/syscall.c | 189 | ||||
-rw-r--r-- | linux-user/syscall_defs.h | 16 | ||||
-rw-r--r-- | linux-user/uname.c (renamed from linux-user/cpu-uname.c) | 101 | ||||
-rw-r--r-- | linux-user/uname.h | 10 | ||||
-rw-r--r-- | target-alpha/translate.c | 2 |
12 files changed, 322 insertions, 160 deletions
@@ -285,7 +285,6 @@ softmmu="yes" linux_user="no" bsd_user="no" guest_base="yes" -uname_release="" aix="no" blobs="yes" pkgversion="" @@ -945,8 +944,6 @@ for opt do ;; --disable-pie) pie="no" ;; - --enable-uname-release=*) uname_release="$optarg" - ;; --enable-werror) werror="yes" ;; --disable-werror) werror="no" @@ -1295,7 +1292,6 @@ Advanced options (experts only): --fmod-lib path to FMOD library --fmod-inc path to FMOD includes --oss-lib path to OSS library - --enable-uname-release=R Return R for uname -r in usermode emulation --cpu=CPU Build for host CPU [$cpu] --disable-uuid disable uuid support --enable-uuid enable uuid support @@ -4128,8 +4124,6 @@ echo "xen support $xen" echo "brlapi support $brlapi" echo "bluez support $bluez" echo "Documentation $docs" -[ ! -z "$uname_release" ] && \ -echo "uname -r $uname_release" echo "GUEST_BASE $guest_base" echo "PIE $pie" echo "vde support $vde" @@ -4544,8 +4538,6 @@ if [ "$bsd" = "yes" ] ; then echo "CONFIG_BSD=y" >> $config_host_mak fi -echo "CONFIG_UNAME_RELEASE=\"$uname_release\"" >> $config_host_mak - if test "$zero_malloc" = "yes" ; then echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak fi diff --git a/include/elf.h b/include/elf.h index 667af6fc63..1599ab22d8 100644 --- a/include/elf.h +++ b/include/elf.h @@ -254,6 +254,7 @@ typedef int64_t Elf64_Sxword; #define AT_SECURE 23 /* boolean, was exec suid-like? */ #define AT_BASE_PLATFORM 24 /* string identifying real platforms */ #define AT_RANDOM 25 /* address of 16 random bytes */ +#define AT_HWCAP2 26 /* extension of AT_HWCAP */ #define AT_EXECFN 31 /* filename of the executable */ #define AT_SYSINFO 32 /* address of kernel entry point */ #define AT_SYSINFO_EHDR 33 /* address of kernel vdso */ diff --git a/linux-user/Makefile.objs b/linux-user/Makefile.objs index 5899d72d3e..fd5021788f 100644 --- a/linux-user/Makefile.objs +++ b/linux-user/Makefile.objs @@ -1,5 +1,5 @@ obj-y = main.o syscall.o strace.o mmap.o signal.o \ - elfload.o linuxload.o uaccess.o cpu-uname.o + elfload.o linuxload.o uaccess.o uname.o obj-$(TARGET_HAS_BFLT) += flatload.o obj-$(TARGET_I386) += vm86.o diff --git a/linux-user/cpu-uname.h b/linux-user/cpu-uname.h deleted file mode 100644 index 32492de71a..0000000000 --- a/linux-user/cpu-uname.h +++ /dev/null @@ -1 +0,0 @@ -const char *cpu_to_uname_machine(void *cpu_env); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index d2380b6ccb..995f999768 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -20,6 +20,7 @@ #undef ARCH_DLINFO #undef ELF_PLATFORM #undef ELF_HWCAP +#undef ELF_HWCAP2 #undef ELF_CLASS #undef ELF_DATA #undef ELF_ARCH @@ -267,17 +268,15 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en #ifdef TARGET_ARM +#ifndef TARGET_AARCH64 +/* 32 bit ARM definitions */ + #define ELF_START_MMAP 0x80000000 #define elf_check_arch(x) ((x) == ELF_MACHINE) #define ELF_ARCH ELF_MACHINE - -#ifdef TARGET_AARCH64 -#define ELF_CLASS ELFCLASS64 -#else #define ELF_CLASS ELFCLASS32 -#endif static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) @@ -285,10 +284,6 @@ static inline void init_thread(struct target_pt_regs *regs, abi_long stack = infop->start_stack; memset(regs, 0, sizeof(*regs)); -#ifdef TARGET_AARCH64 - regs->pc = infop->entry & ~0x3ULL; - regs->sp = stack; -#else regs->ARM_cpsr = 0x10; if (infop->entry & 1) regs->ARM_cpsr |= CPSR_T; @@ -302,7 +297,6 @@ static inline void init_thread(struct target_pt_regs *regs, /* For uClinux PIC binaries. */ /* XXX: Linux does this only on ARM with no MMU (do we care ?) */ regs->ARM_r10 = infop->start_data; -#endif } #define ELF_NREG 18 @@ -346,13 +340,28 @@ enum ARM_HWCAP_ARM_EDSP = 1 << 7, ARM_HWCAP_ARM_JAVA = 1 << 8, ARM_HWCAP_ARM_IWMMXT = 1 << 9, - ARM_HWCAP_ARM_THUMBEE = 1 << 10, - ARM_HWCAP_ARM_NEON = 1 << 11, - ARM_HWCAP_ARM_VFPv3 = 1 << 12, - ARM_HWCAP_ARM_VFPv3D16 = 1 << 13, + ARM_HWCAP_ARM_CRUNCH = 1 << 10, + ARM_HWCAP_ARM_THUMBEE = 1 << 11, + ARM_HWCAP_ARM_NEON = 1 << 12, + ARM_HWCAP_ARM_VFPv3 = 1 << 13, + ARM_HWCAP_ARM_VFPv3D16 = 1 << 14, + ARM_HWCAP_ARM_TLS = 1 << 15, + ARM_HWCAP_ARM_VFPv4 = 1 << 16, + ARM_HWCAP_ARM_IDIVA = 1 << 17, + ARM_HWCAP_ARM_IDIVT = 1 << 18, + ARM_HWCAP_ARM_VFPD32 = 1 << 19, + ARM_HWCAP_ARM_LPAE = 1 << 20, + ARM_HWCAP_ARM_EVTSTRM = 1 << 21, +}; + +enum { + ARM_HWCAP2_ARM_AES = 1 << 0, + ARM_HWCAP2_ARM_PMULL = 1 << 1, + ARM_HWCAP2_ARM_SHA1 = 1 << 2, + ARM_HWCAP2_ARM_SHA2 = 1 << 3, + ARM_HWCAP2_ARM_CRC32 = 1 << 4, }; -#ifndef TARGET_AARCH64 /* The commpage only exists for 32 bit kernels */ #define TARGET_HAS_VALIDATE_GUEST_SPACE @@ -414,9 +423,9 @@ static int validate_guest_space(unsigned long guest_base, return 1; /* All good */ } -#endif #define ELF_HWCAP get_elf_hwcap() +#define ELF_HWCAP2 get_elf_hwcap2() static uint32_t get_elf_hwcap(void) { @@ -427,23 +436,114 @@ static uint32_t get_elf_hwcap(void) hwcaps |= ARM_HWCAP_ARM_HALF; hwcaps |= ARM_HWCAP_ARM_THUMB; hwcaps |= ARM_HWCAP_ARM_FAST_MULT; - hwcaps |= ARM_HWCAP_ARM_FPA; /* probe for the extra features */ #define GET_FEATURE(feat, hwcap) \ do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0) + /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */ + GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP); GET_FEATURE(ARM_FEATURE_VFP, ARM_HWCAP_ARM_VFP); GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT); GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE); GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON); GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPv3); - GET_FEATURE(ARM_FEATURE_VFP_FP16, ARM_HWCAP_ARM_VFPv3D16); + GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS); + GET_FEATURE(ARM_FEATURE_VFP4, ARM_HWCAP_ARM_VFPv4); + GET_FEATURE(ARM_FEATURE_ARM_DIV, ARM_HWCAP_ARM_IDIVA); + GET_FEATURE(ARM_FEATURE_THUMB_DIV, ARM_HWCAP_ARM_IDIVT); + /* All QEMU's VFPv3 CPUs have 32 registers, see VFP_DREG in translate.c. + * Note that the ARM_HWCAP_ARM_VFPv3D16 bit is always the inverse of + * ARM_HWCAP_ARM_VFPD32 (and so always clear for QEMU); it is unrelated + * to our VFP_FP16 feature bit. + */ + GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPD32); + GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE); + + return hwcaps; +} + +static uint32_t get_elf_hwcap2(void) +{ + ARMCPU *cpu = ARM_CPU(thread_cpu); + uint32_t hwcaps = 0; + + GET_FEATURE(ARM_FEATURE_V8_AES, ARM_HWCAP2_ARM_AES); + GET_FEATURE(ARM_FEATURE_CRC, ARM_HWCAP2_ARM_CRC32); + return hwcaps; +} + +#undef GET_FEATURE + +#else +/* 64 bit ARM definitions */ +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ((x) == ELF_MACHINE) + +#define ELF_ARCH ELF_MACHINE +#define ELF_CLASS ELFCLASS64 +#define ELF_PLATFORM "aarch64" + +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ + abi_long stack = infop->start_stack; + memset(regs, 0, sizeof(*regs)); + + regs->pc = infop->entry & ~0x3ULL; + regs->sp = stack; +} + +#define ELF_NREG 34 +typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; + +static void elf_core_copy_regs(target_elf_gregset_t *regs, + const CPUARMState *env) +{ + int i; + + for (i = 0; i < 32; i++) { + (*regs)[i] = tswapreg(env->xregs[i]); + } + (*regs)[32] = tswapreg(env->pc); + (*regs)[33] = tswapreg(pstate_read((CPUARMState *)env)); +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +enum { + ARM_HWCAP_A64_FP = 1 << 0, + ARM_HWCAP_A64_ASIMD = 1 << 1, + ARM_HWCAP_A64_EVTSTRM = 1 << 2, + ARM_HWCAP_A64_AES = 1 << 3, + ARM_HWCAP_A64_PMULL = 1 << 4, + ARM_HWCAP_A64_SHA1 = 1 << 5, + ARM_HWCAP_A64_SHA2 = 1 << 6, + ARM_HWCAP_A64_CRC32 = 1 << 7, +}; + +#define ELF_HWCAP get_elf_hwcap() + +static uint32_t get_elf_hwcap(void) +{ + ARMCPU *cpu = ARM_CPU(thread_cpu); + uint32_t hwcaps = 0; + + hwcaps |= ARM_HWCAP_A64_FP; + hwcaps |= ARM_HWCAP_A64_ASIMD; + + /* probe for the extra features */ +#define GET_FEATURE(feat, hwcap) \ + do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0) + GET_FEATURE(ARM_FEATURE_V8_AES, ARM_HWCAP_A64_PMULL); #undef GET_FEATURE return hwcaps; } -#endif +#endif /* not TARGET_AARCH64 */ +#endif /* TARGET_ARM */ #ifdef TARGET_UNICORE32 @@ -1407,6 +1507,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, #ifdef DLINFO_ARCH_ITEMS size += DLINFO_ARCH_ITEMS * 2; #endif +#ifdef ELF_HWCAP2 + size += 2; +#endif size += envc + argc + 2; size += 1; /* argc itself */ size *= n; @@ -1440,6 +1543,10 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes); +#ifdef ELF_HWCAP2 + NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2); +#endif + if (k_platform) NEW_AUX_ENT(AT_PLATFORM, u_platform); #ifdef ARCH_DLINFO @@ -1455,6 +1562,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, info->auxv_len = sp_auxv - sp; sp = loader_build_argptr(envc, argc, sp, p, 0); + /* Check the right amount of stack was allocated for auxvec, envp & argv. */ + assert(sp_auxv - sp == size); return sp; } diff --git a/linux-user/main.c b/linux-user/main.c index 947358a886..c38fecfdd9 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -69,7 +69,7 @@ unsigned long reserved_va; static void usage(void); static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; -const char *qemu_uname_release = CONFIG_UNAME_RELEASE; +const char *qemu_uname_release; /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so we allocate a bigger stack. Need a better solution, for example diff --git a/linux-user/signal.c b/linux-user/signal.c index 7d6246f448..5b8a01f998 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1242,8 +1242,7 @@ static int target_setup_sigframe(struct target_rt_sigframe *sf, __put_user(env->pc, &sf->uc.tuc_mcontext.pc); __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate); - __put_user(/*current->thread.fault_address*/ 0, - &sf->uc.tuc_mcontext.fault_address); + __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address); for (i = 0; i < TARGET_NSIG_WORDS; i++) { __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9864813b7a..6efeeff2bf 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -60,7 +60,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include <sys/statfs.h> #include <utime.h> #include <sys/sysinfo.h> -#include <sys/utsname.h> //#include <sys/user.h> #include <netinet/ip.h> #include <netinet/tcp.h> @@ -92,7 +91,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include <linux/termios.h> #include <linux/unistd.h> -#include <linux/utsname.h> #include <linux/cdrom.h> #include <linux/hdreg.h> #include <linux/soundcard.h> @@ -110,7 +108,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include <linux/filter.h> #include <linux/blkpg.h> #include "linux_loop.h" -#include "cpu-uname.h" +#include "uname.h" #include "qemu.h" @@ -198,6 +196,11 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \ #define __NR__llseek __NR_lseek #endif +/* Newer kernel ports have llseek() instead of _llseek() */ +#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek) +#define TARGET_NR__llseek TARGET_NR_llseek +#endif + #ifdef __NR_gettid _syscall0(int, gettid) #else @@ -282,40 +285,6 @@ static bitmask_transtbl fcntl_flags_tbl[] = { { 0, 0, 0, 0 } }; -#define COPY_UTSNAME_FIELD(dest, src) \ - do { \ - /* __NEW_UTS_LEN doesn't include terminating null */ \ - (void) strncpy((dest), (src), __NEW_UTS_LEN); \ - (dest)[__NEW_UTS_LEN] = '\0'; \ - } while (0) - -static int sys_uname(struct new_utsname *buf) -{ - struct utsname uts_buf; - - if (uname(&uts_buf) < 0) - return (-1); - - /* - * Just in case these have some differences, we - * translate utsname to new_utsname (which is the - * struct linux kernel uses). - */ - - memset(buf, 0, sizeof(*buf)); - COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname); - COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename); - COPY_UTSNAME_FIELD(buf->release, uts_buf.release); - COPY_UTSNAME_FIELD(buf->version, uts_buf.version); - COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine); -#ifdef _GNU_SOURCE - COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname); -#endif - return (0); - -#undef COPY_UTSNAME_FIELD -} - static int sys_getcwd1(char *buf, size_t size) { if (getcwd(buf, size) == NULL) { @@ -406,7 +375,7 @@ static int sys_inotify_init1(int flags) #endif #define __NR_sys_ppoll __NR_ppoll _syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds, - struct timespec *, timeout, const __sigset_t *, sigmask, + struct timespec *, timeout, const sigset_t *, sigmask, size_t, sigsetsize) #endif @@ -1242,25 +1211,51 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len)); - if ((cmsg->cmsg_level == SOL_SOCKET) && - (cmsg->cmsg_type == SCM_RIGHTS)) { - int *fd = (int *)data; - int *target_fd = (int *)target_data; - int i, numfds = len / sizeof(int); + switch (cmsg->cmsg_level) { + case SOL_SOCKET: + switch (cmsg->cmsg_type) { + case SCM_RIGHTS: + { + int *fd = (int *)data; + int *target_fd = (int *)target_data; + int i, numfds = len / sizeof(int); - for (i = 0; i < numfds; i++) - target_fd[i] = tswap32(fd[i]); - } else if ((cmsg->cmsg_level == SOL_SOCKET) && - (cmsg->cmsg_type == SO_TIMESTAMP) && - (len == sizeof(struct timeval))) { - /* copy struct timeval to target */ - struct timeval *tv = (struct timeval *)data; - struct target_timeval *target_tv = - (struct target_timeval *)target_data; - - target_tv->tv_sec = tswapal(tv->tv_sec); - target_tv->tv_usec = tswapal(tv->tv_usec); - } else { + for (i = 0; i < numfds; i++) + target_fd[i] = tswap32(fd[i]); + break; + } + case SO_TIMESTAMP: + { + struct timeval *tv = (struct timeval *)data; + struct target_timeval *target_tv = + (struct target_timeval *)target_data; + + if (len != sizeof(struct timeval)) + goto unimplemented; + + /* copy struct timeval to target */ + target_tv->tv_sec = tswapal(tv->tv_sec); + target_tv->tv_usec = tswapal(tv->tv_usec); + break; + } + case SCM_CREDENTIALS: + { + struct ucred *cred = (struct ucred *)data; + struct target_ucred *target_cred = + (struct target_ucred *)target_data; + + __put_user(cred->pid, &target_cred->pid); + __put_user(cred->uid, &target_cred->uid); + __put_user(cred->gid, &target_cred->gid); + break; + } + default: + goto unimplemented; + } + break; + + default: + unimplemented: gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); memcpy(target_data, data, len); @@ -4952,72 +4947,6 @@ int host_to_target_waitstatus(int status) return status; } -static int relstr_to_int(const char *s) -{ - /* Convert a uname release string like "2.6.18" to an integer - * of the form 0x020612. (Beware that 0x020612 is *not* 2.6.12.) - */ - int i, n, tmp; - - tmp = 0; - for (i = 0; i < 3; i++) { - n = 0; - while (*s >= '0' && *s <= '9') { - n *= 10; - n += *s - '0'; - s++; - } - tmp = (tmp << 8) + n; - if (*s == '.') { - s++; - } - } - return tmp; -} - -int get_osversion(void) -{ - static int osversion; - struct new_utsname buf; - const char *s; - - if (osversion) - return osversion; - if (qemu_uname_release && *qemu_uname_release) { - s = qemu_uname_release; - } else { - if (sys_uname(&buf)) - return 0; - s = buf.release; - } - osversion = relstr_to_int(s); - return osversion; -} - -void init_qemu_uname_release(void) -{ - /* Initialize qemu_uname_release for later use. - * If the host kernel is too old and the user hasn't asked for - * a specific fake version number, we might want to fake a minimum - * target kernel version. - */ -#ifdef UNAME_MINIMUM_RELEASE - struct new_utsname buf; - - if (qemu_uname_release && *qemu_uname_release) { - return; - } - - if (sys_uname(&buf)) { - return; - } - - if (relstr_to_int(buf.release) < relstr_to_int(UNAME_MINIMUM_RELEASE)) { - qemu_uname_release = UNAME_MINIMUM_RELEASE; - } -#endif -} - static int open_self_maps(void *cpu_env, int fd) { #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) @@ -5225,6 +5154,11 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) { NULL, NULL, NULL } }; + if (is_proc_myself(pathname, "exe")) { + int execfd = qemu_getauxval(AT_EXECFD); + return execfd ? execfd : get_errno(open(exec_path, flags, mode)); + } + for (fake_open = fakes; fake_open->filename; fake_open++) { if (fake_open->cmp(pathname, fake_open->filename)) { break; @@ -6309,7 +6243,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct rusage rusage; ret = get_errno(getrusage(arg1, &rusage)); if (!is_error(ret)) { - host_to_target_rusage(arg2, &rusage); + ret = host_to_target_rusage(arg2, &rusage); } } break; @@ -6974,6 +6908,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_long status_ptr = arg2; struct rusage rusage, *rusage_ptr; abi_ulong target_rusage = arg4; + abi_long rusage_err; if (target_rusage) rusage_ptr = &rusage; else @@ -6985,8 +6920,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (put_user_s32(status, status_ptr)) goto efault; } - if (target_rusage) - host_to_target_rusage(target_rusage, &rusage); + if (target_rusage) { + rusage_err = host_to_target_rusage(target_rusage, &rusage); + if (rusage_err) { + ret = rusage_err; + } + } } } break; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index fdf9a47595..69c3982ee6 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2552,12 +2552,26 @@ struct target_timer_t { abi_ulong ptr; }; +#define TARGET_SIGEV_MAX_SIZE 64 + +/* This is architecture-specific but most architectures use the default */ +#ifdef TARGET_MIPS +#define TARGET_SIGEV_PREAMBLE_SIZE (sizeof(int32_t) * 2 + sizeof(abi_long)) +#else +#define TARGET_SIGEV_PREAMBLE_SIZE (sizeof(int32_t) * 2 \ + + sizeof(target_sigval_t)) +#endif + +#define TARGET_SIGEV_PAD_SIZE ((TARGET_SIGEV_MAX_SIZE \ + - TARGET_SIGEV_PREAMBLE_SIZE) \ + / sizeof(int32_t)) + struct target_sigevent { target_sigval_t sigev_value; int32_t sigev_signo; int32_t sigev_notify; union { - int32_t _pad[ARRAY_SIZE(((struct sigevent *)0)->_sigev_un._pad)]; + int32_t _pad[TARGET_SIGEV_PAD_SIZE]; int32_t _tid; struct { diff --git a/linux-user/cpu-uname.c b/linux-user/uname.c index 5db6e89567..f5d4c66f59 100644 --- a/linux-user/cpu-uname.c +++ b/linux-user/uname.c @@ -21,7 +21,7 @@ #include "qemu.h" //#include "qemu-common.h" -#include "cpu-uname.h" +#include "uname.h" /* return highest utsname machine name for emulated instruction set * @@ -70,3 +70,102 @@ const char *cpu_to_uname_machine(void *cpu_env) return UNAME_MACHINE; #endif } + + +#define COPY_UTSNAME_FIELD(dest, src) \ + do { \ + /* __NEW_UTS_LEN doesn't include terminating null */ \ + (void) strncpy((dest), (src), __NEW_UTS_LEN); \ + (dest)[__NEW_UTS_LEN] = '\0'; \ + } while (0) + +int sys_uname(struct new_utsname *buf) +{ + struct utsname uts_buf; + + if (uname(&uts_buf) < 0) + return (-1); + + /* + * Just in case these have some differences, we + * translate utsname to new_utsname (which is the + * struct linux kernel uses). + */ + + memset(buf, 0, sizeof(*buf)); + COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname); + COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename); + COPY_UTSNAME_FIELD(buf->release, uts_buf.release); + COPY_UTSNAME_FIELD(buf->version, uts_buf.version); + COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine); +#ifdef _GNU_SOURCE + COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname); +#endif + return (0); + +#undef COPY_UTSNAME_FIELD +} + +static int relstr_to_int(const char *s) +{ + /* Convert a uname release string like "2.6.18" to an integer + * of the form 0x020612. (Beware that 0x020612 is *not* 2.6.12.) + */ + int i, n, tmp; + + tmp = 0; + for (i = 0; i < 3; i++) { + n = 0; + while (*s >= '0' && *s <= '9') { + n *= 10; + n += *s - '0'; + s++; + } + tmp = (tmp << 8) + n; + if (*s == '.') { + s++; + } + } + return tmp; +} + +int get_osversion(void) +{ + static int osversion; + struct new_utsname buf; + const char *s; + + if (osversion) + return osversion; + if (qemu_uname_release && *qemu_uname_release) { + s = qemu_uname_release; + } else { + if (sys_uname(&buf)) + return 0; + s = buf.release; + } + osversion = relstr_to_int(s); + return osversion; +} + +void init_qemu_uname_release(void) +{ + /* Initialize qemu_uname_release for later use. + * If the host kernel is too old and the user hasn't asked for + * a specific fake version number, we might want to fake a minimum + * target kernel version. + */ + struct new_utsname buf; + + if (qemu_uname_release && *qemu_uname_release) { + return; + } + + if (sys_uname(&buf)) { + return; + } + + if (relstr_to_int(buf.release) < relstr_to_int(UNAME_MINIMUM_RELEASE)) { + qemu_uname_release = UNAME_MINIMUM_RELEASE; + } +} diff --git a/linux-user/uname.h b/linux-user/uname.h new file mode 100644 index 0000000000..cc62e76cc1 --- /dev/null +++ b/linux-user/uname.h @@ -0,0 +1,10 @@ +#ifndef UNAME_H +#define UNAME_H 1 + +#include <sys/utsname.h> +#include <linux/utsname.h> + +const char *cpu_to_uname_machine(void *cpu_env); +int sys_uname(struct new_utsname *buf); + +#endif /* UNAME _H */ diff --git a/target-alpha/translate.c b/target-alpha/translate.c index d0357ff114..91c3ed1dd4 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -1201,7 +1201,7 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode) break; case 0x3A: /* RDUSP */ - tcg_gen_st_i64(cpu_ir[IR_V0], cpu_env, + tcg_gen_ld_i64(cpu_ir[IR_V0], cpu_env, offsetof(CPUAlphaState, usp)); break; case 0x3C: |