Skip to content

Commit

Permalink
Make mem a refcounted structure
Browse files Browse the repository at this point in the history
Fixes exec after vfork not creating a new memory space
  • Loading branch information
tbodt committed Oct 13, 2017
1 parent 64444f4 commit 820dbdb
Show file tree
Hide file tree
Showing 15 changed files with 63 additions and 36 deletions.
2 changes: 1 addition & 1 deletion emu/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ union xmm_reg {
};

struct cpu_state {
struct mem mem;
struct mem *mem;

// assumes little endian (as does literally everything)
#define _REG(n) \
Expand Down
2 changes: 1 addition & 1 deletion emu/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
#define ty_128 union xmm_reg

#define mem_ptr(addr, type) ({ \
void *ptr = mem_##type##_ptr(&cpu->mem, addr); \
void *ptr = mem_##type##_ptr(cpu->mem, addr); \
if (ptr == NULL) { \
cpu->eip = saved_ip; \
cpu->segfault_addr = addr; \
Expand Down
18 changes: 17 additions & 1 deletion emu/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,26 @@ static void tlb_flush(struct mem *mem);

// this code currently assumes the system page size is 4k

void mem_init(struct mem *mem) {
struct mem *mem_new() {
struct mem *mem = malloc(sizeof(struct mem));
mem->refcount = 1;
mem->pt = calloc(PT_SIZE, sizeof(struct pt_entry *));
mem->tlb = malloc(TLB_SIZE * sizeof(struct tlb_entry));
tlb_flush(mem);
return mem;
}

void mem_retain(struct mem *mem) {
mem->refcount++;
}

void mem_release(struct mem *mem) {
if (mem->refcount-- == 0) {
pt_unmap(mem, 0, PT_SIZE, PT_FORCE);
free(mem->pt);
free(mem->tlb);
free(mem);
}
}

page_t pt_find_hole(struct mem *mem, pages_t size) {
Expand Down
9 changes: 7 additions & 2 deletions emu/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ typedef dword_t page_t;
#define BAD_PAGE 0x10000

struct mem {
unsigned refcount;
struct pt_entry **pt;
struct tlb_entry *tlb;
page_t dirty_page;
};

// Initialize a mem struct
void mem_init(struct mem *mem);
// Create a new address space
struct mem *mem_new();
// Increment the refcount
void mem_retain(struct mem *mem);
// Decrement the refcount, destroy everything in the space if 0
void mem_release(struct mem *mem);

#define PAGE_BITS 12
#define PAGE_SIZE (1 << PAGE_BITS)
Expand Down
8 changes: 4 additions & 4 deletions emu/modrm.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ extern inline struct modrm_info modrm_get_info(byte_t byte);
// them, and returns everything in out parameters.
// TODO currently only does 32-bit
void modrm_decode32(struct cpu_state *cpu, addr_t *addr_out, struct modrm_info *info_out) {
byte_t modrm = *(byte_t *) mem_read_ptr(&cpu->mem, cpu->eip);
byte_t modrm = *(byte_t *) mem_read_ptr(cpu->mem, cpu->eip);
struct modrm_info info = modrm_get_info(modrm);
cpu->eip++;
*info_out = info;
Expand All @@ -95,7 +95,7 @@ void modrm_decode32(struct cpu_state *cpu, addr_t *addr_out, struct modrm_info *
}
} else {
// sib is simple enough to not use a table for
byte_t sib = *(byte_t *) mem_read_ptr(&cpu->mem, cpu->eip);
byte_t sib = *(byte_t *) mem_read_ptr(cpu->mem, cpu->eip);
TRACE("sib %x ", sib);
cpu->eip++;
dword_t reg = 0;
Expand Down Expand Up @@ -136,14 +136,14 @@ void modrm_decode32(struct cpu_state *cpu, addr_t *addr_out, struct modrm_info *
int disp;
switch (info.type) {
case mod_disp8: {
disp = *(int8_t *) mem_read_ptr(&cpu->mem, cpu->eip);
disp = *(int8_t *) mem_read_ptr(cpu->mem, cpu->eip);
TRACE("disp %s0x%x ", (disp < 0 ? "-" : ""), (disp < 0 ? -disp : disp));
*addr_out += disp;
cpu->eip++;
break;
}
case mod_disp32: {
disp = *(int32_t *) mem_read_ptr(&cpu->mem, cpu->eip);
disp = *(int32_t *) mem_read_ptr(cpu->mem, cpu->eip);
TRACE("disp %s0x%x ", (disp < 0 ? "-" : ""), (disp < 0 ? -disp : disp));
*addr_out += disp;
cpu->eip += 4;
Expand Down
19 changes: 10 additions & 9 deletions sys/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ static int load_entry(struct prg_header ph, addr_t bias, struct fd *fd) {
if (ph.flags & PH_W) flags |= P_WRITE;

// TODO stop using fd->real_fd here
if ((err = pt_map_file(&curmem, PAGE(addr),
if ((err = pt_map_file(current->cpu.mem, PAGE(addr),
PAGE_ROUND_UP(filesize + OFFSET(addr)), fd->real_fd,
offset - OFFSET(addr), flags)) < 0)
return err;
Expand All @@ -97,7 +97,7 @@ static int load_entry(struct prg_header ph, addr_t bias, struct fd *fd) {

// then map the pages from after the file mapping up to and including the end of bss
if (bss_size - tail_size != 0)
if ((err = pt_map_nothing(&curmem, PAGE_ROUND_UP(addr + filesize),
if ((err = pt_map_nothing(current->cpu.mem, PAGE_ROUND_UP(addr + filesize),
PAGE_ROUND_UP(bss_size - tail_size), flags)) < 0)
return err;
}
Expand Down Expand Up @@ -163,7 +163,8 @@ int sys_execve(const char *file, char *const argv[], char *const envp[]) {
// from this point on, if any error occurs the process will have to be
// killed before it even starts. please don't be too sad about it, it's
// just a process.
pt_unmap(&curmem, 0, PT_SIZE, PT_FORCE);
mem_release(current->cpu.mem);
current->cpu.mem = mem_new();

addr_t load_addr; // used for AX_PHDR
bool load_addr_set = false;
Expand Down Expand Up @@ -212,7 +213,7 @@ int sys_execve(const char *file, char *const argv[], char *const envp[]) {
pages_t b = PAGE(interp_first->vaddr);
interp_size = a - b;
}
interp_addr = pt_find_hole(&curmem, interp_size) << PAGE_BITS;
interp_addr = pt_find_hole(current->cpu.mem, interp_size) << PAGE_BITS;
// now back to map dat shit! interpreter edition
for (int i = interp_header.phent_count; i >= 0; i--) {
if (interp_ph[i].type != PT_LOAD)
Expand All @@ -226,25 +227,25 @@ int sys_execve(const char *file, char *const argv[], char *const envp[]) {
// map vdso
err = _ENOMEM;
pages_t vdso_pages = sizeof(vdso_data) >> PAGE_BITS;
page_t vdso_page = pt_find_hole(&curmem, vdso_pages);
page_t vdso_page = pt_find_hole(current->cpu.mem, vdso_pages);
if (vdso_page == BAD_PAGE)
goto beyond_hope;
if ((err = pt_map(&curmem, vdso_page, vdso_pages, (void *) vdso_data, 0)) < 0)
if ((err = pt_map(current->cpu.mem, vdso_page, vdso_pages, (void *) vdso_data, 0)) < 0)
goto beyond_hope;
current->vdso = vdso_page << PAGE_BITS;
addr_t vdso_entry = current->vdso + ((struct elf_header *) vdso_data)->entry_point;

// map 3 empty "vvar" pages to satisfy ptraceomatic
page_t vvar_page = pt_find_hole(&curmem, 3);
page_t vvar_page = pt_find_hole(current->cpu.mem, 3);
if (vvar_page == BAD_PAGE)
goto beyond_hope;
if ((err = pt_map_nothing(&curmem, vvar_page, 3, 0)) < 0)
if ((err = pt_map_nothing(current->cpu.mem, vvar_page, 3, 0)) < 0)
goto beyond_hope;

// STACK TIME!

// allocate 1 page of stack at 0xffffd, and let it grow down
if ((err = pt_map_nothing(&curmem, 0xffffd, 1, P_WRITE | P_GROWSDOWN)) < 0) {
if ((err = pt_map_nothing(current->cpu.mem, 0xffffd, 1, P_WRITE | P_GROWSDOWN)) < 0) {
goto beyond_hope;
}
dword_t sp = 0xffffe000;
Expand Down
12 changes: 7 additions & 5 deletions sys/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@
#define CLONE_IO_ 0x80000000

static int copy_memory(struct process *proc, int flags) {
if (flags & CLONE_VM_)
struct mem *mem = proc->cpu.mem;
if (flags & CLONE_VM_) {
mem_retain(mem);
return 0;
struct mem old_mem = proc->cpu.mem;
struct mem *new_mem = &proc->cpu.mem;
mem_init(new_mem);
pt_copy_on_write(&old_mem, 0, new_mem, 0, PT_SIZE);
}
struct mem *new_mem = mem_new();
pt_copy_on_write(mem, 0, new_mem, 0, PT_SIZE);
return 0;
}

Expand Down Expand Up @@ -74,6 +75,7 @@ static int init_process(struct process *proc, dword_t flags, addr_t ctid_addr) {
// 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) {
STRACE("clone()");
if (ptid != 0 || tls != 0) {
FIXME("clone with ptid or ts not null");
return _EINVAL;
Expand Down
4 changes: 2 additions & 2 deletions sys/mm.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ addr_t sys_brk(addr_t new_brk) {
addr_t old_brk = current->brk;
if (new_brk > old_brk) {
// expand heap: map region from old_brk to new_brk
err = pt_map_nothing(&curmem, PAGE_ROUND_UP(old_brk),
err = pt_map_nothing(current->cpu.mem, PAGE_ROUND_UP(old_brk),
PAGE_ROUND_UP(new_brk) - PAGE_ROUND_UP(old_brk), P_WRITE);
if (err < 0) return err;
} else if (new_brk < old_brk) {
// shrink heap: unmap region from new_brk to old_brk
// first page to unmap is PAGE(new_brk);
// last page to unmap is PAGE(old_brk)
pt_unmap(&curmem, PAGE(new_brk), PAGE(old_brk), PT_FORCE);
pt_unmap(current->cpu.mem, PAGE(new_brk), PAGE(old_brk), PT_FORCE);
}
current->brk = new_brk;
}
Expand Down
10 changes: 5 additions & 5 deletions sys/mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ addr_t sys_mmap(addr_t addr, dword_t len, dword_t prot, dword_t flags, fd_t fd_n
pages_t pages = PAGE_ROUND_UP(len);
page_t page;
if (addr == 0) {
page = pt_find_hole(&curmem, pages);
page = pt_find_hole(current->cpu.mem, pages);
if (page == BAD_PAGE)
return _ENOMEM;
} else {
Expand All @@ -33,7 +33,7 @@ addr_t sys_mmap(addr_t addr, dword_t len, dword_t prot, dword_t flags, fd_t fd_n
TODO("MMAP_SHARED");
return _EINVAL;
}
if ((err = pt_map_nothing(&curmem, page, pages, prot)) < 0)
if ((err = pt_map_nothing(current->cpu.mem, page, pages, prot)) < 0)
return err;
} else {
// fd must be valid
Expand All @@ -45,7 +45,7 @@ addr_t sys_mmap(addr_t addr, dword_t len, dword_t prot, dword_t flags, fd_t fd_n
void *memory;
if ((err = fd->ops->mmap(fd, offset, len, prot, flags, &memory)) < 0)
return err;
if ((err = pt_map(&curmem, page, pages, memory, flags)) < 0)
if ((err = pt_map(current->cpu.mem, page, pages, memory, flags)) < 0)
return err;
}
return page << PAGE_BITS;
Expand All @@ -56,7 +56,7 @@ int_t sys_munmap(addr_t addr, uint_t len) {
return _EINVAL;
if (len == 0)
return _EINVAL;
if (pt_unmap(&curmem, PAGE(addr), PAGE_ROUND_UP(len), 0) < 0)
if (pt_unmap(current->cpu.mem, PAGE(addr), PAGE_ROUND_UP(len), 0) < 0)
return _EINVAL;
return 0;
}
Expand All @@ -68,7 +68,7 @@ int_t sys_mprotect(addr_t addr, uint_t len, int_t prot) {
if (prot & ~(P_READ | P_WRITE | P_EXEC))
return _EINVAL;
pages_t pages = PAGE_ROUND_UP(len);
return pt_set_flags(&curmem, PAGE(addr), pages, prot);
return pt_set_flags(current->cpu.mem, PAGE(addr), pages, prot);
}

dword_t sys_madvise(addr_t addr, dword_t len, dword_t advice) {
Expand Down
3 changes: 3 additions & 0 deletions sys/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,6 @@ void start_thread(struct process *proc) {
if (pthread_create(&proc->thread, NULL, process_run, proc) < 0)
abort();
}

// dumps out a tree of the processes, useful for running from a debugger
/* static void pstree( */
1 change: 0 additions & 1 deletion sys/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ struct process {
// current will always give the process that is currently executing
// if I have to stop using __thread, current will become a macro
extern __thread struct process *current;
#define curmem current->cpu.mem

// Creates a new process, returns NULL in case of failure
struct process *process_create(void);
Expand Down
1 change: 1 addition & 0 deletions sys/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ static void itimer_notify(union sigval sv) {
}

dword_t sys_setitimer(dword_t which, addr_t new_val_addr, addr_t old_val_addr) {
STRACE("setitimer");
if (which != ITIMER_REAL_)
TODO("setitimer %d", which);

Expand Down
4 changes: 2 additions & 2 deletions sys/user.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ int user_read_proc(struct process *proc, addr_t addr, void *buf, size_t count) {
char *cbuf = (char *) buf;
size_t i = 0;
while (i < count) {
char *ptr = mem_read_ptr(&proc->cpu.mem, addr + i);
char *ptr = mem_read_ptr(proc->cpu.mem, addr + i);
if (ptr == NULL)
return 1;
cbuf[i] = *ptr;
Expand All @@ -21,7 +21,7 @@ int user_write_proc(struct process *proc, addr_t addr, const void *buf, size_t c
const char *cbuf = (const char *) buf;
size_t i = 0;
while (i < count) {
char *ptr = mem_write_ptr(&proc->cpu.mem, addr + i);
char *ptr = mem_write_ptr(proc->cpu.mem, addr + i);
if (ptr == NULL)
return 1;
*ptr = cbuf[i];
Expand Down
4 changes: 2 additions & 2 deletions tools/ptraceomatic.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,11 @@ static int compare_cpus(struct cpu_state *cpu, int pid, int undefined_flags) {

// compare pages marked dirty
int fd = open_mem(pid);
page_t dirty_page = cpu->mem.dirty_page;
page_t dirty_page = cpu->mem->dirty_page;
char real_page[PAGE_SIZE];
trycall(lseek(fd, dirty_page, SEEK_SET), "compare seek mem");
trycall(read(fd, real_page, PAGE_SIZE), "compare read mem");
void *fake_page = cpu->mem.pt[PAGE(dirty_page)]->data;
void *fake_page = cpu->mem->pt[PAGE(dirty_page)]->data;

if (memcmp(real_page, fake_page, PAGE_SIZE) != 0) {
println("page %x doesn't match", dirty_page);
Expand Down
2 changes: 1 addition & 1 deletion xX_main_Xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ static inline int xX_main_Xx(int argc, char *const argv[]) {

// make a process
current = process_create();
mem_init(&curmem);
current->cpu.mem = mem_new();
current->ppid = 1;
current->uid = current->gid = 0;
current->root = generic_open("/", O_RDONLY_, 0);
Expand Down

0 comments on commit 820dbdb

Please sign in to comment.