mark pages whose refcount were >1 and drop to 1 and are
read/write writable in the pagetable right away instead of waiting for a pagefault. minor optimization. some a sanity check of SLAB-allocated pointers. vm gets its own _exit and __exit like PM, so the stock (library) panic works.
This commit is contained in:
parent
e0f3a5acf1
commit
2dd02cc560
10 changed files with 309 additions and 65 deletions
|
@ -116,3 +116,13 @@ PUBLIC int do_willexit(message *msg)
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PUBLIC void _exit(int code)
|
||||||
|
{
|
||||||
|
sys_exit(SELF);
|
||||||
|
}
|
||||||
|
|
||||||
|
PUBLIC void __exit(int code)
|
||||||
|
{
|
||||||
|
sys_exit(SELF);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
EXTERN struct vmproc vmproc[_NR_PROCS+1];
|
EXTERN struct vmproc vmproc[_NR_PROCS+1];
|
||||||
|
|
||||||
#if SANITYCHECKS
|
#if SANITYCHECKS
|
||||||
|
EXTERN int nocheck;
|
||||||
u32_t data1[200];
|
u32_t data1[200];
|
||||||
#define CHECKADDR 0
|
#define CHECKADDR 0
|
||||||
EXTERN long vm_sanitychecklevel;
|
EXTERN long vm_sanitychecklevel;
|
||||||
|
|
|
@ -99,7 +99,7 @@ PUBLIC vir_bytes arch_map2vir(struct vmproc *vmp, vir_bytes addr)
|
||||||
{
|
{
|
||||||
vir_bytes bottom = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys);
|
vir_bytes bottom = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys);
|
||||||
|
|
||||||
vm_assert(bottom <= addr);
|
/* vm_assert(bottom <= addr); */
|
||||||
|
|
||||||
return addr - bottom;
|
return addr - bottom;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,7 @@ PUBLIC int main(void)
|
||||||
int result, who_e;
|
int result, who_e;
|
||||||
|
|
||||||
#if SANITYCHECKS
|
#if SANITYCHECKS
|
||||||
|
nocheck = 0;
|
||||||
memcpy(data1, CHECKADDR, sizeof(data1));
|
memcpy(data1, CHECKADDR, sizeof(data1));
|
||||||
#endif
|
#endif
|
||||||
SANITYCHECK(SCL_TOP);
|
SANITYCHECK(SCL_TOP);
|
||||||
|
@ -111,7 +112,7 @@ PUBLIC int main(void)
|
||||||
/* Kernel wants to have memory ranges
|
/* Kernel wants to have memory ranges
|
||||||
* verified.
|
* verified.
|
||||||
*/
|
*/
|
||||||
handle_memory();
|
do_memory();
|
||||||
break;
|
break;
|
||||||
case PM_PROC_NR:
|
case PM_PROC_NR:
|
||||||
/* PM sends a notify() on shutdown, which
|
/* PM sends a notify() on shutdown, which
|
||||||
|
@ -122,7 +123,7 @@ PUBLIC int main(void)
|
||||||
/* This indicates a page fault has happened,
|
/* This indicates a page fault has happened,
|
||||||
* which we have to handle.
|
* which we have to handle.
|
||||||
*/
|
*/
|
||||||
handle_pagefaults();
|
do_pagefaults();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* No-one else should send us notifies. */
|
/* No-one else should send us notifies. */
|
||||||
|
|
|
@ -47,9 +47,9 @@ char *pf_errstr(u32_t err)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* handle_pagefaults *
|
* do_pagefaults *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PUBLIC void handle_pagefaults(void)
|
PUBLIC void do_pagefaults(void)
|
||||||
{
|
{
|
||||||
endpoint_t ep;
|
endpoint_t ep;
|
||||||
u32_t addr, err;
|
u32_t addr, err;
|
||||||
|
@ -62,7 +62,7 @@ PUBLIC void handle_pagefaults(void)
|
||||||
int p, wr = PFERR_WRITE(err);
|
int p, wr = PFERR_WRITE(err);
|
||||||
|
|
||||||
if(vm_isokendpt(ep, &p) != OK)
|
if(vm_isokendpt(ep, &p) != OK)
|
||||||
vm_panic("handle_pagefaults: endpoint wrong", ep);
|
vm_panic("do_pagefaults: endpoint wrong", ep);
|
||||||
|
|
||||||
vmp = &vmproc[p];
|
vmp = &vmproc[p];
|
||||||
vm_assert(vmp->vm_flags & VMF_INUSE);
|
vm_assert(vmp->vm_flags & VMF_INUSE);
|
||||||
|
@ -97,7 +97,7 @@ PUBLIC void handle_pagefaults(void)
|
||||||
offset = addr - region->vaddr;
|
offset = addr - region->vaddr;
|
||||||
|
|
||||||
/* Access is allowed; handle it. */
|
/* Access is allowed; handle it. */
|
||||||
if((r=map_pagefault(vmp, region, offset, wr)) != OK) {
|
if((r=map_pf(vmp, region, offset, wr)) != OK) {
|
||||||
printf("VM: pagefault: SIGSEGV %d pagefault not handled\n", ep);
|
printf("VM: pagefault: SIGSEGV %d pagefault not handled\n", ep);
|
||||||
sys_sysctl_stacktrace(vmp->vm_endpoint);
|
sys_sysctl_stacktrace(vmp->vm_endpoint);
|
||||||
if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK)
|
if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK)
|
||||||
|
@ -108,16 +108,16 @@ PUBLIC void handle_pagefaults(void)
|
||||||
|
|
||||||
/* Pagefault is handled, so now reactivate the process. */
|
/* Pagefault is handled, so now reactivate the process. */
|
||||||
if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, r)) != OK)
|
if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, r)) != OK)
|
||||||
vm_panic("handle_pagefaults: sys_vmctl failed", ep);
|
vm_panic("do_pagefaults: sys_vmctl failed", ep);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* handle_memory *
|
* do_memory *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PUBLIC void handle_memory(void)
|
PUBLIC void do_memory(void)
|
||||||
{
|
{
|
||||||
int r, s;
|
int r, s;
|
||||||
endpoint_t who;
|
endpoint_t who;
|
||||||
|
@ -132,7 +132,7 @@ PUBLIC void handle_memory(void)
|
||||||
vir_bytes o;
|
vir_bytes o;
|
||||||
|
|
||||||
if(vm_isokendpt(who, &p) != OK)
|
if(vm_isokendpt(who, &p) != OK)
|
||||||
vm_panic("handle_memory: endpoint wrong", who);
|
vm_panic("do_memory: endpoint wrong", who);
|
||||||
vmp = &vmproc[p];
|
vmp = &vmproc[p];
|
||||||
|
|
||||||
/* Page-align memory and length. */
|
/* Page-align memory and length. */
|
||||||
|
@ -143,13 +143,13 @@ PUBLIC void handle_memory(void)
|
||||||
if(o > 0) len += VM_PAGE_SIZE - o;
|
if(o > 0) len += VM_PAGE_SIZE - o;
|
||||||
|
|
||||||
if(!(region = map_lookup(vmp, mem))) {
|
if(!(region = map_lookup(vmp, mem))) {
|
||||||
printf("VM: handle_memory: memory doesn't exist\n");
|
printf("VM: do_memory: memory doesn't exist\n");
|
||||||
r = EFAULT;
|
r = EFAULT;
|
||||||
} else if(mem + len > region->vaddr + region->length) {
|
} else if(mem + len > region->vaddr + region->length) {
|
||||||
vm_assert(region->vaddr <= mem);
|
vm_assert(region->vaddr <= mem);
|
||||||
vm_panic("handle_memory: not contained", NO_NUM);
|
vm_panic("do_memory: not contained", NO_NUM);
|
||||||
} else if(!(region->flags & VR_WRITABLE) && wrflag) {
|
} else if(!(region->flags & VR_WRITABLE) && wrflag) {
|
||||||
printf("VM: handle_memory: write to unwritable map\n");
|
printf("VM: do_memory: write to unwritable map\n");
|
||||||
r = EFAULT;
|
r = EFAULT;
|
||||||
} else {
|
} else {
|
||||||
vir_bytes offset;
|
vir_bytes offset;
|
||||||
|
@ -168,7 +168,7 @@ PUBLIC void handle_memory(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sys_vmctl(who, VMCTL_MEMREQ_REPLY, r) != OK)
|
if(sys_vmctl(who, VMCTL_MEMREQ_REPLY, r) != OK)
|
||||||
vm_panic("handle_memory: sys_vmctl failed", r);
|
vm_panic("do_memory: sys_vmctl failed", r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,8 +78,8 @@ _PROTOTYPE(int do_map_phys, (message *msg) );
|
||||||
_PROTOTYPE(int do_unmap_phys, (message *msg) );
|
_PROTOTYPE(int do_unmap_phys, (message *msg) );
|
||||||
|
|
||||||
/* pagefaults.c */
|
/* pagefaults.c */
|
||||||
_PROTOTYPE( void handle_pagefaults, (void) );
|
_PROTOTYPE( void do_pagefaults, (void) );
|
||||||
_PROTOTYPE( void handle_memory, (void) );
|
_PROTOTYPE( void do_memory, (void) );
|
||||||
_PROTOTYPE( char *pf_errstr, (u32_t err));
|
_PROTOTYPE( char *pf_errstr, (u32_t err));
|
||||||
|
|
||||||
/* $(ARCH)/pagetable.c */
|
/* $(ARCH)/pagetable.c */
|
||||||
|
@ -111,6 +111,17 @@ _PROTOTYPE(void slabfree,(void *mem, int bytes));
|
||||||
_PROTOTYPE(void slabstats,(void));
|
_PROTOTYPE(void slabstats,(void));
|
||||||
#define SLABALLOC(var) (var = slaballoc(sizeof(*var)))
|
#define SLABALLOC(var) (var = slaballoc(sizeof(*var)))
|
||||||
#define SLABFREE(ptr) slabfree(ptr, sizeof(*(ptr)))
|
#define SLABFREE(ptr) slabfree(ptr, sizeof(*(ptr)))
|
||||||
|
#if SANITYCHECKS
|
||||||
|
_PROTOTYPE(int slabsane,(void *mem, int bytes));
|
||||||
|
#define SLABSANE(ptr) { \
|
||||||
|
if(!slabsane(ptr, sizeof(*(ptr)))) { \
|
||||||
|
printf("VM:%s:%d: SLABSANE(%s)\n", __FILE__, __LINE__, #ptr); \
|
||||||
|
vm_panic("SLABSANE failed", NO_NUM); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define SLABSANE(ptr)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* region.c */
|
/* region.c */
|
||||||
_PROTOTYPE(struct vir_region * map_page_region,(struct vmproc *vmp, \
|
_PROTOTYPE(struct vir_region * map_page_region,(struct vmproc *vmp, \
|
||||||
|
@ -123,7 +134,7 @@ _PROTOTYPE(int map_unmap_region,(struct vmproc *vmp, struct vir_region *vr));
|
||||||
_PROTOTYPE(int map_free_proc,(struct vmproc *vmp));
|
_PROTOTYPE(int map_free_proc,(struct vmproc *vmp));
|
||||||
_PROTOTYPE(int map_proc_copy,(struct vmproc *dst, struct vmproc *src));
|
_PROTOTYPE(int map_proc_copy,(struct vmproc *dst, struct vmproc *src));
|
||||||
_PROTOTYPE(struct vir_region *map_lookup,(struct vmproc *vmp, vir_bytes addr));
|
_PROTOTYPE(struct vir_region *map_lookup,(struct vmproc *vmp, vir_bytes addr));
|
||||||
_PROTOTYPE(int map_pagefault,(struct vmproc *vmp,
|
_PROTOTYPE(int map_pf,(struct vmproc *vmp,
|
||||||
struct vir_region *region, vir_bytes offset, int write));
|
struct vir_region *region, vir_bytes offset, int write));
|
||||||
_PROTOTYPE(int map_handle_memory,(struct vmproc *vmp,
|
_PROTOTYPE(int map_handle_memory,(struct vmproc *vmp,
|
||||||
struct vir_region *region, vir_bytes offset, vir_bytes len, int write));
|
struct vir_region *region, vir_bytes offset, vir_bytes len, int write));
|
||||||
|
|
|
@ -105,6 +105,11 @@ PUBLIC void map_sanitycheck(char *file, int line)
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MYSLABSANE(s) MYASSERT(slabsane(s, sizeof(*(s))))
|
||||||
|
/* Basic pointers check. */
|
||||||
|
ALLREGIONS(MYSLABSANE(vr),MYSLABSANE(pr); MYSLABSANE(pr->ph);MYSLABSANE(pr->parent));
|
||||||
|
ALLREGIONS(MYASSERT(vr->parent == vmp),MYASSERT(pr->parent == vr););
|
||||||
|
|
||||||
/* Do counting for consistency check. */
|
/* Do counting for consistency check. */
|
||||||
ALLREGIONS(;,pr->ph->seencount = 0;);
|
ALLREGIONS(;,pr->ph->seencount = 0;);
|
||||||
ALLREGIONS(;,pr->ph->seencount++;);
|
ALLREGIONS(;,pr->ph->seencount++;);
|
||||||
|
@ -123,6 +128,25 @@ PUBLIC void map_sanitycheck(char *file, int line)
|
||||||
pr->ph->offset + pr->ph->length,
|
pr->ph->offset + pr->ph->length,
|
||||||
pr->ph->refcount, pr->ph->seencount);
|
pr->ph->refcount, pr->ph->seencount);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
int n_others = 0;
|
||||||
|
struct phys_region *others;
|
||||||
|
if(pr->ph->refcount > 0) {
|
||||||
|
MYASSERT(pr->ph->firstregion);
|
||||||
|
if(pr->ph->refcount == 1) {
|
||||||
|
MYASSERT(pr->ph->firstregion == pr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MYASSERT(!pr->ph->firstregion);
|
||||||
|
}
|
||||||
|
for(others = pr->ph->firstregion; others;
|
||||||
|
others = others->next_ph_list) {
|
||||||
|
MYSLABSANE(others);
|
||||||
|
MYASSERT(others->ph == pr->ph);
|
||||||
|
n_others++;
|
||||||
|
}
|
||||||
|
MYASSERT(pr->ph->refcount == n_others);
|
||||||
|
}
|
||||||
MYASSERT(pr->ph->refcount == pr->ph->seencount);
|
MYASSERT(pr->ph->refcount == pr->ph->seencount);
|
||||||
MYASSERT(!(pr->ph->offset % VM_PAGE_SIZE));
|
MYASSERT(!(pr->ph->offset % VM_PAGE_SIZE));
|
||||||
MYASSERT(!(pr->ph->length % VM_PAGE_SIZE)););
|
MYASSERT(!(pr->ph->length % VM_PAGE_SIZE)););
|
||||||
|
@ -171,7 +195,7 @@ PUBLIC int map_ph_writept(struct vmproc *vmp, struct vir_region *vr,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* map_region *
|
* map_page_region *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PUBLIC struct vir_region *map_page_region(vmp, minv, maxv, length,
|
PUBLIC struct vir_region *map_page_region(vmp, minv, maxv, length,
|
||||||
what, flags, mapflags)
|
what, flags, mapflags)
|
||||||
|
@ -269,6 +293,7 @@ int mapflags;
|
||||||
newregion->first = NULL;
|
newregion->first = NULL;
|
||||||
newregion->flags = flags;
|
newregion->flags = flags;
|
||||||
newregion->tag = VRT_NONE;
|
newregion->tag = VRT_NONE;
|
||||||
|
newregion->parent = vmp;
|
||||||
|
|
||||||
/* If we know what we're going to map to, map it right away. */
|
/* If we know what we're going to map to, map it right away. */
|
||||||
if(what != MAP_NONE) {
|
if(what != MAP_NONE) {
|
||||||
|
@ -321,6 +346,76 @@ int mapflags;
|
||||||
return newregion;
|
return newregion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* pb_unreferenced *
|
||||||
|
*===========================================================================*/
|
||||||
|
void pb_unreferenced(struct vir_region *region, struct phys_region *pr)
|
||||||
|
{
|
||||||
|
struct phys_block *pb;
|
||||||
|
int remap = 0;
|
||||||
|
|
||||||
|
SLABSANE(pr);
|
||||||
|
pb = pr->ph;
|
||||||
|
SLABSANE(pb);
|
||||||
|
vm_assert(pb->refcount > 0);
|
||||||
|
pb->refcount--;
|
||||||
|
vm_assert(pb->refcount >= 0);
|
||||||
|
|
||||||
|
SLABSANE(pb->firstregion);
|
||||||
|
if(pb->firstregion == pr) {
|
||||||
|
pb->firstregion = pr->next_ph_list;
|
||||||
|
if(pb->firstregion) {
|
||||||
|
SLABSANE(pb->firstregion);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct phys_region *others;
|
||||||
|
|
||||||
|
for(others = pb->firstregion; others;
|
||||||
|
others = others->next_ph_list) {
|
||||||
|
SLABSANE(others);
|
||||||
|
vm_assert(others->ph == pb);
|
||||||
|
if(others->next_ph_list == pr) {
|
||||||
|
others->next_ph_list = pr->next_ph_list;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vm_assert(others); /* Otherwise, wasn't on the list. */
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pb->refcount == 0) {
|
||||||
|
vm_assert(!pb->firstregion);
|
||||||
|
if(region->flags & VR_ANON) {
|
||||||
|
FREE_MEM(ABS2CLICK(pb->phys),
|
||||||
|
ABS2CLICK(pb->length));
|
||||||
|
} else if(region->flags & VR_DIRECT) {
|
||||||
|
; /* No action required. */
|
||||||
|
} else {
|
||||||
|
vm_panic("strange phys flags", NO_NUM);
|
||||||
|
}
|
||||||
|
SLABFREE(pb);
|
||||||
|
} else {
|
||||||
|
SLABSANE(pb->firstregion);
|
||||||
|
/* If a writable piece of physical memory is now only
|
||||||
|
* referenced once, map it writable right away instead of
|
||||||
|
* waiting for a page fault.
|
||||||
|
*/
|
||||||
|
if(pb->refcount == 1 && (region->flags & VR_WRITABLE)) {
|
||||||
|
vm_assert(pb);
|
||||||
|
vm_assert(pb->firstregion);
|
||||||
|
vm_assert(!pb->firstregion->next_ph_list);
|
||||||
|
vm_assert(pb->firstregion->ph == pb);
|
||||||
|
vm_assert(pb->firstregion->ph == pb);
|
||||||
|
SLABSANE(pb);
|
||||||
|
SLABSANE(pb->firstregion);
|
||||||
|
SLABSANE(pb->firstregion->parent);
|
||||||
|
if(map_ph_writept(pb->firstregion->parent->parent,
|
||||||
|
pb->firstregion->parent, pb, NULL, NULL) != OK) {
|
||||||
|
vm_panic("pb_unreferenced: writept", NO_NUM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* map_free *
|
* map_free *
|
||||||
|
@ -329,22 +424,29 @@ PRIVATE int map_free(struct vir_region *region)
|
||||||
{
|
{
|
||||||
struct phys_region *pr, *nextpr;
|
struct phys_region *pr, *nextpr;
|
||||||
|
|
||||||
|
#if SANITYCHECKS
|
||||||
|
for(pr = region->first; pr; pr = pr->next) {
|
||||||
|
struct phys_region *others;
|
||||||
|
struct phys_block *pb;
|
||||||
|
|
||||||
|
SLABSANE(pr);
|
||||||
|
pb = pr->ph;
|
||||||
|
SLABSANE(pb);
|
||||||
|
SLABSANE(pb->firstregion);
|
||||||
|
|
||||||
|
for(others = pb->firstregion; others;
|
||||||
|
others = others->next_ph_list) {
|
||||||
|
SLABSANE(others);
|
||||||
|
vm_assert(others->ph == pb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for(pr = region->first; pr; pr = nextpr) {
|
for(pr = region->first; pr; pr = nextpr) {
|
||||||
vm_assert(pr->ph->refcount > 0);
|
SANITYCHECK(SCL_DETAIL);
|
||||||
pr->ph->refcount--;
|
pb_unreferenced(region, pr);
|
||||||
nextpr = pr->next;
|
nextpr = pr->next;
|
||||||
region->first = nextpr; /* For sanity checks. */
|
region->first = nextpr; /* For sanity checks. */
|
||||||
if(pr->ph->refcount == 0) {
|
|
||||||
if(region->flags & VR_ANON) {
|
|
||||||
FREE_MEM(ABS2CLICK(pr->ph->phys),
|
|
||||||
ABS2CLICK(pr->ph->length));
|
|
||||||
} else if(region->flags & VR_DIRECT) {
|
|
||||||
; /* No action required. */
|
|
||||||
} else {
|
|
||||||
vm_panic("strange phys flags", NO_NUM);
|
|
||||||
}
|
|
||||||
SLABFREE(pr->ph);
|
|
||||||
}
|
|
||||||
SLABFREE(pr);
|
SLABFREE(pr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,8 +467,16 @@ struct vmproc *vmp;
|
||||||
|
|
||||||
for(r = vmp->vm_regions; r; r = nextr) {
|
for(r = vmp->vm_regions; r; r = nextr) {
|
||||||
nextr = r->next;
|
nextr = r->next;
|
||||||
|
SANITYCHECK(SCL_DETAIL);
|
||||||
|
#if SANITYCHECKS
|
||||||
|
nocheck++;
|
||||||
|
#endif
|
||||||
map_free(r);
|
map_free(r);
|
||||||
vmp->vm_regions = nextr; /* For sanity checks. */
|
vmp->vm_regions = nextr; /* For sanity checks. */
|
||||||
|
#if SANITYCHECKS
|
||||||
|
nocheck--;
|
||||||
|
#endif
|
||||||
|
SANITYCHECK(SCL_DETAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
vmp->vm_regions = NULL;
|
vmp->vm_regions = NULL;
|
||||||
|
@ -412,7 +522,7 @@ vir_bytes length;
|
||||||
phys_bytes what_mem;
|
phys_bytes what_mem;
|
||||||
struct phys_region *physhint;
|
struct phys_region *physhint;
|
||||||
{
|
{
|
||||||
struct phys_region *physr, *newphysr;
|
struct phys_region *newphysr;
|
||||||
struct phys_block *newpb;
|
struct phys_block *newpb;
|
||||||
phys_bytes mem_clicks, clicks;
|
phys_bytes mem_clicks, clicks;
|
||||||
vir_bytes mem;
|
vir_bytes mem;
|
||||||
|
@ -445,19 +555,25 @@ struct phys_region *physhint;
|
||||||
} else {
|
} else {
|
||||||
mem = what_mem;
|
mem = what_mem;
|
||||||
}
|
}
|
||||||
|
SANITYCHECK(SCL_DETAIL);
|
||||||
|
|
||||||
/* New physical block. */
|
/* New physical block. */
|
||||||
newpb->phys = mem;
|
newpb->phys = mem;
|
||||||
newpb->refcount = 1;
|
newpb->refcount = 1;
|
||||||
newpb->offset = offset;
|
newpb->offset = offset;
|
||||||
newpb->length = length;
|
newpb->length = length;
|
||||||
|
newpb->firstregion = newphysr;
|
||||||
|
SLABSANE(newpb->firstregion);
|
||||||
|
|
||||||
/* New physical region. */
|
/* New physical region. */
|
||||||
newphysr->ph = newpb;
|
newphysr->ph = newpb;
|
||||||
|
newphysr->parent = region;
|
||||||
|
newphysr->next_ph_list = NULL; /* No other references to this block. */
|
||||||
|
|
||||||
/* Update pagetable. */
|
/* Update pagetable. */
|
||||||
vm_assert(!(length % VM_PAGE_SIZE));
|
vm_assert(!(length % VM_PAGE_SIZE));
|
||||||
vm_assert(!(newpb->length % VM_PAGE_SIZE));
|
vm_assert(!(newpb->length % VM_PAGE_SIZE));
|
||||||
|
SANITYCHECK(SCL_DETAIL);
|
||||||
if(map_ph_writept(vmp, region, newpb, NULL, NULL) != OK) {
|
if(map_ph_writept(vmp, region, newpb, NULL, NULL) != OK) {
|
||||||
if(what_mem == MAP_NONE)
|
if(what_mem == MAP_NONE)
|
||||||
FREE_MEM(mem_clicks, clicks);
|
FREE_MEM(mem_clicks, clicks);
|
||||||
|
@ -474,6 +590,7 @@ struct phys_region *physhint;
|
||||||
newphysr->next = region->first;
|
newphysr->next = region->first;
|
||||||
region->first = newphysr;
|
region->first = newphysr;
|
||||||
} else {
|
} else {
|
||||||
|
struct phys_region *physr;
|
||||||
for(physr = physhint; physr; physr = physr->next) {
|
for(physr = physhint; physr; physr = physr->next) {
|
||||||
if(!physr->next || physr->next->ph->offset > offset) {
|
if(!physr->next || physr->next->ph->offset > offset) {
|
||||||
newphysr->next = physr->next;
|
newphysr->next = physr->next;
|
||||||
|
@ -510,7 +627,7 @@ struct phys_region *ph;
|
||||||
/* This is only to be done if there is more than one copy. */
|
/* This is only to be done if there is more than one copy. */
|
||||||
vm_assert(ph->ph->refcount > 1);
|
vm_assert(ph->ph->refcount > 1);
|
||||||
|
|
||||||
/* Do actal copy on write; allocate new physblock. */
|
/* Do actual copy on write; allocate new physblock. */
|
||||||
if(!SLABALLOC(newpb)) {
|
if(!SLABALLOC(newpb)) {
|
||||||
printf("VM: map_copy_ph_block: couldn't allocate newpb\n");
|
printf("VM: map_copy_ph_block: couldn't allocate newpb\n");
|
||||||
SANITYCHECK(SCL_FUNCTIONS);
|
SANITYCHECK(SCL_FUNCTIONS);
|
||||||
|
@ -526,13 +643,18 @@ struct phys_region *ph;
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
newmem = CLICK2ABS(newmem_cl);
|
newmem = CLICK2ABS(newmem_cl);
|
||||||
|
vm_assert(ABS2CLICK(newmem) == newmem_cl);
|
||||||
|
|
||||||
ph->ph->refcount--;
|
pb_unreferenced(region, ph);
|
||||||
|
SLABSANE(ph);
|
||||||
|
SLABSANE(ph->ph);
|
||||||
vm_assert(ph->ph->refcount > 0);
|
vm_assert(ph->ph->refcount > 0);
|
||||||
newpb->length = ph->ph->length;
|
newpb->length = ph->ph->length;
|
||||||
newpb->offset = ph->ph->offset;
|
newpb->offset = ph->ph->offset;
|
||||||
newpb->refcount = 1;
|
newpb->refcount = 1;
|
||||||
newpb->phys = newmem;
|
newpb->phys = newmem;
|
||||||
|
newpb->firstregion = ph;
|
||||||
|
ph->next_ph_list = NULL;
|
||||||
|
|
||||||
/* Copy old memory to new memory. */
|
/* Copy old memory to new memory. */
|
||||||
if((r=sys_abscopy(ph->ph->phys, newpb->phys, newpb->length)) != OK) {
|
if((r=sys_abscopy(ph->ph->phys, newpb->phys, newpb->length)) != OK) {
|
||||||
|
@ -564,9 +686,9 @@ struct phys_region *ph;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* map_pagefault *
|
* map_pf *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PUBLIC int map_pagefault(vmp, region, offset, write)
|
PUBLIC int map_pf(vmp, region, offset, write)
|
||||||
struct vmproc *vmp;
|
struct vmproc *vmp;
|
||||||
struct vir_region *region;
|
struct vir_region *region;
|
||||||
vir_bytes offset;
|
vir_bytes offset;
|
||||||
|
@ -613,7 +735,7 @@ int write;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(r != OK)
|
if(r != OK)
|
||||||
printf("VM: map_pagefault: failed (%d)\n", r);
|
printf("VM: map_pf: failed (%d)\n", r);
|
||||||
|
|
||||||
SANITYCHECK(SCL_FUNCTIONS);
|
SANITYCHECK(SCL_FUNCTIONS);
|
||||||
|
|
||||||
|
@ -717,6 +839,14 @@ static int countregions(struct vir_region *vr)
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
PRIVATE struct vir_region *map_copy_region(struct vir_region *vr)
|
PRIVATE struct vir_region *map_copy_region(struct vir_region *vr)
|
||||||
{
|
{
|
||||||
|
/* map_copy_region creates a complete copy of the vir_region
|
||||||
|
* data structure, linking in the same phys_blocks directly,
|
||||||
|
* but all in limbo, i.e., the caller has to link the vir_region
|
||||||
|
* to a process. Therefore it doesn't increase the refcount in
|
||||||
|
* the phys_block; the caller has to do this once it's linked.
|
||||||
|
* The reason for this is to keep the sanity checks working
|
||||||
|
* within this function.
|
||||||
|
*/
|
||||||
struct vir_region *newvr;
|
struct vir_region *newvr;
|
||||||
struct phys_region *ph, *prevph = NULL;
|
struct phys_region *ph, *prevph = NULL;
|
||||||
#if SANITYCHECKS
|
#if SANITYCHECKS
|
||||||
|
@ -739,6 +869,8 @@ PRIVATE struct vir_region *map_copy_region(struct vir_region *vr)
|
||||||
}
|
}
|
||||||
newph->next = NULL;
|
newph->next = NULL;
|
||||||
newph->ph = ph->ph;
|
newph->ph = ph->ph;
|
||||||
|
newph->next_ph_list = NULL;
|
||||||
|
newph->parent = newvr;
|
||||||
if(prevph) prevph->next = newph;
|
if(prevph) prevph->next = newph;
|
||||||
else newvr->first = newph;
|
else newvr->first = newph;
|
||||||
prevph = newph;
|
prevph = newph;
|
||||||
|
@ -783,7 +915,7 @@ struct vmproc *src;
|
||||||
SANITYCHECK(SCL_FUNCTIONS);
|
SANITYCHECK(SCL_FUNCTIONS);
|
||||||
for(vr = src->vm_regions; vr; vr = vr->next) {
|
for(vr = src->vm_regions; vr; vr = vr->next) {
|
||||||
struct vir_region *newvr;
|
struct vir_region *newvr;
|
||||||
struct phys_region *ph;
|
struct phys_region *orig_ph, *new_ph;
|
||||||
SANITYCHECK(SCL_DETAIL);
|
SANITYCHECK(SCL_DETAIL);
|
||||||
if(!(newvr = map_copy_region(vr))) {
|
if(!(newvr = map_copy_region(vr))) {
|
||||||
map_free_proc(dst);
|
map_free_proc(dst);
|
||||||
|
@ -791,13 +923,36 @@ struct vmproc *src;
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
SANITYCHECK(SCL_DETAIL);
|
SANITYCHECK(SCL_DETAIL);
|
||||||
|
newvr->parent = dst;
|
||||||
if(prevvr) { prevvr->next = newvr; }
|
if(prevvr) { prevvr->next = newvr; }
|
||||||
else { dst->vm_regions = newvr; }
|
else { dst->vm_regions = newvr; }
|
||||||
for(ph = vr->first; ph; ph = ph->next) {
|
new_ph = newvr->first;
|
||||||
vm_assert(ph->ph->refcount > 0);
|
for(orig_ph = vr->first; orig_ph; orig_ph = orig_ph->next) {
|
||||||
ph->ph->refcount++;
|
struct phys_block *pb;
|
||||||
vm_assert(ph->ph->refcount > 1);
|
/* Check two physregions both are nonnull,
|
||||||
|
* are different, and match physblocks.
|
||||||
|
*/
|
||||||
|
vm_assert(orig_ph && new_ph);
|
||||||
|
vm_assert(orig_ph != new_ph);
|
||||||
|
pb = orig_ph->ph;
|
||||||
|
vm_assert(pb == new_ph->ph);
|
||||||
|
|
||||||
|
/* Link in new physregion. */
|
||||||
|
vm_assert(!new_ph->next_ph_list);
|
||||||
|
new_ph->next_ph_list = pb->firstregion;
|
||||||
|
pb->firstregion = new_ph;
|
||||||
|
SLABSANE(new_ph);
|
||||||
|
SLABSANE(new_ph->next_ph_list);
|
||||||
|
|
||||||
|
/* Increase phys block refcount */
|
||||||
|
vm_assert(pb->refcount > 0);
|
||||||
|
pb->refcount++;
|
||||||
|
vm_assert(pb->refcount > 1);
|
||||||
|
|
||||||
|
/* Get next new physregion */
|
||||||
|
new_ph = new_ph->next;
|
||||||
}
|
}
|
||||||
|
vm_assert(!new_ph);
|
||||||
SANITYCHECK(SCL_DETAIL);
|
SANITYCHECK(SCL_DETAIL);
|
||||||
prevvr = newvr;
|
prevvr = newvr;
|
||||||
SANITYCHECK(SCL_DETAIL);
|
SANITYCHECK(SCL_DETAIL);
|
||||||
|
|
|
@ -10,11 +10,18 @@ struct phys_block {
|
||||||
vir_bytes length; /* no. of contiguous bytes */
|
vir_bytes length; /* no. of contiguous bytes */
|
||||||
phys_bytes phys; /* physical memory */
|
phys_bytes phys; /* physical memory */
|
||||||
u8_t refcount; /* Refcount of these pages */
|
u8_t refcount; /* Refcount of these pages */
|
||||||
|
|
||||||
|
/* first in list of phys_regions that reference this block */
|
||||||
|
struct phys_region *firstregion;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct phys_region {
|
struct phys_region {
|
||||||
struct phys_region *next; /* next contiguous block */
|
struct phys_region *next; /* next contiguous block */
|
||||||
struct phys_block *ph;
|
struct phys_block *ph;
|
||||||
|
struct vir_region *parent; /* Region that owns this phys_region. */
|
||||||
|
|
||||||
|
/* list of phys_regions that reference the same phys_block */
|
||||||
|
struct phys_region *next_ph_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vir_region {
|
struct vir_region {
|
||||||
|
@ -24,6 +31,7 @@ struct vir_region {
|
||||||
struct phys_region *first; /* phys regions in vir region */
|
struct phys_region *first; /* phys regions in vir region */
|
||||||
u16_t flags;
|
u16_t flags;
|
||||||
u32_t tag; /* Opaque to mapping code. */
|
u32_t tag; /* Opaque to mapping code. */
|
||||||
|
struct vmproc *parent; /* Process that owns this vir_region. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mapping flags: */
|
/* Mapping flags: */
|
||||||
|
@ -38,6 +46,7 @@ struct vir_region {
|
||||||
/* Tag values: */
|
/* Tag values: */
|
||||||
#define VRT_NONE 0xBEEF0000
|
#define VRT_NONE 0xBEEF0000
|
||||||
#define VRT_HEAP 0xBEEF0001
|
#define VRT_HEAP 0xBEEF0001
|
||||||
|
#define VRT_CODE 0xBEEF0002
|
||||||
|
|
||||||
/* map_page_region flags */
|
/* map_page_region flags */
|
||||||
#define MF_PREALLOC 0x01
|
#define MF_PREALLOC 0x01
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
printf("VM:%s:%d: %s failed\n", file, line, #c); \
|
printf("VM:%s:%d: %s failed\n", file, line, #c); \
|
||||||
vm_panic("sanity check failed", NO_NUM); } } while(0)
|
vm_panic("sanity check failed", NO_NUM); } } while(0)
|
||||||
|
|
||||||
#define SANITYCHECK(l) if((l) <= vm_sanitychecklevel) { \
|
#define SANITYCHECK(l) if(!nocheck && ((l) <= vm_sanitychecklevel)) { \
|
||||||
int failflag = 0; \
|
int failflag = 0; \
|
||||||
u32_t *origptr = CHECKADDR;\
|
u32_t *origptr = CHECKADDR;\
|
||||||
int _sanep; \
|
int _sanep; \
|
||||||
|
|
|
@ -94,6 +94,8 @@ PRIVATE struct slabheader {
|
||||||
} *list_head[LIST_NUMBER];
|
} *list_head[LIST_NUMBER];
|
||||||
} slabs[SLABSIZES];
|
} slabs[SLABSIZES];
|
||||||
|
|
||||||
|
FORWARD _PROTOTYPE( int objstats, (void *, int, struct slabheader **, struct slabdata **, int *));
|
||||||
|
|
||||||
#define GETSLAB(b, s) { \
|
#define GETSLAB(b, s) { \
|
||||||
int i; \
|
int i; \
|
||||||
vm_assert((b) >= MINSIZE); \
|
vm_assert((b) >= MINSIZE); \
|
||||||
|
@ -206,6 +208,16 @@ PUBLIC void slab_sanitycheck(char *file, int line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* int slabsane *
|
||||||
|
*===========================================================================*/
|
||||||
|
PUBLIC int slabsane(void *mem, int bytes)
|
||||||
|
{
|
||||||
|
struct slabheader *s;
|
||||||
|
struct slabdata *f;
|
||||||
|
int i;
|
||||||
|
return (objstats(mem, bytes, &s, &f, &i) == OK);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -279,6 +291,12 @@ PUBLIC void *slaballoc(int bytes)
|
||||||
#endif
|
#endif
|
||||||
SLABSANITYCHECK(SCL_FUNCTIONS);
|
SLABSANITYCHECK(SCL_FUNCTIONS);
|
||||||
firstused->sdh.freeguess = i+1;
|
firstused->sdh.freeguess = i+1;
|
||||||
|
|
||||||
|
#if SANITYCHECKS
|
||||||
|
if(!slabsane(ret, bytes))
|
||||||
|
vm_panic("slaballoc: slabsane failed", NO_NUM);
|
||||||
|
#endif
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,6 +311,63 @@ PUBLIC void *slaballoc(int bytes)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* int objstats *
|
||||||
|
*===========================================================================*/
|
||||||
|
PRIVATE int objstats(void *mem, int bytes,
|
||||||
|
struct slabheader **sp, struct slabdata **fp, int *ip)
|
||||||
|
{
|
||||||
|
#define OBJSTATSCHECK(cond) \
|
||||||
|
if(!(cond)) { \
|
||||||
|
printf("VM:objstats: %s failed for ptr 0x%p, %d bytes\n", \
|
||||||
|
#cond, mem, bytes); \
|
||||||
|
return EINVAL; \
|
||||||
|
}
|
||||||
|
|
||||||
|
struct slabheader *s;
|
||||||
|
struct slabdata *f;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
OBJSTATSCHECK((char *) mem >= (char *) VM_PAGE_SIZE);
|
||||||
|
|
||||||
|
#if SANITYCHECKS
|
||||||
|
if(*(u32_t *) mem == JUNK) {
|
||||||
|
util_stacktrace();
|
||||||
|
printf("VM: WARNING: JUNK seen in slab object\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Retrieve entry in slabs[]. */
|
||||||
|
GETSLAB(bytes, s);
|
||||||
|
|
||||||
|
/* Round address down to VM_PAGE_SIZE boundary to get header. */
|
||||||
|
f = (struct slabdata *) ((char *) mem - (vir_bytes) mem % VM_PAGE_SIZE);
|
||||||
|
|
||||||
|
#if SANITYCHECKS
|
||||||
|
OBJSTATSCHECK(f->sdh.magic == MAGIC);
|
||||||
|
#endif
|
||||||
|
OBJSTATSCHECK(f->sdh.list == LIST_USED || f->sdh.list == LIST_FULL);
|
||||||
|
|
||||||
|
/* Make sure it's in range. */
|
||||||
|
OBJSTATSCHECK((char *) mem >= (char *) f->data);
|
||||||
|
OBJSTATSCHECK((char *) mem < (char *) f->data + sizeof(f->data));
|
||||||
|
|
||||||
|
/* Get position. */
|
||||||
|
i = (char *) mem - (char *) f->data;
|
||||||
|
OBJSTATSCHECK(!(i % bytes));
|
||||||
|
i = i / bytes;
|
||||||
|
|
||||||
|
/* Make sure it is marked as allocated. */
|
||||||
|
OBJSTATSCHECK(GETBIT(f, i));
|
||||||
|
|
||||||
|
/* return values */
|
||||||
|
*ip = i;
|
||||||
|
*fp = f;
|
||||||
|
*sp = s;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* void *slabfree *
|
* void *slabfree *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -309,27 +384,9 @@ PUBLIC void slabfree(void *mem, int bytes)
|
||||||
printf("VM: WARNING: likely double free, JUNK seen\n");
|
printf("VM: WARNING: likely double free, JUNK seen\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if(objstats(mem, bytes, &s, &f, &i) != OK) {
|
||||||
/* Retrieve entry in slabs[]. */
|
vm_panic("slabfree objstats failed", NO_NUM);
|
||||||
GETSLAB(bytes, s);
|
}
|
||||||
|
|
||||||
/* Round address down to VM_PAGE_SIZE boundary to get header. */
|
|
||||||
f = (struct slabdata *) ((char *) mem - (vir_bytes) mem % VM_PAGE_SIZE);
|
|
||||||
|
|
||||||
vm_assert(f->sdh.magic == MAGIC);
|
|
||||||
vm_assert(f->sdh.list == LIST_USED || f->sdh.list == LIST_FULL);
|
|
||||||
|
|
||||||
/* Make sure it's in range. */
|
|
||||||
vm_assert((char *) mem >= (char *) f->data);
|
|
||||||
vm_assert((char *) mem < (char *) f->data + sizeof(f->data));
|
|
||||||
|
|
||||||
/* Get position. */
|
|
||||||
i = (char *) mem - (char *) f->data;
|
|
||||||
vm_assert(!(i % bytes));
|
|
||||||
i = i / bytes;
|
|
||||||
|
|
||||||
/* Make sure it _was_ allocated. */
|
|
||||||
vm_assert(GETBIT(f, i));
|
|
||||||
|
|
||||||
/* Free this data. */
|
/* Free this data. */
|
||||||
CLEARBIT(f, i);
|
CLEARBIT(f, i);
|
||||||
|
|
Loading…
Reference in a new issue