basic clone() support

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@40 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2003-03-22 17:31:38 +00:00
parent 612384d771
commit 1b6b029e40
14 changed files with 327 additions and 44 deletions

View file

@ -104,6 +104,40 @@ void write_dt(void *ptr, unsigned long addr, unsigned long limit,
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)
{
printf("gemu version " GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
@ -113,8 +147,6 @@ void usage(void)
exit(1);
}
int main(int argc, char **argv)
{
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_GS, __USER_DS);
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();
}
}
cpu_loop(env);
/* never exits */
return 0;
}

View file

@ -51,7 +51,7 @@ void syscall_init(void);
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
long arg4, long arg5, long arg6);
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
struct CPUX86State;
void cpu_loop(struct CPUX86State *env);
#endif

View file

@ -762,8 +762,48 @@ int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecou
}
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
void syscall_init(void)
{
#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
_mcleanup();
#endif
/* XXX: should free thread stack and CPU env */
_exit(arg1);
ret = 0; /* avoid warning */
break;
@ -807,7 +848,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = do_brk((char *)arg1);
break;
case TARGET_NR_fork:
ret = get_errno(fork());
ret = get_errno(do_fork(cpu_env, SIGCHLD, 0));
break;
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:
goto unimplemented;
case TARGET_NR_clone:
goto unimplemented;
ret = get_errno(do_fork(cpu_env, arg1, arg2));
break;
case TARGET_NR_setdomainname:
ret = get_errno(setdomainname((const char *)arg1, arg2));
break;
@ -1310,7 +1352,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_sysfs:
goto unimplemented;
case TARGET_NR_personality:
ret = get_errno(mprotect((void *)arg1, arg2, arg3));
ret = get_errno(personality(arg1));
break;
case TARGET_NR_afs_syscall:
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_min:
case TARGET_NR_sched_rr_get_interval:
goto unimplemented;
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_setresuid:
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_putpmsg:
case TARGET_NR_vfork:
ret = get_errno(vfork());
ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
break;
case TARGET_NR_ugetrlimit:
case TARGET_NR_truncate64:

View file

@ -24,6 +24,11 @@ struct target_timeval {
target_long tv_usec;
};
struct target_timespec {
target_long tv_sec;
target_long tv_nsec;
};
struct target_iovec {
target_long iov_base; /* Starting address */
target_long iov_len; /* Number of bytes */