Skip to content

Commit

Permalink
Implement vfork, nanosleep, readv, wait4, setitimer
Browse files Browse the repository at this point in the history
  • Loading branch information
tbodt committed Jul 27, 2017
1 parent b75e9bb commit a2fb2f6
Show file tree
Hide file tree
Showing 16 changed files with 192 additions and 29 deletions.
8 changes: 6 additions & 2 deletions emu/interp.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#include "emu/cpu.h"
#include "emu/cpuid.h"

// TODO get rid of these
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare"

#define DECLARE_LOCALS \
dword_t saved_ip = cpu->eip; \
byte_t insn; \
Expand Down Expand Up @@ -228,15 +232,15 @@
#define ADC(src, dst,z) \
SETAF(src, dst,z); \
cpu->of = signed_overflow(add, get(dst,z), get(src,z) + cpu->cf, cpu->res,z) \
|| (get(src,z) + cpu->cf == -1); \
|| (get(src,z) + cpu->cf == (uint(sz(z))) -1); \
cpu->cf = unsigned_overflow(add, get(dst,z), get(src,z) + cpu->cf, cpu->res,z) \
|| (cpu->cf && get(src,z) == (uint(sz(z))) -1); \
set(dst, cpu->res,z); SETRESFLAGS

#define SBB(src, dst,z) \
SETAF(src, dst,z); \
cpu->of = signed_overflow(sub, get(dst,z), get(src,z) + cpu->cf, cpu->res,z) \
|| (get(src,z) + cpu->cf == -1); \
|| (get(src,z) + cpu->cf == (uint(sz(z))) -1); \
cpu->cf = unsigned_overflow(sub, get(dst,z), get(src,z) + cpu->cf, cpu->res,z) \
|| (cpu->cf && get(src,z) == (uint(sz(z))) -1); \
set(dst, cpu->res,z); SETRESFLAGS
Expand Down
2 changes: 1 addition & 1 deletion fs/real.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "sys/calls.h"
#include "sys/fs.h"

