basic clone() support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@40 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									612384d771
								
							
						
					
					
						commit
						1b6b029e40
					
				
							
								
								
									
										9
									
								
								TODO
								
								
								
								
							
							
						
						
									
										9
									
								
								TODO
								
								
								
								
							| 
						 | 
					@ -1,8 +1,9 @@
 | 
				
			||||||
- overrides/16bit for string ops
 | 
					- verify thread support (clone() and various locks)
 | 
				
			||||||
- optimize translated cache chaining (DLL PLT-like system)
 | 
					 | 
				
			||||||
- 64 bit syscalls
 | 
					 | 
				
			||||||
- signals
 | 
					- signals
 | 
				
			||||||
- threads
 | 
					- optimize translated cache chaining (DLL PLT-like system)
 | 
				
			||||||
 | 
					- vm86 syscall support
 | 
				
			||||||
 | 
					- overrides/16bit for string ops
 | 
				
			||||||
 | 
					- more syscalls (in particular all 64 bit ones)
 | 
				
			||||||
- make it self runnable (use same trick as ld.so : include its own relocator and libc)
 | 
					- make it self runnable (use same trick as ld.so : include its own relocator and libc)
 | 
				
			||||||
- improved 16 bit support 
 | 
					- improved 16 bit support 
 | 
				
			||||||
- fix FPU exceptions (in particular: gen_op_fpush not before mem load)
 | 
					- fix FPU exceptions (in particular: gen_op_fpush not before mem load)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										50
									
								
								exec-i386.c
								
								
								
								
							
							
						
						
									
										50
									
								
								exec-i386.c
								
								
								
								
							| 
						 | 
					@ -52,6 +52,52 @@ int nb_tbs;
 | 
				
			||||||
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
 | 
					uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
 | 
				
			||||||
