From: Ben Gras Date: Thu, 18 Mar 2010 17:17:31 +0000 (+0000) Subject: VM: fix kernel mappings for children of non-paged parents. X-Git-Tag: v3.1.7~221 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/addsub.png?a=commitdiff_plain;h=ec30f25d0c118f5f44ff7194c2fe70790148715b;p=minix.git VM: fix kernel mappings for children of non-paged parents. --- diff --git a/servers/vm/exec.c b/servers/vm/exec.c index 7b8535742..754e6a596 100644 --- a/servers/vm/exec.c +++ b/servers/vm/exec.c @@ -266,8 +266,8 @@ SANITYCHECK(SCL_DETAIL); CLICK2ABS(stack_clicks),/* how big is stack, page-aligned */ CLICK2ABS(gap_clicks), /* how big is gap, page-aligned */ 0,0, /* not preallocated */ - VM_STACKTOP /* regular stack top */ - )) != OK) { + VM_STACKTOP, /* regular stack top */ + 0)) != OK) { SANITYCHECK(SCL_DETAIL); printf("VM: new_mem: failed\n"); if(ptok) { @@ -408,12 +408,14 @@ PUBLIC int proc_new(struct vmproc *vmp, phys_bytes gap_bytes, /* gap bytes, page aligned */ phys_bytes text_start, /* text starts here, if preallocated, otherwise 0 */ phys_bytes data_start, /* data starts here, if preallocated, otherwise 0 */ - phys_bytes stacktop + phys_bytes stacktop, + int prealloc_stack ) { int s; vir_bytes hole_bytes; int prealloc; + struct vir_region *reg; vm_assert(!(vstart % VM_PAGE_SIZE)); vm_assert(!(text_bytes % VM_PAGE_SIZE)); @@ -435,15 +437,16 @@ PUBLIC int proc_new(struct vmproc *vmp, #define TEXTFLAGS (PTF_PRESENT | PTF_USER) SANITYCHECK(SCL_DETAIL); if(text_bytes > 0) { - if(!map_page_region(vmp, vstart, 0, text_bytes, + if(!(reg=map_page_region(vmp, vstart, 0, text_bytes, text_start ? text_start : MAP_NONE, - VR_ANON | VR_WRITABLE, text_start ? 0 : MF_PREALLOC)) { + VR_ANON | VR_WRITABLE, text_start ? 0 : MF_PREALLOC))) { SANITYCHECK(SCL_DETAIL); printf("VM: proc_new: map_page_region failed (text)\n"); map_free_proc(vmp); SANITYCHECK(SCL_DETAIL); return(ENOMEM); } + map_region_set_tag(reg, VRT_TEXT); SANITYCHECK(SCL_DETAIL); } SANITYCHECK(SCL_DETAIL); @@ -471,12 +474,15 @@ PUBLIC int proc_new(struct vmproc *vmp, */ hole_bytes = stacktop - data_bytes - stack_bytes - gap_bytes; - if(!map_page_region(vmp, vstart + text_bytes + data_bytes + hole_bytes, + if(!(reg=map_page_region(vmp, + vstart + text_bytes + data_bytes + hole_bytes, 0, stack_bytes + gap_bytes, MAP_NONE, - VR_ANON | VR_WRITABLE, 0) != OK) { + VR_ANON | VR_WRITABLE, prealloc_stack ? MF_PREALLOC : 0)) != OK) { panic("map_page_region failed for stack"); } + map_region_set_tag(reg, VRT_STACK); + vmp->vm_arch.vm_seg[D].mem_phys = ABS2CLICK(vstart + text_bytes); vmp->vm_arch.vm_seg[D].mem_vir = 0; vmp->vm_arch.vm_seg[D].mem_len = ABS2CLICK(data_bytes); @@ -485,6 +491,15 @@ PUBLIC int proc_new(struct vmproc *vmp, text_bytes + data_bytes + gap_bytes + hole_bytes); vmp->vm_arch.vm_seg[S].mem_vir = ABS2CLICK(data_bytes + gap_bytes + hole_bytes); + /* Where are we allowed to start using the rest of the virtual + * address space? + */ + vmp->vm_stacktop = stacktop; + + vmp->vm_flags |= VMF_HASPT; + + if(vmp->vm_endpoint != NONE) { + /* Pretend the stack is the full size of the data segment, so * we get a full-sized data segment, up to VM_DATATOP. * After sys_newmap(), change the stack to what we know the @@ -493,23 +508,16 @@ PUBLIC int proc_new(struct vmproc *vmp, vmp->vm_arch.vm_seg[S].mem_len = (VM_DATATOP >> CLICK_SHIFT) - vmp->vm_arch.vm_seg[S].mem_vir - ABS2CLICK(vstart) - ABS2CLICK(text_bytes); - /* Where are we allowed to start using the rest of the virtual - * address space? - */ - vmp->vm_stacktop = stacktop; - /* What is the final size of the data segment in bytes? */ vmp->vm_arch.vm_data_top = (vmp->vm_arch.vm_seg[S].mem_vir + vmp->vm_arch.vm_seg[S].mem_len) << CLICK_SHIFT; - vmp->vm_flags |= VMF_HASPT; - - if((s=sys_newmap(vmp->vm_endpoint, vmp->vm_arch.vm_seg)) != OK) - panic("sys_newmap (vm) failed: %d", s); - - if((s=pt_bind(&vmp->vm_pt, vmp)) != OK) - panic("exec_newmem: pt_bind failed: %d", s); + if((s=sys_newmap(vmp->vm_endpoint, vmp->vm_arch.vm_seg)) != OK) + panic("sys_newmap (vm) failed: %d", s); + if((s=pt_bind(&vmp->vm_pt, vmp)) != OK) + panic("exec_newmem: pt_bind failed: %d", s); + } return OK; } diff --git a/servers/vm/fork.c b/servers/vm/fork.c index c4db1f7ee..b75935ebb 100644 --- a/servers/vm/fork.c +++ b/servers/vm/fork.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "glo.h" #include "vm.h" @@ -26,6 +27,7 @@ #include "util.h" #include "sanitycheck.h" #include "region.h" +#include "memory.h" /*===========================================================================* * do_fork * @@ -78,18 +80,14 @@ PUBLIC int do_fork(message *msg) vmc->vm_bytecopies = 0; #endif - SANITYCHECK(SCL_DETAIL); + if(pt_new(&vmc->vm_pt) != OK) { + printf("VM: fork: pt_new failed\n"); + return ENOMEM; + } if(fullvm) { SANITYCHECK(SCL_DETAIL); - if(pt_new(&vmc->vm_pt) != OK) { - printf("VM: fork: pt_new failed\n"); - return ENOMEM; - } - - SANITYCHECK(SCL_DETAIL); - if(map_proc_copy(vmc, vmp) != OK) { printf("VM: fork: map_proc_copy failed\n"); pt_free(&vmc->vm_pt); @@ -103,41 +101,77 @@ PUBLIC int do_fork(message *msg) SANITYCHECK(SCL_DETAIL); } else { - phys_bytes prog_bytes, parent_abs, child_abs; /* Intel only */ - phys_clicks prog_clicks, child_base; + vir_bytes sp; + phys_bytes d_abs, s_abs; + vir_bytes text_bytes, data_bytes, stack_bytes, parent_gap_bytes, + child_gap_bytes; + + /* Get SP of new process (using parent). */ + if(get_stack_ptr(vmp->vm_endpoint, &sp) != OK) { + printf("VM: fork: get_stack_ptr failed for %d\n", + vmp->vm_endpoint); + return ENOMEM; + } + + /* Update size of stack segment using current SP. */ + if(adjust(vmp, vmp->vm_arch.vm_seg[D].mem_len, sp) != OK) { + printf("VM: fork: adjust failed for %d\n", + vmp->vm_endpoint); + return ENOMEM; + } - /* Determine how much memory to allocate. Only the data and stack - * need to be copied, because the text segment is either shared or - * of zero length. + /* Copy newly adjust()ed stack segment size to child. */ + vmc->vm_arch.vm_seg[S] = vmp->vm_arch.vm_seg[S]; + + text_bytes = CLICK2ABS(vmc->vm_arch.vm_seg[T].mem_len); + data_bytes = CLICK2ABS(vmc->vm_arch.vm_seg[D].mem_len); + stack_bytes = CLICK2ABS(vmc->vm_arch.vm_seg[S].mem_len); + + /* how much space after break and before lower end (which is the + * logical top) of stack for the parent */ + parent_gap_bytes = CLICK2ABS(vmc->vm_arch.vm_seg[S].mem_vir - + vmc->vm_arch.vm_seg[D].mem_len); - prog_clicks = (phys_clicks) vmp->vm_arch.vm_seg[S].mem_len; - prog_clicks += (vmp->vm_arch.vm_seg[S].mem_vir - vmp->vm_arch.vm_seg[D].mem_vir); - prog_bytes = (phys_bytes) prog_clicks << CLICK_SHIFT; - if ( (child_base = ALLOC_MEM(prog_clicks, 0)) == NO_MEM) { - SANITYCHECK(SCL_FUNCTIONS); - return(ENOMEM); + /* how much space can the child stack grow downwards, below + * the current SP? The rest of the gap is available for the + * heap to grow upwards. + */ + child_gap_bytes = VM_PAGE_SIZE; + + if((r=proc_new(vmc, VM_PROCSTART, + text_bytes, data_bytes, stack_bytes, child_gap_bytes, 0, 0, + CLICK2ABS(vmc->vm_arch.vm_seg[S].mem_vir + + vmc->vm_arch.vm_seg[S].mem_len), 1)) != OK) { + printf("VM: fork: proc_new failed\n"); + return r; } - /* Create a copy of the parent's core image for the child. */ - child_abs = (phys_bytes) child_base << CLICK_SHIFT; - parent_abs = (phys_bytes) vmp->vm_arch.vm_seg[D].mem_phys << CLICK_SHIFT; - s = sys_abscopy(parent_abs, child_abs, prog_bytes); - if (s < 0) panic("do_fork can't copy: %d", s); - - /* A separate I&D child keeps the parents text segment. The data and stack - * segments must refer to the new copy. - */ - if (!(vmc->vm_flags & VMF_SEPARATE)) - vmc->vm_arch.vm_seg[T].mem_phys = child_base; - vmc->vm_arch.vm_seg[D].mem_phys = child_base; - vmc->vm_arch.vm_seg[S].mem_phys = vmc->vm_arch.vm_seg[D].mem_phys + - (vmp->vm_arch.vm_seg[S].mem_vir - vmp->vm_arch.vm_seg[D].mem_vir); - - if(pt_identity(&vmc->vm_pt) != OK) { - printf("VM: fork: pt_identity failed\n"); - return ENOMEM; + if((d_abs = map_lookup_phys(vmc, VRT_HEAP)) == MAP_NONE) + panic("couldn't lookup data"); + if((s_abs = map_lookup_phys(vmc, VRT_STACK)) == MAP_NONE) + panic("couldn't lookup stack"); + + /* Now copy the memory regions. */ + + if(vmc->vm_arch.vm_seg[T].mem_len > 0) { + phys_bytes t_abs; + if((t_abs = map_lookup_phys(vmc, VRT_TEXT)) == MAP_NONE) + panic("couldn't lookup text"); + if(sys_abscopy(CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys), + t_abs, text_bytes) != OK) + panic("couldn't copy text"); } + + if(sys_abscopy(CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys), + d_abs, data_bytes) != OK) + panic("couldn't copy data"); + + if(sys_abscopy( + CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys + + vmc->vm_arch.vm_seg[D].mem_len) + parent_gap_bytes, + s_abs + child_gap_bytes, stack_bytes) != OK) + panic("couldn't copy stack"); } /* Only inherit these flags. */ diff --git a/servers/vm/i386/pagetable.c b/servers/vm/i386/pagetable.c index 5aeab26b0..c045cf9b7 100644 --- a/servers/vm/i386/pagetable.c +++ b/servers/vm/i386/pagetable.c @@ -619,36 +619,6 @@ PUBLIC int pt_new(pt_t *pt) return OK; } -/*===========================================================================* - * pt_identity * - *===========================================================================*/ -PUBLIC int pt_identity(pt_t *pt) -{ -/* Allocate a pagetable that does a 1:1 mapping. */ - int i; - - /* Allocate page directory. */ - if(!pt->pt_dir && - !(pt->pt_dir = vm_allocpage(&pt->pt_dir_phys, VMP_PAGEDIR))) { - return ENOMEM; - } - - for(i = 0; i < I386_VM_DIR_ENTRIES; i++) { - phys_bytes addr; - addr = I386_BIG_PAGE_SIZE*i; - pt->pt_dir[i] = (addr & I386_VM_ADDR_MASK_4MB) | - I386_VM_BIGPAGE| - I386_VM_USER| - I386_VM_PRESENT|I386_VM_WRITE; - pt->pt_pt[i] = NULL; - } - - /* Where to start looking for free virtual address space? */ - pt->pt_virtop = 0; - - return OK; -} - /*===========================================================================* * pt_init * *===========================================================================*/ diff --git a/servers/vm/main.c b/servers/vm/main.c index 55311bdc6..2ee3b0491 100644 --- a/servers/vm/main.c +++ b/servers/vm/main.c @@ -292,7 +292,7 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info) vmp->vm_arch.vm_seg[D].mem_len) - BASICSTACK, CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys), CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys), - VM_STACKTOP) != OK) { + VM_STACKTOP, 0) != OK) { panic("failed proc_new for boot process"); } } diff --git a/servers/vm/proto.h b/servers/vm/proto.h index dbf9bbc01..477aef61b 100644 --- a/servers/vm/proto.h +++ b/servers/vm/proto.h @@ -60,7 +60,8 @@ _PROTOTYPE( struct vmproc *find_share, (struct vmproc *vmp_ign, Ino_t ino, _PROTOTYPE( int do_exec_newmem, (message *msg) ); _PROTOTYPE( int proc_new, (struct vmproc *vmp, phys_bytes start, phys_bytes text, phys_bytes data, phys_bytes stack, phys_bytes gap, - phys_bytes text_here, phys_bytes data_here, vir_bytes stacktop)); + phys_bytes text_here, phys_bytes data_here, vir_bytes stacktop, + int prealloc_stack)); _PROTOTYPE( phys_bytes find_kernel_top, (void) ); /* break.c */ @@ -99,7 +100,6 @@ _PROTOTYPE( int handle_memory, (struct vmproc *vmp, vir_bytes mem, _PROTOTYPE( void pt_init, (phys_bytes limit) ); _PROTOTYPE( void pt_check, (struct vmproc *vmp) ); _PROTOTYPE( int pt_new, (pt_t *pt) ); -_PROTOTYPE( int pt_identity, (pt_t *pt) ); _PROTOTYPE( void pt_free, (pt_t *pt) ); _PROTOTYPE( int pt_writemap, (pt_t *pt, vir_bytes v, phys_bytes physaddr, size_t bytes, u32_t flags, u32_t writemapflags)); @@ -149,6 +149,7 @@ _PROTOTYPE(int map_handle_memory,(struct vmproc *vmp, _PROTOTYPE(void map_printmap, (struct vmproc *vmp)); _PROTOTYPE(int map_writept, (struct vmproc *vmp)); _PROTOTYPE(void printregionstats, (struct vmproc *vmp)); +_PROTOTYPE(phys_bytes map_lookup_phys, (struct vmproc *vmp, u32_t tag)); _PROTOTYPE(struct vir_region * map_region_lookup_tag, (struct vmproc *vmp, u32_t tag)); _PROTOTYPE(void map_region_set_tag, (struct vir_region *vr, u32_t tag)); diff --git a/servers/vm/region.c b/servers/vm/region.c index 1559eb047..efa2bdc3c 100644 --- a/servers/vm/region.c +++ b/servers/vm/region.c @@ -44,17 +44,41 @@ FORWARD _PROTOTYPE(struct vir_region *map_copy_region, (struct vmproc *vmp, stru PRIVATE char *map_name(struct vir_region *vr) { + static char name[100]; + char *typename, *tag; int type = vr->flags & (VR_ANON|VR_DIRECT); switch(type) { case VR_ANON: - return "anonymous"; + typename = "anonymous"; + break; case VR_DIRECT: - return "direct"; + typename = "direct"; + break; default: panic("unknown mapping type: %d", type); } - return "NOTREACHED"; + switch(vr->tag) { + case VRT_TEXT: + tag = "text"; + break; + case VRT_STACK: + tag = "stack"; + break; + case VRT_HEAP: + tag = "heap"; + break; + case VRT_NONE: + tag = "untagged"; + break; + default: + tag = "unknown tag value"; + break; + } + + sprintf(name, "%s, %s", typename, tag); + + return name; } PUBLIC void map_printregion(struct vmproc *vmp, struct vir_region *vr) @@ -62,9 +86,9 @@ PUBLIC void map_printregion(struct vmproc *vmp, struct vir_region *vr) physr_iter iter; struct phys_region *ph; printf("map_printmap: map_name: %s\n", map_name(vr)); - printf("\t%s (len 0x%lx), %s\n", + printf("\t%s (len 0x%lx, %dkB), %s\n", arch_map2str(vmp, vr->vaddr), vr->length, - map_name(vr)); + vr->length/1024, map_name(vr)); printf("\t\tphysblocks:\n"); physr_start_iter_least(vr->phys, &iter); while((ph = physr_get_iter(&iter))) { @@ -1552,3 +1576,33 @@ PUBLIC void printregionstats(struct vmproc *vmp) return; } +/*========================================================================* + * map_lookup_phys * + *========================================================================*/ +phys_bytes +map_lookup_phys(struct vmproc *vmp, u32_t tag) +{ + struct vir_region *vr; + struct phys_region *pr; + physr_iter iter; + + if(!(vr = map_region_lookup_tag(vmp, tag))) { + printf("VM: request for phys of missing region\n"); + return MAP_NONE; + } + + physr_start_iter_least(vr->phys, &iter); + + if(!(pr = physr_get_iter(&iter))) { + printf("VM: request for phys of unmapped region\n"); + return MAP_NONE; + } + + if(pr->offset != 0 || pr->ph->length != vr->length) { + printf("VM: request for phys of partially mapped region\n"); + return MAP_NONE; + } + + return pr->ph->phys; +} + diff --git a/servers/vm/region.h b/servers/vm/region.h index 948ce715a..5b2c980a8 100644 --- a/servers/vm/region.h +++ b/servers/vm/region.h @@ -74,7 +74,8 @@ struct vir_region { /* Tag values: */ #define VRT_NONE 0xBEEF0000 #define VRT_HEAP 0xBEEF0001 -#define VRT_CODE 0xBEEF0002 +#define VRT_TEXT 0xBEEF0002 +#define VRT_STACK 0xBEEF0003 /* map_page_region flags */ #define MF_PREALLOC 0x01