From 40645c7bfd7c4d45381927e1e80081fa827c368a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 19 Sep 2014 02:35:20 +0100 Subject: [PATCH 1/5] linux-user: Enable epoll_pwait syscall for ARM We have support for the epoll_pwait syscall, but it wasn't enabled for ARM guests because we hadn't defined the syscall number; correct this deficiency. Reported-by: Dave Flogeras Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/arm/syscall_nr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h index bef847cfae..7d7be7cfe9 100644 --- a/linux-user/arm/syscall_nr.h +++ b/linux-user/arm/syscall_nr.h @@ -350,7 +350,7 @@ #define TARGET_NR_vmsplice (343) #define TARGET_NR_move_pages (344) #define TARGET_NR_getcpu (345) - /* 346 for epoll_pwait */ +#define TARGET_NR_epoll_pwait (346) #define TARGET_NR_kexec_load (347) #define TARGET_NR_utimensat (348) #define TARGET_NR_signalfd (349) From a59b5e35d181599bc4114ceff3547ef47e713689 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 22 Aug 2014 13:15:50 +0200 Subject: [PATCH 2/5] linux-user: Convert blkpg to use a special subop handler The blkpg ioctl can take different payloads depending on the opcode in its payload structure. Create a new special ioctl handler that can only deal with partition style ones for now. This patch fixes running parted for me. Signed-off-by: Alexander Graf Signed-off-by: Riku Voipio --- linux-user/ioctls.h | 3 ++- linux-user/syscall.c | 53 ++++++++++++++++++++++++++++++++++++++ linux-user/syscall_types.h | 2 +- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 609b27cf0b..e672655100 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -78,7 +78,8 @@ IOCTL(BLKRAGET, IOC_R, MK_PTR(TYPE_LONG)) IOCTL(BLKSSZGET, IOC_R, MK_PTR(TYPE_LONG)) IOCTL(BLKBSZGET, IOC_R, MK_PTR(TYPE_INT)) - IOCTL(BLKPG, IOC_W, MK_PTR(MK_STRUCT(STRUCT_blkpg_ioctl_arg))) + IOCTL_SPECIAL(BLKPG, IOC_W, do_ioctl_blkpg, + MK_PTR(MK_STRUCT(STRUCT_blkpg_ioctl_arg))) #ifdef FIBMAP IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_LONG)) #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 8fe9df7b87..dcb9df90e6 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3696,6 +3696,59 @@ out: return ret; } +static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, + abi_long cmd, abi_long arg) +{ + void *argptr; + int target_size; + const argtype *arg_type = ie->arg_type; + const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) }; + abi_long ret; + + struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp; + struct blkpg_partition host_part; + + /* Read and convert blkpg */ + arg_type++; + target_size = thunk_type_size(arg_type, 0); + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) { + ret = -TARGET_EFAULT; + goto out; + } + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + + switch (host_blkpg->op) { + case BLKPG_ADD_PARTITION: + case BLKPG_DEL_PARTITION: + /* payload is struct blkpg_partition */ + break; + default: + /* Unknown opcode */ + ret = -TARGET_EINVAL; + goto out; + } + + /* Read and convert blkpg->data */ + arg = (abi_long)(uintptr_t)host_blkpg->data; + target_size = thunk_type_size(part_arg_type, 0); + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) { + ret = -TARGET_EFAULT; + goto out; + } + thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + + /* Swizzle the data pointer to our local copy and call! */ + host_blkpg->data = &host_part; + ret = get_errno(ioctl(fd, ie->host_cmd, host_blkpg)); + +out: + return ret; +} + static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, abi_long cmd, abi_long arg) { diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 9d0c92d054..1fd4ee0bfd 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -252,4 +252,4 @@ STRUCT(blkpg_ioctl_arg, TYPE_INT, /* op */ TYPE_INT, /* flags */ TYPE_INT, /* datalen */ - MK_PTR(MK_STRUCT(STRUCT_blkpg_partition))) /* data */ + TYPE_PTRVOID) /* data */ From e52a99f756eff14935edd1893dc9ec7660078f82 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 22 Aug 2014 13:56:18 +0200 Subject: [PATCH 3/5] linux-user: Simplify timerid checks on g_posix_timers range We check whether the passed in timer id is negative on all calls that involve g_posix_timers. However, these checks are bogus. First off we limit the timer_id to 16 bits which is not what Linux does. Then we check whether it's negative which it can't be because we masked it. We can safely remove the masking. For the negativity check we can just treat the timerid as unsigned and only check for upper boundaries. Signed-off-by: Alexander Graf Signed-off-by: Riku Voipio --- linux-user/syscall.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index dcb9df90e6..7087a56dd1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -9615,11 +9615,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { /* args: timer_t timerid, int flags, const struct itimerspec *new_value, * struct itimerspec * old_value */ - arg1 &= 0xffff; - if (arg3 == 0 || arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) { + target_ulong timerid = arg1; + + if (arg3 == 0 || timerid >= ARRAY_SIZE(g_posix_timers)) { ret = -TARGET_EINVAL; } else { - timer_t htimer = g_posix_timers[arg1]; + timer_t htimer = g_posix_timers[timerid]; struct itimerspec hspec_new = {{0},}, hspec_old = {{0},}; target_to_host_itimerspec(&hspec_new, arg3); @@ -9635,13 +9636,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_timer_gettime: { /* args: timer_t timerid, struct itimerspec *curr_value */ - arg1 &= 0xffff; + target_ulong timerid = arg1; + if (!arg2) { return -TARGET_EFAULT; - } else if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) { + } else if (timerid >= ARRAY_SIZE(g_posix_timers)) { ret = -TARGET_EINVAL; } else { - timer_t htimer = g_posix_timers[arg1]; + timer_t htimer = g_posix_timers[timerid]; struct itimerspec hspec; ret = get_errno(timer_gettime(htimer, &hspec)); @@ -9657,11 +9659,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_timer_getoverrun: { /* args: timer_t timerid */ - arg1 &= 0xffff; - if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) { + target_ulong timerid = arg1; + + if (timerid >= ARRAY_SIZE(g_posix_timers)) { ret = -TARGET_EINVAL; } else { - timer_t htimer = g_posix_timers[arg1]; + timer_t htimer = g_posix_timers[timerid]; ret = get_errno(timer_getoverrun(htimer)); } break; @@ -9672,13 +9675,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_timer_delete: { /* args: timer_t timerid */ - arg1 &= 0xffff; - if (arg1 < 0 || arg1 >= ARRAY_SIZE(g_posix_timers)) { + target_ulong timerid = arg1; + + if (timerid >= ARRAY_SIZE(g_posix_timers)) { ret = -TARGET_EINVAL; } else { - timer_t htimer = g_posix_timers[arg1]; + timer_t htimer = g_posix_timers[timerid]; ret = get_errno(timer_delete(htimer)); - g_posix_timers[arg1] = 0; + g_posix_timers[timerid] = 0; } break; } From d80a1905942afecafc04dba4bf51103cd30d37a1 Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Wed, 1 Oct 2014 16:05:46 +0300 Subject: [PATCH 4/5] linux-user: don't include timerfd if not needed Without this, builds on older systems fail with: qemu/linux-user/syscall.c:61:25: warning: sys/timerfd.h: No such file or directory v2: fix the usual case where CONFIG_TIMERFD is enabled.. Signed-off-by: Riku Voipio --- linux-user/syscall.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7087a56dd1..a175cc15f8 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -58,7 +58,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include #include -#include #include #include //#include @@ -67,6 +66,9 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include #include "qemu-common.h" +#ifdef CONFIG_TIMERFD +#include +#endif #ifdef TARGET_GPROF #include #endif From 1a1c4db9b298956e89caf53b09b6a7a960d55d66 Mon Sep 17 00:00:00 2001 From: Mikhail Ilyin Date: Mon, 8 Sep 2014 17:28:56 +0400 Subject: [PATCH 5/5] translate-all.c: memory walker initial address miscalculation The initial base address is miscalculated in walk_memory_regions(). It has to be shifted TARGET_PAGE_BITS more. Holder variables are extended to target_ulong size otherwise they don't fit for MIPS N32 (a 32-bit ABI with a 64-bit address space) and qemu won't compile. The issue led to incorrect debug output of memory maps and a mis-formed coredumped file. Signed-off-by: Mikhail Ilyin Signed-off-by: Riku Voipio --- include/exec/cpu-all.h | 4 ++-- linux-user/elfload.c | 18 +++++++++--------- translate-all.c | 33 ++++++++++++++++----------------- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index f9d132fc0b..c085804aed 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -232,8 +232,8 @@ extern uintptr_t qemu_host_page_mask; #if defined(CONFIG_USER_ONLY) void page_dump(FILE *f); -typedef int (*walk_memory_regions_fn)(void *, abi_ulong, - abi_ulong, unsigned long); +typedef int (*walk_memory_regions_fn)(void *, target_ulong, + target_ulong, unsigned long); int walk_memory_regions(void *, walk_memory_regions_fn); int page_get_flags(target_ulong address); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index bea803bd13..1c04fcf3cc 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2355,9 +2355,9 @@ struct elf_note_info { }; struct vm_area_struct { - abi_ulong vma_start; /* start vaddr of memory region */ - abi_ulong vma_end; /* end vaddr of memory region */ - abi_ulong vma_flags; /* protection etc. flags for the region */ + target_ulong vma_start; /* start vaddr of memory region */ + target_ulong vma_end; /* end vaddr of memory region */ + abi_ulong vma_flags; /* protection etc. flags for the region */ QTAILQ_ENTRY(vm_area_struct) vma_link; }; @@ -2368,13 +2368,13 @@ struct mm_struct { static struct mm_struct *vma_init(void); static void vma_delete(struct mm_struct *); -static int vma_add_mapping(struct mm_struct *, abi_ulong, - abi_ulong, abi_ulong); +static int vma_add_mapping(struct mm_struct *, target_ulong, + target_ulong, abi_ulong); static int vma_get_mapping_count(const struct mm_struct *); static struct vm_area_struct *vma_first(const struct mm_struct *); static struct vm_area_struct *vma_next(struct vm_area_struct *); static abi_ulong vma_dump_size(const struct vm_area_struct *); -static int vma_walker(void *priv, abi_ulong start, abi_ulong end, +static int vma_walker(void *priv, target_ulong start, target_ulong end, unsigned long flags); static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t); @@ -2466,8 +2466,8 @@ static void vma_delete(struct mm_struct *mm) g_free(mm); } -static int vma_add_mapping(struct mm_struct *mm, abi_ulong start, - abi_ulong end, abi_ulong flags) +static int vma_add_mapping(struct mm_struct *mm, target_ulong start, + target_ulong end, abi_ulong flags) { struct vm_area_struct *vma; @@ -2535,7 +2535,7 @@ static abi_ulong vma_dump_size(const struct vm_area_struct *vma) return (vma->vma_end - vma->vma_start); } -static int vma_walker(void *priv, abi_ulong start, abi_ulong end, +static int vma_walker(void *priv, target_ulong start, target_ulong end, unsigned long flags) { struct mm_struct *mm = (struct mm_struct *)priv; diff --git a/translate-all.c b/translate-all.c index 2e0265ae27..ba5c8403d3 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1660,30 +1660,30 @@ void cpu_interrupt(CPUState *cpu, int mask) struct walk_memory_regions_data { walk_memory_regions_fn fn; void *priv; - uintptr_t start; + target_ulong start; int prot; }; static int walk_memory_regions_end(struct walk_memory_regions_data *data, - abi_ulong end, int new_prot) + target_ulong end, int new_prot) { - if (data->start != -1ul) { + if (data->start != -1u) { int rc = data->fn(data->priv, data->start, end, data->prot); if (rc != 0) { return rc; } } - data->start = (new_prot ? end : -1ul); + data->start = (new_prot ? end : -1u); data->prot = new_prot; return 0; } static int walk_memory_regions_1(struct walk_memory_regions_data *data, - abi_ulong base, int level, void **lp) + target_ulong base, int level, void **lp) { - abi_ulong pa; + target_ulong pa; int i, rc; if (*lp == NULL) { @@ -1708,7 +1708,7 @@ static int walk_memory_regions_1(struct walk_memory_regions_data *data, void **pp = *lp; for (i = 0; i < V_L2_SIZE; ++i) { - pa = base | ((abi_ulong)i << + pa = base | ((target_ulong)i << (TARGET_PAGE_BITS + V_L2_BITS * level)); rc = walk_memory_regions_1(data, pa, level - 1, pp + i); if (rc != 0) { @@ -1727,13 +1727,12 @@ int walk_memory_regions(void *priv, walk_memory_regions_fn fn) data.fn = fn; data.priv = priv; - data.start = -1ul; + data.start = -1u; data.prot = 0; for (i = 0; i < V_L1_SIZE; i++) { - int rc = walk_memory_regions_1(&data, (abi_ulong)i << V_L1_SHIFT, + int rc = walk_memory_regions_1(&data, (target_ulong)i << (V_L1_SHIFT + TARGET_PAGE_BITS), V_L1_SHIFT / V_L2_BITS - 1, l1_map + i); - if (rc != 0) { return rc; } @@ -1742,13 +1741,13 @@ int walk_memory_regions(void *priv, walk_memory_regions_fn fn) return walk_memory_regions_end(&data, 0, 0); } -static int dump_region(void *priv, abi_ulong start, - abi_ulong end, unsigned long prot) +static int dump_region(void *priv, target_ulong start, + target_ulong end, unsigned long prot) { FILE *f = (FILE *)priv; - (void) fprintf(f, TARGET_ABI_FMT_lx"-"TARGET_ABI_FMT_lx - " "TARGET_ABI_FMT_lx" %c%c%c\n", + (void) fprintf(f, TARGET_FMT_lx"-"TARGET_FMT_lx + " "TARGET_FMT_lx" %c%c%c\n", start, end, end - start, ((prot & PAGE_READ) ? 'r' : '-'), ((prot & PAGE_WRITE) ? 'w' : '-'), @@ -1760,7 +1759,7 @@ static int dump_region(void *priv, abi_ulong start, /* dump memory mappings */ void page_dump(FILE *f) { - const int length = sizeof(abi_ulong) * 2; + const int length = sizeof(target_ulong) * 2; (void) fprintf(f, "%-*s %-*s %-*s %s\n", length, "start", length, "end", length, "size", "prot"); walk_memory_regions(f, dump_region); @@ -1788,7 +1787,7 @@ void page_set_flags(target_ulong start, target_ulong end, int flags) guest address space. If this assert fires, it probably indicates a missing call to h2g_valid. */ #if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS - assert(end < ((abi_ulong)1 << L1_MAP_ADDR_SPACE_BITS)); + assert(end < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS)); #endif assert(start < end); @@ -1825,7 +1824,7 @@ int page_check_range(target_ulong start, target_ulong len, int flags) guest address space. If this assert fires, it probably indicates a missing call to h2g_valid. */ #if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS - assert(start < ((abi_ulong)1 << L1_MAP_ADDR_SPACE_BITS)); + assert(start < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS)); #endif if (len == 0) {