uint8_t *code_gen_ptr;
 | 
					uint8_t *code_gen_ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* thread support */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __powerpc__
 | 
				
			||||||
 | 
					static inline int testandset (int *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    __asm__ __volatile__ (
 | 
				
			||||||
 | 
					                          "0:    lwarx %0,0,%1 ;"
 | 
				
			||||||
 | 
					                          "      xor. %0,%3,%0;"
 | 
				
			||||||
 | 
					                          "      bne 1f;"
 | 
				
			||||||
 | 
					                          "      stwcx. %2,0,%1;"
 | 
				
			||||||
 | 
					                          "      bne- 0b;"
 | 
				
			||||||
 | 
					                          "1:    "
 | 
				
			||||||
 | 
					                          : "=&r" (ret)
 | 
				
			||||||
 | 
					                          : "r" (p), "r" (1), "r" (0)
 | 
				
			||||||
 | 
					                          : "cr0", "memory");
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __i386__
 | 
				
			||||||
 | 
					static inline int testandset (int *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char ret;
 | 
				
			||||||
 | 
					    long int readval;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
 | 
				
			||||||
 | 
					                          : "=q" (ret), "=m" (*p), "=a" (readval)
 | 
				
			||||||
 | 
					                          : "r" (1), "m" (*p), "a" (0)
 | 
				
			||||||
 | 
					                          : "memory");
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int global_cpu_lock = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cpu_lock(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    while (testandset(&global_cpu_lock));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cpu_unlock(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    global_cpu_lock = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef DEBUG_EXEC
 | 
					#ifdef DEBUG_EXEC
 | 
				
			||||||
static const char *cc_op_str[] = {
 | 
					static const char *cc_op_str[] = {
 | 
				
			||||||
    "DYNAMIC",
 | 
					    "DYNAMIC",
 | 
				
			||||||
| 
						 | 
					@ -266,11 +312,15 @@ int cpu_x86_exec(CPUX86State *env1)
 | 
				
			||||||
            tc_ptr = tb->tc_ptr;
 | 
					            tc_ptr = tb->tc_ptr;
 | 
				
			||||||
            if (!tb->tc_ptr) {
 | 
					            if (!tb->tc_ptr) {
 | 
				
			||||||
                /* if no translated code available, then translate it now */
 | 
					                /* if no translated code available, then translate it now */
 | 
				
			||||||
 | 
					                /* XXX: very inefficient: we lock all the cpus when
 | 
				
			||||||
 | 
					                   generating code */
 | 
				
			||||||
 | 
					                cpu_lock();
 | 
				
			||||||
                tc_ptr = code_gen_ptr;
 | 
					                tc_ptr = code_gen_ptr;
 | 
				
			||||||
                cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
 | 
					                cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
 | 
				
			||||||
                                 &code_gen_size, pc, cs_base, flags);
 | 
					                                 &code_gen_size, pc, cs_base, flags);
 | 
				
			||||||
                tb->tc_ptr = tc_ptr;
 | 
					                tb->tc_ptr = tc_ptr;
 | 
				
			||||||
                code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
 | 
					                code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
 | 
				
			||||||
 | 
					                cpu_unlock();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            /* execute the generated code */
 | 
					            /* execute the generated code */
 | 
				
			||||||
            gen_func = (void *)tc_ptr;
 | 
					            gen_func = (void *)tc_ptr;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -139,3 +139,5 @@ typedef struct CCTable {
 | 
				
			||||||
extern CCTable cc_table[];
 | 
					extern CCTable cc_table[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void load_seg(int seg_reg, int selector);
 | 
					void load_seg(int seg_reg, int selector);
 | 
				
			||||||
 | 
					void cpu_lock(void);
 | 
				
			||||||
 | 
					void cpu_unlock(void);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,6 +104,40 @@ void write_dt(void *ptr, unsigned long addr, unsigned long limit,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint64_t gdt_table[6];
 | 
					uint64_t gdt_table[6];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cpu_loop(struct CPUX86State *env)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for(;;) {
 | 
				
			||||||
 | 
					        int err;
 | 
				
			||||||
 | 
					        uint8_t *pc;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        err = cpu_x86_exec(env);
 | 
				
			||||||
 | 
					        pc = env->seg_cache[R_CS].base + env->eip;
 | 
				
			||||||
 | 
					        switch(err) {
 | 
				
			||||||
 | 
					        case EXCP0D_GPF:
 | 
				
			||||||
 | 
					            if (pc[0] == 0xcd && pc[1] == 0x80) {
 | 
				
			||||||
 | 
					                /* syscall */
 | 
				
			||||||
 | 
					                env->eip += 2;
 | 
				
			||||||
 | 
					                env->regs[R_EAX] = do_syscall(env, 
 | 
				
			||||||
 | 
					                                              env->regs[R_EAX], 
 | 
				
			||||||
 | 
					                                              env->regs[R_EBX],
 | 
				
			||||||
 | 
					                                              env->regs[R_ECX],
 | 
				
			||||||
 | 
					                                              env->regs[R_EDX],
 | 
				
			||||||
 | 
					                                              env->regs[R_ESI],
 | 
				
			||||||
 | 
					                                              env->regs[R_EDI],
 | 
				
			||||||
 | 
					                                              env->regs[R_EBP]);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                goto trap_error;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					        trap_error:
 | 
				
			||||||
 | 
					            fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", 
 | 
				
			||||||
 | 
					                    (long)pc, err);
 | 
				
			||||||
 | 
					            abort();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void usage(void)
 | 
					void usage(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    printf("gemu version " GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
 | 
					    printf("gemu version " GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
 | 
				
			||||||
| 
						 | 
					@ -113,8 +147,6 @@ void usage(void)
 | 
				
			||||||
    exit(1);
 | 
					    exit(1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const char *filename;
 | 
					    const char *filename;
 | 
				
			||||||
| 
						 | 
					@ -193,35 +225,7 @@ int main(int argc, char **argv)
 | 
				
			||||||
    cpu_x86_load_seg(env, R_FS, __USER_DS);
 | 
					    cpu_x86_load_seg(env, R_FS, __USER_DS);
 | 
				
			||||||
    cpu_x86_load_seg(env, R_GS, __USER_DS);
 | 
					    cpu_x86_load_seg(env, R_GS, __USER_DS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for(;;) {
 | 
					    cpu_loop(env);
 | 
				
			||||||
        int err;
 | 
					    /* never exits */
 | 
				
			||||||
        uint8_t *pc;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        err = cpu_x86_exec(env);
 | 
					 | 
				
			||||||
        pc = env->seg_cache[R_CS].base + env->eip;
 | 
					 | 
				
			||||||
        switch(err) {
 | 
					 | 
				
			||||||
        case EXCP0D_GPF:
 | 
					 | 
				
			||||||
            if (pc[0] == 0xcd && pc[1] == 0x80) {
 | 
					 | 
				
			||||||
                /* syscall */
 | 
					 | 
				
			||||||
                env->eip += 2;
 | 
					 | 
				
			||||||
                env->regs[R_EAX] = do_syscall(env, 
 | 
					 | 
				
			||||||
                                              env->regs[R_EAX], 
 | 
					 | 
				
			||||||
                                              env->regs[R_EBX],
 | 
					 | 
				
			||||||
                                              env->regs[R_ECX],
 | 
					 | 
				
			||||||
                                              env->regs[R_EDX],
 | 
					 | 
				
			||||||
                                              env->regs[R_ESI],
 | 
					 | 
				
			||||||
                                              env->regs[R_EDI],
 | 
					 | 
				
			||||||
                                              env->regs[R_EBP]);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                goto trap_error;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        default:
 | 
					 | 
				
			||||||
        trap_error:
 | 
					 | 
				
			||||||
            fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", 
 | 
					 | 
				
			||||||
                    (long)pc, err);
 | 
					 | 
				
			||||||
            abort();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,7 +51,7 @@ void syscall_init(void);
 | 
				
			||||||
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, 
 | 
					long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, 
 | 
				
			||||||
                long arg4, long arg5, long arg6);
 | 
					                long arg4, long arg5, long arg6);
 | 
				
			||||||
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
 | 
					void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
 | 
				
			||||||
 | 
					struct CPUX86State;
 | 
				
			||||||
 | 
					void cpu_loop(struct CPUX86State *env);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -762,8 +762,48 @@ int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecou
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* this stack is the equivalent of the kernel stack associated with a
 | 
				
			||||||
 | 
					   thread/process */
 | 
				
			||||||
 | 
					#define NEW_STACK_SIZE 8192
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int clone_func(void *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CPUX86State *env = arg;
 | 
				
			||||||
 | 
					    cpu_loop(env);
 | 
				
			||||||
 | 
					    /* never exits */
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    uint8_t *new_stack;
 | 
				
			||||||
 | 
					    CPUX86State *new_env;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (flags & CLONE_VM) {
 | 
				
			||||||
 | 
					        if (!newsp)
 | 
				
			||||||
 | 
					            newsp = env->regs[R_ESP];
 | 
				
			||||||
 | 
					        new_stack = malloc(NEW_STACK_SIZE);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /* we create a new CPU instance. */
 | 
				
			||||||
 | 
					        new_env = cpu_x86_init();
 | 
				
			||||||
 | 
					        memcpy(new_env, env, sizeof(CPUX86State));
 | 
				
			||||||
 | 
					        new_env->regs[R_ESP] = newsp;
 | 
				
			||||||
 | 
					        new_env->regs[R_EAX] = 0;
 | 
				
			||||||
 | 
					        ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        /* if no CLONE_VM, we consider it is a fork */
 | 
				
			||||||
 | 
					        if ((flags & ~CSIGNAL) != 0)
 | 
				
			||||||
 | 
					            return -EINVAL;
 | 
				
			||||||
 | 
					        ret = fork();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void syscall_init(void)
 | 
					void syscall_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); 
 | 
					#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); 
 | 
				
			||||||
| 
						 | 
					@ -788,6 +828,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 | 
				
			||||||
#ifdef HAVE_GPROF
 | 
					#ifdef HAVE_GPROF
 | 
				
			||||||
        _mcleanup();
 | 
					        _mcleanup();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					        /* XXX: should free thread stack and CPU env */
 | 
				
			||||||
        _exit(arg1);
 | 
					        _exit(arg1);
 | 
				
			||||||
        ret = 0; /* avoid warning */
 | 
					        ret = 0; /* avoid warning */
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
| 
						 | 
					@ -807,7 +848,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 | 
				
			||||||
        ret = do_brk((char *)arg1);
 | 
					        ret = do_brk((char *)arg1);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case TARGET_NR_fork:
 | 
					    case TARGET_NR_fork:
 | 
				
			||||||
        ret = get_errno(fork());
 | 
					        ret = get_errno(do_fork(cpu_env, SIGCHLD, 0));
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case TARGET_NR_waitpid:
 | 
					    case TARGET_NR_waitpid:
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
| 
						 | 
					@ -1241,7 +1282,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 | 
				
			||||||
    case TARGET_NR_sigreturn:
 | 
					    case TARGET_NR_sigreturn:
 | 
				
			||||||
        goto unimplemented;
 | 
					        goto unimplemented;
 | 
				
			||||||
    case TARGET_NR_clone:
 | 
					    case TARGET_NR_clone:
 | 
				
			||||||
        goto unimplemented;
 | 
					        ret = get_errno(do_fork(cpu_env, arg1, arg2));
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    case TARGET_NR_setdomainname:
 | 
					    case TARGET_NR_setdomainname:
 | 
				
			||||||
        ret = get_errno(setdomainname((const char *)arg1, arg2));
 | 
					        ret = get_errno(setdomainname((const char *)arg1, arg2));
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
| 
						 | 
					@ -1310,7 +1352,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 | 
				
			||||||
    case TARGET_NR_sysfs:
 | 
					    case TARGET_NR_sysfs:
 | 
				
			||||||
        goto unimplemented;
 | 
					        goto unimplemented;
 | 
				
			||||||
    case TARGET_NR_personality:
 | 
					    case TARGET_NR_personality:
 | 
				
			||||||
        ret = get_errno(mprotect((void *)arg1, arg2, arg3));
 | 
					        ret = get_errno(personality(arg1));
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case TARGET_NR_afs_syscall:
 | 
					    case TARGET_NR_afs_syscall:
 | 
				
			||||||
        goto unimplemented;
 | 
					        goto unimplemented;
 | 
				
			||||||
| 
						 | 
					@ -1447,7 +1489,23 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 | 
				
			||||||
    case TARGET_NR_sched_get_priority_max:
 | 
					    case TARGET_NR_sched_get_priority_max:
 | 
				
			||||||
    case TARGET_NR_sched_get_priority_min:
 | 
					    case TARGET_NR_sched_get_priority_min:
 | 
				
			||||||
    case TARGET_NR_sched_rr_get_interval:
 | 
					    case TARGET_NR_sched_rr_get_interval:
 | 
				
			||||||
 | 
					        goto unimplemented;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
    case TARGET_NR_nanosleep:
 | 
					    case TARGET_NR_nanosleep:
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            struct target_timespec *target_req = (void *)arg1;
 | 
				
			||||||
 | 
					            struct target_timespec *target_rem = (void *)arg2;
 | 
				
			||||||
 | 
					            struct timespec req, rem;
 | 
				
			||||||
 | 
					            req.tv_sec = tswapl(target_req->tv_sec);
 | 
				
			||||||
 | 
					            req.tv_nsec = tswapl(target_req->tv_nsec);
 | 
				
			||||||
 | 
					            ret = get_errno(nanosleep(&req, &rem));
 | 
				
			||||||
 | 
					            if (target_rem) {
 | 
				
			||||||
 | 
					                target_rem->tv_sec = tswapl(rem.tv_sec);
 | 
				
			||||||
 | 
					                target_rem->tv_nsec = tswapl(rem.tv_nsec);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case TARGET_NR_mremap:
 | 
					    case TARGET_NR_mremap:
 | 
				
			||||||
    case TARGET_NR_setresuid:
 | 
					    case TARGET_NR_setresuid:
 | 
				
			||||||
    case TARGET_NR_getresuid:
 | 
					    case TARGET_NR_getresuid:
 | 
				
			||||||
| 
						 | 
					@ -1481,7 +1539,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 | 
				
			||||||
    case TARGET_NR_getpmsg:
 | 
					    case TARGET_NR_getpmsg:
 | 
				
			||||||
    case TARGET_NR_putpmsg:
 | 
					    case TARGET_NR_putpmsg:
 | 
				
			||||||
    case TARGET_NR_vfork:
 | 
					    case TARGET_NR_vfork:
 | 
				
			||||||
        ret = get_errno(vfork());
 | 
					        ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case TARGET_NR_ugetrlimit:
 | 
					    case TARGET_NR_ugetrlimit:
 | 
				
			||||||
    case TARGET_NR_truncate64:
 | 
					    case TARGET_NR_truncate64:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,11 @@ struct target_timeval {
 | 
				
			||||||
    target_long tv_usec;
 | 
					    target_long tv_usec;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct target_timespec {
 | 
				
			||||||
 | 
					    target_long tv_sec;
 | 
				
			||||||
 | 
					    target_long tv_nsec;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct target_iovec {
 | 
					struct target_iovec {
 | 
				
			||||||
    target_long iov_base;   /* Starting address */
 | 
					    target_long iov_base;   /* Starting address */
 | 
				
			||||||
    target_long iov_len;   /* Number of bytes */
 | 
					    target_long iov_len;   /* Number of bytes */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								op-i386.c
								
								
								
								
							
							
						
						
									
										11
									
								
								op-i386.c
								
								
								
								
							| 
						 | 
					@ -2272,3 +2272,14 @@ void OPPROTO op_fninit(void)
 | 
				
			||||||
    env->fptags[6] = 1;
 | 
					    env->fptags[6] = 1;
 | 
				
			||||||
    env->fptags[7] = 1;
 | 
					    env->fptags[7] = 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* threading support */
 | 
				
			||||||
 | 
					void OPPROTO op_lock(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    cpu_lock();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void OPPROTO op_unlock(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    cpu_unlock();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -530,3 +530,5 @@ DEF(fnstcw_A0)
 | 
				
			||||||
DEF(fldcw_A0)
 | 
					DEF(fldcw_A0)
 | 
				
			||||||
DEF(fclex)
 | 
					DEF(fclex)
 | 
				
			||||||
DEF(fninit)
 | 
					DEF(fninit)
 | 
				
			||||||
 | 
					DEF(lock)
 | 
				
			||||||
 | 
					DEF(unlock)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@ CFLAGS=-Wall -O2 -g
 | 
				
			||||||
LDFLAGS=
 | 
					LDFLAGS=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ($(ARCH),i386)
 | 
					ifeq ($(ARCH),i386)
 | 
				
			||||||
TESTS=test2 sha1-i386 test-i386
 | 
					TESTS=testclone testsig testthread sha1-i386 test-i386
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
TESTS+=sha1
 | 
					TESTS+=sha1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,9 +16,15 @@ hello: hello.c
 | 
				
			||||||
	$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
 | 
						$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
 | 
				
			||||||
	strip hello
 | 
						strip hello
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test2: test2.c
 | 
					testclone: testclone.c
 | 
				
			||||||
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
 | 
						$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					testsig: testsig.c
 | 
				
			||||||
 | 
						$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					testthread: testthread.c
 | 
				
			||||||
 | 
						$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# i386 emulation test (test various opcodes) */
 | 
					# i386 emulation test (test various opcodes) */
 | 
				
			||||||
test-i386: test-i386.c test-i386-code16.S \
 | 
					test-i386: test-i386.c test-i386-code16.S \
 | 
				
			||||||
           test-i386.h test-i386-shift.h test-i386-muldiv.h
 | 
					           test-i386.h test-i386-shift.h test-i386-muldiv.h
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,61 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					#include <pthread.h>
 | 
				
			||||||
 | 
					#include <sys/wait.h>
 | 
				
			||||||
 | 
					#include <sched.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int thread1_func(void *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    char buf[512];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(i=0;i<10;i++) {
 | 
				
			||||||
 | 
					        snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg);
 | 
				
			||||||
 | 
					        write(1, buf, strlen(buf));
 | 
				
			||||||
 | 
					        usleep(100 * 1000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int thread2_func(void *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    char buf[512];
 | 
				
			||||||
 | 
					    for(i=0;i<20;i++) {
 | 
				
			||||||
 | 
					        snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg);
 | 
				
			||||||
 | 
					        write(1, buf, strlen(buf));
 | 
				
			||||||
 | 
					        usleep(120 * 1000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define STACK_SIZE 16384
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_clone(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint8_t *stack1, *stack2;
 | 
				
			||||||
 | 
					    int pid1, pid2, status1, status2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    stack1 = malloc(STACK_SIZE);
 | 
				
			||||||
 | 
					    pid1 = clone(thread1_func, stack1 + STACK_SIZE, 
 | 
				
			||||||
 | 
					                 CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    stack2 = malloc(STACK_SIZE);
 | 
				
			||||||
 | 
					    pid2 = clone(thread2_func, stack2 + STACK_SIZE, 
 | 
				
			||||||
 | 
					                 CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (waitpid(pid1, &status1, 0) != pid1);
 | 
				
			||||||
 | 
					    while (waitpid(pid2, &status2, 0) != pid2);
 | 
				
			||||||
 | 
					    printf("status1=0x%x\n", status1);
 | 
				
			||||||
 | 
					    printf("status2=0x%x\n", status2);
 | 
				
			||||||
 | 
					    printf("End of clone test.\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    test_clone();
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void alarm_handler(int sig)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    printf("alarm signal=%d\n", sig);
 | 
				
			||||||
 | 
					    alarm(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct sigaction act;
 | 
				
			||||||
 | 
					    act.sa_handler = alarm_handler;
 | 
				
			||||||
 | 
					    sigemptyset(&act.sa_mask);
 | 
				
			||||||
 | 
					    act.sa_flags = 0;
 | 
				
			||||||
 | 
					    sigaction(SIGALRM, &act, NULL);
 | 
				
			||||||
 | 
					    alarm(1);
 | 
				
			||||||
 | 
					    for(;;) {
 | 
				
			||||||
 | 
					        sleep(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,50 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					#include <pthread.h>
 | 
				
			||||||
 | 
					#include <sys/wait.h>
 | 
				
			||||||
 | 
					#include <sched.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *thread1_func(void *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    char buf[512];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(i=0;i<10;i++) {
 | 
				
			||||||
 | 
					        snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg);
 | 
				
			||||||
 | 
					        write(1, buf, strlen(buf));
 | 
				
			||||||
 | 
					        usleep(100 * 1000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *thread2_func(void *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    char buf[512];
 | 
				
			||||||
 | 
					    for(i=0;i<20;i++) {
 | 
				
			||||||
 | 
					        snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg);
 | 
				
			||||||
 | 
					        write(1, buf, strlen(buf));
 | 
				
			||||||
 | 
					        usleep(150 * 1000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_pthread(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    pthread_t tid1, tid2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pthread_create(&tid1, NULL, thread1_func, "hello1");
 | 
				
			||||||
 | 
					    pthread_create(&tid2, NULL, thread2_func, "hello2");
 | 
				
			||||||
 | 
					    pthread_join(tid1, NULL);
 | 
				
			||||||
 | 
					    pthread_join(tid2, NULL);
 | 
				
			||||||
 | 
					    printf("End of pthread test.\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    test_pthread();
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1395,6 +1395,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
 | 
				
			||||||
    s->aflag = aflag;
 | 
					    s->aflag = aflag;
 | 
				
			||||||
    s->dflag = dflag;
 | 
					    s->dflag = dflag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* lock generation */
 | 
				
			||||||
 | 
					    if (prefixes & PREFIX_LOCK)
 | 
				
			||||||
 | 
					        gen_op_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* now check op code */
 | 
					    /* now check op code */
 | 
				
			||||||
 reswitch:
 | 
					 reswitch:
 | 
				
			||||||
    switch(b) {
 | 
					    switch(b) {
 | 
				
			||||||
| 
						 | 
					@ -3153,8 +3157,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        goto illegal_op;
 | 
					        goto illegal_op;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /* lock generation */
 | 
				
			||||||
 | 
					    if (s->prefix & PREFIX_LOCK)
 | 
				
			||||||
 | 
					        gen_op_unlock();
 | 
				
			||||||
    return (long)s->pc;
 | 
					    return (long)s->pc;
 | 
				
			||||||
 illegal_op:
 | 
					 illegal_op:
 | 
				
			||||||
 | 
					    /* XXX: ensure that no lock was generated */
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3609,6 +3617,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
 | 
				
			||||||
            pc += count;
 | 
					            pc += count;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        fprintf(logfile, "\n");
 | 
					        fprintf(logfile, "\n");
 | 
				
			||||||
 | 
					        fflush(logfile);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue