From 6672b0b22a8ab92ad3a07889c2220a7568a3da30 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 20 Jan 2011 03:28:02 +0000 Subject: [PATCH 01/12] linux-user: Add support for -version option Add support to the linux-user qemu for the -version command line option, bringing it into line with the system emulation qemu. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/main.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 0d627d68dd..e651bfdad8 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2624,14 +2624,21 @@ void cpu_loop (CPUState *env) } #endif /* TARGET_ALPHA */ +static void version(void) +{ + printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION + ", Copyright (c) 2003-2008 Fabrice Bellard\n"); +} + static void usage(void) { - printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n" - "usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n" + version(); + printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n" "Linux CPU emulator (compiled for %s emulation)\n" "\n" "Standard options:\n" "-h print this help\n" + "-version display version information and exit\n" "-g port wait gdb connection to port\n" "-L path set the elf interpreter prefix (default=%s)\n" "-s size set the stack size in bytes (default=%ld)\n" @@ -2886,8 +2893,10 @@ int main(int argc, char **argv, char **envp) singlestep = 1; } else if (!strcmp(r, "strace")) { do_strace = 1; - } else - { + } else if (!strcmp(r, "version")) { + version(); + exit(0); + } else { usage(); } } From 8d79de6e42947a4a11ad7c7bb87e8f745a4f8321 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 17 Jan 2011 21:36:06 +0100 Subject: [PATCH 02/12] linux-user: Fix possible realloc memory leak Extract from "man realloc": "If realloc() fails the original block is left untouched; it is not freed or moved." Fix a possible memory leak (reported by cppcheck). Cc: Riku Voipio Signed-off-by: Stefan Weil Signed-off-by: Riku Voipio --- linux-user/elfload.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 33d776de41..08c44d8933 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1481,7 +1481,7 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) struct elf_shdr *shdr; char *strings; struct syminfo *s; - struct elf_sym *syms; + struct elf_sym *syms, *new_syms; shnum = hdr->e_shnum; i = shnum * sizeof(struct elf_shdr); @@ -1550,12 +1550,14 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) that we threw away. Whether or not this has any effect on the memory allocation depends on the malloc implementation and how many symbols we managed to discard. */ - syms = realloc(syms, nsyms * sizeof(*syms)); - if (syms == NULL) { + new_syms = realloc(syms, nsyms * sizeof(*syms)); + if (new_syms == NULL) { free(s); + free(syms); free(strings); return; } + syms = new_syms; qsort(syms, nsyms, sizeof(*syms), symcmp); From 73160d952922157f16946e8ebb4419072de4c657 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 7 Feb 2011 01:05:49 -0500 Subject: [PATCH 03/12] linux-user: fix sizeof handling for getsockopt Signed-off-by: Mike Frysinger Signed-off-by: Riku Voipio --- linux-user/syscall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 499c4d7d62..6116ab5f0c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1448,7 +1448,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, return -TARGET_EFAULT; if (len < 0) return -TARGET_EINVAL; - lv = sizeof(int); + lv = sizeof(lv); ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); if (ret < 0) return ret; @@ -1485,7 +1485,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, return -TARGET_EFAULT; if (len < 0) return -TARGET_EINVAL; - lv = sizeof(int); + lv = sizeof(lv); ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); if (ret < 0) return ret; From 1af02e83c00fe269fbbaeaccc7c0b914ad277d18 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 7 Feb 2011 01:05:50 -0500 Subject: [PATCH 04/12] linux-user/elfload: add FDPIC support Signed-off-by: Mike Frysinger Signed-off-by: Riku Voipio --- elf.h | 19 ++++++++++++ linux-user/elfload.c | 71 ++++++++++++++++++++++++++++++++++++++++++++ linux-user/qemu.h | 7 +++++ 3 files changed, 97 insertions(+) diff --git a/elf.h b/elf.h index 7067c90fb0..d2f24f466d 100644 --- a/elf.h +++ b/elf.h @@ -1191,6 +1191,25 @@ typedef struct elf64_note { Elf64_Word n_type; /* Content type */ } Elf64_Nhdr; + +/* This data structure represents a PT_LOAD segment. */ +struct elf32_fdpic_loadseg { + /* Core address to which the segment is mapped. */ + Elf32_Addr addr; + /* VMA recorded in the program header. */ + Elf32_Addr p_vaddr; + /* Size of this segment in memory. */ + Elf32_Word p_memsz; +}; +struct elf32_fdpic_loadmap { + /* Protocol version number, must be zero. */ + Elf32_Half version; + /* Number of segments in this map. */ + Elf32_Half nsegs; + /* The actual memory map. */ + struct elf32_fdpic_loadseg segs[/*nsegs*/]; +}; + #ifdef ELF_CLASS #if ELF_CLASS == ELFCLASS32 diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 08c44d8933..2de83e4bfb 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1075,6 +1075,33 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot) } } +#ifdef CONFIG_USE_FDPIC +static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp) +{ + uint16_t n; + struct elf32_fdpic_loadseg *loadsegs = info->loadsegs; + + /* elf32_fdpic_loadseg */ + n = info->nsegs; + while (n--) { + sp -= 12; + put_user_u32(loadsegs[n].addr, sp+0); + put_user_u32(loadsegs[n].p_vaddr, sp+4); + put_user_u32(loadsegs[n].p_memsz, sp+8); + } + + /* elf32_fdpic_loadmap */ + sp -= 4; + put_user_u16(0, sp+0); /* version */ + put_user_u16(info->nsegs, sp+2); /* nsegs */ + + info->personality = PER_LINUX_FDPIC; + info->loadmap_addr = sp; + + return sp; +} +#endif + static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, struct elfhdr *exec, struct image_info *info, @@ -1087,6 +1114,21 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, const int n = sizeof(elf_addr_t); sp = p; + +#ifdef CONFIG_USE_FDPIC + /* Needs to be before we load the env/argc/... */ + if (elf_is_fdpic(exec)) { + /* Need 4 byte alignment for these structs */ + sp &= ~3; + sp = loader_build_fdpic_loadmap(info, sp); + info->other_info = interp_info; + if (interp_info) { + interp_info->other_info = info; + sp = loader_build_fdpic_loadmap(interp_info, sp); + } + } +#endif + u_platform = 0; k_platform = ELF_PLATFORM; if (k_platform) { @@ -1197,6 +1239,11 @@ static void load_elf_image(const char *image_name, int image_fd, } bswap_phdr(phdr, ehdr->e_phnum); +#ifdef CONFIG_USE_FDPIC + info->nsegs = 0; + info->pt_dynamic_addr = 0; +#endif + /* Find the maximum size of the image and allocate an appropriate amount of memory to handle that. */ loaddr = -1, hiaddr = 0; @@ -1210,6 +1257,9 @@ static void load_elf_image(const char *image_name, int image_fd, if (a > hiaddr) { hiaddr = a; } +#ifdef CONFIG_USE_FDPIC + ++info->nsegs; +#endif } } @@ -1290,6 +1340,27 @@ static void load_elf_image(const char *image_name, int image_fd, } load_bias = load_addr - loaddr; +#ifdef CONFIG_USE_FDPIC + { + struct elf32_fdpic_loadseg *loadsegs = info->loadsegs = + qemu_malloc(sizeof(*loadsegs) * info->nsegs); + + for (i = 0; i < ehdr->e_phnum; ++i) { + switch (phdr[i].p_type) { + case PT_DYNAMIC: + info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias; + break; + case PT_LOAD: + loadsegs->addr = phdr[i].p_vaddr + load_bias; + loadsegs->p_vaddr = phdr[i].p_vaddr; + loadsegs->p_memsz = phdr[i].p_memsz; + ++loadsegs; + break; + } + } + } +#endif + info->load_bias = load_bias; info->load_addr = load_addr; info->entry = ehdr->e_entry + load_bias; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 32de2413f8..250814d9f7 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -51,6 +51,13 @@ struct image_info { abi_ulong arg_start; abi_ulong arg_end; int personality; +#ifdef CONFIG_USE_FDPIC + abi_ulong loadmap_addr; + uint16_t nsegs; + void *loadsegs; + abi_ulong pt_dynamic_addr; + struct image_info *other_info; +#endif }; #ifdef TARGET_I386 From d8035d4cfce42e0268e39e109d5abf01d9f25259 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 7 Feb 2011 01:05:51 -0500 Subject: [PATCH 05/12] linux-user: add ppoll syscall support Some architectures (like Blackfin) only implement ppoll (and skip poll). So add support for it using existing poll code. Reviewed-by: Peter Maydell Signed-off-by: Mike Frysinger Signed-off-by: Riku Voipio --- linux-user/syscall.c | 57 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 6116ab5f0c..bb6ef43a9e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -529,6 +529,15 @@ static int sys_inotify_init1(int flags) #undef TARGET_NR_inotify_rm_watch #endif /* CONFIG_INOTIFY */ +#if defined(TARGET_NR_ppoll) +#ifndef __NR_ppoll +# define __NR_ppoll -1 +#endif +#define __NR_sys_ppoll __NR_ppoll +_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds, + struct timespec *, timeout, const __sigset_t *, sigmask, + size_t, sigsetsize) +#endif extern int personality(int); extern int flock(int, int); @@ -6230,8 +6239,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = do_select(arg1, arg2, arg3, arg4, arg5); break; #endif -#ifdef TARGET_NR_poll +#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll) +# ifdef TARGET_NR_poll case TARGET_NR_poll: +# endif +# ifdef TARGET_NR_ppoll + case TARGET_NR_ppoll: +# endif { struct target_pollfd *target_pfd; unsigned int nfds = arg2; @@ -6242,12 +6256,51 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1); if (!target_pfd) goto efault; + pfd = alloca(sizeof(struct pollfd) * nfds); for(i = 0; i < nfds; i++) { pfd[i].fd = tswap32(target_pfd[i].fd); pfd[i].events = tswap16(target_pfd[i].events); } - ret = get_errno(poll(pfd, nfds, timeout)); + +# ifdef TARGET_NR_ppoll + if (num == TARGET_NR_ppoll) { + struct timespec _timeout_ts, *timeout_ts = &_timeout_ts; + target_sigset_t *target_set; + sigset_t _set, *set = &_set; + + if (arg3) { + if (target_to_host_timespec(timeout_ts, arg3)) { + unlock_user(target_pfd, arg1, 0); + goto efault; + } + } else { + timeout_ts = NULL; + } + + if (arg4) { + target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1); + if (!target_set) { + unlock_user(target_pfd, arg1, 0); + goto efault; + } + target_to_host_sigset(set, target_set); + } else { + set = NULL; + } + + ret = get_errno(sys_ppoll(pfd, nfds, timeout_ts, set, _NSIG/8)); + + if (!is_error(ret) && arg3) { + host_to_target_timespec(arg3, timeout_ts); + } + if (arg4) { + unlock_user(target_set, arg4, 0); + } + } else +# endif + ret = get_errno(poll(pfd, nfds, timeout)); + if (!is_error(ret)) { for(i = 0; i < nfds; i++) { target_pfd[i].revents = tswap16(pfd[i].revents); From 906c1b8ec8ed8987662e2697af20b9ca19c659b5 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 7 Feb 2011 01:05:52 -0500 Subject: [PATCH 06/12] linux-user: decode MAP_{UNINITIALIZED,EXECUTABLE} in strace Signed-off-by: Mike Frysinger Signed-off-by: Riku Voipio --- linux-user/strace.c | 4 ++++ linux-user/syscall_defs.h | 1 + 2 files changed, 5 insertions(+) diff --git a/linux-user/strace.c b/linux-user/strace.c index bf9a0d9391..a8786bb9e0 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -398,6 +398,7 @@ UNUSED static struct flags mmap_flags[] = { FLAG_TARGET(MAP_DENYWRITE), FLAG_TARGET(MAP_FIXED), FLAG_TARGET(MAP_GROWSDOWN), + FLAG_TARGET(MAP_EXECUTABLE), #ifdef MAP_LOCKED FLAG_TARGET(MAP_LOCKED), #endif @@ -407,6 +408,9 @@ UNUSED static struct flags mmap_flags[] = { FLAG_TARGET(MAP_NORESERVE), #ifdef MAP_POPULATE FLAG_TARGET(MAP_POPULATE), +#endif +#ifdef TARGET_MAP_UNINITIALIZED + FLAG_TARGET(MAP_UNINITIALIZED), #endif FLAG_END, }; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index d02a9bf401..4742ac0272 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -999,6 +999,7 @@ struct target_winsize { #define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */ #define TARGET_MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ #define TARGET_MAP_NONBLOCK 0x10000 /* do not block on IO */ +#define TARGET_MAP_UNINITIALIZED 0x4000000 /* for anonymous mmap, memory could be uninitialized */ #endif #if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_CRIS) From 82a39595f7c70aecfb4649ae5a125147b62131f8 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 7 Feb 2011 01:05:53 -0500 Subject: [PATCH 07/12] linux-user/FLAT: fix auto-stack sizing The current auto-stack sizing works like it does on a NOMMU system; the problem is that this only works if the envp/argv arrays are fairly slim. On a desktop system, this is rarely the case, and can easily blow past the stack and into data/text regions as the default stack for FLAT progs is a mere 4KiB. So rather than rely on the NOMMU calculation (which is only there because NOMMU can't easily allocate gobs of contiguous mem), calc the full space actually needed and let the MMU host make space. Signed-off-by: Mike Frysinger Signed-off-by: Riku Voipio --- linux-user/flatload.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 8f9f4a5fcc..d8b4476325 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -733,8 +733,15 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, * pedantic and include space for the argv/envp array as it may have * a lot of entries. */ -#define TOP_OF_ARGS (TARGET_PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *)) - stack_len = TOP_OF_ARGS - bprm->p; /* the strings */ + stack_len = 0; + for (i = 0; i < bprm->argc; ++i) { + /* the argv strings */ + stack_len += strlen(bprm->argv[i]); + } + for (i = 0; i < bprm->envc; ++i) { + /* the envp strings */ + stack_len += strlen(bprm->envp[i]); + } stack_len += (bprm->argc + 1) * 4; /* the argv array */ stack_len += (bprm->envc + 1) * 4; /* the envp array */ From c3109ba1b109f84929abbfe0462d910d5aa8617c Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 7 Feb 2011 01:05:54 -0500 Subject: [PATCH 08/12] linux-user/FLAT: allow targets to override FLAT processing This brings flatload.c more in line with the current Linux FLAT loader which allows targets to handle various FLAT aspects in their own way. For the common behavior, the new functions get stubbed out. Signed-off-by: Mike Frysinger Signed-off-by: Riku Voipio --- Makefile.target | 2 +- linux-user/flatload.c | 27 +++++++++++---------------- linux-user/target_flat.h | 10 ++++++++++ 3 files changed, 22 insertions(+), 17 deletions(-) create mode 100644 linux-user/target_flat.h diff --git a/Makefile.target b/Makefile.target index b0ba95f76e..48e6c00a5d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -107,7 +107,7 @@ ifdef CONFIG_LINUX_USER $(call set-vpath, $(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)) -QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) +QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \ elfload.o linuxload.o uaccess.o gdbstub.o cpu-uname.o \ qemu-malloc.o $(oslib-obj-y) diff --git a/linux-user/flatload.c b/linux-user/flatload.c index d8b4476325..cd7af7cdff 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -41,6 +41,8 @@ #include "qemu.h" #include "flat.h" +#define ntohl(x) be32_to_cpu(x) +#include //#define DEBUG @@ -50,14 +52,6 @@ #define DBG_FLT(...) #endif -#define flat_reloc_valid(reloc, size) ((reloc) <= (size)) -#define flat_old_ram_flag(flag) (flag) -#ifdef TARGET_WORDS_BIGENDIAN -#define flat_get_relocate_addr(relval) (relval) -#else -#define flat_get_relocate_addr(relval) bswap32(relval) -#endif - #define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */ #define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */ @@ -78,8 +72,6 @@ static int load_flat_shared_library(int id, struct lib_info *p); struct linux_binprm; -#define ntohl(x) be32_to_cpu(x) - /****************************************************************************/ /* * create_flat_tables() parses the env- and arg-strings in new user @@ -625,6 +617,7 @@ static int load_flat_file(struct linux_binprm * bprm, * __start to address 4 so that is okay). */ if (rev > OLD_FLAT_VERSION) { + abi_ulong persistent = 0; for (i = 0; i < relocs; i++) { abi_ulong addr, relval; @@ -633,6 +626,9 @@ static int load_flat_file(struct linux_binprm * bprm, relocated first). */ if (get_user_ual(relval, reloc + i * sizeof(abi_ulong))) return -EFAULT; + relval = ntohl(relval); + if (flat_set_persistent(relval, &persistent)) + continue; addr = flat_get_relocate_addr(relval); rp = calc_reloc(addr, libinfo, id, 1); if (rp == RELOC_FAILED) @@ -641,22 +637,20 @@ static int load_flat_file(struct linux_binprm * bprm, /* Get the pointer's value. */ if (get_user_ual(addr, rp)) return -EFAULT; + addr = flat_get_addr_from_rp(rp, relval, flags, &persistent); if (addr != 0) { /* * Do the relocation. PIC relocs in the data section are * already in target order */ - -#ifndef TARGET_WORDS_BIGENDIAN if ((flags & FLAT_FLAG_GOTPIC) == 0) - addr = bswap32(addr); -#endif + addr = ntohl(addr); addr = calc_reloc(addr, libinfo, id, 0); if (addr == RELOC_FAILED) return -ENOEXEC; /* Write back the relocated pointer. */ - if (put_user_ual(addr, rp)) + if (flat_put_addr_at_rp(rp, addr, relval)) return -EFAULT; } } @@ -782,7 +776,8 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, stack_len *= sizeof(abi_ulong); if ((sp + stack_len) & 15) sp -= 16 - ((sp + stack_len) & 15); - sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1); + sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, + flat_argvp_envp_on_stack()); /* Fake some return addresses to ensure the call chain will * initialise library in order for us. We are required to call diff --git a/linux-user/target_flat.h b/linux-user/target_flat.h new file mode 100644 index 0000000000..0ba6bdd12e --- /dev/null +++ b/linux-user/target_flat.h @@ -0,0 +1,10 @@ +/* If your arch needs to do custom stuff, create your own target_flat.h + * header file in linux-user// + */ +#define flat_argvp_envp_on_stack() 1 +#define flat_reloc_valid(reloc, size) ((reloc) <= (size)) +#define flat_old_ram_flag(flag) (flag) +#define flat_get_relocate_addr(relval) (relval) +#define flat_get_addr_from_rp(rp, relval, flags, persistent) (rp) +#define flat_set_persistent(relval, persistent) (*persistent) +#define flat_put_addr_at_rp(rp, addr, relval) put_user_ual(addr, rp) From 737de1d1357b13f162b26ca0b775eb375594833a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 7 Feb 2011 01:05:55 -0500 Subject: [PATCH 09/12] linux-user: implement sched_{g,s}etaffinity Signed-off-by: Mike Frysinger Signed-off-by: Riku Voipio --- linux-user/syscall.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index bb6ef43a9e..4412a9b143 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -235,6 +235,12 @@ _syscall6(int,sys_futex,int *,uaddr,int,op,int,val, const struct timespec *,timeout,int *,uaddr2,int,val3) #endif #endif +#define __NR_sys_sched_getaffinity __NR_sched_getaffinity +_syscall3(int, sys_sched_getaffinity, pid_t, pid, unsigned int, len, + unsigned long *, user_mask_ptr); +#define __NR_sys_sched_setaffinity __NR_sched_setaffinity +_syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len, + unsigned long *, user_mask_ptr); static bitmask_transtbl fcntl_flags_tbl[] = { { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, }, @@ -6354,6 +6360,67 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, return value. */ ret = -TARGET_ENOTDIR; break; + case TARGET_NR_sched_getaffinity: + { + unsigned int mask_size; + unsigned long *mask; + + /* + * sched_getaffinity needs multiples of ulong, so need to take + * care of mismatches between target ulong and host ulong sizes. + */ + if (arg2 & (sizeof(abi_ulong) - 1)) { + ret = -TARGET_EINVAL; + break; + } + mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1); + + mask = alloca(mask_size); + ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask)); + + if (!is_error(ret)) { + if (arg2 > ret) { + /* Zero out any extra space kernel didn't fill */ + unsigned long zero = arg2 - ret; + p = alloca(zero); + memset(p, 0, zero); + if (copy_to_user(arg3 + zero, p, zero)) { + goto efault; + } + arg2 = ret; + } + if (copy_to_user(arg3, mask, arg2)) { + goto efault; + } + ret = arg2; + } + } + break; + case TARGET_NR_sched_setaffinity: + { + unsigned int mask_size; + unsigned long *mask; + + /* + * sched_setaffinity needs multiples of ulong, so need to take + * care of mismatches between target ulong and host ulong sizes. + */ + if (arg2 & (sizeof(abi_ulong) - 1)) { + ret = -TARGET_EINVAL; + break; + } + mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1); + + mask = alloca(mask_size); + if (!lock_user_struct(VERIFY_READ, p, arg3, 1)) { + goto efault; + } + memcpy(mask, p, arg2); + unlock_user_struct(p, arg2, 0); + + ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask)); + } + break; case TARGET_NR_sched_setparam: { struct sched_param *target_schp; From 2296f194dfde4c0a54f249d3fdb8c8ca21dc611b Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 7 Feb 2011 01:05:56 -0500 Subject: [PATCH 10/12] user: speed up init_paths a bit The current init_paths code will attempt to opendir() every single file it finds. This can obviously generated a huge number of syscalls with even a moderately small sysroot that will fail. Since the readdir() call provides the file type in the struct itself, use it. On my system, this prevents over 1000 syscalls from being made at every invocation of a target binary, and I only have a C library installed. Signed-off-by: Mike Frysinger Signed-off-by: Riku Voipio --- path.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/path.c b/path.c index 0d2bf149e4..ef3f277f17 100644 --- a/path.c +++ b/path.c @@ -38,7 +38,8 @@ static int strneq(const char *s1, unsigned int n, const char *s2) return s2[i] == 0; } -static struct pathelem *add_entry(struct pathelem *root, const char *name); +static struct pathelem *add_entry(struct pathelem *root, const char *name, + unsigned char type); static struct pathelem *new_entry(const char *root, struct pathelem *parent, @@ -56,6 +57,15 @@ static struct pathelem *new_entry(const char *root, #define streq(a,b) (strcmp((a), (b)) == 0) +/* Not all systems provide this feature */ +#if defined(DT_DIR) && defined(DT_UNKNOWN) +# define dirent_type(dirent) ((dirent)->d_type) +# define is_dir_maybe(type) ((type) == DT_DIR || (type) == DT_UNKNOWN) +#else +# define dirent_type(dirent) (1) +# define is_dir_maybe(type) (type) +#endif + static struct pathelem *add_dir_maybe(struct pathelem *path) { DIR *dir; @@ -65,7 +75,7 @@ static struct pathelem *add_dir_maybe(struct pathelem *path) while ((dirent = readdir(dir)) != NULL) { if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){ - path = add_entry(path, dirent->d_name); + path = add_entry(path, dirent->d_name, dirent_type(dirent)); } } closedir(dir); @@ -73,16 +83,22 @@ static struct pathelem *add_dir_maybe(struct pathelem *path) return path; } -static struct pathelem *add_entry(struct pathelem *root, const char *name) +static struct pathelem *add_entry(struct pathelem *root, const char *name, + unsigned char type) { + struct pathelem **e; + root->num_entries++; root = realloc(root, sizeof(*root) + sizeof(root->entries[0])*root->num_entries); + e = &root->entries[root->num_entries-1]; + + *e = new_entry(root->pathname, root, name); + if (is_dir_maybe(type)) { + *e = add_dir_maybe(*e); + } - root->entries[root->num_entries-1] = new_entry(root->pathname, root, name); - root->entries[root->num_entries-1] - = add_dir_maybe(root->entries[root->num_entries-1]); return root; } From 8d9016c0919bab1fdf3a36c0f72d012924bb7efd Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 7 Feb 2011 01:05:57 -0500 Subject: [PATCH 11/12] linux-user: fix build errors for mmap2-only ports The current print_mmap func is only enabled when the target supports the mmap syscall, but both mmap and mmap2 syscalls use it. This leads to a build failure when the target supports mmap2 but not mmap. Signed-off-by: Mike Frysinger Signed-off-by: Riku Voipio --- linux-user/strace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index a8786bb9e0..18366661cd 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1203,7 +1203,7 @@ print_utimensat(const struct syscallname *name, } #endif -#ifdef TARGET_NR_mmap +#if defined(TARGET_NR_mmap) || defined(TARGET_NR_mmap2) static void print_mmap(const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, From 898b1bebf97e5f973624a4e513da45dffefdb9b7 Mon Sep 17 00:00:00 2001 From: Martin Mohring Date: Tue, 8 Feb 2011 14:48:56 +0200 Subject: [PATCH 12/12] linux-user: fix for loopmount ioctl In case a chrooted build uses XEN or KVM, a looped mount needs to be done to setup the chroot. The ioctl for loop mount works correctly for arm, mips, ppc32 and sh4, so its now activated. Signed-off-by: Riku Voipio --- linux-user/ioctls.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index acff781081..526aaa2a76 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -312,10 +312,8 @@ IOCTL(LOOP_CLR_FD, 0, TYPE_INT) IOCTL(LOOP_SET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info))) IOCTL(LOOP_GET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info))) -#if 0 /* These have some problems - not fully tested */ IOCTL(LOOP_SET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64))) IOCTL(LOOP_GET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64))) -#endif IOCTL(LOOP_CHANGE_FD, 0, TYPE_INT) IOCTL(MTIOCTOP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_mtop)))