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
This commit is contained in:
commit
497aebb99e
77
arm-semi.c
77
arm-semi.c
|
@ -373,42 +373,61 @@ 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;
|
||||
|
||||
s = cmdline_buffer;
|
||||
while (*arg && len > 2) {
|
||||
int n = strlen(*arg);
|
||||
|
||||
if (s != cmdline_buffer) {
|
||||
*(s++) = ' ';
|
||||
len--;
|
||||
if (!arm_cmdline_len || host_cmdline_len > arm_cmdline_len) {
|
||||
return -1; /* not enough space to store command line */
|
||||
}
|
||||
if (n >= len)
|
||||
n = len - 1;
|
||||
memcpy(s, *arg, n);
|
||||
s += n;
|
||||
len -= n;
|
||||
arg++;
|
||||
}
|
||||
/* Null terminate the string. */
|
||||
*s = 0;
|
||||
len = s - cmdline_buffer;
|
||||
|
||||
/* Unlock the buffer on the ARM side. */
|
||||
unlock_user(cmdline_buffer, ARG(0), len);
|
||||
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);
|
||||
|
||||
/* Adjust the commandline length argument. */
|
||||
SET_ARG(1, len);
|
||||
SET_ARG(1, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return success if commandline fit into buffer. */
|
||||
return *arg ? -1 : 0;
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -50,7 +50,6 @@ struct image_info {
|
|||
abi_ulong entry;
|
||||
abi_ulong code_offset;
|
||||
abi_ulong data_offset;
|
||||
char **host_argv;
|
||||
int personality;
|
||||
};
|
||||
|
||||
|
|
18
configure
vendored
18
configure
vendored
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -50,7 +50,6 @@ struct image_info {
|
|||
abi_ulong saved_auxv;
|
||||
abi_ulong arg_start;
|
||||
abi_ulong arg_end;
|
||||
char **host_argv;
|
||||
int personality;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
@ -7364,6 +7464,29 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
case TARGET_NR_fallocate:
|
||||
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:
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue