From: Ben Gras Date: Mon, 17 Dec 2012 18:26:52 +0000 (+0000) Subject: vm: replace phys avl by array X-Git-Tag: v3.2.1~151 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/Bv9ARM.ch11.html?a=commitdiff_plain;h=29edcad310c8b7b5e4d185d4c29dc13bfdf6d085;p=minix.git vm: replace phys avl by array . make vm be able to use malloc() by overriding brk() and minix_mmap() functions . phys regions can then be malloc()ed and free()d instead of being in an avl tree, which is slightly faster . 'offset' field in phys_region can go too (offset is implied by position in array) but leads to bigger code changes --- diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index 2578b3200..a07a57216 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -95,6 +95,13 @@ void utrace(struct ut *, int); # define _MALLOC_UNLOCK() if (__isthreaded) _SPINUNLOCK(&thread_lock); #endif /* __FreeBSD__ */ +/* #undef these things so that malloc uses the non-internal symbols. + * This is necessary for VM to be able to define its own versions, and + * use this malloc. + */ +#undef minix_mmap +#undef minix_munmap + #include #include diff --git a/servers/vm/Makefile b/servers/vm/Makefile index 22edc6ded..c87f50a0b 100644 --- a/servers/vm/Makefile +++ b/servers/vm/Makefile @@ -4,7 +4,7 @@ PROG= vm SRCS= main.c alloc.c utility.c exit.c fork.c break.c \ mmap.c slaballoc.c region.c pagefaults.c \ - physravl.c rs.c queryexit.c yieldedavl.c regionavl.c pb.c \ + rs.c queryexit.c yieldedavl.c regionavl.c pb.c \ mem_anon.c mem_directphys.c mem_anon_contig.c mem_shared.c DPADD+= ${LIBSYS} diff --git a/servers/vm/arch/i386/pagetable.c b/servers/vm/arch/i386/pagetable.c index 9ceac7409..19051299b 100644 --- a/servers/vm/arch/i386/pagetable.c +++ b/servers/vm/arch/i386/pagetable.c @@ -54,25 +54,22 @@ struct vmproc *vmprocess = &vmproc[VM_PROC_NR]; * circular dependency on allocating memory and writing it into VM's * page table. */ -#if defined(__i386__) #if SANITYCHECKS #define SPAREPAGES 100 #define STATIC_SPAREPAGES 90 #else -#define SPAREPAGES 15 -#define STATIC_SPAREPAGES 10 +#define SPAREPAGES 20 +#define STATIC_SPAREPAGES 15 #endif -#elif defined(__arm__) + #define SPAREPAGEDIRS 11 #define STATIC_SPAREPAGEDIRS 10 -#define SPAREPAGES 250 -#define STATIC_SPAREPAGES 100 + int missing_sparedirs = SPAREPAGEDIRS; static struct { void *pagedir; phys_bytes phys; } sparepagedirs[SPAREPAGEDIRS]; -#endif int missing_spares = SPAREPAGES; static struct { @@ -143,11 +140,7 @@ void pt_sanitycheck(pt_t *pt, char *file, int line) /*===========================================================================* * findhole * *===========================================================================*/ -#if defined(__i386__) -static u32_t findhole(void) -#elif defined(__arm__) static u32_t findhole(int pages) -#endif { /* Find a space in the virtual address space of VM. */ u32_t curv; @@ -159,7 +152,9 @@ static u32_t findhole(int pages) u32_t holev; #endif - vmin = (vir_bytes) (&_end) & ARCH_VM_ADDR_MASK; /* marks end of VM BSS */ + vmin = (vir_bytes) (&_end); /* marks end of VM BSS */ + vmin += 1024*1024*1024; /* reserve 1GB virtual address space for VM heap */ + vmin &= ARCH_VM_ADDR_MASK; vmax = VM_STACKTOP; /* Input sanity check. */ @@ -298,10 +293,10 @@ static void *vm_getsparepage(phys_bytes *phys) return sp; } } + printf("no spare found, %d missing\n", missing_spares); return NULL; } -#if defined(__arm__) /*===========================================================================* * vm_getsparepagedir * *===========================================================================*/ @@ -322,7 +317,6 @@ static void *vm_getsparepagedir(phys_bytes *phys) } return NULL; } -#endif /*===========================================================================* * vm_checkspares * @@ -332,7 +326,7 @@ static void *vm_checkspares(void) int s, n = 0; static int total = 0, worst = 0; assert(missing_spares >= 0 && missing_spares <= SPAREPAGES); - for(s = 0; s < SPAREPAGES && missing_spares > 0; s++) + for(s = 0; s < SPAREPAGES && missing_spares > 0; s++) { if(!sparepages[s].page) { n++; if((sparepages[s].page = vm_allocpage(&sparepages[s].phys, @@ -343,6 +337,7 @@ static void *vm_checkspares(void) } else { printf("VM: warning: couldn't get new spare page\n"); } + } } if(worst < n) worst = n; total += n; @@ -376,14 +371,14 @@ static void *vm_checksparedirs(void) return NULL; } - #endif + static int pt_init_done; /*===========================================================================* * vm_allocpage * *===========================================================================*/ -void *vm_allocpage(phys_bytes *phys, int reason) +void *vm_allocpages(phys_bytes *phys, int reason, int pages) { /* Allocate a page for use by VM itself. */ phys_bytes newpage; @@ -392,13 +387,13 @@ void *vm_allocpage(phys_bytes *phys, int reason) int r; static int level = 0; void *ret; -#if defined(__arm__) - u32_t mem_bytes, mem_clicks, mem_flags; -#endif + u32_t mem_flags = 0; pt = &vmprocess->vm_pt; assert(reason >= 0 && reason < VMP_CATEGORIES); + assert(pages > 0); + level++; assert(level >= 1); @@ -406,16 +401,13 @@ void *vm_allocpage(phys_bytes *phys, int reason) if((level > 1) || !pt_init_done) { void *s; -#if defined(__i386__) + s=vm_getsparepage(phys); -#elif defined(__arm__) - if (reason == VMP_PAGEDIR) - s=vm_getsparepagedir(phys); - else - s=vm_getsparepage(phys); + if(pages == 1) s=vm_getsparepage(phys); + else if(pages == 4) s=vm_getsparepagedir(phys); + else panic("%d pages", pages); -#endif level--; if(!s) { util_stacktrace(); @@ -427,23 +419,14 @@ void *vm_allocpage(phys_bytes *phys, int reason) #if defined(__arm__) if (reason == VMP_PAGEDIR) { - mem_bytes = ARCH_PAGEDIR_SIZE; - mem_flags = PAF_ALIGN16K; - } else { - mem_bytes = VM_PAGE_SIZE; - mem_flags = 0; + mem_flags |= PAF_ALIGN16K; } - mem_clicks = mem_bytes / VM_PAGE_SIZE * CLICKSPERPAGE; - #endif + /* VM does have a pagetable, so get a page and map it in there. * Where in our virtual address space can we put it? */ -#if defined(__i386__) - loc = findhole(); -#elif defined(__arm__) - loc = findhole(mem_bytes / VM_PAGE_SIZE); -#endif + loc = findhole(pages); if(loc == NO_MEM) { level--; printf("VM: vm_allocpage: findhole failed\n"); @@ -453,11 +436,7 @@ void *vm_allocpage(phys_bytes *phys, int reason) /* Allocate page of memory for use by VM. As VM * is trusted, we don't have to pre-clear it. */ -#if defined(__i386__) - if((newpage = alloc_mem(CLICKSPERPAGE, 0)) == NO_MEM) { -#elif defined(__arm__) - if((newpage = alloc_mem(mem_clicks, mem_flags)) == NO_MEM) { -#endif + if((newpage = alloc_mem(pages, mem_flags)) == NO_MEM) { level--; printf("VM: vm_allocpage: alloc_mem failed\n"); return NULL; @@ -466,16 +445,13 @@ void *vm_allocpage(phys_bytes *phys, int reason) *phys = CLICK2ABS(newpage); /* Map this page into our address space. */ -#if defined(__i386__) - if((r=pt_writemap(vmprocess, pt, loc, *phys, VM_PAGE_SIZE, - ARCH_VM_PTE_PRESENT | ARCH_VM_PTE_USER | ARCH_VM_PTE_RW, 0)) != OK) { - free_mem(newpage, CLICKSPERPAGE); -#elif defined(__arm__) - if((r=pt_writemap(vmprocess, pt, loc, *phys, mem_bytes, - ARCH_VM_PTE_PRESENT | ARCH_VM_PTE_USER | ARCH_VM_PTE_RW | - ARM_VM_PTE_WB | ARM_VM_PTE_SHAREABLE, 0)) != OK) { - free_mem(newpage, mem_clicks); + if((r=pt_writemap(vmprocess, pt, loc, *phys, VM_PAGE_SIZE*pages, + ARCH_VM_PTE_PRESENT | ARCH_VM_PTE_USER | ARCH_VM_PTE_RW +#if defined(__arm__) + | ARM_VM_PTE_WB | ARM_VM_PTE_SHAREABLE #endif + , 0)) != OK) { + free_mem(newpage, pages); printf("vm_allocpage writemap failed\n"); level--; return NULL; @@ -494,6 +470,11 @@ void *vm_allocpage(phys_bytes *phys, int reason) return ret; } +void *vm_allocpage(phys_bytes *phys, int reason) +{ + return vm_allocpages(phys, reason, 1); +} + /*===========================================================================* * vm_pagelock * *===========================================================================*/ @@ -1089,12 +1070,12 @@ int pt_new(pt_t *pt) * the page directories (the page_directories data). */ if(!pt->pt_dir && - !(pt->pt_dir = vm_allocpage((phys_bytes *)&pt->pt_dir_phys, VMP_PAGEDIR))) { + !(pt->pt_dir = vm_allocpages((phys_bytes *)&pt->pt_dir_phys, + VMP_PAGEDIR, ARCH_PAGEDIR_SIZE/VM_PAGE_SIZE))) { return ENOMEM; } -#if defined(__arm__) + assert(!((u32_t)pt->pt_dir_phys % ARCH_PAGEDIR_SIZE)); -#endif for(i = 0; i < ARCH_VM_DIR_ENTRIES; i++) { pt->pt_dir[i] = 0; /* invalid entry (PRESENT bit = 0) */ @@ -1360,6 +1341,8 @@ void pt_init(void) pt_init_done = 1; + vm_checkspares(); + /* All OK. */ return; } diff --git a/servers/vm/mem_anon_contig.c b/servers/vm/mem_anon_contig.c index ec61ceadc..f11adc676 100644 --- a/servers/vm/mem_anon_contig.c +++ b/servers/vm/mem_anon_contig.c @@ -39,7 +39,6 @@ static int anon_contig_new(struct vir_region *region) u32_t allocflags; phys_bytes new_pages, new_page_cl, cur_ph; int p, pages; - physr_iter iter; allocflags = vrallocflags(region->flags); @@ -68,20 +67,15 @@ static int anon_contig_new(struct vir_region *region) cur_ph = new_pages = CLICK2ABS(new_page_cl); - physr_start_iter_least(region->phys, &iter); - for(p = 0; p < pages; p++) { - struct phys_region *pr = physr_get_iter(&iter); + struct phys_region *pr = physblock_get(region, p * VM_PAGE_SIZE); assert(pr); assert(pr->ph); assert(pr->ph->phys == MAP_NONE); assert(pr->offset == p * VM_PAGE_SIZE); pr->ph->phys = cur_ph + pr->offset; - physr_incr_iter(&iter); } - assert(!physr_get_iter(&iter)); - return OK; } diff --git a/servers/vm/mem_shared.c b/servers/vm/mem_shared.c index f5b9d6ce5..17252efe5 100644 --- a/servers/vm/mem_shared.c +++ b/servers/vm/mem_shared.c @@ -129,12 +129,11 @@ static int shared_pagefault(struct vmproc *vmp, struct vir_region *region, assert(ph->ph->phys == MAP_NONE); pb_free(ph->ph); - if(!(pr = physr_search(src_region->phys, ph->offset, AVL_EQUAL))) { + if(!(pr = physblock_get(src_region, ph->offset))) { int r; if((r=map_pf(src_vmp, src_region, ph->offset, write)) != OK) return r; - if(!(pr = physr_search(src_region->phys, ph->offset, - AVL_EQUAL))) { + if(!(pr = physblock_get(src_region, ph->offset))) { panic("missing region after pagefault handling"); } } diff --git a/servers/vm/pb.c b/servers/vm/pb.c index 736c7f986..b2d33c1bf 100644 --- a/servers/vm/pb.c +++ b/servers/vm/pb.c @@ -27,7 +27,6 @@ #include "glo.h" #include "region.h" #include "sanitycheck.h" -#include "physravl.h" #include "memlist.h" struct phys_block *pb_new(phys_bytes phys) @@ -84,7 +83,7 @@ struct phys_region *pb_reference(struct phys_block *newpb, /* New physical region. */ pb_link(newphysr, newpb, offset, region); - physr_insert(region->phys, newphysr); + physblock_set(region, offset, newphysr); return newphysr; } @@ -129,5 +128,5 @@ void pb_unreferenced(struct vir_region *region, struct phys_region *pr, int rm) pr->ph = NULL; - if(rm) physr_remove(region->phys, pr->offset); + if(rm) physblock_set(region, pr->offset, NULL); } diff --git a/servers/vm/phys_region.h b/servers/vm/phys_region.h index ca68fa9db..f8e1b5e0d 100644 --- a/servers/vm/phys_region.h +++ b/servers/vm/phys_region.h @@ -17,10 +17,6 @@ typedef struct phys_region { /* list of phys_regions that reference the same phys_block */ struct phys_region *next_ph_list; - - /* AVL fields */ - struct phys_region *less, *greater; - int factor; } phys_region_t; #endif diff --git a/servers/vm/physravl.c b/servers/vm/physravl.c deleted file mode 100644 index e96014ed4..000000000 --- a/servers/vm/physravl.c +++ /dev/null @@ -1,7 +0,0 @@ - -#include "proto.h" -#include "sanitycheck.h" -#include "phys_region.h" -#include "physravl_defs.h" -#include "cavl_impl.h" - diff --git a/servers/vm/physravl.h b/servers/vm/physravl.h deleted file mode 100644 index 10b526a17..000000000 --- a/servers/vm/physravl.h +++ /dev/null @@ -1,10 +0,0 @@ - -#ifndef _PHYSRAVL_H -#define _PHYSRAVL_H - -#include "phys_region.h" -#include "physravl_defs.h" -#include "cavl_if.h" -#include "unavl.h" - -#endif diff --git a/servers/vm/physravl_defs.h b/servers/vm/physravl_defs.h deleted file mode 100644 index b188a616b..000000000 --- a/servers/vm/physravl_defs.h +++ /dev/null @@ -1,20 +0,0 @@ - -#include - -#define AVL_UNIQUE(id) physr_ ## id -#define AVL_HANDLE phys_region_t * -#define AVL_KEY vir_bytes -#define AVL_MAX_DEPTH 30 /* good for 2 million nodes */ -#define AVL_NULL NULL -#define AVL_GET_LESS(h, a) (h)->less -#define AVL_GET_GREATER(h, a) (h)->greater -#define AVL_SET_LESS(h1, h2) USE((h1), (h1)->less = h2;); -#define AVL_SET_GREATER(h1, h2) USE((h1), (h1)->greater = h2;); -#define AVL_GET_BALANCE_FACTOR(h) (h)->factor -#define AVL_SET_BALANCE_FACTOR(h, f) USE((h), (h)->factor = f;); -#define AVL_SET_ROOT(h, v) USE((h), (h)->root = v;); -#define AVL_COMPARE_KEY_KEY(k1, k2) ((k1) > (k2) ? 1 : ((k1) < (k2) ? -1 : 0)) -#define AVL_COMPARE_KEY_NODE(k, h) AVL_COMPARE_KEY_KEY((k), (h)->offset) -#define AVL_COMPARE_NODE_NODE(h1, h2) AVL_COMPARE_KEY_KEY((h1)->offset, (h2)->offset) -#define AVL_INSIDE_STRUCT char pad[4]; - diff --git a/servers/vm/proto.h b/servers/vm/proto.h index d38f59022..1882cafe9 100644 --- a/servers/vm/proto.h +++ b/servers/vm/proto.h @@ -92,6 +92,7 @@ int pt_writemap(struct vmproc * vmp, pt_t *pt, vir_bytes v, phys_bytes int pt_checkrange(pt_t *pt, vir_bytes v, size_t bytes, int write); int pt_bind(pt_t *pt, struct vmproc *who); void *vm_allocpage(phys_bytes *p, int cat); +void *vm_allocpages(phys_bytes *p, int cat, int pages); void *vm_allocpagedir(phys_bytes *p); void pt_cycle(void); int pt_mapkernel(pt_t *pt); @@ -145,9 +146,12 @@ void printregionstats(struct vmproc *vmp); void map_setparent(struct vmproc *vmp); int yielded_block_cmp(struct block_id *, struct block_id *); struct phys_region *map_clone_ph_block(struct vmproc *vmp, - struct vir_region *region, struct phys_region *ph, physr_iter *iter); + struct vir_region *region, struct phys_region *ph); u32_t vrallocflags(u32_t flags); int map_free(struct vir_region *region); +struct phys_region *physblock_get(struct vir_region *region, vir_bytes offset); +void physblock_set(struct vir_region *region, vir_bytes offset, + struct phys_region *newphysr); struct vir_region * map_region_lookup_tag(struct vmproc *vmp, u32_t tag); diff --git a/servers/vm/region.c b/servers/vm/region.c index ee54cef69..21b6e7044 100644 --- a/servers/vm/region.c +++ b/servers/vm/region.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -25,7 +26,7 @@ #include "glo.h" #include "region.h" #include "sanitycheck.h" -#include "physravl.h" +#include "yieldedavl.h" #include "memlist.h" #include "memtype.h" @@ -74,23 +75,50 @@ static yielded_avl *get_yielded_avl(block_id_t id) return &vm_yielded_blocks[h]; } -void map_printregion(struct vmproc *vmp, struct vir_region *vr) +void map_printregion(struct vir_region *vr) { - physr_iter iter; + int i; struct phys_region *ph; printf("map_printmap: map_name: %s\n", vr->memtype->name); printf("\t%lx (len 0x%lx, %lukB), %p\n", vr->vaddr, vr->length, vr->length/1024, vr->memtype->name); printf("\t\tphysblocks:\n"); - physr_start_iter_least(vr->phys, &iter); - while((ph = physr_get_iter(&iter))) { + for(i = 0; i < vr->length/VM_PAGE_SIZE; i++) { + if(!(ph=vr->physblocks[i])) continue; printf("\t\t@ %lx (refs %d): phys 0x%lx\n", (vr->vaddr + ph->offset), ph->ph->refcount, ph->ph->phys); - physr_incr_iter(&iter); } } +struct phys_region *physblock_get(struct vir_region *region, vir_bytes offset) +{ + int i; + struct phys_region *foundregion; + assert(!(offset % VM_PAGE_SIZE)); + assert(offset >= 0 && offset < region->length); + i = offset/VM_PAGE_SIZE; + if((foundregion = region->physblocks[i])) + assert(foundregion->offset == offset); + return foundregion; +} + +void physblock_set(struct vir_region *region, vir_bytes offset, + struct phys_region *newphysr) +{ + int i; + assert(!(offset % VM_PAGE_SIZE)); + assert(offset >= 0 && offset < region->length); + i = offset/VM_PAGE_SIZE; + if(newphysr) { + assert(!region->physblocks[i]); + assert(newphysr->offset == offset); + } else { + assert(region->physblocks[i]); + } + region->physblocks[i] = newphysr; +} + /*===========================================================================* * map_printmap * *===========================================================================*/ @@ -104,7 +132,7 @@ struct vmproc *vmp; region_start_iter_least(&vmp->vm_regions_avl, &iter); while((vr = region_get_iter(&iter))) { - map_printregion(vmp, vr); + map_printregion(vr); region_incr_iter(&iter); } } @@ -156,7 +184,7 @@ static int map_sanitycheck_pt(struct vmproc *vmp, if(r != OK) { printf("proc %d phys_region 0x%lx sanity check failed\n", vmp->vm_endpoint, pr->offset); - map_printregion(vmp, vr); + map_printregion(vr); } return r; @@ -176,19 +204,20 @@ void map_sanitycheck(char *file, int line) */ #define ALLREGIONS(regioncode, physcode) \ for(vmp = vmproc; vmp < &vmproc[VMP_NR]; vmp++) { \ + vir_bytes voffset; \ region_iter v_iter; \ struct vir_region *vr; \ if(!(vmp->vm_flags & VMF_INUSE)) \ continue; \ region_start_iter_least(&vmp->vm_regions_avl, &v_iter); \ while((vr = region_get_iter(&v_iter))) { \ - physr_iter iter; \ struct phys_region *pr; \ regioncode; \ - physr_start_iter_least(vr->phys, &iter); \ - while((pr = physr_get_iter(&iter))) { \ + for(voffset = 0; voffset < vr->length; \ + voffset += VM_PAGE_SIZE) { \ + if(!(pr = physblock_get(vr, voffset))) \ + continue; \ physcode; \ - physr_incr_iter(&iter); \ } \ region_incr_iter(&v_iter); \ } \ @@ -201,6 +230,7 @@ void map_sanitycheck(char *file, int line) /* Do counting for consistency check. */ ALLREGIONS(;,USE(pr->ph, pr->ph->seencount = 0;);); + ALLREGIONS(;,MYASSERT(pr->offset == voffset);); ALLREGIONS(;,USE(pr->ph, pr->ph->seencount++;); if(pr->ph->seencount == 1) { if(pr->parent->memtype->ev_sanitycheck) @@ -466,12 +496,19 @@ static vir_bytes region_find_slot(struct vmproc *vmp, return region_find_slot_range(vmp, minv, maxv, length); } +static int phys_slot(vir_bytes len) +{ + assert(!(len % VM_PAGE_SIZE)); + return len / VM_PAGE_SIZE; +} + struct vir_region *region_new(struct vmproc *vmp, vir_bytes startv, vir_bytes length, int flags, mem_type_t *memtype) { - physr_avl *phavl; struct vir_region *newregion; + struct phys_region **physregions; static u32_t id; + int slots = phys_slot(length); if(!(SLABALLOC(newregion))) { printf("vm: region_new: could not allocate\n"); @@ -490,14 +527,13 @@ USE(newregion, newregion->lower = newregion->higher = NULL; newregion->parent = vmp;); - SLABALLOC(phavl); - if(!phavl) { - printf("VM: region_new: allocating phys avl failed\n"); + if(!(physregions = calloc(slots, sizeof(struct phys_region *)))) { + printf("VM: region_new: allocating phys blocks failed\n"); SLABFREE(newregion); return NULL; } - USE(newregion, newregion->phys = phavl;); - physr_init(newregion->phys); + + USE(newregion, newregion->physblocks = physregions;); return newregion; } @@ -543,8 +579,9 @@ mem_type_t *memtype; if(mapflags & MF_PREALLOC) { if(map_handle_memory(vmp, newregion, 0, length, 1) != OK) { printf("VM: map_page_region: prealloc failed\n"); + free(newregion->physblocks); USE(newregion, - SLABFREE(newregion->phys);); + newregion->physblocks = NULL;); SLABFREE(newregion); return NULL; } @@ -580,51 +617,37 @@ static int map_subfree(struct vir_region *region, vir_bytes start, vir_bytes len) { struct phys_region *pr; - physr_iter iter; vir_bytes end = start+len; - - int full = 0; + vir_bytes voffset; #if SANITYCHECKS - { SLABSANE(region); - SLABSANE(region->phys); - physr_start_iter_least(region->phys, &iter); - while((pr = physr_get_iter(&iter))) { + for(voffset = 0; voffset < phys_slot(region->length); + voffset += VM_PAGE_SIZE) { struct phys_region *others; struct phys_block *pb; + if(!(pr = physblock_get(region, voffset))) + continue; + pb = pr->ph; for(others = pb->firstregion; others; others = others->next_ph_list) { assert(others->ph == pb); } - physr_incr_iter(&iter); - } } #endif - if(start == 0 && len == region->length) - full = 1; - - physr_init_iter(&iter); - physr_start_iter(region->phys, &iter, start, AVL_GREATER_EQUAL); - while((pr = physr_get_iter(&iter))) { - physr_incr_iter(&iter); - if(pr->offset >= end) - break; - pb_unreferenced(region, pr, !full); - if(!full) { - physr_start_iter(region->phys, &iter, - pr->offset, AVL_GREATER_EQUAL); - } + for(voffset = start; voffset < end; voffset+=VM_PAGE_SIZE) { + if(!(pr = physblock_get(region, voffset))) + continue; + assert(pr->offset >= start); + assert(pr->offset < end); + pb_unreferenced(region, pr, 1); SLABFREE(pr); } - if(full) - physr_init(region->phys); - return OK; } @@ -642,9 +665,8 @@ int map_free(struct vir_region *region) if(region->memtype->ev_delete) region->memtype->ev_delete(region); - - USE(region, - SLABFREE(region->phys);); + free(region->physblocks); + region->physblocks = NULL; SLABFREE(region); return OK; @@ -829,7 +851,7 @@ struct phys_region **physr; if(offset >= r->vaddr && offset < r->vaddr + r->length) { ph = offset - r->vaddr; if(physr) { - *physr = physr_search(r->phys, ph, AVL_EQUAL); + *physr = physblock_get(r, ph); if(*physr) assert((*physr)->offset == ph); } return r; @@ -862,11 +884,10 @@ u32_t vrallocflags(u32_t flags) /*===========================================================================* * map_clone_ph_block * *===========================================================================*/ -struct phys_region *map_clone_ph_block(vmp, region, ph, iter) +struct phys_region *map_clone_ph_block(vmp, region, ph) struct vmproc *vmp; struct vir_region *region; struct phys_region *ph; -physr_iter *iter; { vir_bytes offset; u32_t allocflags; @@ -927,15 +948,10 @@ physr_iter *iter; if(copy_abs2region(physaddr, region, offset, VM_PAGE_SIZE) != OK) panic("copy_abs2region failed, no good reason for that"); - newpr = physr_search(region->phys, offset, AVL_EQUAL); + newpr = physblock_get(region, offset); assert(newpr); assert(newpr->offset == offset); - if(iter) { - physr_start_iter(region->phys, iter, offset, AVL_EQUAL); - assert(physr_get_iter(iter) == newpr); - } - SANITYCHECK(SCL_FUNCTIONS); return newpr; @@ -964,7 +980,7 @@ int write; SANITYCHECK(SCL_FUNCTIONS); - if(!(ph = physr_search(region->phys, offset, AVL_EQUAL))) { + if(!(ph = physblock_get(region, offset))) { struct phys_block *pb; /* New block. */ @@ -993,6 +1009,7 @@ int write; if(!write || !region->memtype->writable(ph)) { assert(region->memtype->ev_pagefault); assert(ph->ph); + if((r = region->memtype->ev_pagefault(vmp, region, ph, write)) == SUSPEND) { panic("map_pf: memtype->ev_pagefault returned SUSPEND\n"); @@ -1071,21 +1088,6 @@ int map_pin_memory(struct vmproc *vmp) return OK; } -#if SANITYCHECKS -static int count_phys_regions(struct vir_region *vr) -{ - int n = 0; - struct phys_region *ph; - physr_iter iter; - physr_start_iter_least(vr->phys, &iter); - while((ph = physr_get_iter(&iter))) { - n++; - physr_incr_iter(&iter); - } - return n; -} -#endif - /*===========================================================================* * map_copy_region * *===========================================================================*/ @@ -1102,11 +1104,11 @@ static struct vir_region *map_copy_region(struct vmproc *vmp, struct vir_region struct vir_region *newvr; struct phys_region *ph; int r; - physr_iter iter; #if SANITYCHECKS int cr; - cr = count_phys_regions(vr); + cr = physregions(vr); #endif + vir_bytes p; if(!(newvr = region_new(vr->parent, vr->vaddr, vr->length, vr->flags, vr->memtype))) return NULL; @@ -1117,21 +1119,20 @@ static struct vir_region *map_copy_region(struct vmproc *vmp, struct vir_region return NULL; } - physr_start_iter_least(vr->phys, &iter); - while((ph = physr_get_iter(&iter))) { + for(p = 0; p < phys_slot(vr->length); p++) { + if(!(ph = physblock_get(vr, p*VM_PAGE_SIZE))) continue; struct phys_region *newph = pb_reference(ph->ph, ph->offset, newvr); if(!newph) { map_free(newvr); return NULL; } #if SANITYCHECKS USE(newph, newph->written = 0;); - assert(count_phys_regions(vr) == cr); + assert(physregions(vr) == cr); #endif - physr_incr_iter(&iter); } #if SANITYCHECKS - assert(count_phys_regions(vr) == count_phys_regions(newvr)); + assert(physregions(vr) == physregions(newvr)); #endif return newvr; @@ -1145,13 +1146,13 @@ int copy_abs2region(phys_bytes abs, struct vir_region *destregion, { assert(destregion); - assert(destregion->phys); + assert(destregion->physblocks); while(len > 0) { phys_bytes sublen, suboffset; struct phys_region *ph; assert(destregion); - assert(destregion->phys); - if(!(ph = physr_search(destregion->phys, offset, AVL_LESS_EQUAL))) { + assert(destregion->physblocks); + if(!(ph = physblock_get(destregion, offset))) { printf("VM: copy_abs2region: no phys region found (1).\n"); return EFAULT; } @@ -1195,11 +1196,9 @@ int map_writept(struct vmproc *vmp) region_start_iter_least(&vmp->vm_regions_avl, &v_iter); while((vr = region_get_iter(&v_iter))) { - physr_iter ph_iter; - physr_start_iter_least(vr->phys, &ph_iter); - - while((ph = physr_get_iter(&ph_iter))) { - physr_incr_iter(&ph_iter); + vir_bytes p; + for(p = 0; p < vr->length; p += VM_PAGE_SIZE) { + if(!(ph = physblock_get(vr, p))) continue; if((r=map_ph_writept(vmp, vr, ph)) != OK) { printf("VM: map_writept: failed\n"); @@ -1250,34 +1249,30 @@ struct vir_region *start_src_vr; SANITYCHECK(SCL_FUNCTIONS); while((vr = region_get_iter(&v_iter))) { - physr_iter iter_orig, iter_new; struct vir_region *newvr; - struct phys_region *orig_ph, *new_ph; if(!(newvr = map_copy_region(dst, vr))) { map_free_proc(dst); return ENOMEM; } USE(newvr, newvr->parent = dst;); region_insert(&dst->vm_regions_avl, newvr); - physr_start_iter_least(vr->phys, &iter_orig); - physr_start_iter_least(newvr->phys, &iter_new); - while((orig_ph = physr_get_iter(&iter_orig))) { - struct phys_block *pb; - new_ph = physr_get_iter(&iter_new); - /* Check two physregions both are nonnull, - * are different, and match physblocks. - */ + assert(vr->length == newvr->length); + +#if SANITYCHECKS + { + vir_bytes vaddr; + struct phys_region *orig_ph, *new_ph; + assert(vr->physblocks != newvr->physblocks); + for(vaddr = 0; vaddr < vr->length; vaddr += VM_PAGE_SIZE) { + orig_ph = physblock_get(vr, vaddr); + new_ph = physblock_get(newvr, vaddr); + if(!orig_ph) { assert(!new_ph); continue;} assert(new_ph); - assert(orig_ph); assert(orig_ph != new_ph); - pb = orig_ph->ph; assert(orig_ph->ph == new_ph->ph); - - /* Get next new physregion */ - physr_incr_iter(&iter_orig); - physr_incr_iter(&iter_new); } - assert(!physr_get_iter(&iter_new)); + } +#endif region_incr_iter(&v_iter); } @@ -1292,6 +1287,8 @@ int map_region_extend_upto_v(struct vmproc *vmp, vir_bytes v) { vir_bytes offset = v; struct vir_region *vr, *nextvr; + struct phys_region **newpr; + int newslots, prevslots, addedslots; offset = roundup(offset, VM_PAGE_SIZE); @@ -1300,7 +1297,24 @@ int map_region_extend_upto_v(struct vmproc *vmp, vir_bytes v) return ENOMEM; } + if(vr->vaddr + vr->length >= v) return OK; + assert(vr->vaddr <= offset); + newslots = phys_slot(offset - vr->vaddr); + prevslots = phys_slot(vr->length); + assert(newslots >= prevslots); + addedslots = newslots - prevslots; + + if(!(newpr = realloc(vr->physblocks, + newslots * sizeof(struct phys_region *)))) { + printf("VM: map_region_extend_upto_v: realloc failed\n"); + return ENOMEM; + } + + vr->physblocks = newpr; + memset(vr->physblocks + prevslots, 0, + addedslots * sizeof(struct phys_region *)); + if((nextvr = getnextvr(vr))) { assert(offset <= nextvr->vaddr); } @@ -1328,6 +1342,7 @@ int map_unmap_region(struct vmproc *vmp, struct vir_region *r, * memory it used to reference if any. */ vir_bytes regionstart; + int freeslots = phys_slot(len); SANITYCHECK(SCL_FUNCTIONS); @@ -1344,7 +1359,8 @@ int map_unmap_region(struct vmproc *vmp, struct vir_region *r, /* if unmap was at start/end of this region, it actually shrinks */ if(offset == 0) { struct phys_region *pr; - physr_iter iter; + vir_bytes voffset; + int remslots; region_remove(&vmp->vm_regions_avl, r->vaddr); @@ -1352,20 +1368,23 @@ int map_unmap_region(struct vmproc *vmp, struct vir_region *r, r->vaddr += len; r->length -= len;); + remslots = phys_slot(r->length); + region_insert(&vmp->vm_regions_avl, r); /* vaddr has increased; to make all the phys_regions * point to the same addresses, make them shrink by the * same amount. */ - physr_init_iter(&iter); - physr_start_iter(r->phys, &iter, offset, AVL_GREATER_EQUAL); - - while((pr = physr_get_iter(&iter))) { + for(voffset = offset; voffset < r->length; + voffset += VM_PAGE_SIZE) { + if(!(pr = physblock_get(r, voffset))) continue; assert(pr->offset >= offset); USE(pr, pr->offset -= len;); - physr_incr_iter(&iter); } + if(remslots) + memmove(r->physblocks, r->physblocks + freeslots, + remslots * sizeof(struct phys_region *)); } else if(offset + len == r->length) { assert(len <= r->length); r->length -= len; @@ -1459,10 +1478,10 @@ static void get_usage_info_vm(struct vm_usage_info *vui) void get_usage_info(struct vmproc *vmp, struct vm_usage_info *vui) { struct vir_region *vr; - physr_iter iter; struct phys_region *ph; region_iter v_iter; region_start_iter_least(&vmp->vm_regions_avl, &v_iter); + vir_bytes voffset; memset(vui, 0, sizeof(*vui)); @@ -1477,8 +1496,8 @@ void get_usage_info(struct vmproc *vmp, struct vm_usage_info *vui) } while((vr = region_get_iter(&v_iter))) { - physr_start_iter_least(vr->phys, &iter); - while((ph = physr_get_iter(&iter))) { + for(voffset = 0; voffset < vr->length; voffset += VM_PAGE_SIZE) { + if(!(ph = physblock_get(vr, voffset))) continue; /* All present pages are counted towards the total. */ vui->vui_total += VM_PAGE_SIZE; @@ -1490,7 +1509,6 @@ void get_usage_info(struct vmproc *vmp, struct vm_usage_info *vui) if (vr->flags & VR_SHARED) vui->vui_shared += VM_PAGE_SIZE; } - physr_incr_iter(&iter); } region_incr_iter(&v_iter); } @@ -1515,13 +1533,18 @@ int get_region_info(struct vmproc *vmp, struct vm_region_info *vri, if(!(vr = region_get_iter(&v_iter))) return 0; for(count = 0; (vr = region_get_iter(&v_iter)) && count < max; count++, vri++) { - struct phys_region *ph1, *ph2; + struct phys_region *ph1 = NULL, *ph2 = NULL; + vir_bytes voffset; /* Report part of the region that's actually in use. */ /* Get first and last phys_regions, if any */ - ph1 = physr_search_least(vr->phys); - ph2 = physr_search_greatest(vr->phys); + for(voffset = 0; voffset > vr->length; voffset += VM_PAGE_SIZE) { + struct phys_region *ph; + if(!(ph = physblock_get(vr, voffset))) continue; + if(!ph1) ph1 = ph; + ph2 = ph; + } if(!ph1 || !ph2) { assert(!ph1 && !ph2); continue; } /* Report start+length of region starting from lowest use. */ @@ -1548,18 +1571,17 @@ void printregionstats(struct vmproc *vmp) { struct vir_region *vr; struct phys_region *pr; - physr_iter iter; vir_bytes used = 0, weighted = 0; region_iter v_iter; region_start_iter_least(&vmp->vm_regions_avl, &v_iter); while((vr = region_get_iter(&v_iter))) { + vir_bytes voffset; region_incr_iter(&v_iter); if(vr->flags & VR_DIRECT) continue; - physr_start_iter_least(vr->phys, &iter); - while((pr = physr_get_iter(&iter))) { - physr_incr_iter(&iter); + for(voffset = 0; voffset < vr->length; voffset+=VM_PAGE_SIZE) { + if(!(pr = physblock_get(vr, voffset))) continue; used += VM_PAGE_SIZE; weighted += VM_PAGE_SIZE / pr->ph->refcount; } @@ -1594,7 +1616,7 @@ get_clean_phys_region(struct vmproc *vmp, vir_bytes vaddr, struct vir_region **r assert(ph->ph->refcount > 0); if(ph->ph->refcount > 1) { if(!(ph = map_clone_ph_block(vmp, region, - ph, NULL))) { + ph))) { printf("VM: get_clean_phys_region: ph copy failed\n"); return NULL; } @@ -1893,11 +1915,10 @@ void map_setparent(struct vmproc *vmp) int physregions(struct vir_region *vr) { int n = 0; - physr_iter iter; - physr_start_iter_least(vr->phys, &iter); - while(physr_get_iter(&iter)) { - n++; - physr_incr_iter(&iter); + vir_bytes voffset; + for(voffset = 0; voffset < vr->length; voffset += VM_PAGE_SIZE) { + if(physblock_get(vr, voffset)) + n++; } return n; } diff --git a/servers/vm/region.h b/servers/vm/region.h index 4e9365b6a..6899339d9 100644 --- a/servers/vm/region.h +++ b/servers/vm/region.h @@ -17,7 +17,6 @@ #include #include "phys_region.h" -#include "physravl.h" #include "memtype.h" #include "vm.h" @@ -38,7 +37,7 @@ struct phys_block { typedef struct vir_region { vir_bytes vaddr; /* virtual address, offset from pagetable */ vir_bytes length; /* length in bytes */ - physr_avl *phys; /* avl tree of physical memory blocks */ + struct phys_region **physblocks; u16_t flags; struct vmproc *parent; /* Process that owns this vir_region. */ mem_type_t *memtype; /* Default instantiated memory type. */ diff --git a/servers/vm/utility.c b/servers/vm/utility.c index a23a1996c..b7d19c111 100644 --- a/servers/vm/utility.c +++ b/servers/vm/utility.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "proto.h" #include "glo.h" @@ -264,3 +265,55 @@ int swap_proc_dyn_data(struct vmproc *src_vmp, struct vmproc *dst_vmp) return OK; } +void *minix_mmap(void *addr, size_t len, int f, int f2, int f3, off_t o) +{ + void *ret; + phys_bytes p; + + assert(!addr); + assert(!(len % VM_PAGE_SIZE)); + + ret = vm_allocpages(&p, VMP_SLAB, len/VM_PAGE_SIZE); + + if(!ret) return MAP_FAILED; + memset(ret, 0, len); + return ret; +} + +int minix_munmap(void * addr, size_t len) +{ + vm_freepages((vir_bytes) addr, roundup(len, VM_PAGE_SIZE)/VM_PAGE_SIZE); + return 0; +} + +int _brk(void *addr) +{ + vir_bytes target = roundup((vir_bytes)addr, VM_PAGE_SIZE), v; + extern char _end; + extern char *_brksize; + static vir_bytes prevbrk = (vir_bytes) &_end; + struct vmproc *vmprocess = &vmproc[VM_PROC_NR]; + + for(v = roundup(prevbrk, VM_PAGE_SIZE); v < target; + v += VM_PAGE_SIZE) { + phys_bytes mem, newpage = alloc_mem(1, 0); + if(newpage == NO_MEM) return -1; + mem = CLICK2ABS(newpage); + if(pt_writemap(vmprocess, &vmprocess->vm_pt, + v, mem, VM_PAGE_SIZE, + ARCH_VM_PTE_PRESENT | ARCH_VM_PTE_USER | ARCH_VM_PTE_RW, 0) != OK) { + free_mem(newpage, 1); + return -1; + } + prevbrk = v + VM_PAGE_SIZE; + } + + _brksize = (char *) addr; + + if(sys_vmctl(SELF, VMCTL_FLUSHTLB, 0) != OK) + panic("flushtlb failed"); + + return 0; +} + + diff --git a/servers/vm/vmproc.h b/servers/vm/vmproc.h index 1c9c488bc..ded51ff44 100644 --- a/servers/vm/vmproc.h +++ b/servers/vm/vmproc.h @@ -7,8 +7,6 @@ #include "pt.h" #include "vm.h" -#include "physravl.h" -#include "yieldedavl.h" #include "regionavl.h" struct vmproc;