VM: make mapping types explicit

Introduce explicit abstractions for different mapping types,
handling the instantiation, forking, pagefaults and freeing of
anonymous memory, direct physical mappings, shared memory and
physically contiguous anonymous memory as separate types, making
region.c more generic.

Also some other genericification like merging the 3 munmap cases
into one.

COW and SMAP safemap code is still implicit in region.c.
This commit is contained in:
Ben Gras 2012-10-11 15:15:49 +02:00
parent fd4ddef49a
commit d343041caa
24 changed files with 888 additions and 863 deletions

View file

@ -55,7 +55,6 @@ typedef __off_t off_t; /* file offset */
#define MAP_ALIGN64K 0x0040 /* physically aligned at 64kB */
#define MAP_LOWER1M 0x0080 /* physically below 16MB */
#define MAP_ALIGNMENT_64KB MAP_ALIGN64K
#define MAP_IPC_SHARED 0x0100 /* share changes */
#define MAP_FIXED 0x0200 /* require mapping to happen at hint */
#define MAP_THIRDPARTY 0x0400 /* perform on behalf of any process */

View file

@ -7,7 +7,7 @@ struct shm_struct {
int id;
struct shmid_ds shmid_ds;
vir_bytes page;
phys_bytes phys;
int vm_id;
};
static struct shm_struct shm_list[MAX_SHM_NR];
static int shm_list_nr = 0;
@ -73,12 +73,10 @@ int do_shmget(message *m)
shm = &shm_list[shm_list_nr];
memset(shm, 0, sizeof(struct shm_struct));
shm->page = (vir_bytes) minix_mmap(0, size,
PROT_READ|PROT_WRITE,
MAP_CONTIG|MAP_PREALLOC|MAP_ANON|MAP_IPC_SHARED,
-1, 0);
PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
if (shm->page == (vir_bytes) MAP_FAILED)
return ENOMEM;
shm->phys = vm_getphys(SELF_E, (void *) shm->page);
shm->vm_id = vm_getphys(SELF_E, (void *) shm->page);
memset((void *)shm->page, 0, size);
shm->shmid_ds.shm_perm.cuid =
@ -185,16 +183,16 @@ void update_refcount_and_destroy(void)
int do_shmdt(message *m)
{
vir_bytes addr;
phys_bytes paddr;
phys_bytes vm_id;
int i;
addr = m->SHMDT_ADDR;
if ((paddr = vm_getphys(who_e, (void *) addr)) == 0)
if ((vm_id = vm_getphys(who_e, (void *) addr)) == 0)
return EINVAL;
for (i = 0; i < shm_list_nr; i++) {
if (shm_list[i].phys == paddr) {
if (shm_list[i].vm_id == vm_id) {
struct shm_struct *shm = &shm_list[i];
shm->shmid_ds.shm_atime = time(NULL);
@ -206,7 +204,8 @@ int do_shmdt(message *m)
}
}
if (i == shm_list_nr)
fprintf(stderr, "IPC: do_shmdt impossible error!\n");
printf("IPC: do_shmdt impossible error! could not find id %lu to unmap\n",
vm_id);
update_refcount_and_destroy();

View file

@ -42,12 +42,11 @@ static void print_region(struct vm_region_info *vri, int *n)
/* NULL indicates the end of a list of mappings, nothing else to do */
if (!vri) return;
printf(" %08lx-%08lx %c%c%c %c (%lu kB)\n", vri->vri_addr,
printf(" %08lx-%08lx %c%c%c (%lu kB)\n", vri->vri_addr,
vri->vri_addr + vri->vri_length,
(vri->vri_prot & PROT_READ) ? 'r' : '-',
(vri->vri_prot & PROT_WRITE) ? 'w' : '-',
(vri->vri_prot & PROT_EXEC) ? 'x' : '-',
(vri->vri_flags & MAP_IPC_SHARED) ? 's' : 'p',
vri->vri_length / 1024L);
(*n)++;
}

View file

@ -349,12 +349,11 @@ static int dump_regions(int slot)
break;
for (i = 0; i < r; i++) {
buf_printf("%08lx-%08lx %c%c%c %c\n",
buf_printf("%08lx-%08lx %c%c%c\n",
vri[i].vri_addr, vri[i].vri_addr + vri[i].vri_length,
(vri[i].vri_prot & PROT_READ) ? 'r' : '-',
(vri[i].vri_prot & PROT_WRITE) ? 'w' : '-',
(vri[i].vri_prot & PROT_EXEC) ? 'x' : '-',
(vri[i].vri_flags & MAP_IPC_SHARED) ? 's' : 'p');
(vri[i].vri_prot & PROT_EXEC) ? 'x' : '-');
count++;
}

View file

@ -4,7 +4,8 @@
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
physravl.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}
LDADD+= -lsys -lexec

View file

@ -361,98 +361,3 @@ int usedpages_add_f(phys_bytes addr, phys_bytes len, char *file, int line)
#endif
/*===========================================================================*
* alloc_mem_in_list *
*===========================================================================*/
struct memlist *alloc_mem_in_list(phys_bytes bytes, u32_t flags, phys_bytes known)
{
phys_bytes rempages, phys_count;
struct memlist *head = NULL, *tail = NULL;
assert(bytes > 0);
assert(!(bytes % VM_PAGE_SIZE));
rempages = bytes / VM_PAGE_SIZE;
assert(!(flags & PAF_CONTIG));
if(known != MAP_NONE) {
phys_count = known;
}
do {
struct memlist *ml;
phys_bytes mem;
vir_bytes freed = 0;
do {
if(known == MAP_NONE) {
mem = alloc_pages(1, flags);
if(mem == NO_MEM) {
freed = free_yielded(rempages * VM_PAGE_SIZE);
}
} else {
mem = ABS2CLICK(phys_count);
phys_count += VM_PAGE_SIZE;
assert(mem != NO_MEM);
}
} while(mem == NO_MEM && freed > 0);
if(mem == NO_MEM) {
printf("alloc_mem_in_list: giving up, %lukB missing\n",
rempages * VM_PAGE_SIZE/1024);
printmemstats();
free_mem_list(head, 1);
return NULL;
}
if(!(SLABALLOC(ml))) {
free_mem_list(head, 1);
free_pages(mem, VM_PAGE_SIZE);
return NULL;
}
USE(ml, ml->phys = CLICK2ABS(mem); ml->next = NULL;);
if(tail) {
USE(tail,
tail->next = ml;);
}
tail = ml;
if(!head)
head = ml;
rempages--;
} while(rempages > 0);
return head;
}
/*===========================================================================*
* free_mem_list *
*===========================================================================*/
void free_mem_list(struct memlist *list, int all)
{
while(list) {
struct memlist *next;
next = list->next;
assert(!(list->phys % VM_PAGE_SIZE));
if(all)
free_pages(list->phys / VM_PAGE_SIZE, 1);
SLABFREE(list);
list = next;
}
}
/*===========================================================================*
* print_mem_list *
*===========================================================================*/
void print_mem_list(struct memlist *list)
{
while(list) {
printf("0x%lx-0x%lx", list->phys, list->phys+VM_PAGE_SIZE-1);
printf(" ");
list = list->next;
}
printf("\n");
}

View file

@ -28,5 +28,11 @@ EXTERN int sc_lastline;
EXTERN char *sc_lastfile;
#endif
/* mem types */
EXTERN mem_type_t mem_type_anon, /* anonymous memory */
mem_type_directphys, /* direct physical mapping memory */
mem_type_anon_contig, /* physically contig anon memory */
mem_type_shared; /* memory shared by multiple processes */
/* total number of memory pages */
EXTERN int total_pages;

View file

@ -231,8 +231,9 @@ static void boot_alloc(struct exec_info *execi, off_t vaddr,
{
struct vmproc *vmp = ((struct vm_exec_info *) execi->opaque)->vmp;
if(!(map_page_region(vmp, vaddr, 0,
len, MAP_NONE, VR_ANON | VR_WRITABLE | VR_UNINITIALIZED, flags))) {
if(!(map_page_region(vmp, vaddr, 0, len,
VR_ANON | VR_WRITABLE | VR_UNINITIALIZED, flags,
&mem_type_anon))) {
panic("VM: exec: map_page_region for boot process failed");
}
}
@ -387,7 +388,7 @@ void init_vm(void)
CALLMAP(VM_MMAP, do_mmap);
CALLMAP(VM_MUNMAP, do_munmap);
CALLMAP(VM_MAP_PHYS, do_map_phys);
CALLMAP(VM_UNMAP_PHYS, do_unmap_phys);
CALLMAP(VM_UNMAP_PHYS, do_munmap);
/* Calls from PM. */
CALLMAP(VM_EXIT, do_exit);
@ -408,7 +409,7 @@ void init_vm(void)
CALLMAP(VM_REMAP, do_remap);
CALLMAP(VM_REMAP_RO, do_remap);
CALLMAP(VM_GETPHYS, do_get_phys);
CALLMAP(VM_SHM_UNMAP, do_shared_unmap);
CALLMAP(VM_SHM_UNMAP, do_munmap);
CALLMAP(VM_GETREF, do_get_refcount);
CALLMAP(VM_INFO, do_info);
CALLMAP(VM_QUERY_EXIT, do_query_exit);

148
servers/vm/mem_anon.c Normal file
View file

@ -0,0 +1,148 @@
/* This file implements the methods of anonymous memory.
*
* Anonymous memory is memory that is for private use to a process
* and can not be related to a file (hence anonymous).
*/
#include <assert.h>
#include "proto.h"
#include "vm.h"
#include "region.h"
#include "glo.h"
/* These functions are static so as to not pollute the
* global namespace, and are accessed through their function
* pointers.
*/
static int anon_reference(struct phys_region *pr);
static int anon_unreference(struct phys_region *pr);
static int anon_pagefault(struct vmproc *vmp, struct vir_region *region,
struct phys_region *ph, int write);
static int anon_sanitycheck(struct phys_region *pr, char *file, int line);
static int anon_writable(struct phys_region *pr);
static int anon_resize(struct vmproc *vmp, struct vir_region *vr, vir_bytes l);
static u32_t anon_regionid(struct vir_region *region);
static int anon_refcount(struct vir_region *vr);
struct mem_type mem_type_anon = {
.name = "anonymous memory",
.ev_reference = anon_reference,
.ev_unreference = anon_unreference,
.ev_pagefault = anon_pagefault,
.ev_resize = anon_resize,
.ev_sanitycheck = anon_sanitycheck,
.regionid = anon_regionid,
.writable = anon_writable,
.refcount = anon_refcount
};
static int anon_reference(struct phys_region *pr)
{
return OK;
}
static int anon_unreference(struct phys_region *pr)
{
assert(pr->ph->refcount == 0);
if(pr->ph->phys != MAP_NONE)
free_mem(ABS2CLICK(pr->ph->phys), 1);
return OK;
}
static int anon_pagefault(struct vmproc *vmp, struct vir_region *region,
struct phys_region *ph, int write)
{
phys_bytes new_page, new_page_cl;
struct phys_block *pb;
u32_t allocflags;
allocflags = vrallocflags(region->flags);
assert(ph->ph->refcount > 0);
if((new_page_cl = alloc_mem(1, allocflags)) == NO_MEM)
return ENOMEM;
new_page = CLICK2ABS(new_page_cl);
/* Totally new block? Create it. */
if(ph->ph->phys == MAP_NONE) {
ph->ph->phys = new_page;
assert(ph->ph->phys != MAP_NONE);
return OK;
}
if(ph->ph->refcount < 2 || !write) {
printf("anon_pagefault: %d refcount, %d write - not handling pagefault\n",
ph->ph->refcount, write);
return OK;
}
assert(region->flags & VR_WRITABLE);
if(ph->ph->share_flag != PBSH_COW) {
printf("VM: write RO mapped pages.\n");
free_mem(new_page_cl, 1);
return EFAULT;
}
if(sys_abscopy(ph->ph->phys, new_page, VM_PAGE_SIZE) != OK) {
panic("VM: abscopy failed\n");
return EFAULT;
}
if(!(pb = pb_new(new_page))) {
free_mem(new_page_cl, 1);
return ENOMEM;
}
pb_unreferenced(region, ph, 0);
pb_link(ph, pb, ph->offset, region);
return OK;
}
static int anon_sanitycheck(struct phys_region *pr, char *file, int line)
{
MYASSERT(usedpages_add(pr->ph->phys, VM_PAGE_SIZE) == OK);
return OK;
}
static int anon_writable(struct phys_region *pr)
{
assert(pr->ph->refcount > 0);
if(pr->parent->remaps > 0)
return 1;
return pr->ph->phys != MAP_NONE && pr->ph->refcount == 1;
}
static int anon_resize(struct vmproc *vmp, struct vir_region *vr, vir_bytes l)
{
/* Shrinking not implemented; silently ignored.
* (Which is ok for brk().)
*/
if(l <= vr->length)
return OK;
assert(vr);
assert(vr->flags & VR_ANON);
assert(!(l % VM_PAGE_SIZE));
USE(vr, vr->length = l;);
return OK;
}
static u32_t anon_regionid(struct vir_region *region)
{
return region->id;
}
static int anon_refcount(struct vir_region *vr)
{
return 1 + vr->remaps;
}

View file

@ -0,0 +1,116 @@
/* This file implements the methods of physically contiguous anonymous memory. */
#include <assert.h>
#include "proto.h"
#include "vm.h"
#include "region.h"
#include "glo.h"
static int anon_contig_reference(struct phys_region *pr);
static int anon_contig_unreference(struct phys_region *pr);
static int anon_contig_pagefault(struct vmproc *vmp, struct vir_region *region,
struct phys_region *ph, int write);
static int anon_contig_sanitycheck(struct phys_region *pr, char *file, int line);
static int anon_contig_writable(struct phys_region *pr);
static int anon_contig_resize(struct vmproc *vmp, struct vir_region *vr, vir_bytes l);
static int anon_contig_new(struct vir_region *vr);
struct mem_type mem_type_anon_contig = {
.name = "anonymous memory (physically contiguous)",
.ev_new = anon_contig_new,
.ev_reference = anon_contig_reference,
.ev_unreference = anon_contig_unreference,
.ev_pagefault = anon_contig_pagefault,
.ev_resize = anon_contig_resize,
.ev_sanitycheck = anon_contig_sanitycheck,
.writable = anon_contig_writable
};
static int anon_contig_pagefault(struct vmproc *vmp, struct vir_region *region,
struct phys_region *ph, int write)
{
panic("anon_contig_pagefault: pagefault cannot happen");
}
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);
pages = region->length/VM_PAGE_SIZE;
assert(physregions(region) == 0);
for(p = 0; p < pages; p++) {
struct phys_block *pb = pb_new(MAP_NONE);
struct phys_region *pr = NULL;
if(pb)
pr = pb_reference(pb, p * VM_PAGE_SIZE, region);
if(!pr) {
if(pb) pb_free(pb);
map_free(region);
return ENOMEM;
}
}
assert(physregions(region) == pages);
if((new_page_cl = alloc_mem(pages, allocflags)) == NO_MEM) {
map_free(region);
return ENOMEM;
}
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);
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;
}
static int anon_contig_resize(struct vmproc *vmp, struct vir_region *vr, vir_bytes l)
{
printf("VM: cannot resize physically contiguous memory.\n");
return ENOMEM;
}
static int anon_contig_reference(struct phys_region *pr)
{
printf("VM: cannot fork with physically contig memory.\n");
return ENOMEM;
}
/* Methods inherited from the anonymous memory methods. */
static int anon_contig_unreference(struct phys_region *pr)
{
return mem_type_anon.ev_unreference(pr);
}
static int anon_contig_sanitycheck(struct phys_region *pr, char *file, int line)
{
return mem_type_anon.ev_sanitycheck(pr, file, line);
}
static int anon_contig_writable(struct phys_region *pr)
{
return mem_type_anon.writable(pr);
}

View file

@ -0,0 +1,72 @@
/* This file implements the methods of direct physical mapping.
*
* A direct physical mapping is done by accepting the physical
* memory address and range from the caller and allowing direct
* access to it. Most significantly, no physical memory is allocated
* when it's mapped or freed when it's unmapped. E.g. device memory.
*/
#include "vm.h"
/* These functions are static so as to not pollute the
* global namespace, and are accessed through their function
* pointers.
*/
static int phys_reference(struct phys_region *pr);
static int phys_unreference(struct phys_region *pr);
static int phys_writable(struct phys_region *pr);
static int phys_pagefault(struct vmproc *vmp, struct vir_region *region,
struct phys_region *ph, int write);
static int phys_copy(struct vir_region *vr, struct vir_region *newvr);
struct mem_type mem_type_directphys = {
.name = "physical memory mapping",
.ev_reference = phys_reference,
.ev_copy = phys_copy,
.ev_unreference = phys_unreference,
.writable = phys_writable,
.ev_pagefault = phys_pagefault
};
static int phys_reference(struct phys_region *pr)
{
panic("%s", __FUNCTION__);
return OK;
}
static int phys_unreference(struct phys_region *pr)
{
return OK;
}
static int phys_pagefault(struct vmproc *vmp, struct vir_region *region,
struct phys_region *ph, int write)
{
phys_bytes arg = region->param.phys, phmem;
assert(arg != MAP_NONE);
assert(ph->ph->phys == MAP_NONE);
phmem = arg + ph->offset;
assert(phmem != MAP_NONE);
ph->ph->phys = phmem;
return OK;
}
static int phys_writable(struct phys_region *pr)
{
assert(pr->ph->refcount > 0);
return pr->ph->phys != MAP_NONE;
}
void phys_setphys(struct vir_region *vr, phys_bytes phys)
{
vr->param.phys = phys;
}
static int phys_copy(struct vir_region *vr, struct vir_region *newvr)
{
newvr->param.phys = vr->param.phys;
return OK;
}

