diff options
author | Aurelien Jarno <aurelien@aurel32.net> | 2011-01-08 16:25:48 +0100 |
---|---|---|
committer | Aurelien Jarno <aurelien@aurel32.net> | 2011-01-08 16:25:48 +0100 |
commit | 497aebb99e0700ba30b9b8d1e86f3452dcb18b28 (patch) | |
tree | 78f9a68f060f06363012c3d78cef715c4a0859b7 | |
parent | cb752a608c514c1f493144f25828b3ff15049f5e (diff) | |
parent | 67af42ac5a6227d61a8ef4ba7289ada9418f2fb8 (diff) |
Merge branch 'linux-user-for-upstream' of git://gitorious.org/qemu-maemo/qemu
* 'linux-user-for-upstream' of git://gitorious.org/qemu-maemo/qemu:
Remove dead code for ARM semihosting commandline handling
Fix commandline handling for ARM semihosted executables
linux-user: Fix incorrect NaN detection in ARM nwfpe emulation
softfloat: Implement floatx80_is_any_nan() and float128_is_any_nan()
linux-user: Implement FS_IOC_FIEMAP ioctl
linux-user: Support ioctls whose parameter size is not constant
linux-user: Implement sync_file_range{,2} syscalls
-rw-r--r-- | arm-semi.c | 79 | ||||
-rw-r--r-- | bsd-user/bsdload.c | 2 | ||||
-rw-r--r-- | bsd-user/qemu.h | 1 | ||||
-rwxr-xr-x | configure | 18 | ||||
-rw-r--r-- | fpu/softfloat.h | 11 | ||||
-rw-r--r-- | linux-user/arm/nwfpe/fpa11_cprt.c | 14 | ||||
-rw-r--r-- | linux-user/ioctls.h | 4 | ||||
-rw-r--r-- | linux-user/linuxload.c | 2 | ||||
-rw-r--r-- | linux-user/qemu.h | 1 | ||||
-rw-r--r-- | linux-user/strace.list | 6 | ||||
-rw-r--r-- | linux-user/syscall.c | 129 | ||||
-rw-r--r-- | linux-user/syscall_defs.h | 1 | ||||
-rw-r--r-- | linux-user/syscall_types.h | 16 |
13 files changed, 238 insertions, 46 deletions
diff --git a/arm-semi.c b/arm-semi.c index 0687b03006..1d5179b601 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -373,45 +373,64 @@ uint32_t do_arm_semihosting(CPUState *env) #ifdef CONFIG_USER_ONLY /* Build a commandline from the original argv. */ { - char **arg = ts->info->host_argv; - int len = ARG(1); - /* lock the buffer on the ARM side */ - char *cmdline_buffer = (char*)lock_user(VERIFY_WRITE, ARG(0), len, 0); + char *arm_cmdline_buffer; + const char *host_cmdline_buffer; - if (!cmdline_buffer) - /* FIXME - should this error code be -TARGET_EFAULT ? */ - return (uint32_t)-1; + unsigned int i; + unsigned int arm_cmdline_len = ARG(1); + unsigned int host_cmdline_len = + ts->info->arg_end-ts->info->arg_start; + + if (!arm_cmdline_len || host_cmdline_len > arm_cmdline_len) { + return -1; /* not enough space to store command line */ + } - s = cmdline_buffer; - while (*arg && len > 2) { - int n = strlen(*arg); + if (!host_cmdline_len) { + /* We special-case the "empty command line" case (argc==0). + Just provide the terminating 0. */ + arm_cmdline_buffer = lock_user(VERIFY_WRITE, ARG(0), 1, 0); + arm_cmdline_buffer[0] = 0; + unlock_user(arm_cmdline_buffer, ARG(0), 1); - if (s != cmdline_buffer) { - *(s++) = ' '; - len--; - } - if (n >= len) - n = len - 1; - memcpy(s, *arg, n); - s += n; - len -= n; - arg++; + /* Adjust the commandline length argument. */ + SET_ARG(1, 0); + return 0; } - /* Null terminate the string. */ - *s = 0; - len = s - cmdline_buffer; - /* Unlock the buffer on the ARM side. */ - unlock_user(cmdline_buffer, ARG(0), len); + /* lock the buffers on the ARM side */ + arm_cmdline_buffer = + lock_user(VERIFY_WRITE, ARG(0), host_cmdline_len, 0); + host_cmdline_buffer = + lock_user(VERIFY_READ, ts->info->arg_start, + host_cmdline_len, 1); - /* Adjust the commandline length argument. */ - SET_ARG(1, len); + if (arm_cmdline_buffer && host_cmdline_buffer) + { + /* the last argument is zero-terminated; + no need for additional termination */ + memcpy(arm_cmdline_buffer, host_cmdline_buffer, + host_cmdline_len); - /* Return success if commandline fit into buffer. */ - return *arg ? -1 : 0; + /* separate arguments by white spaces */ + for (i = 0; i < host_cmdline_len-1; i++) { + if (arm_cmdline_buffer[i] == 0) { + arm_cmdline_buffer[i] = ' '; + } + } + + /* Adjust the commandline length argument. */ + SET_ARG(1, host_cmdline_len-1); + } + + /* Unlock the buffers on the ARM side. */ + unlock_user(arm_cmdline_buffer, ARG(0), host_cmdline_len); + unlock_user((void*)host_cmdline_buffer, ts->info->arg_start, 0); + + /* Return success if we could return a commandline. */ + return (arm_cmdline_buffer && host_cmdline_buffer) ? 0 : -1; } #else - return -1; + return -1; #endif case SYS_HEAPINFO: { diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c index 14a93bf39b..6d9bb6fb4e 100644 --- a/bsd-user/bsdload.c +++ b/bsd-user/bsdload.c @@ -176,8 +176,6 @@ int loader_exec(const char * filename, char ** argv, char ** envp, retval = prepare_binprm(&bprm); - infop->host_argv = argv; - if(retval>=0) { if (bprm.buf[0] == 0x7f && bprm.buf[1] == 'E' diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 976361622d..e343894ab1 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -50,7 +50,6 @@ struct image_info { abi_ulong entry; abi_ulong code_offset; abi_ulong data_offset; - char **host_argv; int personality; }; @@ -2075,6 +2075,21 @@ if compile_prog "$ARCH_CFLAGS" "" ; then fallocate=yes fi +# check for sync_file_range +sync_file_range=no +cat > $TMPC << EOF +#include <fcntl.h> + +int main(void) +{ + sync_file_range(0, 0, 0, 0); + return 0; +} +EOF +if compile_prog "$ARCH_CFLAGS" "" ; then + sync_file_range=yes +fi + # check for dup3 dup3=no cat > $TMPC << EOF @@ -2613,6 +2628,9 @@ fi if test "$fallocate" = "yes" ; then echo "CONFIG_FALLOCATE=y" >> $config_host_mak fi +if test "$sync_file_range" = "yes" ; then + echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak +fi if test "$dup3" = "yes" ; then echo "CONFIG_DUP3=y" >> $config_host_mak fi diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 15052cc470..a6d0f16b42 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -489,6 +489,11 @@ INLINE int floatx80_is_zero(floatx80 a) return (a.high & 0x7fff) == 0 && a.low == 0; } +INLINE int floatx80_is_any_nan(floatx80 a) +{ + return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1); +} + #endif #ifdef FLOAT128 @@ -556,6 +561,12 @@ INLINE int float128_is_zero(float128 a) return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0; } +INLINE int float128_is_any_nan(float128 a) +{ + return ((a.high >> 48) & 0x7fff) == 0x7fff && + ((a.low != 0) || ((a.high & 0xffffffffffffLL) != 0)); +} + #endif #else /* CONFIG_SOFTFLOAT */ diff --git a/linux-user/arm/nwfpe/fpa11_cprt.c b/linux-user/arm/nwfpe/fpa11_cprt.c index 0e61b585a0..be54e9515d 100644 --- a/linux-user/arm/nwfpe/fpa11_cprt.c +++ b/linux-user/arm/nwfpe/fpa11_cprt.c @@ -199,21 +199,21 @@ static unsigned int PerformComparison(const unsigned int opcode) { case typeSingle: //printk("single.\n"); - if (float32_is_quiet_nan(fpa11->fpreg[Fn].fSingle)) + if (float32_is_any_nan(fpa11->fpreg[Fn].fSingle)) goto unordered; rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); break; case typeDouble: //printk("double.\n"); - if (float64_is_quiet_nan(fpa11->fpreg[Fn].fDouble)) + if (float64_is_any_nan(fpa11->fpreg[Fn].fDouble)) goto unordered; rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; case typeExtended: //printk("extended.\n"); - if (floatx80_is_quiet_nan(fpa11->fpreg[Fn].fExtended)) + if (floatx80_is_any_nan(fpa11->fpreg[Fn].fExtended)) goto unordered; rFn = fpa11->fpreg[Fn].fExtended; break; @@ -225,7 +225,7 @@ static unsigned int PerformComparison(const unsigned int opcode) { //printk("Fm is a constant: #%d.\n",Fm); rFm = getExtendedConstant(Fm); - if (floatx80_is_quiet_nan(rFm)) + if (floatx80_is_any_nan(rFm)) goto unordered; } else @@ -235,21 +235,21 @@ static unsigned int PerformComparison(const unsigned int opcode) { case typeSingle: //printk("single.\n"); - if (float32_is_quiet_nan(fpa11->fpreg[Fm].fSingle)) + if (float32_is_any_nan(fpa11->fpreg[Fm].fSingle)) goto unordered; rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); break; case typeDouble: //printk("double.\n"); - if (float64_is_quiet_nan(fpa11->fpreg[Fm].fDouble)) + if (float64_is_any_nan(fpa11->fpreg[Fm].fDouble)) goto unordered; rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); break; case typeExtended: //printk("extended.\n"); - if (floatx80_is_quiet_nan(fpa11->fpreg[Fm].fExtended)) + if (floatx80_is_any_nan(fpa11->fpreg[Fm].fExtended)) goto unordered; rFm = fpa11->fpreg[Fm].fExtended; break; diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 769e1bcb81..538e2572bb 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -76,6 +76,10 @@ #ifdef FIGETBSZ IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG)) #endif +#ifdef FS_IOC_FIEMAP + IOCTL_SPECIAL(FS_IOC_FIEMAP, IOC_W | IOC_R, do_ioctl_fs_ioc_fiemap, + MK_PTR(MK_STRUCT(STRUCT_fiemap))) +#endif IOCTL(SIOCATMARK, 0, TYPE_NULL) IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 9ee27c3558..ac8c486c5f 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -174,8 +174,6 @@ int loader_exec(const char * filename, char ** argv, char ** envp, retval = prepare_binprm(bprm); - infop->host_argv = argv; - if(retval>=0) { if (bprm->buf[0] == 0x7f && bprm->buf[1] == 'E' diff --git a/linux-user/qemu.h b/linux-user/qemu.h index e66a02bce3..32de2413f8 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -50,7 +50,6 @@ struct image_info { abi_ulong saved_auxv; abi_ulong arg_start; abi_ulong arg_end; - char **host_argv; int personality; }; diff --git a/linux-user/strace.list b/linux-user/strace.list index 97b7f7691d..d7be0e7a68 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -1518,3 +1518,9 @@ #ifdef TARGET_NR_utimensat { TARGET_NR_utimensat, "utimensat", NULL, print_utimensat, NULL }, #endif +#ifdef TARGET_NR_sync_file_range +{ TARGET_NR_sync_file_range, "sync_file_range", NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_sync_file_range2 +{ TARGET_NR_sync_file_range2, "sync_file_range2", NULL, NULL, NULL }, +#endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c3e870654d..f10e17ae23 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -83,6 +83,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include <linux/kd.h> #include <linux/mtio.h> #include <linux/fs.h> +#include <linux/fiemap.h> #include <linux/fb.h> #include <linux/vt.h> #include "linux_loop.h" @@ -2965,13 +2966,19 @@ enum { #undef STRUCT #undef STRUCT_SPECIAL -typedef struct IOCTLEntry { +typedef struct IOCTLEntry IOCTLEntry; + +typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, abi_long cmd, abi_long arg); + +struct IOCTLEntry { unsigned int target_cmd; unsigned int host_cmd; const char *name; int access; + do_ioctl_fn *do_ioctl; const argtype arg_type[5]; -} IOCTLEntry; +}; #define IOC_R 0x0001 #define IOC_W 0x0002 @@ -2979,9 +2986,98 @@ typedef struct IOCTLEntry { #define MAX_STRUCT_SIZE 4096 +/* So fiemap access checks don't overflow on 32 bit systems. + * This is very slightly smaller than the limit imposed by + * the underlying kernel. + */ +#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \ + / sizeof(struct fiemap_extent)) + +static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, abi_long cmd, abi_long arg) +{ + /* The parameter for this ioctl is a struct fiemap followed + * by an array of struct fiemap_extent whose size is set + * in fiemap->fm_extent_count. The array is filled in by the + * ioctl. + */ + int target_size_in, target_size_out; + struct fiemap *fm; + const argtype *arg_type = ie->arg_type; + const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) }; + void *argptr, *p; + abi_long ret; + int i, extent_size = thunk_type_size(extent_arg_type, 0); + uint32_t outbufsz; + int free_fm = 0; + + assert(arg_type[0] == TYPE_PTR); + assert(ie->access == IOC_RW); + arg_type++; + target_size_in = thunk_type_size(arg_type, 0); + argptr = lock_user(VERIFY_READ, arg, target_size_in, 1); + if (!argptr) { + return -TARGET_EFAULT; + } + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + fm = (struct fiemap *)buf_temp; + if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) { + return -TARGET_EINVAL; + } + + outbufsz = sizeof (*fm) + + (sizeof(struct fiemap_extent) * fm->fm_extent_count); + + if (outbufsz > MAX_STRUCT_SIZE) { + /* We can't fit all the extents into the fixed size buffer. + * Allocate one that is large enough and use it instead. + */ + fm = malloc(outbufsz); + if (!fm) { + return -TARGET_ENOMEM; + } + memcpy(fm, buf_temp, sizeof(struct fiemap)); + free_fm = 1; + } + ret = get_errno(ioctl(fd, ie->host_cmd, fm)); + if (!is_error(ret)) { + target_size_out = target_size_in; + /* An extent_count of 0 means we were only counting the extents + * so there are no structs to copy + */ + if (fm->fm_extent_count != 0) { + target_size_out += fm->fm_mapped_extents * extent_size; + } + argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0); + if (!argptr) { + ret = -TARGET_EFAULT; + } else { + /* Convert the struct fiemap */ + thunk_convert(argptr, fm, arg_type, THUNK_TARGET); + if (fm->fm_extent_count != 0) { + p = argptr + target_size_in; + /* ...and then all the struct fiemap_extents */ + for (i = 0; i < fm->fm_mapped_extents; i++) { + thunk_convert(p, &fm->fm_extents[i], extent_arg_type, + THUNK_TARGET); + p += extent_size; + } + } + unlock_user(argptr, arg, target_size_out); + } + } + if (free_fm) { + free(fm); + } + return ret; +} + static IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, ...) \ - { TARGET_ ## cmd, cmd, #cmd, access, { __VA_ARGS__ } }, + { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } }, +#define IOCTL_SPECIAL(cmd, access, dofn, ...) \ + { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } }, #include "ioctls.h" { 0, 0, }, }; @@ -3011,6 +3107,10 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) #if defined(DEBUG) gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name); #endif + if (ie->do_ioctl) { + return ie->do_ioctl(ie, buf_temp, fd, cmd, arg); + } + switch(arg_type[0]) { case TYPE_NULL: /* no argument */ @@ -7365,6 +7465,29 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(fallocate(arg1, arg2, arg3, arg4)); break; #endif +#if defined(CONFIG_SYNC_FILE_RANGE) +#if defined(TARGET_NR_sync_file_range) + case TARGET_NR_sync_file_range: +#if TARGET_ABI_BITS == 32 + ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3), + target_offset64(arg4, arg5), arg6)); +#else + ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4)); +#endif + break; +#endif +#if defined(TARGET_NR_sync_file_range2) + case TARGET_NR_sync_file_range2: + /* This is like sync_file_range but the arguments are reordered */ +#if TARGET_ABI_BITS == 32 + ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4), + target_offset64(arg5, arg6), arg2)); +#else + ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2)); +#endif + break; +#endif +#endif default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 20c93d0f7f..d02a9bf401 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -783,6 +783,7 @@ struct target_pollfd { #define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */ #define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */ #define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */ +#define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap) /* cdrom commands */ #define TARGET_CDROMPAUSE 0x5301 /* Pause Audio Operation */ diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 340dbd367f..0e67cd8f30 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -165,3 +165,19 @@ STRUCT(vt_stat, TYPE_SHORT, /* v_active */ TYPE_SHORT, /* v_signal */ TYPE_SHORT) /* v_state */ + +STRUCT(fiemap_extent, + TYPE_ULONGLONG, /* fe_logical */ + TYPE_ULONGLONG, /* fe_physical */ + TYPE_ULONGLONG, /* fe_length */ + MK_ARRAY(TYPE_ULONGLONG, 2), /* fe_reserved64[2] */ + TYPE_INT, /* fe_flags */ + MK_ARRAY(TYPE_INT, 3)) /* fe_reserved[3] */ + +STRUCT(fiemap, + TYPE_ULONGLONG, /* fm_start */ + TYPE_ULONGLONG, /* fm_length */ + TYPE_INT, /* fm_flags */ + TYPE_INT, /* fm_mapped_extents */ + TYPE_INT, /* fm_extent_count */ + TYPE_INT) /* fm_reserved */ |