summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurelien Jarno <aurelien@aurel32.net>2011-01-08 16:25:48 +0100
committerAurelien Jarno <aurelien@aurel32.net>2011-01-08 16:25:48 +0100
commit497aebb99e0700ba30b9b8d1e86f3452dcb18b28 (patch)
tree78f9a68f060f06363012c3d78cef715c4a0859b7
parentcb752a608c514c1f493144f25828b3ff15049f5e (diff)
parent67af42ac5a6227d61a8ef4ba7289ada9418f2fb8 (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.c79
-rw-r--r--bsd-user/bsdload.c2
-rw-r--r--bsd-user/qemu.h1
-rwxr-xr-xconfigure18
-rw-r--r--fpu/softfloat.h11
-rw-r--r--linux-user/arm/nwfpe/fpa11_cprt.c14
-rw-r--r--linux-user/ioctls.h4
-rw-r--r--linux-user/linuxload.c2
-rw-r--r--linux-user/qemu.h1
-rw-r--r--linux-user/strace.list6
-rw-r--r--linux-user/syscall.c129
-rw-r--r--linux-user/syscall_defs.h1
-rw-r--r--linux-user/syscall_types.h16
13 files changed, 238 insertions, 46 deletions
diff --git a/arm-semi.c b/arm-semi.c
index 0687b0300..1d5179b60 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 14a93bf39..6d9bb6fb4 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 976361622..e343894ab 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;
};
diff --git a/configure b/configure
index 47e4cf04c..831a741c7 100755
--- a/configure
+++ b/configure
@@ -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 15052cc47..a6d0f16b4 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 0e61b585a..be54e9515 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 769e1bcb8..538e2572b 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 9ee27c355..ac8c486c5 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 e66a02bce..32de2413f 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 97b7f7691..d7be0e7a6 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 c3e870654..f10e17ae2 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 20c93d0f7..d02a9bf40 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 340dbd367..0e67cd8f3 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 */