202
servers/vm/mem_shared.c Normal file
View file

@ -0,0 +1,202 @@
/* This file implements the methods of shared memory. */
#include <assert.h>
#include "proto.h"
#include "vm.h"
#include "region.h"
#include "glo.h"
/* These functions are static so as to not pollute the
* global namespace, and are accessed through their function
* pointers.
*/
static int shared_reference(struct phys_region *pr);
static int shared_unreference(struct phys_region *pr);
static int shared_pagefault(struct vmproc *vmp, struct vir_region *region,
struct phys_region *ph, int write);
static int shared_sanitycheck(struct phys_region *pr, char *file, int line);
static int shared_writable(struct phys_region *pr);
static void shared_delete(struct vir_region *region);
static u32_t shared_regionid(struct vir_region *region);
static int shared_copy(struct vir_region *vr, struct vir_region *newvr);
static int shared_refcount(struct vir_region *vr);
struct mem_type mem_type_shared = {
.name = "shared memory",
.ev_reference = shared_reference,
.ev_copy = shared_copy,
.ev_unreference = shared_unreference,
.ev_pagefault = shared_pagefault,
.ev_sanitycheck = shared_sanitycheck,
.ev_delete = shared_delete,
.regionid = shared_regionid,
.refcount = shared_refcount,
.writable = shared_writable
};
static int shared_reference(struct phys_region *pr)
{
return OK;
}
static int shared_unreference(struct phys_region *pr)
{
return mem_type_anon.ev_unreference(pr);
}
static int getsrc(struct vir_region *region,
struct vmproc **vmp, struct vir_region **r)
{
int srcproc;
if(region->memtype != &mem_type_shared) {
printf("shared region hasn't shared type but %s.\n",
region->memtype->name);
return EINVAL;
}
if(!region->param.shared.ep || !region->param.shared.vaddr) {
printf("shared region has not defined source region.\n");
util_stacktrace();
return EINVAL;
}
if(vm_isokendpt((endpoint_t) region->param.shared.ep, &srcproc) != OK) {
printf("VM: shared memory with missing source process.\n");
util_stacktrace();
return EINVAL;
}
*vmp = &vmproc[srcproc];
if(!(*r=map_lookup(*vmp, region->param.shared.vaddr, NULL))) {
printf("VM: shared memory with missing vaddr 0x%lx.\n",
region->param.shared.vaddr);
return EINVAL;
}
if((*r)->memtype != &mem_type_anon) {
printf("source region hasn't anon type but %s.\n",
(*r)->memtype->name);
return EINVAL;
}
if(region->param.shared.id != (*r)->id) {
printf("source region has no matching id\n");
return EINVAL;
}
return OK;
}
static u32_t shared_regionid(struct vir_region *vr)
{
struct vir_region *src_region;
struct vmproc *src_vmp;
if(getsrc(vr, &src_vmp, &src_region) != OK)
return 0;
return src_region->id;
}
static void shared_delete(struct vir_region *region)
{
struct vir_region *src_region;
struct vmproc *src_vmp;
if(getsrc(region, &src_vmp, &src_region) != OK)
return;
assert(src_region->remaps > 0);
src_region->remaps--;
}
static int shared_pagefault(struct vmproc *vmp, struct vir_region *region,
struct phys_region *ph, int write)
{
struct vir_region *src_region;
struct vmproc *src_vmp;
struct phys_region *pr;
if(getsrc(region, &src_vmp, &src_region) != OK) {
return EINVAL;
}
assert(ph->ph->phys == MAP_NONE);
pb_free(ph->ph);
if(!(pr = physr_search(src_region->phys, ph->offset, AVL_EQUAL))) {
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))) {
panic("missing region after pagefault handling");
}
}
pb_link(ph, pr->ph, ph->offset, region);
return OK;
}
static int shared_sanitycheck(struct phys_region *pr, char *file, int line)
{
return OK;
}
static int shared_writable(struct phys_region *pr)
{
assert(pr->ph->refcount > 0);
return pr->ph->phys != MAP_NONE;
}
void shared_setsource(struct vir_region *vr, endpoint_t ep,
struct vir_region *src_vr)
{
struct vmproc *vmp;
struct vir_region *srcvr;
int id = src_vr->id;
vir_bytes vaddr = src_vr->vaddr;
assert(vr->memtype == &mem_type_shared);
if(!ep || !vaddr || !id) {
printf("VM: shared_setsource: zero ep/vaddr/id - ignoring\n");
return;
}
vr->param.shared.ep = ep;
vr->param.shared.vaddr = vaddr;
vr->param.shared.id = id;
if(getsrc(vr, &vmp, &srcvr) != OK)
panic("initial getsrc failed");
assert(srcvr == src_vr);
srcvr->remaps++;
}
static int shared_copy(struct vir_region *vr, struct vir_region *newvr)
{
struct vmproc *vmp;
struct vir_region *srcvr;
if(getsrc(vr, &vmp, &srcvr) != OK)
panic("copy: original getsrc failed");
shared_setsource(newvr, vr->param.shared.ep, srcvr);
return OK;
}
static int shared_refcount(struct vir_region *vr)
{
return 1 + vr->remaps;
}