char *strnprepend(char *str, const char *prefix, int max) {
char *strnprepend(char *str, const char *prefix, size_t max) {
if (strlen(str) + strlen(prefix) + 1 > max)
return NULL;
const char *src = str + strlen(str) + 1;
Expand Down
4 changes: 3 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@ emu_src = [
]

threads = dependency('threads')
librt = meson.get_compiler('c').find_library('rt', required: false)

libish = library('ish', sys_src + emu_src,
include_directories: includes)
include_directories: includes,
dependencies: [librt, threads])
ish = declare_dependency(
link_with: libish,
include_directories: includes)
Expand Down
2 changes: 1 addition & 1 deletion misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#endif
#define TRACEI(msg, ...) TRACE(msg "\t", ##__VA_ARGS__)

#define TODO(msg, ...) TRACE("TODO: " msg "\n", ##__VA_ARGS__); abort()
#define TODO(msg, ...) { printf("TODO: " msg "\n", ##__VA_ARGS__); abort(); }
#define FIXME(msg, ...) printf("FIXME " msg "\n", ##__VA_ARGS__)

#if defined(__i386__) || defined(__x86_64__)
Expand Down
11 changes: 7 additions & 4 deletions sys/calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,21 @@ syscall_t syscall_table[] = {
[85] = (syscall_t) sys_readlink,
[90] = (syscall_t) sys_mmap,
[91] = (syscall_t) sys_munmap,
[104] = (syscall_t) sys_setitimer,
[114] = (syscall_t) sys_wait4,
[116] = (syscall_t) sys_sysinfo,
[120] = (syscall_t) sys_clone,
[122] = (syscall_t) _sys_uname,
[125] = (syscall_t) sys_mprotect,
[140] = (syscall_t) sys__llseek,
[145] = (syscall_t) sys_readv,
[146] = (syscall_t) sys_writev,
[162] = (syscall_t) sys_nanosleep,
[183] = (syscall_t) sys_getcwd,
[174] = (syscall_t) sys_rt_sigaction,
[175] = (syscall_t) sys_rt_sigprocmask,
[187] = (syscall_t) sys_sendfile,
[190] = (syscall_t) sys_vfork,
[192] = (syscall_t) sys_mmap2,
[195] = (syscall_t) sys_stat64,
[196] = (syscall_t) sys_lstat64,
Expand All @@ -70,8 +75,7 @@ void handle_interrupt(struct cpu_state *cpu, int interrupt) {
if (syscall_num >= NUM_SYSCALLS || syscall_table[syscall_num] == NULL) {
// TODO SIGSYS
printf("missing syscall %d\n", syscall_num);
if (send_signal(SIGSYS_) < 0)
printf("send sigsys failed\n");
send_signal(current, SIGSYS_);
} else {
TRACE("syscall %d ", syscall_num);
int result = syscall_table[syscall_num](cpu->ebx, cpu->ecx, cpu->edx, cpu->esi, cpu->edi, cpu->ebp);
Expand All @@ -85,8 +89,7 @@ void handle_interrupt(struct cpu_state *cpu, int interrupt) {
sys_exit(1);
} else if (interrupt == INT_UNDEFINED) {
printf("illegal instruction\n");
if (send_signal(SIGILL_) < 0)
printf("send sigill failed\n");
send_signal(current, SIGILL_);
} else {
printf("exiting\n");
sys_exit(interrupt);
Expand Down
24 changes: 24 additions & 0 deletions sys/calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ void user_put_count(addr_t addr, const void *buf, size_t count);

// process lifecycle
dword_t sys_clone(dword_t flags, addr_t stack, addr_t ptid, addr_t tls, addr_t ctid);
dword_t sys_vfork();
int sys_execve(const char *file, char *const argv[], char *const envp[]);
dword_t _sys_execve(addr_t file, addr_t argv, addr_t envp);
dword_t sys_exit(dword_t status);
dword_t sys_exit_group(dword_t status);
dword_t sys_wait4(dword_t pid, addr_t status_addr, dword_t options, addr_t rusage_addr);
dword_t sys_waitpid(dword_t pid, addr_t status_addr, dword_t options);

// memory management
Expand All @@ -49,6 +51,7 @@ struct io_vec {
#define LSEEK_CUR 1
#define LSEEK_END 2
dword_t sys_read(fd_t fd_no, addr_t buf_addr, dword_t size);
dword_t sys_readv(fd_t fd_no, addr_t iovec_addr, dword_t iovec_count);
dword_t sys_write(fd_t fd_no, addr_t buf_addr, dword_t size);
dword_t sys_writev(fd_t fd_no, addr_t iovec_addr, dword_t iovec_count);
dword_t sys__llseek(fd_t f, dword_t off_high, dword_t off_low, addr_t res_addr, dword_t whence);
Expand Down Expand Up @@ -126,6 +129,27 @@ dword_t sys_time(addr_t time_out);
#define CLOCK_MONOTONIC_ 1
dword_t sys_clock_gettime(dword_t clock, addr_t tp);

struct timeval_ {
dword_t sec;
dword_t usec;
};
struct timespec_ {
dword_t sec;
dword_t nsec;
};

#define ITIMER_REAL_ 0
#define ITIMER_VIRTUAL_ 1
#define ITIMER_PROF_ 2
struct itimerval_ {
struct timeval_ interval;
struct timeval_ value;
};
dword_t sys_getitimer(dword_t which, addr_t val);
dword_t sys_setitimer(dword_t which, addr_t new_val, addr_t old_val);

dword_t sys_nanosleep(addr_t req, addr_t rem);

typedef int (*syscall_t)(dword_t,dword_t,dword_t,dword_t,dword_t,dword_t);

#endif
1 change: 1 addition & 0 deletions sys/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ int sys_execve(const char *file, char *const argv[], char *const envp[]) {

current->cpu.esp = sp;
current->cpu.eip = entry;
pthread_cond_broadcast(&current->vfork_done);

err = 0;
out_free_interp:
Expand Down
40 changes: 36 additions & 4 deletions sys/exit.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ noreturn void do_exit(int status) {
current->zombie = true;
pthread_cond_broadcast(&current->parent->child_exit);
pthread_mutex_unlock(&current->parent->lock);

pthread_mutex_lock(&current->lock);
pthread_cond_broadcast(&current->vfork_done);
pthread_mutex_unlock(&current->lock);

pthread_exit(NULL);
}

Expand All @@ -21,17 +26,40 @@ dword_t sys_exit_group(dword_t status) {
sys_exit(status);
}

static int reap_if_zombie(struct process *proc, addr_t status_addr) {
struct rusage_ {
struct timeval_ utime;
struct timeval_ stime;
dword_t maxrss;
dword_t ixrss;
dword_t idrss;
dword_t isrss;
dword_t minflt;
dword_t majflt;
dword_t nswap;
dword_t inblock;
dword_t oublock;
dword_t msgsnd;
dword_t msgrcv;
dword_t nsignals;
dword_t nvcsw;
dword_t nivcsw;
};

static int reap_if_zombie(struct process *proc, addr_t status_addr, addr_t rusage_addr) {
if (proc->zombie) {
if (status_addr != 0)
user_put(status_addr, proc->exit_code);
if (rusage_addr != 0) {
struct rusage_ rusage = {};
user_put_count(rusage_addr, &rusage, sizeof(rusage));
}
process_destroy(proc);
return 1;
}
return 0;
}

dword_t sys_waitpid(dword_t pid, addr_t status_addr, dword_t options) {
dword_t sys_wait4(dword_t pid, addr_t status_addr, dword_t options, addr_t rusage_addr) {
if (pid == (dword_t) -1) {
if (list_empty(&current->children))
return _ESRCH;
Expand All @@ -47,12 +75,12 @@ dword_t sys_waitpid(dword_t pid, addr_t status_addr, dword_t options) {
struct process *proc;
list_for_each_entry(&current->children, proc, siblings) {
pid = proc->pid;
if (reap_if_zombie(proc, status_addr))
if (reap_if_zombie(proc, status_addr, rusage_addr))
goto found_zombie;
}
} else {
// check if this child is a zombie
if (reap_if_zombie(process_for_pid(pid), status_addr))
if (reap_if_zombie(process_for_pid(pid), status_addr, rusage_addr))
goto found_zombie;
}

Expand All @@ -64,3 +92,7 @@ dword_t sys_waitpid(dword_t pid, addr_t status_addr, dword_t options) {
pthread_mutex_unlock(&current->lock);
return pid;
}

dword_t sys_waitpid(dword_t pid, addr_t status_addr, dword_t options) {
return sys_wait4(pid, status_addr, options, 0);
}
16 changes: 16 additions & 0 deletions sys/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@ dword_t sys_read(fd_t fd_no, addr_t buf_addr, dword_t size) {
return res;
}

dword_t sys_readv(fd_t fd_no, addr_t iovec_addr, dword_t iovec_count) {
struct io_vec iovecs[iovec_count];
user_get_count(iovec_addr, iovecs, sizeof(iovecs));
int res;
dword_t count = 0;
for (unsigned i = 0; i < iovec_count; i++) {
res = sys_read(fd_no, iovecs[i].base, iovecs[i].len);
if (iovecs[i].len != 0 && res == 0)
break;
if (res < 0)
return res;
count += res;
}
return count;
}

dword_t sys_write(fd_t fd_no, addr_t buf_addr, dword_t size) {
char buf[size];
user_get_count(buf_addr, buf, size);
Expand Down
2 changes: 1 addition & 1 deletion sys/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,6 @@ extern const struct fs_ops realfs;
extern const struct fd_ops realfs_fdops; // TODO remove from header file

// TODO put this somewhere else
char *strnprepend(char *str, const char *prefix, int max);
char *strnprepend(char *str, const char *prefix, size_t max);

#endif
23 changes: 18 additions & 5 deletions sys/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ struct process *process_create() {
list_init(&proc->siblings);
pthread_mutex_init(&proc->lock, NULL);
pthread_cond_init(&proc->child_exit, NULL);
pthread_cond_init(&proc->vfork_done, NULL);
proc->has_timer = false;
procs[proc->pid] = proc;
return proc;
}
Expand Down Expand Up @@ -92,10 +94,6 @@ static int copy_memory(struct process *proc, int flags) {
return 0;
}

// eax = syscall number
// ebx = flags
// ecx = stack
// edx, esi, edi = unimplemented garbage
static int dup_process(int flags, addr_t stack, addr_t ptid, addr_t tls, addr_t ctid, struct process **p) {
if (ptid != 0 || tls != 0) {
FIXME("clone with ptid or ts not null");
Expand All @@ -112,6 +110,7 @@ static int dup_process(int flags, addr_t stack, addr_t ptid, addr_t tls, addr_t
struct process *proc = process_create();
if (proc == NULL)
return _ENOMEM;
pthread_mutex_lock(&proc->lock);
dword_t pid = proc->pid;
*proc = *current;
proc->pid = pid;
Expand All @@ -129,18 +128,32 @@ static int dup_process(int flags, addr_t stack, addr_t ptid, addr_t tls, addr_t
user_put_proc(proc, ctid, proc->pid);
start_thread(proc);

*p = proc;
if (flags & CLONE_VFORK_)
pthread_cond_wait(&proc->vfork_done, &proc->lock);

pthread_mutex_unlock(&proc->lock);
if (p)
*p = proc;
return 0;

fail_free_proc:
pthread_mutex_unlock(&proc->lock);
free(proc);
return err;
}

// eax = syscall number
// ebx = flags
// ecx = stack
// edx, esi, edi = unimplemented garbage
dword_t sys_clone(dword_t flags, addr_t stack, addr_t ptid, addr_t tls, addr_t ctid) {
struct process *proc;
int err = dup_process(flags, stack, ptid, tls, ctid, &proc);
if (err < 0)
return err;
return proc->pid;
}

dword_t sys_vfork() {
return sys_clone(CLONE_VFORK_ | CLONE_VM_ | SIGCHLD_, current->cpu.esp, 0, 0, 0);
}
6 changes: 6 additions & 0 deletions sys/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,18 @@ struct process {
struct list children;
struct list siblings;

bool has_timer;
timer_t timer;

// the next two fields are protected by the lock on the parent process, not
// the lock on the process. this is because waitpid locks the parent
// process to wait for any of its children to exit.
dword_t exit_code;
bool zombie;
pthread_cond_t child_exit;

pthread_cond_t vfork_done;

pthread_mutex_t lock;
};

Expand Down
16 changes: 8 additions & 8 deletions sys/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
int xsave_extra = 0;
int fxsave_extra = 0;

int send_signal(int sig) {
if (current->sigactions[sig].handler == SIG_IGN_)
return 0;
if (current->sigactions[sig].handler == SIG_DFL_)
void send_signal(struct process *proc, int sig) {
if (proc->sigactions[sig].handler == SIG_IGN_)
return;
if (proc->sigactions[sig].handler == SIG_DFL_)
sys_exit(0);

// setup the frame
struct sigframe_ frame = {};
frame.sig = sig;

struct cpu_state *cpu = &current->cpu;
struct cpu_state *cpu = &proc->cpu;
frame.sc.ax = cpu->eax;
frame.sc.bx = cpu->ebx;
frame.sc.cx = cpu->ecx;
Expand All @@ -36,15 +36,15 @@ int send_signal(int sig) {
fprintf(stderr, "sigreturn not found in vdso, this should never happen\n");
abort();
}
frame.pretcode = current->vdso + sigreturn_addr;
frame.pretcode = proc->vdso + sigreturn_addr;
// for legacy purposes
frame.retcode.popmov = 0xb858;
frame.retcode.nr_sigreturn = 173; // rt_sigreturn
frame.retcode.int80 = 0x80cd;

// set up registers for signal handler
cpu->eax = sig;
cpu->eip = current->sigactions[sig].handler;
cpu->eip = proc->sigactions[sig].handler;

dword_t sp = cpu->esp;
if (xsave_extra) {
Expand All @@ -64,7 +64,7 @@ int send_signal(int sig) {
// install frame
user_put_count(sp, &frame, sizeof(frame));

return 0;
return;
}

static int do_sigaction(int sig, const struct sigaction_ *action, struct sigaction_ *oldaction) {
Expand Down
Loading

0 comments on commit a2fb2f6

Please sign in to comment.