Merge remote-tracking branch 'riku/linux-user-for-upstream' into staging
This commit is contained in:
		
						commit
						11ddeea91a
					
				@ -332,6 +332,49 @@ enum
 | 
				
			|||||||
    ARM_HWCAP_ARM_VFPv3D16  = 1 << 13,
 | 
					    ARM_HWCAP_ARM_VFPv3D16  = 1 << 13,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TARGET_HAS_GUEST_VALIDATE_BASE
 | 
				
			||||||
 | 
					/* We want the opportunity to check the suggested base */
 | 
				
			||||||
 | 
					bool guest_validate_base(unsigned long guest_base)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    unsigned long real_start, test_page_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* We need to check that we can force a fault on access to the
 | 
				
			||||||
 | 
					     * commpage at 0xffff0fxx
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    test_page_addr = guest_base + (0xffff0f00 & qemu_host_page_mask);
 | 
				
			||||||
 | 
					    /* Note it needs to be writeable to let us initialise it */
 | 
				
			||||||
 | 
					    real_start = (unsigned long)
 | 
				
			||||||
 | 
					                 mmap((void *)test_page_addr, qemu_host_page_size,
 | 
				
			||||||
 | 
					                     PROT_READ | PROT_WRITE,
 | 
				
			||||||
 | 
					                     MAP_ANONYMOUS | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* If we can't map it then try another address */
 | 
				
			||||||
 | 
					    if (real_start == -1ul) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (real_start != test_page_addr) {
 | 
				
			||||||
 | 
					        /* OS didn't put the page where we asked - unmap and reject */
 | 
				
			||||||
 | 
					        munmap((void *)real_start, qemu_host_page_size);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Leave the page mapped
 | 
				
			||||||
 | 
					     * Populate it (mmap should have left it all 0'd)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Kernel helper versions */
 | 
				
			||||||
 | 
					    __put_user(5, (uint32_t *)g2h(0xffff0ffcul));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Now it's populated make it RO */
 | 
				
			||||||
 | 
					    if (mprotect((void *)test_page_addr, qemu_host_page_size, PROT_READ)) {
 | 
				
			||||||
 | 
					        perror("Protecting guest commpage");
 | 
				
			||||||
 | 
					        exit(-1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 1; /* All good */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF               \
 | 
					#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF               \
 | 
				
			||||||
                   | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT      \
 | 
					                   | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT      \
 | 
				
			||||||
                   | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP              \
 | 
					                   | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP              \
 | 
				
			||||||
@ -1309,6 +1352,14 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
 | 
				
			|||||||
    return sp;
 | 
					    return sp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef TARGET_HAS_GUEST_VALIDATE_BASE
 | 
				
			||||||
 | 
					/* If the guest doesn't have a validation function just agree */
 | 
				
			||||||
 | 
					bool guest_validate_base(unsigned long guest_base)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void probe_guest_base(const char *image_name,
 | 
					static void probe_guest_base(const char *image_name,
 | 
				
			||||||
                             abi_ulong loaddr, abi_ulong hiaddr)
 | 
					                             abi_ulong loaddr, abi_ulong hiaddr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -1345,7 +1396,9 @@ static void probe_guest_base(const char *image_name,
 | 
				
			|||||||
            if (real_start == (unsigned long)-1) {
 | 
					            if (real_start == (unsigned long)-1) {
 | 
				
			||||||
                goto exit_perror;
 | 
					                goto exit_perror;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (real_start == host_start) {
 | 
					            guest_base = real_start - loaddr;
 | 
				
			||||||
 | 
					            if ((real_start == host_start) &&
 | 
				
			||||||
 | 
					                guest_validate_base(guest_base)) {
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            /* That address didn't work.  Unmap and try a different one.
 | 
					            /* That address didn't work.  Unmap and try a different one.
 | 
				
			||||||
@ -1368,7 +1421,6 @@ static void probe_guest_base(const char *image_name,
 | 
				
			|||||||
        qemu_log("Relocating guest address space from 0x"
 | 
					        qemu_log("Relocating guest address space from 0x"
 | 
				
			||||||
                 TARGET_ABI_FMT_lx " to 0x%lx\n",
 | 
					                 TARGET_ABI_FMT_lx " to 0x%lx\n",
 | 
				
			||||||
                 loaddr, real_start);
 | 
					                 loaddr, real_start);
 | 
				
			||||||
        guest_base = real_start - loaddr;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -39,6 +39,11 @@
 | 
				
			|||||||
char *exec_path;
 | 
					char *exec_path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int singlestep;
 | 
					int singlestep;
 | 
				
			||||||
 | 
					const char *filename;
 | 
				
			||||||
 | 
					const char *argv0;
 | 
				
			||||||
 | 
					int gdbstub_port;
 | 
				
			||||||
 | 
					envlist_t *envlist;
 | 
				
			||||||
 | 
					const char *cpu_model;
 | 
				
			||||||
unsigned long mmap_min_addr;
 | 
					unsigned long mmap_min_addr;
 | 
				
			||||||
#if defined(CONFIG_USE_GUEST_BASE)
 | 
					#if defined(CONFIG_USE_GUEST_BASE)
 | 
				
			||||||
unsigned long guest_base;
 | 
					unsigned long guest_base;
 | 
				
			||||||
@ -46,6 +51,8 @@ int have_guest_base;
 | 
				
			|||||||
unsigned long reserved_va;
 | 
					unsigned long reserved_va;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void usage(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
 | 
					static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
 | 
				
			||||||
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
 | 
					const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -456,6 +463,83 @@ void cpu_loop(CPUX86State *env)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#ifdef TARGET_ARM
 | 
					#ifdef TARGET_ARM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
 | 
				
			||||||
 | 
					 * Input:
 | 
				
			||||||
 | 
					 * r0 = pointer to oldval
 | 
				
			||||||
 | 
					 * r1 = pointer to newval
 | 
				
			||||||
 | 
					 * r2 = pointer to target value
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Output:
 | 
				
			||||||
 | 
					 * r0 = 0 if *ptr was changed, non-0 if no exchange happened
 | 
				
			||||||
 | 
					 * C set if *ptr was changed, clear if no exchange happened
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note segv's in kernel helpers are a bit tricky, we can set the
 | 
				
			||||||
 | 
					 * data address sensibly but the PC address is just the entry point.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint64_t oldval, newval, val;
 | 
				
			||||||
 | 
					    uint32_t addr, cpsr;
 | 
				
			||||||
 | 
					    target_siginfo_t info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Based on the 32 bit code in do_kernel_trap */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* XXX: This only works between threads, not between processes.
 | 
				
			||||||
 | 
					       It's probably possible to implement this with native host
 | 
				
			||||||
 | 
					       operations. However things like ldrex/strex are much harder so
 | 
				
			||||||
 | 
					       there's not much point trying.  */
 | 
				
			||||||
 | 
					    start_exclusive();
 | 
				
			||||||
 | 
					    cpsr = cpsr_read(env);
 | 
				
			||||||
 | 
					    addr = env->regs[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (get_user_u64(oldval, env->regs[0])) {
 | 
				
			||||||
 | 
					        env->cp15.c6_data = env->regs[0];
 | 
				
			||||||
 | 
					        goto segv;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (get_user_u64(newval, env->regs[1])) {
 | 
				
			||||||
 | 
					        env->cp15.c6_data = env->regs[1];
 | 
				
			||||||
 | 
					        goto segv;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (get_user_u64(val, addr)) {
 | 
				
			||||||
 | 
					        env->cp15.c6_data = addr;
 | 
				
			||||||
 | 
					        goto segv;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (val == oldval) {
 | 
				
			||||||
 | 
					        val = newval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (put_user_u64(val, addr)) {
 | 
				
			||||||
 | 
					            env->cp15.c6_data = addr;
 | 
				
			||||||
 | 
					            goto segv;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        env->regs[0] = 0;
 | 
				
			||||||
 | 
					        cpsr |= CPSR_C;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        env->regs[0] = -1;
 | 
				
			||||||
 | 
					        cpsr &= ~CPSR_C;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cpsr_write(env, cpsr, CPSR_C);
 | 
				
			||||||
 | 
					    end_exclusive();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					segv:
 | 
				
			||||||
 | 
					    end_exclusive();
 | 
				
			||||||
 | 
					    /* We get the PC of the entry address - which is as good as anything,
 | 
				
			||||||
 | 
					       on a real kernel what you get depends on which mode it uses. */
 | 
				
			||||||
 | 
					    info.si_signo = SIGSEGV;
 | 
				
			||||||
 | 
					    info.si_errno = 0;
 | 
				
			||||||
 | 
					    /* XXX: check env->error_code */
 | 
				
			||||||
 | 
					    info.si_code = TARGET_SEGV_MAPERR;
 | 
				
			||||||
 | 
					    info._sifields._sigfault._addr = env->cp15.c6_data;
 | 
				
			||||||
 | 
					    queue_signal(env, info.si_signo, &info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    end_exclusive();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Handle a jump to the kernel code page.  */
 | 
					/* Handle a jump to the kernel code page.  */
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
do_kernel_trap(CPUARMState *env)
 | 
					do_kernel_trap(CPUARMState *env)
 | 
				
			||||||
@ -495,6 +579,10 @@ do_kernel_trap(CPUARMState *env)
 | 
				
			|||||||
    case 0xffff0fe0: /* __kernel_get_tls */
 | 
					    case 0xffff0fe0: /* __kernel_get_tls */
 | 
				
			||||||
        env->regs[0] = env->cp15.c13_tls2;
 | 
					        env->regs[0] = env->cp15.c13_tls2;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					    case 0xffff0f60: /* __kernel_cmpxchg64 */
 | 
				
			||||||
 | 
					        arm_kernel_cmpxchg64_helper(env);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -752,7 +840,6 @@ void cpu_loop(CPUARMState *env)
 | 
				
			|||||||
            goto do_segv;
 | 
					            goto do_segv;
 | 
				
			||||||
        case EXCP_DATA_ABORT:
 | 
					        case EXCP_DATA_ABORT:
 | 
				
			||||||
            addr = env->cp15.c6_data;
 | 
					            addr = env->cp15.c6_data;
 | 
				
			||||||
            goto do_segv;
 | 
					 | 
				
			||||||
        do_segv:
 | 
					        do_segv:
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                info.si_signo = SIGSEGV;
 | 
					                info.si_signo = SIGSEGV;
 | 
				
			||||||
@ -1669,7 +1756,7 @@ void cpu_loop(CPUPPCState *env)
 | 
				
			|||||||
#define MIPS_SYS(name, args) args,
 | 
					#define MIPS_SYS(name, args) args,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const uint8_t mips_syscall_args[] = {
 | 
					static const uint8_t mips_syscall_args[] = {
 | 
				
			||||||
	MIPS_SYS(sys_syscall	, 0)	/* 4000 */
 | 
						MIPS_SYS(sys_syscall	, 8)	/* 4000 */
 | 
				
			||||||
	MIPS_SYS(sys_exit	, 1)
 | 
						MIPS_SYS(sys_exit	, 1)
 | 
				
			||||||
	MIPS_SYS(sys_fork	, 0)
 | 
						MIPS_SYS(sys_fork	, 0)
 | 
				
			||||||
	MIPS_SYS(sys_read	, 3)
 | 
						MIPS_SYS(sys_read	, 3)
 | 
				
			||||||
@ -2090,11 +2177,22 @@ void cpu_loop(CPUMIPSState *env)
 | 
				
			|||||||
                sp_reg = env->active_tc.gpr[29];
 | 
					                sp_reg = env->active_tc.gpr[29];
 | 
				
			||||||
                switch (nb_args) {
 | 
					                switch (nb_args) {
 | 
				
			||||||
                /* these arguments are taken from the stack */
 | 
					                /* these arguments are taken from the stack */
 | 
				
			||||||
                /* FIXME - what to do if get_user() fails? */
 | 
					                case 8:
 | 
				
			||||||
                case 8: get_user_ual(arg8, sp_reg + 28);
 | 
					                    if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
 | 
				
			||||||
                case 7: get_user_ual(arg7, sp_reg + 24);
 | 
					                        goto done_syscall;
 | 
				
			||||||
                case 6: get_user_ual(arg6, sp_reg + 20);
 | 
					                    }
 | 
				
			||||||
                case 5: get_user_ual(arg5, sp_reg + 16);
 | 
					                case 7:
 | 
				
			||||||
 | 
					                    if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
 | 
				
			||||||
 | 
					                        goto done_syscall;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                case 6:
 | 
				
			||||||
 | 
					                    if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
 | 
				
			||||||
 | 
					                        goto done_syscall;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                case 5:
 | 
				
			||||||
 | 
					                    if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
 | 
				
			||||||
 | 
					                        goto done_syscall;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                default:
 | 
					                default:
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -2105,6 +2203,7 @@ void cpu_loop(CPUMIPSState *env)
 | 
				
			|||||||
                                 env->active_tc.gpr[7],
 | 
					                                 env->active_tc.gpr[7],
 | 
				
			||||||
                                 arg5, arg6, arg7, arg8);
 | 
					                                 arg5, arg6, arg7, arg8);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					done_syscall:
 | 
				
			||||||
            if (ret == -TARGET_QEMU_ESIGRETURN) {
 | 
					            if (ret == -TARGET_QEMU_ESIGRETURN) {
 | 
				
			||||||
                /* Returning from a successful sigreturn syscall.
 | 
					                /* Returning from a successful sigreturn syscall.
 | 
				
			||||||
                   Avoid clobbering register state.  */
 | 
					                   Avoid clobbering register state.  */
 | 
				
			||||||
@ -2787,57 +2886,6 @@ void cpu_loop(CPUS390XState *env)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#endif /* TARGET_S390X */
 | 
					#endif /* TARGET_S390X */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void version(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
 | 
					 | 
				
			||||||
           ", Copyright (c) 2003-2008 Fabrice Bellard\n");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void usage(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    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"
 | 
					 | 
				
			||||||
           "-cpu model        select CPU (-cpu ? for list)\n"
 | 
					 | 
				
			||||||
           "-drop-ld-preload  drop LD_PRELOAD for target process\n"
 | 
					 | 
				
			||||||
           "-E var=value      sets/modifies targets environment variable(s)\n"
 | 
					 | 
				
			||||||
           "-U var            unsets targets environment variable(s)\n"
 | 
					 | 
				
			||||||
           "-0 argv0          forces target process argv[0] to be argv0\n"
 | 
					 | 
				
			||||||
#if defined(CONFIG_USE_GUEST_BASE)
 | 
					 | 
				
			||||||
           "-B address        set guest_base address to address\n"
 | 
					 | 
				
			||||||
           "-R size           reserve size bytes for guest virtual address space\n"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
           "\n"
 | 
					 | 
				
			||||||
           "Debug options:\n"
 | 
					 | 
				
			||||||
           "-d options   activate log (logfile=%s)\n"
 | 
					 | 
				
			||||||
           "-p pagesize  set the host page size to 'pagesize'\n"
 | 
					 | 
				
			||||||
           "-singlestep  always run in singlestep mode\n"
 | 
					 | 
				
			||||||
           "-strace      log system calls\n"
 | 
					 | 
				
			||||||
           "\n"
 | 
					 | 
				
			||||||
           "Environment variables:\n"
 | 
					 | 
				
			||||||
           "QEMU_STRACE       Print system calls and arguments similar to the\n"
 | 
					 | 
				
			||||||
           "                  'strace' program.  Enable by setting to any value.\n"
 | 
					 | 
				
			||||||
           "You can use -E and -U options to set/unset environment variables\n"
 | 
					 | 
				
			||||||
           "for target process.  It is possible to provide several variables\n"
 | 
					 | 
				
			||||||
           "by repeating the option.  For example:\n"
 | 
					 | 
				
			||||||
           "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
 | 
					 | 
				
			||||||
           "Note that if you provide several changes to single variable\n"
 | 
					 | 
				
			||||||
           "last change will stay in effect.\n"
 | 
					 | 
				
			||||||
           ,
 | 
					 | 
				
			||||||
           TARGET_ARCH,
 | 
					 | 
				
			||||||
           interp_prefix,
 | 
					 | 
				
			||||||
           guest_stack_size,
 | 
					 | 
				
			||||||
           DEBUG_LOGFILE);
 | 
					 | 
				
			||||||
    exit(1);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
THREAD CPUState *thread_env;
 | 
					THREAD CPUState *thread_env;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void task_settid(TaskState *ts)
 | 
					void task_settid(TaskState *ts)
 | 
				
			||||||
@ -2874,25 +2922,357 @@ void init_task_state(TaskState *ts)
 | 
				
			|||||||
    ts->sigqueue_table[i].next = NULL;
 | 
					    ts->sigqueue_table[i].next = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_help(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    usage();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_log(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int mask;
 | 
				
			||||||
 | 
					    const CPULogItem *item;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mask = cpu_str_to_log_mask(arg);
 | 
				
			||||||
 | 
					    if (!mask) {
 | 
				
			||||||
 | 
					        printf("Log items (comma separated):\n");
 | 
				
			||||||
 | 
					        for (item = cpu_log_items; item->mask != 0; item++) {
 | 
				
			||||||
 | 
					            printf("%-10s %s\n", item->name, item->help);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cpu_set_log(mask);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_set_env(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char *r, *p, *token;
 | 
				
			||||||
 | 
					    r = p = strdup(arg);
 | 
				
			||||||
 | 
					    while ((token = strsep(&p, ",")) != NULL) {
 | 
				
			||||||
 | 
					        if (envlist_setenv(envlist, token) != 0) {
 | 
				
			||||||
 | 
					            usage();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free(r);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_unset_env(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char *r, *p, *token;
 | 
				
			||||||
 | 
					    r = p = strdup(arg);
 | 
				
			||||||
 | 
					    while ((token = strsep(&p, ",")) != NULL) {
 | 
				
			||||||
 | 
					        if (envlist_unsetenv(envlist, token) != 0) {
 | 
				
			||||||
 | 
					            usage();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free(r);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_argv0(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    argv0 = strdup(arg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_stack_size(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char *p;
 | 
				
			||||||
 | 
					    guest_stack_size = strtoul(arg, &p, 0);
 | 
				
			||||||
 | 
					    if (guest_stack_size == 0) {
 | 
				
			||||||
 | 
					        usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (*p == 'M') {
 | 
				
			||||||
 | 
					        guest_stack_size *= 1024 * 1024;
 | 
				
			||||||
 | 
					    } else if (*p == 'k' || *p == 'K') {
 | 
				
			||||||
 | 
					        guest_stack_size *= 1024;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_ld_prefix(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    interp_prefix = strdup(arg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_pagesize(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qemu_host_page_size = atoi(arg);
 | 
				
			||||||
 | 
					    if (qemu_host_page_size == 0 ||
 | 
				
			||||||
 | 
					        (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "page size must be a power of two\n");
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_gdb(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gdbstub_port = atoi(arg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_uname(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qemu_uname_release = strdup(arg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_cpu(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    cpu_model = strdup(arg);
 | 
				
			||||||
 | 
					    if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
 | 
				
			||||||
 | 
					        /* XXX: implement xxx_cpu_list for targets that still miss it */
 | 
				
			||||||
 | 
					#if defined(cpu_list_id)
 | 
				
			||||||
 | 
					        cpu_list_id(stdout, &fprintf, "");
 | 
				
			||||||
 | 
					#elif defined(cpu_list)
 | 
				
			||||||
 | 
					        cpu_list(stdout, &fprintf); /* deprecated */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(CONFIG_USE_GUEST_BASE)
 | 
				
			||||||
 | 
					static void handle_arg_guest_base(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    guest_base = strtol(arg, NULL, 0);
 | 
				
			||||||
 | 
					    have_guest_base = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_reserved_va(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char *p;
 | 
				
			||||||
 | 
					    int shift = 0;
 | 
				
			||||||
 | 
					    reserved_va = strtoul(arg, &p, 0);
 | 
				
			||||||
 | 
					    switch (*p) {
 | 
				
			||||||
 | 
					    case 'k':
 | 
				
			||||||
 | 
					    case 'K':
 | 
				
			||||||
 | 
					        shift = 10;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 'M':
 | 
				
			||||||
 | 
					        shift = 20;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 'G':
 | 
				
			||||||
 | 
					        shift = 30;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (shift) {
 | 
				
			||||||
 | 
					        unsigned long unshifted = reserved_va;
 | 
				
			||||||
 | 
					        p++;
 | 
				
			||||||
 | 
					        reserved_va <<= shift;
 | 
				
			||||||
 | 
					        if (((reserved_va >> shift) != unshifted)
 | 
				
			||||||
 | 
					#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
 | 
				
			||||||
 | 
					            || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					            ) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "Reserved virtual address too big\n");
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (*p) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_singlestep(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    singlestep = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_strace(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    do_strace = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handle_arg_version(const char *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
 | 
				
			||||||
 | 
					           ", Copyright (c) 2003-2008 Fabrice Bellard\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct qemu_argument {
 | 
				
			||||||
 | 
					    const char *argv;
 | 
				
			||||||
 | 
					    const char *env;
 | 
				
			||||||
 | 
					    bool has_arg;
 | 
				
			||||||
 | 
					    void (*handle_opt)(const char *arg);
 | 
				
			||||||
 | 
					    const char *example;
 | 
				
			||||||
 | 
					    const char *help;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct qemu_argument arg_table[] = {
 | 
				
			||||||
 | 
					    {"h",          "",                 false, handle_arg_help,
 | 
				
			||||||
 | 
					     "",           "print this help"},
 | 
				
			||||||
 | 
					    {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
 | 
				
			||||||
 | 
					     "port",       "wait gdb connection to 'port'"},
 | 
				
			||||||
 | 
					    {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
 | 
				
			||||||
 | 
					     "path",       "set the elf interpreter prefix to 'path'"},
 | 
				
			||||||
 | 
					    {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
 | 
				
			||||||
 | 
					     "size",       "set the stack size to 'size' bytes"},
 | 
				
			||||||
 | 
					    {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
 | 
				
			||||||
 | 
					     "model",      "select CPU (-cpu ? for list)"},
 | 
				
			||||||
 | 
					    {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
 | 
				
			||||||
 | 
					     "var=value",  "sets targets environment variable (see below)"},
 | 
				
			||||||
 | 
					    {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
 | 
				
			||||||
 | 
					     "var",        "unsets targets environment variable (see below)"},
 | 
				
			||||||
 | 
					    {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
 | 
				
			||||||
 | 
					     "argv0",      "forces target process argv[0] to be 'argv0'"},
 | 
				
			||||||
 | 
					    {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
 | 
				
			||||||
 | 
					     "uname",      "set qemu uname release string to 'uname'"},
 | 
				
			||||||
 | 
					#if defined(CONFIG_USE_GUEST_BASE)
 | 
				
			||||||
 | 
					    {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
 | 
				
			||||||
 | 
					     "address",    "set guest_base address to 'address'"},
 | 
				
			||||||
 | 
					    {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
 | 
				
			||||||
 | 
					     "size",       "reserve 'size' bytes for guest virtual address space"},
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    {"d",          "QEMU_LOG",         true,  handle_arg_log,
 | 
				
			||||||
 | 
					     "options",    "activate log"},
 | 
				
			||||||
 | 
					    {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
 | 
				
			||||||
 | 
					     "pagesize",   "set the host page size to 'pagesize'"},
 | 
				
			||||||
 | 
					    {"singlestep", "QEMU_SINGLESTEP",  false, handle_arg_singlestep,
 | 
				
			||||||
 | 
					     "",           "run in singlestep mode"},
 | 
				
			||||||
 | 
					    {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
 | 
				
			||||||
 | 
					     "",           "log system calls"},
 | 
				
			||||||
 | 
					    {"version",    "QEMU_VERSION",     false, handle_arg_version,
 | 
				
			||||||
 | 
					     "",           "log system calls"},
 | 
				
			||||||
 | 
					    {NULL, NULL, false, NULL, NULL, NULL}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void usage(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct qemu_argument *arginfo;
 | 
				
			||||||
 | 
					    int maxarglen;
 | 
				
			||||||
 | 
					    int maxenvlen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
 | 
				
			||||||
 | 
					           "Linux CPU emulator (compiled for " TARGET_ARCH " emulation)\n"
 | 
				
			||||||
 | 
					           "\n"
 | 
				
			||||||
 | 
					           "Options and associated environment variables:\n"
 | 
				
			||||||
 | 
					           "\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    maxarglen = maxenvlen = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
 | 
				
			||||||
 | 
					        if (strlen(arginfo->env) > maxenvlen) {
 | 
				
			||||||
 | 
					            maxenvlen = strlen(arginfo->env);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (strlen(arginfo->argv) > maxarglen) {
 | 
				
			||||||
 | 
					            maxarglen = strlen(arginfo->argv);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("%-*s%-*sDescription\n", maxarglen+3, "Argument",
 | 
				
			||||||
 | 
					            maxenvlen+1, "Env-variable");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
 | 
				
			||||||
 | 
					        if (arginfo->has_arg) {
 | 
				
			||||||
 | 
					            printf("-%s %-*s %-*s %s\n", arginfo->argv,
 | 
				
			||||||
 | 
					                    (int)(maxarglen-strlen(arginfo->argv)), arginfo->example,
 | 
				
			||||||
 | 
					                    maxenvlen, arginfo->env, arginfo->help);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            printf("-%-*s %-*s %s\n", maxarglen+1, arginfo->argv,
 | 
				
			||||||
 | 
					                    maxenvlen, arginfo->env,
 | 
				
			||||||
 | 
					                    arginfo->help);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("\n"
 | 
				
			||||||
 | 
					           "Defaults:\n"
 | 
				
			||||||
 | 
					           "QEMU_LD_PREFIX  = %s\n"
 | 
				
			||||||
 | 
					           "QEMU_STACK_SIZE = %ld byte\n"
 | 
				
			||||||
 | 
					           "QEMU_LOG        = %s\n",
 | 
				
			||||||
 | 
					           interp_prefix,
 | 
				
			||||||
 | 
					           guest_stack_size,
 | 
				
			||||||
 | 
					           DEBUG_LOGFILE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("\n"
 | 
				
			||||||
 | 
					           "You can use -E and -U options or the QEMU_SET_ENV and\n"
 | 
				
			||||||
 | 
					           "QEMU_UNSET_ENV environment variables to set and unset\n"
 | 
				
			||||||
 | 
					           "environment variables for the target process.\n"
 | 
				
			||||||
 | 
					           "It is possible to provide several variables by separating them\n"
 | 
				
			||||||
 | 
					           "by commas in getsubopt(3) style. Additionally it is possible to\n"
 | 
				
			||||||
 | 
					           "provide the -E and -U options multiple times.\n"
 | 
				
			||||||
 | 
					           "The following lines are equivalent:\n"
 | 
				
			||||||
 | 
					           "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
 | 
				
			||||||
 | 
					           "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
 | 
				
			||||||
 | 
					           "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
 | 
				
			||||||
 | 
					           "Note that if you provide several changes to a single variable\n"
 | 
				
			||||||
 | 
					           "the last change will stay in effect.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int parse_args(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const char *r;
 | 
				
			||||||
 | 
					    int optind;
 | 
				
			||||||
 | 
					    struct qemu_argument *arginfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
 | 
				
			||||||
 | 
					        if (arginfo->env == NULL) {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        r = getenv(arginfo->env);
 | 
				
			||||||
 | 
					        if (r != NULL) {
 | 
				
			||||||
 | 
					            arginfo->handle_opt(r);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    optind = 1;
 | 
				
			||||||
 | 
					    for (;;) {
 | 
				
			||||||
 | 
					        if (optind >= argc) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        r = argv[optind];
 | 
				
			||||||
 | 
					        if (r[0] != '-') {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        optind++;
 | 
				
			||||||
 | 
					        r++;
 | 
				
			||||||
 | 
					        if (!strcmp(r, "-")) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
 | 
				
			||||||
 | 
					            if (!strcmp(r, arginfo->argv)) {
 | 
				
			||||||
 | 
					                if (optind >= argc) {
 | 
				
			||||||
 | 
					                    usage();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                arginfo->handle_opt(argv[optind]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (arginfo->has_arg) {
 | 
				
			||||||
 | 
					                    optind++;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* no option matched the current argv */
 | 
				
			||||||
 | 
					        if (arginfo->handle_opt == NULL) {
 | 
				
			||||||
 | 
					            usage();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (optind >= argc) {
 | 
				
			||||||
 | 
					        usage();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    filename = argv[optind];
 | 
				
			||||||
 | 
					    exec_path = argv[optind];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return optind;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv, char **envp)
 | 
					int main(int argc, char **argv, char **envp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const char *filename;
 | 
					 | 
				
			||||||
    const char *cpu_model;
 | 
					 | 
				
			||||||
    const char *log_file = DEBUG_LOGFILE;
 | 
					    const char *log_file = DEBUG_LOGFILE;
 | 
				
			||||||
    const char *log_mask = NULL;
 | 
					 | 
				
			||||||
    struct target_pt_regs regs1, *regs = ®s1;
 | 
					    struct target_pt_regs regs1, *regs = ®s1;
 | 
				
			||||||
    struct image_info info1, *info = &info1;
 | 
					    struct image_info info1, *info = &info1;
 | 
				
			||||||
    struct linux_binprm bprm;
 | 
					    struct linux_binprm bprm;
 | 
				
			||||||
    TaskState *ts;
 | 
					    TaskState *ts;
 | 
				
			||||||
    CPUState *env;
 | 
					    CPUState *env;
 | 
				
			||||||
    int optind;
 | 
					    int optind;
 | 
				
			||||||
    const char *r;
 | 
					 | 
				
			||||||
    int gdbstub_port = 0;
 | 
					 | 
				
			||||||
    char **target_environ, **wrk;
 | 
					    char **target_environ, **wrk;
 | 
				
			||||||
    char **target_argv;
 | 
					    char **target_argv;
 | 
				
			||||||
    int target_argc;
 | 
					    int target_argc;
 | 
				
			||||||
    envlist_t *envlist = NULL;
 | 
					 | 
				
			||||||
    const char *argv0 = NULL;
 | 
					 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2927,156 +3307,9 @@ int main(int argc, char **argv, char **envp)
 | 
				
			|||||||
    cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
 | 
					    cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    optind = 1;
 | 
					 | 
				
			||||||
    for(;;) {
 | 
					 | 
				
			||||||
        if (optind >= argc)
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        r = argv[optind];
 | 
					 | 
				
			||||||
        if (r[0] != '-')
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        optind++;
 | 
					 | 
				
			||||||
        r++;
 | 
					 | 
				
			||||||
        if (!strcmp(r, "-")) {
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "d")) {
 | 
					 | 
				
			||||||
            if (optind >= argc) {
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            log_mask = argv[optind++];
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "D")) {
 | 
					 | 
				
			||||||
            if (optind >= argc) {
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            log_file = argv[optind++];
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "E")) {
 | 
					 | 
				
			||||||
            r = argv[optind++];
 | 
					 | 
				
			||||||
            if (envlist_setenv(envlist, r) != 0)
 | 
					 | 
				
			||||||
                usage();
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "ignore-environment")) {
 | 
					 | 
				
			||||||
            envlist_free(envlist);
 | 
					 | 
				
			||||||
            if ((envlist = envlist_create()) == NULL) {
 | 
					 | 
				
			||||||
                (void) fprintf(stderr, "Unable to allocate envlist\n");
 | 
					 | 
				
			||||||
                exit(1);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "U")) {
 | 
					 | 
				
			||||||
            r = argv[optind++];
 | 
					 | 
				
			||||||
            if (envlist_unsetenv(envlist, r) != 0)
 | 
					 | 
				
			||||||
                usage();
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "0")) {
 | 
					 | 
				
			||||||
            r = argv[optind++];
 | 
					 | 
				
			||||||
            argv0 = r;
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "s")) {
 | 
					 | 
				
			||||||
            if (optind >= argc)
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            r = argv[optind++];
 | 
					 | 
				
			||||||
            guest_stack_size = strtoul(r, (char **)&r, 0);
 | 
					 | 
				
			||||||
            if (guest_stack_size == 0)
 | 
					 | 
				
			||||||
                usage();
 | 
					 | 
				
			||||||
            if (*r == 'M')
 | 
					 | 
				
			||||||
                guest_stack_size *= 1024 * 1024;
 | 
					 | 
				
			||||||
            else if (*r == 'k' || *r == 'K')
 | 
					 | 
				
			||||||
                guest_stack_size *= 1024;
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "L")) {
 | 
					 | 
				
			||||||
            interp_prefix = argv[optind++];
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "p")) {
 | 
					 | 
				
			||||||
            if (optind >= argc)
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            qemu_host_page_size = atoi(argv[optind++]);
 | 
					 | 
				
			||||||
            if (qemu_host_page_size == 0 ||
 | 
					 | 
				
			||||||
                (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
 | 
					 | 
				
			||||||
                fprintf(stderr, "page size must be a power of two\n");
 | 
					 | 
				
			||||||
                exit(1);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "g")) {
 | 
					 | 
				
			||||||
            if (optind >= argc)
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            gdbstub_port = atoi(argv[optind++]);
 | 
					 | 
				
			||||||
	} else if (!strcmp(r, "r")) {
 | 
					 | 
				
			||||||
	    qemu_uname_release = argv[optind++];
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "cpu")) {
 | 
					 | 
				
			||||||
            cpu_model = argv[optind++];
 | 
					 | 
				
			||||||
            if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
 | 
					 | 
				
			||||||
/* XXX: implement xxx_cpu_list for targets that still miss it */
 | 
					 | 
				
			||||||
#if defined(cpu_list_id)
 | 
					 | 
				
			||||||
                cpu_list_id(stdout, &fprintf, "");
 | 
					 | 
				
			||||||
#elif defined(cpu_list)
 | 
					 | 
				
			||||||
                cpu_list(stdout, &fprintf); /* deprecated */
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
                exit(1);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
#if defined(CONFIG_USE_GUEST_BASE)
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "B")) {
 | 
					 | 
				
			||||||
           guest_base = strtol(argv[optind++], NULL, 0);
 | 
					 | 
				
			||||||
           have_guest_base = 1;
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "R")) {
 | 
					 | 
				
			||||||
            char *p;
 | 
					 | 
				
			||||||
            int shift = 0;
 | 
					 | 
				
			||||||
            reserved_va = strtoul(argv[optind++], &p, 0);
 | 
					 | 
				
			||||||
            switch (*p) {
 | 
					 | 
				
			||||||
            case 'k':
 | 
					 | 
				
			||||||
            case 'K':
 | 
					 | 
				
			||||||
                shift = 10;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 'M':
 | 
					 | 
				
			||||||
                shift = 20;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 'G':
 | 
					 | 
				
			||||||
                shift = 30;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (shift) {
 | 
					 | 
				
			||||||
                unsigned long unshifted = reserved_va;
 | 
					 | 
				
			||||||
                p++;
 | 
					 | 
				
			||||||
                reserved_va <<= shift;
 | 
					 | 
				
			||||||
                if (((reserved_va >> shift) != unshifted)
 | 
					 | 
				
			||||||
#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
 | 
					 | 
				
			||||||
                    || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
                    ) {
 | 
					 | 
				
			||||||
                    fprintf(stderr, "Reserved virtual address too big\n");
 | 
					 | 
				
			||||||
                    exit(1);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (*p) {
 | 
					 | 
				
			||||||
                fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
 | 
					 | 
				
			||||||
                exit(1);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "drop-ld-preload")) {
 | 
					 | 
				
			||||||
            (void) envlist_unsetenv(envlist, "LD_PRELOAD");
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "singlestep")) {
 | 
					 | 
				
			||||||
            singlestep = 1;
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "strace")) {
 | 
					 | 
				
			||||||
            do_strace = 1;
 | 
					 | 
				
			||||||
        } else if (!strcmp(r, "version")) {
 | 
					 | 
				
			||||||
            version();
 | 
					 | 
				
			||||||
            exit(0);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            usage();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    /* init debug */
 | 
					    /* init debug */
 | 
				
			||||||
    cpu_set_log_filename(log_file);
 | 
					    cpu_set_log_filename(log_file);
 | 
				
			||||||
    if (log_mask) {
 | 
					    optind = parse_args(argc, argv);
 | 
				
			||||||
        int mask;
 | 
					 | 
				
			||||||
        const CPULogItem *item;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        mask = cpu_str_to_log_mask(log_mask);
 | 
					 | 
				
			||||||
        if (!mask) {
 | 
					 | 
				
			||||||
            printf("Log items (comma separated):\n");
 | 
					 | 
				
			||||||
            for (item = cpu_log_items; item->mask != 0; item++) {
 | 
					 | 
				
			||||||
                printf("%-10s %s\n", item->name, item->help);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            exit(1);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        cpu_set_log(mask);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (optind >= argc) {
 | 
					 | 
				
			||||||
        usage();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    filename = argv[optind];
 | 
					 | 
				
			||||||
    exec_path = argv[optind];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Zero out regs */
 | 
					    /* Zero out regs */
 | 
				
			||||||
    memset(regs, 0, sizeof(struct target_pt_regs));
 | 
					    memset(regs, 0, sizeof(struct target_pt_regs));
 | 
				
			||||||
@ -3180,6 +3413,13 @@ int main(int argc, char **argv, char **envp)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
 | 
					        qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (reserved_va || have_guest_base) {
 | 
				
			||||||
 | 
					        if (!guest_validate_base(guest_base)) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "Guest base/Reserved VA rejected by guest code\n");
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
#endif /* CONFIG_USE_GUEST_BASE */
 | 
					#endif /* CONFIG_USE_GUEST_BASE */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
@ -3568,7 +3808,11 @@ int main(int argc, char **argv, char **envp)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (gdbstub_port) {
 | 
					    if (gdbstub_port) {
 | 
				
			||||||
        gdbserver_start (gdbstub_port);
 | 
					        if (gdbserver_start(gdbstub_port) < 0) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "qemu: could not open gdbserver on port %d\n",
 | 
				
			||||||
 | 
					                    gdbstub_port);
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        gdb_handlesig(env, 0);
 | 
					        gdb_handlesig(env, 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    cpu_loop(env);
 | 
					    cpu_loop(env);
 | 
				
			||||||
 | 
				
			|||||||
@ -202,6 +202,12 @@ int get_osversion(void);
 | 
				
			|||||||
void fork_start(void);
 | 
					void fork_start(void);
 | 
				
			||||||
void fork_end(int child);
 | 
					void fork_end(int child);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return true if the proposed guest_base is suitable for the guest.
 | 
				
			||||||
 | 
					 * The guest code may leave a page mapped and populate it if the
 | 
				
			||||||
 | 
					 * address is suitable.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool guest_validate_base(unsigned long guest_base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "qemu-log.h"
 | 
					#include "qemu-log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* strace.c */
 | 
					/* strace.c */
 | 
				
			||||||
 | 
				
			|||||||
@ -70,6 +70,9 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 | 
				
			|||||||
#ifdef CONFIG_EPOLL
 | 
					#ifdef CONFIG_EPOLL
 | 
				
			||||||
#include <sys/epoll.h>
 | 
					#include <sys/epoll.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CONFIG_ATTR
 | 
				
			||||||
 | 
					#include <attr/xattr.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define termios host_termios
 | 
					#define termios host_termios
 | 
				
			||||||
#define winsize host_winsize
 | 
					#define winsize host_winsize
 | 
				
			||||||
@ -796,6 +799,15 @@ abi_long do_brk(abi_ulong new_brk)
 | 
				
			|||||||
                                        MAP_ANON|MAP_PRIVATE, 0, 0));
 | 
					                                        MAP_ANON|MAP_PRIVATE, 0, 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (mapped_addr == brk_page) {
 | 
					    if (mapped_addr == brk_page) {
 | 
				
			||||||
 | 
					        /* Heap contents are initialized to zero, as for anonymous
 | 
				
			||||||
 | 
					         * mapped pages.  Technically the new pages are already
 | 
				
			||||||
 | 
					         * initialized to zero since they *are* anonymous mapped
 | 
				
			||||||
 | 
					         * pages, however we have to take care with the contents that
 | 
				
			||||||
 | 
					         * come from the remaining part of the previous page: it may
 | 
				
			||||||
 | 
					         * contains garbage data due to a previous heap usage (grown
 | 
				
			||||||
 | 
					         * then shrunken).  */
 | 
				
			||||||
 | 
					        memset(g2h(target_brk), 0, brk_page - target_brk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        target_brk = new_brk;
 | 
					        target_brk = new_brk;
 | 
				
			||||||
        brk_page = HOST_PAGE_ALIGN(target_brk);
 | 
					        brk_page = HOST_PAGE_ALIGN(target_brk);
 | 
				
			||||||
        DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk);
 | 
					        DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk);
 | 
				
			||||||
@ -7632,22 +7644,67 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CONFIG_ATTR
 | 
				
			||||||
#ifdef TARGET_NR_setxattr
 | 
					#ifdef TARGET_NR_setxattr
 | 
				
			||||||
    case TARGET_NR_setxattr:
 | 
					 | 
				
			||||||
    case TARGET_NR_lsetxattr:
 | 
					    case TARGET_NR_lsetxattr:
 | 
				
			||||||
    case TARGET_NR_fsetxattr:
 | 
					    case TARGET_NR_fsetxattr:
 | 
				
			||||||
    case TARGET_NR_getxattr:
 | 
					 | 
				
			||||||
    case TARGET_NR_lgetxattr:
 | 
					    case TARGET_NR_lgetxattr:
 | 
				
			||||||
    case TARGET_NR_fgetxattr:
 | 
					    case TARGET_NR_fgetxattr:
 | 
				
			||||||
    case TARGET_NR_listxattr:
 | 
					    case TARGET_NR_listxattr:
 | 
				
			||||||
    case TARGET_NR_llistxattr:
 | 
					    case TARGET_NR_llistxattr:
 | 
				
			||||||
    case TARGET_NR_flistxattr:
 | 
					    case TARGET_NR_flistxattr:
 | 
				
			||||||
    case TARGET_NR_removexattr:
 | 
					 | 
				
			||||||
    case TARGET_NR_lremovexattr:
 | 
					    case TARGET_NR_lremovexattr:
 | 
				
			||||||
    case TARGET_NR_fremovexattr:
 | 
					    case TARGET_NR_fremovexattr:
 | 
				
			||||||
        ret = -TARGET_EOPNOTSUPP;
 | 
					        ret = -TARGET_EOPNOTSUPP;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					    case TARGET_NR_setxattr:
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            void *p, *n, *v;
 | 
				
			||||||
 | 
					            p = lock_user_string(arg1);
 | 
				
			||||||
 | 
					            n = lock_user_string(arg2);
 | 
				
			||||||
 | 
					            v = lock_user(VERIFY_READ, arg3, arg4, 1);
 | 
				
			||||||
 | 
					            if (p && n && v) {
 | 
				
			||||||
 | 
					                ret = get_errno(setxattr(p, n, v, arg4, arg5));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                ret = -TARGET_EFAULT;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            unlock_user(p, arg1, 0);
 | 
				
			||||||
 | 
					            unlock_user(n, arg2, 0);
 | 
				
			||||||
 | 
					            unlock_user(v, arg3, 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case TARGET_NR_getxattr:
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            void *p, *n, *v;
 | 
				
			||||||
 | 
					            p = lock_user_string(arg1);
 | 
				
			||||||
 | 
					            n = lock_user_string(arg2);
 | 
				
			||||||
 | 
					            v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
 | 
				
			||||||
 | 
					            if (p && n && v) {
 | 
				
			||||||
 | 
					                ret = get_errno(getxattr(p, n, v, arg4));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                ret = -TARGET_EFAULT;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            unlock_user(p, arg1, 0);
 | 
				
			||||||
 | 
					            unlock_user(n, arg2, 0);
 | 
				
			||||||
 | 
					            unlock_user(v, arg3, arg4);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case TARGET_NR_removexattr:
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            void *p, *n;
 | 
				
			||||||
 | 
					            p = lock_user_string(arg1);
 | 
				
			||||||
 | 
					            n = lock_user_string(arg2);
 | 
				
			||||||
 | 
					            if (p && n) {
 | 
				
			||||||
 | 
					                ret = get_errno(removexattr(p, n));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                ret = -TARGET_EFAULT;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            unlock_user(p, arg1, 0);
 | 
				
			||||||
 | 
					            unlock_user(n, arg2, 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#endif /* CONFIG_ATTR */
 | 
				
			||||||
#ifdef TARGET_NR_set_thread_area
 | 
					#ifdef TARGET_NR_set_thread_area
 | 
				
			||||||
    case TARGET_NR_set_thread_area:
 | 
					    case TARGET_NR_set_thread_area:
 | 
				
			||||||
#if defined(TARGET_MIPS)
 | 
					#if defined(TARGET_MIPS)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user