26
servers/vm/memtype.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef _MEMTYPE_H
#define _MEMTYPE_H 1
struct vmproc;
struct vir_region;
struct phys_region;
typedef struct mem_type {
char *name; /* human-readable name */
int (*ev_new)(struct vir_region *region);
void (*ev_delete)(struct vir_region *region);
int (*ev_reference)(struct phys_region *pr);
int (*ev_unreference)(struct phys_region *pr);
int (*ev_pagefault)(struct vmproc *vmp, struct vir_region *region,
struct phys_region *ph, int write);
int (*ev_resize)(struct vmproc *vmp, struct vir_region *vr, vir_bytes len);
int (*writable)(struct phys_region *pr);
int (*ev_sanitycheck)(struct phys_region *pr, char *file, int line);
int (*ev_copy)(struct vir_region *vr, struct vir_region *newvr);
u32_t (*regionid)(struct vir_region *vr);
int (*refcount)(struct vir_region *vr);
} mem_type_t;
#endif

View file

@ -64,6 +64,7 @@ int do_mmap(message *m)
vmp = &vmproc[n];
if(m->VMM_FD == -1 || (m->VMM_FLAGS & MAP_ANON)) {
mem_type_t *mt;
u32_t vrflags = VR_ANON | VR_WRITABLE;
size_t len = (vir_bytes) m->VMM_LEN;
@ -84,15 +85,10 @@ int do_mmap(message *m)
if(!execpriv) return EPERM;
vrflags |= VR_UNINITIALIZED;
}
if(m->VMM_FLAGS & MAP_IPC_SHARED) {
vrflags |= VR_SHARED;
/* Shared memory has to be preallocated. */
if((m->VMM_FLAGS & (MAP_PREALLOC|MAP_ANON)) !=
(MAP_PREALLOC|MAP_ANON)) {
return EINVAL;
}
}
if(m->VMM_FLAGS & MAP_CONTIG) vrflags |= VR_CONTIG;
if(m->VMM_FLAGS & MAP_CONTIG) {
vrflags |= VR_CONTIG;
mt = &mem_type_anon_contig;
} else mt = &mem_type_anon;
if(len % VM_PAGE_SIZE)
len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE);
@ -101,15 +97,15 @@ int do_mmap(message *m)
if (m->VMM_ADDR || (m->VMM_FLAGS & MAP_FIXED)) {
/* An address is given, first try at that address. */
addr = m->VMM_ADDR;
vr = map_page_region(vmp, addr, 0, len, MAP_NONE,
vrflags, mfflags);
vr = map_page_region(vmp, addr, 0, len,
vrflags, mfflags, mt);
if(!vr && (m->VMM_FLAGS & MAP_FIXED))
return ENOMEM;
}
if (!vr) {
/* No address given or address already in use. */
vr = map_page_region(vmp, 0, VM_DATATOP, len,
MAP_NONE, vrflags, mfflags);
vrflags, mfflags, mt);
}
if (!vr) {
return ENOMEM;
@ -198,59 +194,28 @@ int do_map_phys(message *m)
if(len % VM_PAGE_SIZE)
len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE);
if(!(vr = map_page_region(vmp, 0, VM_DATATOP, len, startaddr,
VR_DIRECT | VR_NOPF | VR_WRITABLE, 0))) {
if(!(vr = map_page_region(vmp, 0, VM_DATATOP, len,
VR_DIRECT | VR_WRITABLE, 0, &mem_type_directphys))) {
return ENOMEM;
}
phys_setphys(vr, startaddr);
m->VMMP_VADDR_REPLY = (void *) (vr->vaddr + offset);
return OK;
}
/*===========================================================================*
* do_unmap_phys *
*===========================================================================*/
int do_unmap_phys(message *m)
{
int r, n;
struct vmproc *vmp;
endpoint_t target;
struct vir_region *region;
target = m->VMUP_EP;
if(target == SELF)
target = m->m_source;
if((r=vm_isokendpt(target, &n)) != OK)
return EINVAL;
vmp = &vmproc[n];
if(!(region = map_lookup(vmp, (vir_bytes) m->VMUM_ADDR, NULL))) {
return EINVAL;
}
if(!(region->flags & VR_DIRECT)) {
return EINVAL;
}
if(map_unmap_region(vmp, region, 0, region->length) != OK) {
return EINVAL;
}
return OK;
}
/*===========================================================================*
* do_remap *
*===========================================================================*/
int do_remap(message *m)
{
int dn, sn;
vir_bytes da, sa, startv;
vir_bytes da, sa;
size_t size;
struct vir_region *region;
u32_t flags;
struct vir_region *src_region, *vr;
struct vmproc *dvmp, *svmp;
int r;
int readonly;
@ -275,80 +240,41 @@ int do_remap(message *m)
dvmp = &vmproc[dn];
svmp = &vmproc[sn];
/* da is not translated by arch_vir2map(),
* it's handled a little differently,
* since in map_remap(), we have to know
* about whether the user needs to bind to
* THAT address or be chosen by the system.
*/
if (!(region = map_lookup(svmp, sa, NULL)))
if (!(src_region = map_lookup(svmp, sa, NULL)))
return EINVAL;
if(region->vaddr != sa) {
if(src_region->vaddr != sa) {
printf("VM: do_remap: not start of region.\n");
return EFAULT;
}
if(!(region->flags & VR_SHARED)) {
printf("VM: do_remap: not shared.\n");
return EFAULT;
}
if (size % VM_PAGE_SIZE)
size += VM_PAGE_SIZE - size % VM_PAGE_SIZE;
if(size != region->length) {
if(size != src_region->length) {
printf("VM: do_remap: not size of region.\n");
return EFAULT;
}
if ((r = map_remap(dvmp, da, size, region, &startv, readonly)) != OK)
return r;
flags = VR_SHARED;
if(!readonly)
flags |= VR_WRITABLE;
m->VMRE_RETA = (char *) startv;
return OK;
}
if(da)
vr = map_page_region(dvmp, da, 0, size, flags, 0,
&mem_type_shared);
else
vr = map_page_region(dvmp, 0, VM_DATATOP, size, flags, 0,
&mem_type_shared);
/*===========================================================================*
* do_shared_unmap *
*===========================================================================*/
int do_shared_unmap(message *m)
{
int r, n;
struct vmproc *vmp;
endpoint_t target;
struct vir_region *vr;
vir_bytes addr;
target = m->VMUN_ENDPT;
if (target == SELF)
target = m->m_source;
if ((r = vm_isokendpt(target, &n)) != OK)
return EINVAL;
vmp = &vmproc[n];
addr = m->VMUN_ADDR;
if(!(vr = map_lookup(vmp, addr, NULL))) {
printf("VM: addr 0x%lx not found.\n", m->VMUN_ADDR);
return EFAULT;
if(!vr) {
printf("VM: re-map of shared area failed\n");
return ENOMEM;
}
if(vr->vaddr != addr) {
printf("VM: wrong address for shared_unmap.\n");
return EFAULT;
}
if(!(vr->flags & VR_SHARED)) {
printf("VM: address does not point to shared region.\n");
return EFAULT;
}
if(map_unmap_region(vmp, vr, 0, vr->length) != OK)
panic("do_shared_unmap: map_unmap_region failed");
shared_setsource(vr, svmp->vm_endpoint, src_region);
m->VMRE_RETA = (char *) vr->vaddr;
return OK;
}
@ -411,15 +337,26 @@ int do_munmap(message *m)
struct vmproc *vmp;
vir_bytes addr, len, offset;
struct vir_region *vr;
endpoint_t target = SELF;
if((r=vm_isokendpt(m->m_source, &n)) != OK) {
if(m->m_type == VM_UNMAP_PHYS) {
target = m->VMUP_EP;
} else if(m->m_type == VM_SHM_UNMAP) {
target = m->VMUN_ENDPT;
}
if(target == SELF)
target = m->m_source;
if((r=vm_isokendpt(target, &n)) != OK) {
panic("do_mmap: message from strange source: %d", m->m_source);
}
vmp = &vmproc[n];
assert(m->m_type == VM_MUNMAP);
addr = (vir_bytes) (vir_bytes) m->VMUM_ADDR;
if(m->m_type == VM_SHM_UNMAP) {
addr = (vir_bytes) m->VMUN_ADDR;
} else addr = (vir_bytes) m->VMUM_ADDR;
if(!(vr = map_lookup(vmp, addr, NULL))) {
printf("VM: unmap: virtual address %p not found in %d\n",
@ -430,7 +367,9 @@ int do_munmap(message *m)
if(addr % VM_PAGE_SIZE)
return EFAULT;
len = roundup(m->VMUM_LEN, VM_PAGE_SIZE);
if(m->m_type == VM_SHM_UNMAP) {
len = vr->length;
} else len = roundup(m->VMUM_LEN, VM_PAGE_SIZE);
offset = addr - vr->vaddr;

View file

@ -86,11 +86,6 @@ void do_pagefaults(message *m)
return;
}
/* Make sure this isn't a region that isn't supposed
* to cause pagefaults.
*/
assert(!(region->flags & VR_NOPF));
/* If process was writing, see if it's writable. */
if(!(region->flags & VR_WRITABLE) && wr) {
printf("VM: pagefault: SIGSEGV %d ro map 0x%x %s\n",
@ -191,7 +186,6 @@ int handle_memory(struct vmproc *vmp, vir_bytes mem, vir_bytes len, int wrflag)
} else {
vir_bytes offset, sublen;
assert(region->vaddr <= mem);
assert(!(region->flags & VR_NOPF));
assert(!(region->vaddr % VM_PAGE_SIZE));
offset = mem - region->vaddr;
sublen = len;

View file

@ -40,8 +40,8 @@ struct phys_block *pb_new(phys_bytes phys)
return NULL;
}
assert(!(phys % VM_PAGE_SIZE));
assert(phys != MAP_NONE);
if(phys != MAP_NONE)
assert(!(phys % VM_PAGE_SIZE));
USE(newpb,
newpb->phys = phys;
@ -52,7 +52,28 @@ USE(newpb,
return newpb;
}
struct phys_region *pb_reference(struct phys_block *newpb, vir_bytes offset, struct vir_region *region)
void pb_free(struct phys_block *pb)
{
if(pb->phys != MAP_NONE)
free_mem(ABS2CLICK(pb->phys), 1);
SLABFREE(pb);
}
void pb_link(struct phys_region *newphysr, struct phys_block *newpb,
vir_bytes offset, struct vir_region *parent)
{
USE(newphysr,
newphysr->offset = offset;
newphysr->ph = newpb;
newphysr->parent = parent;
newphysr->next_ph_list = newpb->firstregion;
newphysr->memtype = parent->memtype;
newpb->firstregion = newphysr;);
newpb->refcount++;
}
struct phys_region *pb_reference(struct phys_block *newpb,
vir_bytes offset, struct vir_region *region)
{
struct phys_region *newphysr;
@ -62,14 +83,8 @@ struct phys_region *pb_reference(struct phys_block *newpb, vir_bytes offset, str
}
/* New physical region. */
USE(newphysr,
newphysr->offset = offset;
newphysr->ph = newpb;
newphysr->parent = region;
newphysr->next_ph_list = newpb->firstregion;
newpb->firstregion = newphysr;);
pb_link(newphysr, newpb, offset, region);
newpb->refcount++;
physr_insert(region->phys, newphysr);
return newphysr;
@ -106,15 +121,14 @@ void pb_unreferenced(struct vir_region *region, struct phys_region *pr, int rm)
if(pb->refcount == 0) {
assert(!pb->firstregion);
if(region->flags & VR_ANON) {
free_mem(ABS2CLICK(pb->phys), 1);
} else if(region->flags & VR_DIRECT) {
; /* No action required. */
} else {
panic("strange phys flags");
}
int r;
if((r = region->memtype->ev_unreference(pr)) != OK)
panic("unref failed, %d", r);
SLABFREE(pb);
}
pr->ph = NULL;
if(rm) physr_remove(region->phys, pr->offset);
}

View file

@ -3,6 +3,8 @@
#include <stddef.h>
#include "memtype.h"
typedef struct phys_region {
struct phys_block *ph;
struct vir_region *parent; /* vir_region or NULL if yielded */
@ -11,6 +13,8 @@ typedef struct phys_region {
int written; /* written to pagetable */
#endif
mem_type_t *memtype;
/* list of phys_regions that reference the same phys_block */
struct phys_region *next_ph_list;

View file

@ -3,6 +3,5 @@
#include "sanitycheck.h"
#include "phys_region.h"
#include "physravl_defs.h"
#include "cavl_if.h"
#include "cavl_impl.h"

View file

@ -1,3 +1,4 @@
#include <minix/u64.h>
#define AVL_UNIQUE(id) physr_ ## id
@ -16,3 +17,4 @@
#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];

View file

@ -20,15 +20,12 @@ struct phys_region;
/* alloc.c */
void mem_sanitycheck(char *file, int line);
phys_clicks alloc_mem(phys_clicks clicks, u32_t flags);
struct memlist *alloc_mem_in_list(phys_bytes bytes, u32_t flags, phys_bytes known);
void memstats(int *nodes, int *pages, int *largest);
void printmemstats(void);
void usedpages_reset(void);
int usedpages_add_f(phys_bytes phys, phys_bytes len, char *file, int
line);
void free_mem(phys_clicks base, phys_clicks clicks);
void free_mem_list(struct memlist *list, int all);
void print_mem_list(struct memlist *ml);
#define usedpages_add(a, l) usedpages_add_f(a, l, __FILE__, __LINE__)
void mem_init(struct memory *chunks);
@ -68,7 +65,6 @@ int do_map_phys(message *msg);
int do_unmap_phys(message *msg);
int do_remap(message *m);
int do_get_phys(message *m);
int do_shared_unmap(message *m);
int do_get_refcount(message *m);
/* pagefaults.c */
@ -124,13 +120,12 @@ int slabsane_f(char *file, int line, void *mem, int bytes);
/* region.c */
void map_region_init(void);
struct vir_region * map_page_region(struct vmproc *vmp, vir_bytes min,
vir_bytes max, vir_bytes length, vir_bytes what, u32_t flags, int
mapflags);
vir_bytes max, vir_bytes length, u32_t flags, int mapflags,
mem_type_t *memtype);
struct vir_region * map_proc_kernel(struct vmproc *dst);
int map_region_extend(struct vmproc *vmp, struct vir_region *vr,
vir_bytes delta);
int map_region_extend_upto_v(struct vmproc *vmp, vir_bytes vir);
int map_region_shrink(struct vir_region *vr, vir_bytes delta);
int map_unmap_region(struct vmproc *vmp, struct vir_region *vr,
vir_bytes offset, vir_bytes len);
int map_free_proc(struct vmproc *vmp);
@ -149,15 +144,18 @@ int map_writept(struct vmproc *vmp);
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);
u32_t vrallocflags(u32_t flags);
int map_free(struct vir_region *region);
struct vir_region * map_region_lookup_tag(struct vmproc *vmp, u32_t
tag);
void map_region_set_tag(struct vir_region *vr, u32_t tag);
u32_t map_region_get_tag(struct vir_region *vr);
int map_remap(struct vmproc *dvmp, vir_bytes da, size_t size, struct
vir_region *region, vir_bytes *r, int ro);
int map_get_phys(struct vmproc *vmp, vir_bytes addr, phys_bytes *r);
int map_get_ref(struct vmproc *vmp, vir_bytes addr, u8_t *cnt);
int physregions(struct vir_region *vr);
void get_stats_info(struct vm_stats_info *vsi);
void get_usage_info(struct vmproc *vmp, struct vm_usage_info *vui);
@ -188,6 +186,15 @@ void init_query_exit(void);
/* pb.c */
struct phys_block *pb_new(phys_bytes phys);
void pb_free(struct phys_block *);
struct phys_region *pb_reference(struct phys_block *newpb,
vir_bytes offset, struct vir_region *region);
void pb_unreferenced(struct vir_region *region, struct phys_region *pr, int rm);
void pb_link(struct phys_region *newphysr, struct phys_block *newpb,
vir_bytes offset, struct vir_region *parent);
/* mem_directphys.c */
void phys_setphys(struct vir_region *vr, phys_bytes startaddr);
/* mem_shared.c */
void shared_setsource(struct vir_region *vr, endpoint_t ep, struct vir_region *src);

File diff suppressed because it is too large Load diff

View file

@ -18,6 +18,8 @@
#include "phys_region.h"
#include "physravl.h"
#include "memtype.h"
#include "vm.h"
struct phys_block {
#if SANITYCHECKS
@ -29,6 +31,9 @@ struct phys_block {
#define PBSH_SMAP 2
u8_t share_flag; /* PBSH_COW or PBSH_SMAP */
/* what kind of memory is it? */
mem_type_t *memtype;
/* first in list of phys_regions that reference this block */
struct phys_region *firstregion;
};
@ -38,8 +43,19 @@ typedef struct vir_region {
vir_bytes length; /* length in bytes */
physr_avl *phys; /* avl tree of physical memory blocks */
u16_t flags;
u32_t tag; /* Opaque to mapping code. */
struct vmproc *parent; /* Process that owns this vir_region. */
mem_type_t *memtype; /* Default instantiated memory type. */
int remaps;
u32_t id; /* unique id */
union {
phys_bytes phys;
struct {
endpoint_t ep;
vir_bytes vaddr;
int id;
} shared;
} param;
/* AVL fields */
struct vir_region *lower, *higher;
@ -48,7 +64,6 @@ typedef struct vir_region {
/* Mapping flags: */
#define VR_WRITABLE 0x001 /* Process may write here. */
#define VR_NOPF 0x002 /* May not generate page faults. */
#define VR_PHYS64K 0x004 /* Physical memory must be 64k aligned. */
#define VR_LOWER16MB 0x008
#define VR_LOWER1MB 0x010
@ -60,12 +75,6 @@ typedef struct vir_region {
#define VR_ANON 0x100 /* Memory to be cleared and allocated */
#define VR_DIRECT 0x200 /* Mapped, but not managed by VM */
/* Tag values: */
#define VRT_NONE 0xBEEF0000
#define VRT_HEAP 0xBEEF0001
#define VRT_TEXT 0xBEEF0002
#define VRT_STACK 0xBEEF0003
/* map_page_region flags */
#define MF_PREALLOC 0x01

View file

@ -47,6 +47,7 @@
#define SANITYCHECK(l)
#define SLABSANITYCHECK(l)
#define SLABSANE(ptr)
#define MYASSERT(c)
#endif
#if MEMPROTECT

View file

@ -1,4 +1,23 @@
#ifndef _VM_H
#define _VM_H 1
#define _SYSTEM 1
/* Compile in asserts and custom sanity checks at all? */
#define SANITYCHECKS 0
#define VMSTATS 0
/* VM behaviour */
#define MEMPROTECT 0 /* Slab objects not mapped. Access with USE() */
#define JUNKFREE 0 /* Fill freed pages with junk */
#include <sys/errno.h>
#include <memory.h>
#include "sanitycheck.h"
#include "region.h"
/* Memory flags to pt_allocmap() and alloc_mem(). */
#define PAF_CLEAR 0x01 /* Clear physical memory. */
#define PAF_CONTIG 0x02 /* Physically contiguous. */
@ -12,14 +31,6 @@
/* special value for v in pt_allocmap */
#define AM_AUTO ((u32_t) -1)
/* Compile in asserts and custom sanity checks at all? */
#define SANITYCHECKS 0
#define VMSTATS 0
/* VM behaviour */
#define MEMPROTECT 0 /* Slab objects not mapped. Access with USE() */
#define JUNKFREE 0 /* Fill freed pages with junk */
/* How noisy are we supposed to be? */
#define VERBOSE 0
#define LU_DEBUG 0
@ -50,3 +61,5 @@
#define MAP_NONE 0xFFFFFFFE
#define NO_MEM ((phys_clicks) MAP_NONE) /* returned by alloc_mem() with mem is up */
#endif