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
This commit is contained in:
parent
cee2d9a296
commit
29edcad310
15 changed files with 262 additions and 246 deletions
|
@ -95,6 +95,13 @@ void utrace(struct ut *, int);
|
||||||
# define _MALLOC_UNLOCK() if (__isthreaded) _SPINUNLOCK(&thread_lock);
|
# define _MALLOC_UNLOCK() if (__isthreaded) _SPINUNLOCK(&thread_lock);
|
||||||
#endif /* __FreeBSD__ */
|
#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 <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
PROG= vm
|
PROG= vm
|
||||||
SRCS= main.c alloc.c utility.c exit.c fork.c break.c \
|
SRCS= main.c alloc.c utility.c exit.c fork.c break.c \
|
||||||
mmap.c slaballoc.c region.c pagefaults.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
|
mem_anon.c mem_directphys.c mem_anon_contig.c mem_shared.c
|
||||||
|
|
||||||
DPADD+= ${LIBSYS}
|
DPADD+= ${LIBSYS}
|
||||||
|
|
|
@ -54,25 +54,22 @@ struct vmproc *vmprocess = &vmproc[VM_PROC_NR];
|
||||||
* circular dependency on allocating memory and writing it into VM's
|
* circular dependency on allocating memory and writing it into VM's
|
||||||
* page table.
|
* page table.
|
||||||
*/
|
*/
|
||||||
#if defined(__i386__)
|
|
||||||
#if SANITYCHECKS
|
#if SANITYCHECKS
|
||||||
#define SPAREPAGES 100
|
#define SPAREPAGES 100
|
||||||
#define STATIC_SPAREPAGES 90
|
#define STATIC_SPAREPAGES 90
|
||||||
#else
|
#else
|
||||||
#define SPAREPAGES 15
|
#define SPAREPAGES 20
|
||||||
#define STATIC_SPAREPAGES 10
|
#define STATIC_SPAREPAGES 15
|
||||||
#endif
|
#endif
|
||||||
#elif defined(__arm__)
|
|
||||||
#define SPAREPAGEDIRS 11
|
#define SPAREPAGEDIRS 11
|
||||||
#define STATIC_SPAREPAGEDIRS 10
|
#define STATIC_SPAREPAGEDIRS 10
|
||||||
#define SPAREPAGES 250
|
|
||||||
#define STATIC_SPAREPAGES 100
|
|
||||||
int missing_sparedirs = SPAREPAGEDIRS;
|
int missing_sparedirs = SPAREPAGEDIRS;
|
||||||
static struct {
|
static struct {
|
||||||
void *pagedir;
|
void *pagedir;
|
||||||
phys_bytes phys;
|
phys_bytes phys;
|
||||||
} sparepagedirs[SPAREPAGEDIRS];
|
} sparepagedirs[SPAREPAGEDIRS];
|
||||||
#endif
|
|
||||||
|
|
||||||
int missing_spares = SPAREPAGES;
|
int missing_spares = SPAREPAGES;
|
||||||
static struct {
|
static struct {
|
||||||
|
@ -143,11 +140,7 @@ void pt_sanitycheck(pt_t *pt, char *file, int line)
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* findhole *
|
* findhole *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
#if defined(__i386__)
|
|
||||||
static u32_t findhole(void)
|
|
||||||
#elif defined(__arm__)
|
|
||||||
static u32_t findhole(int pages)
|
static u32_t findhole(int pages)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
/* Find a space in the virtual address space of VM. */
|
/* Find a space in the virtual address space of VM. */
|
||||||
u32_t curv;
|
u32_t curv;
|
||||||
|
@ -159,7 +152,9 @@ static u32_t findhole(int pages)
|
||||||
u32_t holev;
|
u32_t holev;
|
||||||
#endif
|
#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;
|
vmax = VM_STACKTOP;
|
||||||
|
|
||||||
/* Input sanity check. */
|
/* Input sanity check. */
|
||||||
|
@ -298,10 +293,10 @@ static void *vm_getsparepage(phys_bytes *phys)
|
||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
printf("no spare found, %d missing\n", missing_spares);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__arm__)
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* vm_getsparepagedir *
|
* vm_getsparepagedir *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -322,7 +317,6 @@ static void *vm_getsparepagedir(phys_bytes *phys)
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* vm_checkspares *
|
* vm_checkspares *
|
||||||
|
@ -332,7 +326,7 @@ static void *vm_checkspares(void)
|
||||||
int s, n = 0;
|
int s, n = 0;
|
||||||
static int total = 0, worst = 0;
|
static int total = 0, worst = 0;
|
||||||
assert(missing_spares >= 0 && missing_spares <= SPAREPAGES);
|
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) {
|
if(!sparepages[s].page) {
|
||||||
n++;
|
n++;
|
||||||
if((sparepages[s].page = vm_allocpage(&sparepages[s].phys,
|
if((sparepages[s].page = vm_allocpage(&sparepages[s].phys,
|
||||||
|
@ -344,6 +338,7 @@ static void *vm_checkspares(void)
|
||||||
printf("VM: warning: couldn't get new spare page\n");
|
printf("VM: warning: couldn't get new spare page\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if(worst < n) worst = n;
|
if(worst < n) worst = n;
|
||||||
total += n;
|
total += n;
|
||||||
|
|
||||||
|
@ -376,14 +371,14 @@ static void *vm_checksparedirs(void)
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int pt_init_done;
|
static int pt_init_done;
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* vm_allocpage *
|
* 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. */
|
/* Allocate a page for use by VM itself. */
|
||||||
phys_bytes newpage;
|
phys_bytes newpage;
|
||||||
|
@ -392,13 +387,13 @@ void *vm_allocpage(phys_bytes *phys, int reason)
|
||||||
int r;
|
int r;
|
||||||
static int level = 0;
|
static int level = 0;
|
||||||
void *ret;
|
void *ret;
|
||||||
#if defined(__arm__)
|
u32_t mem_flags = 0;
|
||||||
u32_t mem_bytes, mem_clicks, mem_flags;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pt = &vmprocess->vm_pt;
|
pt = &vmprocess->vm_pt;
|
||||||
assert(reason >= 0 && reason < VMP_CATEGORIES);
|
assert(reason >= 0 && reason < VMP_CATEGORIES);
|
||||||
|
|
||||||
|
assert(pages > 0);
|
||||||
|
|
||||||
level++;
|
level++;
|
||||||
|
|
||||||
assert(level >= 1);
|
assert(level >= 1);
|
||||||
|
@ -406,16 +401,13 @@ void *vm_allocpage(phys_bytes *phys, int reason)
|
||||||
|
|
||||||
if((level > 1) || !pt_init_done) {
|
if((level > 1) || !pt_init_done) {
|
||||||
void *s;
|
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);
|
s=vm_getsparepage(phys);
|
||||||
|
|
||||||
#endif
|
if(pages == 1) s=vm_getsparepage(phys);
|
||||||
|
else if(pages == 4) s=vm_getsparepagedir(phys);
|
||||||
|
else panic("%d pages", pages);
|
||||||
|
|
||||||
level--;
|
level--;
|
||||||
if(!s) {
|
if(!s) {
|
||||||
util_stacktrace();
|
util_stacktrace();
|
||||||
|
@ -427,23 +419,14 @@ void *vm_allocpage(phys_bytes *phys, int reason)
|
||||||
|
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
if (reason == VMP_PAGEDIR) {
|
if (reason == VMP_PAGEDIR) {
|
||||||
mem_bytes = ARCH_PAGEDIR_SIZE;
|
mem_flags |= PAF_ALIGN16K;
|
||||||
mem_flags = PAF_ALIGN16K;
|
|
||||||
} else {
|
|
||||||
mem_bytes = VM_PAGE_SIZE;
|
|
||||||
mem_flags = 0;
|
|
||||||
}
|
}
|
||||||
mem_clicks = mem_bytes / VM_PAGE_SIZE * CLICKSPERPAGE;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* VM does have a pagetable, so get a page and map it in there.
|
/* VM does have a pagetable, so get a page and map it in there.
|
||||||
* Where in our virtual address space can we put it?
|
* Where in our virtual address space can we put it?
|
||||||
*/
|
*/
|
||||||
#if defined(__i386__)
|
loc = findhole(pages);
|
||||||
loc = findhole();
|
|
||||||
#elif defined(__arm__)
|
|
||||||
loc = findhole(mem_bytes / VM_PAGE_SIZE);
|
|
||||||
#endif
|
|
||||||
if(loc == NO_MEM) {
|
if(loc == NO_MEM) {
|
||||||
level--;
|
level--;
|
||||||
printf("VM: vm_allocpage: findhole failed\n");
|
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
|
/* Allocate page of memory for use by VM. As VM
|
||||||
* is trusted, we don't have to pre-clear it.
|
* is trusted, we don't have to pre-clear it.
|
||||||
*/
|
*/
|
||||||
#if defined(__i386__)
|
if((newpage = alloc_mem(pages, mem_flags)) == NO_MEM) {
|
||||||
if((newpage = alloc_mem(CLICKSPERPAGE, 0)) == NO_MEM) {
|
|
||||||
#elif defined(__arm__)
|
|
||||||
if((newpage = alloc_mem(mem_clicks, mem_flags)) == NO_MEM) {
|
|
||||||
#endif
|
|
||||||
level--;
|
level--;
|
||||||
printf("VM: vm_allocpage: alloc_mem failed\n");
|
printf("VM: vm_allocpage: alloc_mem failed\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -466,16 +445,13 @@ void *vm_allocpage(phys_bytes *phys, int reason)
|
||||||
*phys = CLICK2ABS(newpage);
|
*phys = CLICK2ABS(newpage);
|
||||||
|
|
||||||
/* Map this page into our address space. */
|
/* Map this page into our address space. */
|
||||||
#if defined(__i386__)
|
if((r=pt_writemap(vmprocess, pt, loc, *phys, VM_PAGE_SIZE*pages,
|
||||||
if((r=pt_writemap(vmprocess, pt, loc, *phys, VM_PAGE_SIZE,
|
ARCH_VM_PTE_PRESENT | ARCH_VM_PTE_USER | ARCH_VM_PTE_RW
|
||||||
ARCH_VM_PTE_PRESENT | ARCH_VM_PTE_USER | ARCH_VM_PTE_RW, 0)) != OK) {
|
#if defined(__arm__)
|
||||||
free_mem(newpage, CLICKSPERPAGE);
|
| ARM_VM_PTE_WB | ARM_VM_PTE_SHAREABLE
|
||||||
#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);
|
|
||||||
#endif
|
#endif
|
||||||
|
, 0)) != OK) {
|
||||||
|
free_mem(newpage, pages);
|
||||||
printf("vm_allocpage writemap failed\n");
|
printf("vm_allocpage writemap failed\n");
|
||||||
level--;
|
level--;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -494,6 +470,11 @@ void *vm_allocpage(phys_bytes *phys, int reason)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *vm_allocpage(phys_bytes *phys, int reason)
|
||||||
|
{
|
||||||
|
return vm_allocpages(phys, reason, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* vm_pagelock *
|
* vm_pagelock *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -1089,12 +1070,12 @@ int pt_new(pt_t *pt)
|
||||||
* the page directories (the page_directories data).
|
* the page directories (the page_directories data).
|
||||||
*/
|
*/
|
||||||
if(!pt->pt_dir &&
|
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;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
#if defined(__arm__)
|
|
||||||
assert(!((u32_t)pt->pt_dir_phys % ARCH_PAGEDIR_SIZE));
|
assert(!((u32_t)pt->pt_dir_phys % ARCH_PAGEDIR_SIZE));
|
||||||
#endif
|
|
||||||
|
|
||||||
for(i = 0; i < ARCH_VM_DIR_ENTRIES; i++) {
|
for(i = 0; i < ARCH_VM_DIR_ENTRIES; i++) {
|
||||||
pt->pt_dir[i] = 0; /* invalid entry (PRESENT bit = 0) */
|
pt->pt_dir[i] = 0; /* invalid entry (PRESENT bit = 0) */
|
||||||
|
@ -1360,6 +1341,8 @@ void pt_init(void)
|
||||||
|
|
||||||
pt_init_done = 1;
|
pt_init_done = 1;
|
||||||
|
|
||||||
|
vm_checkspares();
|
||||||
|
|
||||||
/* All OK. */
|
/* All OK. */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,6 @@ static int anon_contig_new(struct vir_region *region)
|
||||||
u32_t allocflags;
|
u32_t allocflags;
|
||||||
phys_bytes new_pages, new_page_cl, cur_ph;
|
phys_bytes new_pages, new_page_cl, cur_ph;
|
||||||
int p, pages;
|
int p, pages;
|
||||||
physr_iter iter;
|
|
||||||
|
|
||||||
allocflags = vrallocflags(region->flags);
|
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);
|
cur_ph = new_pages = CLICK2ABS(new_page_cl);
|
||||||
|
|
||||||
physr_start_iter_least(region->phys, &iter);
|
|
||||||
|
|
||||||
for(p = 0; p < pages; p++) {
|
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);
|
||||||
assert(pr->ph);
|
assert(pr->ph);
|
||||||
assert(pr->ph->phys == MAP_NONE);
|
assert(pr->ph->phys == MAP_NONE);
|
||||||
assert(pr->offset == p * VM_PAGE_SIZE);
|
assert(pr->offset == p * VM_PAGE_SIZE);
|
||||||
pr->ph->phys = cur_ph + pr->offset;
|
pr->ph->phys = cur_ph + pr->offset;
|
||||||
physr_incr_iter(&iter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!physr_get_iter(&iter));
|
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,12 +129,11 @@ static int shared_pagefault(struct vmproc *vmp, struct vir_region *region,
|
||||||
assert(ph->ph->phys == MAP_NONE);
|
assert(ph->ph->phys == MAP_NONE);
|
||||||
pb_free(ph->ph);
|
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;
|
int r;
|
||||||
if((r=map_pf(src_vmp, src_region, ph->offset, write)) != OK)
|
if((r=map_pf(src_vmp, src_region, ph->offset, write)) != OK)
|
||||||
return r;
|
return r;
|
||||||
if(!(pr = physr_search(src_region->phys, ph->offset,
|
if(!(pr = physblock_get(src_region, ph->offset))) {
|
||||||
AVL_EQUAL))) {
|
|
||||||
panic("missing region after pagefault handling");
|
panic("missing region after pagefault handling");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include "glo.h"
|
#include "glo.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "sanitycheck.h"
|
#include "sanitycheck.h"
|
||||||
#include "physravl.h"
|
|
||||||
#include "memlist.h"
|
#include "memlist.h"
|
||||||
|
|
||||||
struct phys_block *pb_new(phys_bytes phys)
|
struct phys_block *pb_new(phys_bytes phys)
|
||||||
|
@ -84,7 +83,7 @@ struct phys_region *pb_reference(struct phys_block *newpb,
|
||||||
/* New physical region. */
|
/* New physical region. */
|
||||||
pb_link(newphysr, newpb, offset, region);
|
pb_link(newphysr, newpb, offset, region);
|
||||||
|
|
||||||
physr_insert(region->phys, newphysr);
|
physblock_set(region, offset, newphysr);
|
||||||
|
|
||||||
return newphysr;
|
return newphysr;
|
||||||
}
|
}
|
||||||
|
@ -129,5 +128,5 @@ void pb_unreferenced(struct vir_region *region, struct phys_region *pr, int rm)
|
||||||
|
|
||||||
pr->ph = NULL;
|
pr->ph = NULL;
|
||||||
|
|
||||||
if(rm) physr_remove(region->phys, pr->offset);
|
if(rm) physblock_set(region, pr->offset, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,6 @@ typedef struct phys_region {
|
||||||
|
|
||||||
/* list of phys_regions that reference the same phys_block */
|
/* list of phys_regions that reference the same phys_block */
|
||||||
struct phys_region *next_ph_list;
|
struct phys_region *next_ph_list;
|
||||||
|
|
||||||
/* AVL fields */
|
|
||||||
struct phys_region *less, *greater;
|
|
||||||
int factor;
|
|
||||||
} phys_region_t;
|
} phys_region_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
|
|
||||||
#include "proto.h"
|
|
||||||
#include "sanitycheck.h"
|
|
||||||
#include "phys_region.h"
|
|
||||||
#include "physravl_defs.h"
|
|
||||||
#include "cavl_impl.h"
|
|
||||||
|
|
|
@ -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
|
|
|
@ -1,20 +0,0 @@
|
||||||
|
|
||||||
#include <minix/u64.h>
|
|
||||||
|
|
||||||
#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];
|
|
||||||
|
|
|
@ -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_checkrange(pt_t *pt, vir_bytes v, size_t bytes, int write);
|
||||||
int pt_bind(pt_t *pt, struct vmproc *who);
|
int pt_bind(pt_t *pt, struct vmproc *who);
|
||||||
void *vm_allocpage(phys_bytes *p, int cat);
|
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 *vm_allocpagedir(phys_bytes *p);
|
||||||
void pt_cycle(void);
|
void pt_cycle(void);
|
||||||
int pt_mapkernel(pt_t *pt);
|
int pt_mapkernel(pt_t *pt);
|
||||||
|
@ -145,9 +146,12 @@ void printregionstats(struct vmproc *vmp);
|
||||||
void map_setparent(struct vmproc *vmp);
|
void map_setparent(struct vmproc *vmp);
|
||||||
int yielded_block_cmp(struct block_id *, struct block_id *);
|
int yielded_block_cmp(struct block_id *, struct block_id *);
|
||||||
struct phys_region *map_clone_ph_block(struct vmproc *vmp,
|
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);
|
u32_t vrallocflags(u32_t flags);
|
||||||
int map_free(struct vir_region *region);
|
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
|
struct vir_region * map_region_lookup_tag(struct vmproc *vmp, u32_t
|
||||||
tag);
|
tag);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -25,7 +26,7 @@
|
||||||
#include "glo.h"
|
#include "glo.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "sanitycheck.h"
|
#include "sanitycheck.h"
|
||||||
#include "physravl.h"
|
#include "yieldedavl.h"
|
||||||
#include "memlist.h"
|
#include "memlist.h"
|
||||||
#include "memtype.h"
|
#include "memtype.h"
|
||||||
|
|
||||||
|
@ -74,23 +75,50 @@ static yielded_avl *get_yielded_avl(block_id_t id)
|
||||||
return &vm_yielded_blocks[h];
|
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;
|
struct phys_region *ph;
|
||||||
printf("map_printmap: map_name: %s\n", vr->memtype->name);
|
printf("map_printmap: map_name: %s\n", vr->memtype->name);
|
||||||
printf("\t%lx (len 0x%lx, %lukB), %p\n",
|
printf("\t%lx (len 0x%lx, %lukB), %p\n",
|
||||||
vr->vaddr, vr->length, vr->length/1024, vr->memtype->name);
|
vr->vaddr, vr->length, vr->length/1024, vr->memtype->name);
|
||||||
printf("\t\tphysblocks:\n");
|
printf("\t\tphysblocks:\n");
|
||||||
physr_start_iter_least(vr->phys, &iter);
|
for(i = 0; i < vr->length/VM_PAGE_SIZE; i++) {
|
||||||
while((ph = physr_get_iter(&iter))) {
|
if(!(ph=vr->physblocks[i])) continue;
|
||||||
printf("\t\t@ %lx (refs %d): phys 0x%lx\n",
|
printf("\t\t@ %lx (refs %d): phys 0x%lx\n",
|
||||||
(vr->vaddr + ph->offset),
|
(vr->vaddr + ph->offset),
|
||||||
ph->ph->refcount, ph->ph->phys);
|
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 *
|
* map_printmap *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -104,7 +132,7 @@ struct vmproc *vmp;
|
||||||
|
|
||||||
region_start_iter_least(&vmp->vm_regions_avl, &iter);
|
region_start_iter_least(&vmp->vm_regions_avl, &iter);
|
||||||
while((vr = region_get_iter(&iter))) {
|
while((vr = region_get_iter(&iter))) {
|
||||||
map_printregion(vmp, vr);
|
map_printregion(vr);
|
||||||
region_incr_iter(&iter);
|
region_incr_iter(&iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,7 +184,7 @@ static int map_sanitycheck_pt(struct vmproc *vmp,
|
||||||
if(r != OK) {
|
if(r != OK) {
|
||||||
printf("proc %d phys_region 0x%lx sanity check failed\n",
|
printf("proc %d phys_region 0x%lx sanity check failed\n",
|
||||||
vmp->vm_endpoint, pr->offset);
|
vmp->vm_endpoint, pr->offset);
|
||||||
map_printregion(vmp, vr);
|
map_printregion(vr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
@ -176,19 +204,20 @@ void map_sanitycheck(char *file, int line)
|
||||||
*/
|
*/
|
||||||
#define ALLREGIONS(regioncode, physcode) \
|
#define ALLREGIONS(regioncode, physcode) \
|
||||||
for(vmp = vmproc; vmp < &vmproc[VMP_NR]; vmp++) { \
|
for(vmp = vmproc; vmp < &vmproc[VMP_NR]; vmp++) { \
|
||||||
|
vir_bytes voffset; \
|
||||||
region_iter v_iter; \
|
region_iter v_iter; \
|
||||||
struct vir_region *vr; \
|
struct vir_region *vr; \
|
||||||
if(!(vmp->vm_flags & VMF_INUSE)) \
|
if(!(vmp->vm_flags & VMF_INUSE)) \
|
||||||
continue; \
|
continue; \
|
||||||
region_start_iter_least(&vmp->vm_regions_avl, &v_iter); \
|
region_start_iter_least(&vmp->vm_regions_avl, &v_iter); \
|
||||||
while((vr = region_get_iter(&v_iter))) { \
|
while((vr = region_get_iter(&v_iter))) { \
|
||||||
physr_iter iter; \
|
|
||||||
struct phys_region *pr; \
|
struct phys_region *pr; \
|
||||||
regioncode; \
|
regioncode; \
|
||||||
physr_start_iter_least(vr->phys, &iter); \
|
for(voffset = 0; voffset < vr->length; \
|
||||||
while((pr = physr_get_iter(&iter))) { \
|
voffset += VM_PAGE_SIZE) { \
|
||||||
|
if(!(pr = physblock_get(vr, voffset))) \
|
||||||
|
continue; \
|
||||||
physcode; \
|
physcode; \
|
||||||
physr_incr_iter(&iter); \
|
|
||||||
} \
|
} \
|
||||||
region_incr_iter(&v_iter); \
|
region_incr_iter(&v_iter); \
|
||||||
} \
|
} \
|
||||||
|
@ -201,6 +230,7 @@ void map_sanitycheck(char *file, int line)
|
||||||
|
|
||||||
/* Do counting for consistency check. */
|
/* Do counting for consistency check. */
|
||||||
ALLREGIONS(;,USE(pr->ph, pr->ph->seencount = 0;););
|
ALLREGIONS(;,USE(pr->ph, pr->ph->seencount = 0;););
|
||||||
|
ALLREGIONS(;,MYASSERT(pr->offset == voffset););
|
||||||
ALLREGIONS(;,USE(pr->ph, pr->ph->seencount++;);
|
ALLREGIONS(;,USE(pr->ph, pr->ph->seencount++;);
|
||||||
if(pr->ph->seencount == 1) {
|
if(pr->ph->seencount == 1) {
|
||||||
if(pr->parent->memtype->ev_sanitycheck)
|
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);
|
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,
|
struct vir_region *region_new(struct vmproc *vmp, vir_bytes startv, vir_bytes length,
|
||||||
int flags, mem_type_t *memtype)
|
int flags, mem_type_t *memtype)
|
||||||
{
|
{
|
||||||
physr_avl *phavl;
|
|
||||||
struct vir_region *newregion;
|
struct vir_region *newregion;
|
||||||
|
struct phys_region **physregions;
|
||||||
static u32_t id;
|
static u32_t id;
|
||||||
|
int slots = phys_slot(length);
|
||||||
|
|
||||||
if(!(SLABALLOC(newregion))) {
|
if(!(SLABALLOC(newregion))) {
|
||||||
printf("vm: region_new: could not allocate\n");
|
printf("vm: region_new: could not allocate\n");
|
||||||
|
@ -490,14 +527,13 @@ USE(newregion,
|
||||||
newregion->lower = newregion->higher = NULL;
|
newregion->lower = newregion->higher = NULL;
|
||||||
newregion->parent = vmp;);
|
newregion->parent = vmp;);
|
||||||
|
|
||||||
SLABALLOC(phavl);
|
if(!(physregions = calloc(slots, sizeof(struct phys_region *)))) {
|
||||||
if(!phavl) {
|
printf("VM: region_new: allocating phys blocks failed\n");
|
||||||
printf("VM: region_new: allocating phys avl failed\n");
|
|
||||||
SLABFREE(newregion);
|
SLABFREE(newregion);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
USE(newregion, newregion->phys = phavl;);
|
|
||||||
physr_init(newregion->phys);
|
USE(newregion, newregion->physblocks = physregions;);
|
||||||
|
|
||||||
return newregion;
|
return newregion;
|
||||||
}
|
}
|
||||||
|
@ -543,8 +579,9 @@ mem_type_t *memtype;
|
||||||
if(mapflags & MF_PREALLOC) {
|
if(mapflags & MF_PREALLOC) {
|
||||||
if(map_handle_memory(vmp, newregion, 0, length, 1) != OK) {
|
if(map_handle_memory(vmp, newregion, 0, length, 1) != OK) {
|
||||||
printf("VM: map_page_region: prealloc failed\n");
|
printf("VM: map_page_region: prealloc failed\n");
|
||||||
|
free(newregion->physblocks);
|
||||||
USE(newregion,
|
USE(newregion,
|
||||||
SLABFREE(newregion->phys););
|
newregion->physblocks = NULL;);
|
||||||
SLABFREE(newregion);
|
SLABFREE(newregion);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -580,51 +617,37 @@ static int map_subfree(struct vir_region *region,
|
||||||
vir_bytes start, vir_bytes len)
|
vir_bytes start, vir_bytes len)
|
||||||
{
|
{
|
||||||
struct phys_region *pr;
|
struct phys_region *pr;
|
||||||
physr_iter iter;
|
|
||||||
vir_bytes end = start+len;
|
vir_bytes end = start+len;
|
||||||
|
vir_bytes voffset;
|
||||||
int full = 0;
|
|
||||||
|
|
||||||
#if SANITYCHECKS
|
#if SANITYCHECKS
|
||||||
{
|
|
||||||
SLABSANE(region);
|
SLABSANE(region);
|
||||||
SLABSANE(region->phys);
|
for(voffset = 0; voffset < phys_slot(region->length);
|
||||||
physr_start_iter_least(region->phys, &iter);
|
voffset += VM_PAGE_SIZE) {
|
||||||
while((pr = physr_get_iter(&iter))) {
|
|
||||||
struct phys_region *others;
|
struct phys_region *others;
|
||||||
struct phys_block *pb;
|
struct phys_block *pb;
|
||||||
|
|
||||||
|
if(!(pr = physblock_get(region, voffset)))
|
||||||
|
continue;
|
||||||
|
|
||||||
pb = pr->ph;
|
pb = pr->ph;
|
||||||
|
|
||||||
for(others = pb->firstregion; others;
|
for(others = pb->firstregion; others;
|
||||||
others = others->next_ph_list) {
|
others = others->next_ph_list) {
|
||||||
assert(others->ph == pb);
|
assert(others->ph == pb);
|
||||||
}
|
}
|
||||||
physr_incr_iter(&iter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(start == 0 && len == region->length)
|
for(voffset = start; voffset < end; voffset+=VM_PAGE_SIZE) {
|
||||||
full = 1;
|
if(!(pr = physblock_get(region, voffset)))
|
||||||
|
continue;
|
||||||
physr_init_iter(&iter);
|
assert(pr->offset >= start);
|
||||||
physr_start_iter(region->phys, &iter, start, AVL_GREATER_EQUAL);
|
assert(pr->offset < end);
|
||||||
while((pr = physr_get_iter(&iter))) {
|
pb_unreferenced(region, pr, 1);
|
||||||
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);
|
|
||||||
}
|
|
||||||
SLABFREE(pr);
|
SLABFREE(pr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(full)
|
|
||||||
physr_init(region->phys);
|
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,9 +665,8 @@ int map_free(struct vir_region *region)
|
||||||
|
|
||||||
if(region->memtype->ev_delete)
|
if(region->memtype->ev_delete)
|
||||||
region->memtype->ev_delete(region);
|
region->memtype->ev_delete(region);
|
||||||
|
free(region->physblocks);
|
||||||
USE(region,
|
region->physblocks = NULL;
|
||||||
SLABFREE(region->phys););
|
|
||||||
SLABFREE(region);
|
SLABFREE(region);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
@ -829,7 +851,7 @@ struct phys_region **physr;
|
||||||
if(offset >= r->vaddr && offset < r->vaddr + r->length) {
|
if(offset >= r->vaddr && offset < r->vaddr + r->length) {
|
||||||
ph = offset - r->vaddr;
|
ph = offset - r->vaddr;
|
||||||
if(physr) {
|
if(physr) {
|
||||||
*physr = physr_search(r->phys, ph, AVL_EQUAL);
|
*physr = physblock_get(r, ph);
|
||||||
if(*physr) assert((*physr)->offset == ph);
|
if(*physr) assert((*physr)->offset == ph);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
|
@ -862,11 +884,10 @@ u32_t vrallocflags(u32_t flags)
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* map_clone_ph_block *
|
* 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 vmproc *vmp;
|
||||||
struct vir_region *region;
|
struct vir_region *region;
|
||||||
struct phys_region *ph;
|
struct phys_region *ph;
|
||||||
physr_iter *iter;
|
|
||||||
{
|
{
|
||||||
vir_bytes offset;
|
vir_bytes offset;
|
||||||
u32_t allocflags;
|
u32_t allocflags;
|
||||||
|
@ -927,15 +948,10 @@ physr_iter *iter;
|
||||||
if(copy_abs2region(physaddr, region, offset, VM_PAGE_SIZE) != OK)
|
if(copy_abs2region(physaddr, region, offset, VM_PAGE_SIZE) != OK)
|
||||||
panic("copy_abs2region failed, no good reason for that");
|
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);
|
||||||
assert(newpr->offset == offset);
|
assert(newpr->offset == offset);
|
||||||
|
|
||||||
if(iter) {
|
|
||||||
physr_start_iter(region->phys, iter, offset, AVL_EQUAL);
|
|
||||||
assert(physr_get_iter(iter) == newpr);
|
|
||||||
}
|
|
||||||
|
|
||||||
SANITYCHECK(SCL_FUNCTIONS);
|
SANITYCHECK(SCL_FUNCTIONS);
|
||||||
|
|
||||||
return newpr;
|
return newpr;
|
||||||
|
@ -964,7 +980,7 @@ int write;
|
||||||
|
|
||||||
SANITYCHECK(SCL_FUNCTIONS);
|
SANITYCHECK(SCL_FUNCTIONS);
|
||||||
|
|
||||||
if(!(ph = physr_search(region->phys, offset, AVL_EQUAL))) {
|
if(!(ph = physblock_get(region, offset))) {
|
||||||
struct phys_block *pb;
|
struct phys_block *pb;
|
||||||
|
|
||||||
/* New block. */
|
/* New block. */
|
||||||
|
@ -993,6 +1009,7 @@ int write;
|
||||||
if(!write || !region->memtype->writable(ph)) {
|
if(!write || !region->memtype->writable(ph)) {
|
||||||
assert(region->memtype->ev_pagefault);
|
assert(region->memtype->ev_pagefault);
|
||||||
assert(ph->ph);
|
assert(ph->ph);
|
||||||
|
|
||||||
if((r = region->memtype->ev_pagefault(vmp,
|
if((r = region->memtype->ev_pagefault(vmp,
|
||||||
region, ph, write)) == SUSPEND) {
|
region, ph, write)) == SUSPEND) {
|
||||||
panic("map_pf: memtype->ev_pagefault returned SUSPEND\n");
|
panic("map_pf: memtype->ev_pagefault returned SUSPEND\n");
|
||||||
|
@ -1071,21 +1088,6 @@ int map_pin_memory(struct vmproc *vmp)
|
||||||
return OK;
|
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 *
|
* 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 vir_region *newvr;
|
||||||
struct phys_region *ph;
|
struct phys_region *ph;
|
||||||
int r;
|
int r;
|
||||||
physr_iter iter;
|
|
||||||
#if SANITYCHECKS
|
#if SANITYCHECKS
|
||||||
int cr;
|
int cr;
|
||||||
cr = count_phys_regions(vr);
|
cr = physregions(vr);
|
||||||
#endif
|
#endif
|
||||||
|
vir_bytes p;
|
||||||
|
|
||||||
if(!(newvr = region_new(vr->parent, vr->vaddr, vr->length, vr->flags, vr->memtype)))
|
if(!(newvr = region_new(vr->parent, vr->vaddr, vr->length, vr->flags, vr->memtype)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1117,21 +1119,20 @@ static struct vir_region *map_copy_region(struct vmproc *vmp, struct vir_region
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
physr_start_iter_least(vr->phys, &iter);
|
for(p = 0; p < phys_slot(vr->length); p++) {
|
||||||
while((ph = physr_get_iter(&iter))) {
|
if(!(ph = physblock_get(vr, p*VM_PAGE_SIZE))) continue;
|
||||||
struct phys_region *newph = pb_reference(ph->ph, ph->offset, newvr);
|
struct phys_region *newph = pb_reference(ph->ph, ph->offset, newvr);
|
||||||
|
|
||||||
if(!newph) { map_free(newvr); return NULL; }
|
if(!newph) { map_free(newvr); return NULL; }
|
||||||
|
|
||||||
#if SANITYCHECKS
|
#if SANITYCHECKS
|
||||||
USE(newph, newph->written = 0;);
|
USE(newph, newph->written = 0;);
|
||||||
assert(count_phys_regions(vr) == cr);
|
assert(physregions(vr) == cr);
|
||||||
#endif
|
#endif
|
||||||
physr_incr_iter(&iter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SANITYCHECKS
|
#if SANITYCHECKS
|
||||||
assert(count_phys_regions(vr) == count_phys_regions(newvr));
|
assert(physregions(vr) == physregions(newvr));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return newvr;
|
return newvr;
|
||||||
|
@ -1145,13 +1146,13 @@ int copy_abs2region(phys_bytes abs, struct vir_region *destregion,
|
||||||
|
|
||||||
{
|
{
|
||||||
assert(destregion);
|
assert(destregion);
|
||||||
assert(destregion->phys);
|
assert(destregion->physblocks);
|
||||||
while(len > 0) {
|
while(len > 0) {
|
||||||
phys_bytes sublen, suboffset;
|
phys_bytes sublen, suboffset;
|
||||||
struct phys_region *ph;
|
struct phys_region *ph;
|
||||||
assert(destregion);
|
assert(destregion);
|
||||||
assert(destregion->phys);
|
assert(destregion->physblocks);
|
||||||
if(!(ph = physr_search(destregion->phys, offset, AVL_LESS_EQUAL))) {
|
if(!(ph = physblock_get(destregion, offset))) {
|
||||||
printf("VM: copy_abs2region: no phys region found (1).\n");
|
printf("VM: copy_abs2region: no phys region found (1).\n");
|
||||||
return EFAULT;
|
return EFAULT;
|
||||||
}
|
}
|
||||||
|
@ -1195,11 +1196,9 @@ int map_writept(struct vmproc *vmp)
|
||||||
region_start_iter_least(&vmp->vm_regions_avl, &v_iter);
|
region_start_iter_least(&vmp->vm_regions_avl, &v_iter);
|
||||||
|
|
||||||
while((vr = region_get_iter(&v_iter))) {
|
while((vr = region_get_iter(&v_iter))) {
|
||||||
physr_iter ph_iter;
|
vir_bytes p;
|
||||||
physr_start_iter_least(vr->phys, &ph_iter);
|
for(p = 0; p < vr->length; p += VM_PAGE_SIZE) {
|
||||||
|
if(!(ph = physblock_get(vr, p))) continue;
|
||||||
while((ph = physr_get_iter(&ph_iter))) {
|
|
||||||
physr_incr_iter(&ph_iter);
|
|
||||||
|
|
||||||
if((r=map_ph_writept(vmp, vr, ph)) != OK) {
|
if((r=map_ph_writept(vmp, vr, ph)) != OK) {
|
||||||
printf("VM: map_writept: failed\n");
|
printf("VM: map_writept: failed\n");
|
||||||
|
@ -1250,34 +1249,30 @@ struct vir_region *start_src_vr;
|
||||||
SANITYCHECK(SCL_FUNCTIONS);
|
SANITYCHECK(SCL_FUNCTIONS);
|
||||||
|
|
||||||
while((vr = region_get_iter(&v_iter))) {
|
while((vr = region_get_iter(&v_iter))) {
|
||||||
physr_iter iter_orig, iter_new;
|
|
||||||
struct vir_region *newvr;
|
struct vir_region *newvr;
|
||||||
struct phys_region *orig_ph, *new_ph;
|
|
||||||
if(!(newvr = map_copy_region(dst, vr))) {
|
if(!(newvr = map_copy_region(dst, vr))) {
|
||||||
map_free_proc(dst);
|
map_free_proc(dst);
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
USE(newvr, newvr->parent = dst;);
|
USE(newvr, newvr->parent = dst;);
|
||||||
region_insert(&dst->vm_regions_avl, newvr);
|
region_insert(&dst->vm_regions_avl, newvr);
|
||||||
physr_start_iter_least(vr->phys, &iter_orig);
|
assert(vr->length == newvr->length);
|
||||||
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(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 */
|
#if SANITYCHECKS
|
||||||
physr_incr_iter(&iter_orig);
|
{
|
||||||
physr_incr_iter(&iter_new);
|
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 != new_ph);
|
||||||
|
assert(orig_ph->ph == new_ph->ph);
|
||||||
}
|
}
|
||||||
assert(!physr_get_iter(&iter_new));
|
}
|
||||||
|
#endif
|
||||||
region_incr_iter(&v_iter);
|
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;
|
vir_bytes offset = v;
|
||||||
struct vir_region *vr, *nextvr;
|
struct vir_region *vr, *nextvr;
|
||||||
|
struct phys_region **newpr;
|
||||||
|
int newslots, prevslots, addedslots;
|
||||||
|
|
||||||
offset = roundup(offset, VM_PAGE_SIZE);
|
offset = roundup(offset, VM_PAGE_SIZE);
|
||||||
|
|
||||||
|
@ -1300,7 +1297,24 @@ int map_region_extend_upto_v(struct vmproc *vmp, vir_bytes v)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(vr->vaddr + vr->length >= v) return OK;
|
||||||
|
|
||||||
assert(vr->vaddr <= offset);
|
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))) {
|
if((nextvr = getnextvr(vr))) {
|
||||||
assert(offset <= nextvr->vaddr);
|
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.
|
* memory it used to reference if any.
|
||||||
*/
|
*/
|
||||||
vir_bytes regionstart;
|
vir_bytes regionstart;
|
||||||
|
int freeslots = phys_slot(len);
|
||||||
|
|
||||||
SANITYCHECK(SCL_FUNCTIONS);
|
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 unmap was at start/end of this region, it actually shrinks */
|
||||||
if(offset == 0) {
|
if(offset == 0) {
|
||||||
struct phys_region *pr;
|
struct phys_region *pr;
|
||||||
physr_iter iter;
|
vir_bytes voffset;
|
||||||
|
int remslots;
|
||||||
|
|
||||||
region_remove(&vmp->vm_regions_avl, r->vaddr);
|
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->vaddr += len;
|
||||||
r->length -= len;);
|
r->length -= len;);
|
||||||
|
|
||||||
|
remslots = phys_slot(r->length);
|
||||||
|
|
||||||
region_insert(&vmp->vm_regions_avl, r);
|
region_insert(&vmp->vm_regions_avl, r);
|
||||||
|
|
||||||
/* vaddr has increased; to make all the phys_regions
|
/* vaddr has increased; to make all the phys_regions
|
||||||
* point to the same addresses, make them shrink by the
|
* point to the same addresses, make them shrink by the
|
||||||
* same amount.
|
* same amount.
|
||||||
*/
|
*/
|
||||||
physr_init_iter(&iter);
|
for(voffset = offset; voffset < r->length;
|
||||||
physr_start_iter(r->phys, &iter, offset, AVL_GREATER_EQUAL);
|
voffset += VM_PAGE_SIZE) {
|
||||||
|
if(!(pr = physblock_get(r, voffset))) continue;
|
||||||
while((pr = physr_get_iter(&iter))) {
|
|
||||||
assert(pr->offset >= offset);
|
assert(pr->offset >= offset);
|
||||||
USE(pr, pr->offset -= len;);
|
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) {
|
} else if(offset + len == r->length) {
|
||||||
assert(len <= r->length);
|
assert(len <= r->length);
|
||||||
r->length -= len;
|
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)
|
void get_usage_info(struct vmproc *vmp, struct vm_usage_info *vui)
|
||||||
{
|
{
|
||||||
struct vir_region *vr;
|
struct vir_region *vr;
|
||||||
physr_iter iter;
|
|
||||||
struct phys_region *ph;
|
struct phys_region *ph;
|
||||||
region_iter v_iter;
|
region_iter v_iter;
|
||||||
region_start_iter_least(&vmp->vm_regions_avl, &v_iter);
|
region_start_iter_least(&vmp->vm_regions_avl, &v_iter);
|
||||||
|
vir_bytes voffset;
|
||||||
|
|
||||||
memset(vui, 0, sizeof(*vui));
|
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))) {
|
while((vr = region_get_iter(&v_iter))) {
|
||||||
physr_start_iter_least(vr->phys, &iter);
|
for(voffset = 0; voffset < vr->length; voffset += VM_PAGE_SIZE) {
|
||||||
while((ph = physr_get_iter(&iter))) {
|
if(!(ph = physblock_get(vr, voffset))) continue;
|
||||||
/* All present pages are counted towards the total. */
|
/* All present pages are counted towards the total. */
|
||||||
vui->vui_total += VM_PAGE_SIZE;
|
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)
|
if (vr->flags & VR_SHARED)
|
||||||
vui->vui_shared += VM_PAGE_SIZE;
|
vui->vui_shared += VM_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
physr_incr_iter(&iter);
|
|
||||||
}
|
}
|
||||||
region_incr_iter(&v_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;
|
if(!(vr = region_get_iter(&v_iter))) return 0;
|
||||||
|
|
||||||
for(count = 0; (vr = region_get_iter(&v_iter)) && count < max; count++, vri++) {
|
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. */
|
/* Report part of the region that's actually in use. */
|
||||||
|
|
||||||
/* Get first and last phys_regions, if any */
|
/* Get first and last phys_regions, if any */
|
||||||
ph1 = physr_search_least(vr->phys);
|
for(voffset = 0; voffset > vr->length; voffset += VM_PAGE_SIZE) {
|
||||||
ph2 = physr_search_greatest(vr->phys);
|
struct phys_region *ph;
|
||||||
|
if(!(ph = physblock_get(vr, voffset))) continue;
|
||||||
|
if(!ph1) ph1 = ph;
|
||||||
|
ph2 = ph;
|
||||||
|
}
|
||||||
if(!ph1 || !ph2) { assert(!ph1 && !ph2); continue; }
|
if(!ph1 || !ph2) { assert(!ph1 && !ph2); continue; }
|
||||||
|
|
||||||
/* Report start+length of region starting from lowest use. */
|
/* Report start+length of region starting from lowest use. */
|
||||||
|
@ -1548,18 +1571,17 @@ void printregionstats(struct vmproc *vmp)
|
||||||
{
|
{
|
||||||
struct vir_region *vr;
|
struct vir_region *vr;
|
||||||
struct phys_region *pr;
|
struct phys_region *pr;
|
||||||
physr_iter iter;
|
|
||||||
vir_bytes used = 0, weighted = 0;
|
vir_bytes used = 0, weighted = 0;
|
||||||
region_iter v_iter;
|
region_iter v_iter;
|
||||||
region_start_iter_least(&vmp->vm_regions_avl, &v_iter);
|
region_start_iter_least(&vmp->vm_regions_avl, &v_iter);
|
||||||
|
|
||||||
while((vr = region_get_iter(&v_iter))) {
|
while((vr = region_get_iter(&v_iter))) {
|
||||||
|
vir_bytes voffset;
|
||||||
region_incr_iter(&v_iter);
|
region_incr_iter(&v_iter);
|
||||||
if(vr->flags & VR_DIRECT)
|
if(vr->flags & VR_DIRECT)
|
||||||
continue;
|
continue;
|
||||||
physr_start_iter_least(vr->phys, &iter);
|
for(voffset = 0; voffset < vr->length; voffset+=VM_PAGE_SIZE) {
|
||||||
while((pr = physr_get_iter(&iter))) {
|
if(!(pr = physblock_get(vr, voffset))) continue;
|
||||||
physr_incr_iter(&iter);
|
|
||||||
used += VM_PAGE_SIZE;
|
used += VM_PAGE_SIZE;
|
||||||
weighted += VM_PAGE_SIZE / pr->ph->refcount;
|
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);
|
assert(ph->ph->refcount > 0);
|
||||||
if(ph->ph->refcount > 1) {
|
if(ph->ph->refcount > 1) {
|
||||||
if(!(ph = map_clone_ph_block(vmp, region,
|
if(!(ph = map_clone_ph_block(vmp, region,
|
||||||
ph, NULL))) {
|
ph))) {
|
||||||
printf("VM: get_clean_phys_region: ph copy failed\n");
|
printf("VM: get_clean_phys_region: ph copy failed\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1893,11 +1915,10 @@ void map_setparent(struct vmproc *vmp)
|
||||||
int physregions(struct vir_region *vr)
|
int physregions(struct vir_region *vr)
|
||||||
{
|
{
|
||||||
int n = 0;
|
int n = 0;
|
||||||
physr_iter iter;
|
vir_bytes voffset;
|
||||||
physr_start_iter_least(vr->phys, &iter);
|
for(voffset = 0; voffset < vr->length; voffset += VM_PAGE_SIZE) {
|
||||||
while(physr_get_iter(&iter)) {
|
if(physblock_get(vr, voffset))
|
||||||
n++;
|
n++;
|
||||||
physr_incr_iter(&iter);
|
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include <minix/const.h>
|
#include <minix/const.h>
|
||||||
|
|
||||||
#include "phys_region.h"
|
#include "phys_region.h"
|
||||||
#include "physravl.h"
|
|
||||||
#include "memtype.h"
|
#include "memtype.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
|
@ -38,7 +37,7 @@ struct phys_block {
|
||||||
typedef struct vir_region {
|
typedef struct vir_region {
|
||||||
vir_bytes vaddr; /* virtual address, offset from pagetable */
|
vir_bytes vaddr; /* virtual address, offset from pagetable */
|
||||||
vir_bytes length; /* length in bytes */
|
vir_bytes length; /* length in bytes */
|
||||||
physr_avl *phys; /* avl tree of physical memory blocks */
|
struct phys_region **physblocks;
|
||||||
u16_t flags;
|
u16_t flags;
|
||||||
struct vmproc *parent; /* Process that owns this vir_region. */
|
struct vmproc *parent; /* Process that owns this vir_region. */
|
||||||
mem_type_t *memtype; /* Default instantiated memory type. */
|
mem_type_t *memtype; /* Default instantiated memory type. */
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "glo.h"
|
#include "glo.h"
|
||||||
|
@ -264,3 +265,55 @@ int swap_proc_dyn_data(struct vmproc *src_vmp, struct vmproc *dst_vmp)
|
||||||
return OK;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
#include "pt.h"
|
#include "pt.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#include "physravl.h"
|
|
||||||
#include "yieldedavl.h"
|
|
||||||
#include "regionavl.h"
|
#include "regionavl.h"
|
||||||
|
|
||||||
struct vmproc;
|
struct vmproc;
|
||||||
|
|
Loading…
Reference in a new issue