if(addr) {
*addr = m.VM_RS_CTL_ADDR;
}
- if(addr) {
+ if(len) {
*len = m.VM_RS_CTL_LEN;
}
printf("VM: unannounced VM_EXIT %d\n", msg->VME_ENDPOINT);
return EINVAL;
}
+ if(vmp->vm_flags & VMF_VM_INSTANCE) {
+ vmp->vm_flags &= ~VMF_VM_INSTANCE;
+ num_vm_instances--;
+ }
{
/* Free pagetable and pages allocated by pt code. */
/* total number of memory pages */
EXTERN int total_pages;
+EXTERN int num_vm_instances;
/* Initialize the structures for queryexit */
init_query_exit();
+
+ /* Mark VM instances. */
+ num_vm_instances = 1;
+ vmproc[VM_PROC_NR].vm_flags |= VMF_VM_INSTANCE;
}
/*===========================================================================*
phys_bytes phys;
} sparepagedirs[SPAREPAGEDIRS];
-extern char _end;
-#define is_staticaddr(v) ((vir_bytes) (v) < (vir_bytes) &_end)
+#define is_staticaddr(v) ((vir_bytes) (v) < VM_OWN_HEAPSTART)
#define MAX_KERNMAPPINGS 10
static struct {
u32_t holev = NO_MEM;
int holesize = -1;
- 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 = vmin + 100 * 1024 * 1024; /* allow 100MB of address space for VM */
+ vmin = VM_OWN_MMAPBASE;
+ vmax = VM_OWN_MMAPTOP;
/* Input sanity check. */
assert(vmin + VM_PAGE_SIZE >= vmin);
int pt_ptmap(struct vmproc *src_vmp, struct vmproc *dst_vmp)
{
/* Transfer mappings to page dir and page tables from source process and
- * destination process. Make sure all the mappings are above the stack, not
- * to corrupt valid mappings in the data segment of the destination process.
+ * destination process.
*/
int pde, r;
phys_bytes physaddr;
int get_stack_ptr(int proc_nr, vir_bytes *sp);
int do_info(message *);
int swap_proc_slot(struct vmproc *src_vmp, struct vmproc *dst_vmp);
-int swap_proc_dyn_data(struct vmproc *src_vmp, struct vmproc *dst_vmp);
+int swap_proc_dyn_data(struct vmproc *src_vmp, struct vmproc *dst_vmp,
+ int sys_upd_flags);
+void adjust_proc_refs(void);
int do_getrusage(message *m);
/* exit.c */
int map_unmap_range(struct vmproc *vmp, vir_bytes, vir_bytes);
int map_free_proc(struct vmproc *vmp);
int map_proc_copy(struct vmproc *dst, struct vmproc *src);
-int map_proc_copy_from(struct vmproc *dst, struct vmproc *src, struct
- vir_region *start_src_vr);
+int map_proc_copy_range(struct vmproc *dst, struct vmproc *src, struct
+ vir_region *start_src_vr, struct vir_region *end_src_vr);
struct vir_region *map_lookup(struct vmproc *vmp, vir_bytes addr,
struct phys_region **pr);
int map_pf(struct vmproc *vmp, struct vir_region *region, vir_bytes
int map_ph_writept(struct vmproc *vmp, struct vir_region *vr,
struct phys_region *pr);
-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);
+struct vir_region* map_region_lookup_type(struct vmproc *vmp, u32_t flags);
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);
unsigned int physregions(struct vir_region *vr);
/* Copy all the memory regions from the src process to the dst process. */
region_init(&dst->vm_regions_avl);
- return map_proc_copy_from(dst, src, NULL);
+ return map_proc_copy_range(dst, src, NULL, NULL);
}
/*========================================================================*
- * map_proc_copy_from *
+ * map_proc_copy_range *
*========================================================================*/
-int map_proc_copy_from(struct vmproc *dst, struct vmproc *src,
- struct vir_region *start_src_vr)
+int map_proc_copy_range(struct vmproc *dst, struct vmproc *src,
+ struct vir_region *start_src_vr, struct vir_region *end_src_vr)
{
struct vir_region *vr;
region_iter v_iter;
if(!start_src_vr)
start_src_vr = region_search_least(&src->vm_regions_avl);
+ if(!end_src_vr)
+ end_src_vr = region_search_greatest(&src->vm_regions_avl);
- assert(start_src_vr);
+ assert(start_src_vr && end_src_vr);
assert(start_src_vr->parent == src);
region_start_iter(&src->vm_regions_avl, &v_iter,
start_src_vr->vaddr, AVL_EQUAL);
assert(region_get_iter(&v_iter) == start_src_vr);
- /* Copy source regions after the destination's last region (if any). */
+ /* Copy source regions into the destination. */
SANITYCHECK(SCL_FUNCTIONS);
}
}
#endif
+ if(vr == end_src_vr) {
+ break;
+ }
region_incr_iter(&v_iter);
}
}
+/*========================================================================*
+ * map_region_lookup_type *
+ *========================================================================*/
+struct vir_region* map_region_lookup_type(struct vmproc *vmp, u32_t type)
+{
+ struct vir_region *vr;
+ struct phys_region *pr;
+ vir_bytes used = 0, weighted = 0;
+ region_iter v_iter;
+ region_start_iter_least(&vmp->vm_regions_avl, &v_iter);
+
+ while((vr = region_get_iter(&v_iter))) {
+ region_incr_iter(&v_iter);
+ if(vr->flags & type)
+ return vr;
+ }
+
+ return NULL;
+}
+
/*========================================================================*
* map_get_phys *
*========================================================================*/
/* Mapping type: */
#define VR_ANON 0x100 /* Memory to be cleared and allocated */
#define VR_DIRECT 0x200 /* Mapped, but not managed by VM */
+#define VR_PREALLOC_MAP 0x400 /* Preallocated map. */
-/* map_page_region flags */
-#define MF_PREALLOC 0x01
+/* map_page_region_flags */
+#define MF_PREALLOC 0x01
#endif
#include <minix/bitmap.h>
#include <minix/rs.h>
+#include <sys/mman.h>
+
#include <errno.h>
#include <string.h>
#include <env.h>
src_e = m_ptr->m_lsys_vm_update.src;
dst_e = m_ptr->m_lsys_vm_update.dst;
sys_upd_flags = m_ptr->m_lsys_vm_update.flags;
+ reply_e = m_ptr->m_source;
/* Lookup slots for source and destination process. */
if(vm_isokendpt(src_e, &src_p) != OK) {
}
dst_vmp = &vmproc[dst_p];
+ /* Check flags. */
+ if((sys_upd_flags & (SF_VM_ROLLBACK|SF_VM_NOMMAP)) == 0) {
+ /* Can't preallocate when transfering mmapped regions. */
+ if(map_region_lookup_type(dst_vmp, VR_PREALLOC_MAP)) {
+ return ENOSYS;
+ }
+ }
+
/* Let the kernel do the update first. */
r = sys_update(src_e, dst_e,
sys_upd_flags & SF_VM_ROLLBACK ? SYS_UPD_ROLLBACK : 0);
if(r != OK) {
return r;
}
- r = swap_proc_dyn_data(src_vmp, dst_vmp);
+ r = swap_proc_dyn_data(src_vmp, dst_vmp, sys_upd_flags);
if(r != OK) {
return r;
}
pt_bind(&src_vmp->vm_pt, src_vmp);
pt_bind(&dst_vmp->vm_pt, dst_vmp);
- /* Reply, update-aware. */
- reply_e = m_ptr->m_source;
- if(reply_e == src_e) reply_e = dst_e;
- else if(reply_e == dst_e) reply_e = src_e;
- m_ptr->m_type = OK;
- r = ipc_send(reply_e, m_ptr);
- if(r != OK) {
- panic("ipc_send() error");
+ /* Reply in case of external request, update-aware. */
+ if(reply_e != VM_PROC_NR) {
+ if(reply_e == src_e) reply_e = dst_e;
+ else if(reply_e == dst_e) reply_e = src_e;
+ m_ptr->m_type = OK;
+ r = ipc_send(reply_e, m_ptr);
+ if(r != OK) {
+ panic("ipc_send() error");
+ }
}
return SUSPEND;
this_vm_vmp = &vmproc[VM_PROC_NR];
+ /* Check if the operation is allowed. */
+ assert(num_vm_instances == 1 || num_vm_instances == 2);
+ if(num_vm_instances == 2) {
+ printf("VM can currently support no more than 2 VM instances at the time.");
+ return EPERM;
+ }
+
+ /* Copy settings from current VM. */
+ new_vm_vmp->vm_flags |= VMF_VM_INSTANCE;
+ num_vm_instances++;
+
/* Pin memory for the new VM instance. */
r = map_pin_memory(new_vm_vmp);
if(r != OK) {
static int rs_memctl_map_prealloc(struct vmproc *vmp,
vir_bytes *addr, size_t *len)
{
-#if 0
struct vir_region *vr;
+ vir_bytes base, top;
+ int is_vm;
+
if(*len <= 0) {
return EINVAL;
}
*len = CLICK_CEIL(*len);
- if(!(vr = map_page_region(vmp, VM_DATATOP - *len, VM_DATATOP, *len,
- MAP_NONE, VR_ANON|VR_WRITABLE|VR_CONTIG, MF_PREALLOC))) {
+ is_vm = (vmp->vm_endpoint == VM_PROC_NR);
+ base = is_vm ? VM_OWN_MMAPBASE : VM_MMAPBASE;
+ top = is_vm ? VM_OWN_MMAPTOP : VM_MMAPTOP;
+
+ if (!(vr = map_page_region(vmp, base, top, *len,
+ VR_ANON|VR_WRITABLE|VR_UNINITIALIZED, MF_PREALLOC,
+ &mem_type_anon))) {
return ENOMEM;
}
- map_region_set_tag(vr, VRT_PREALLOC_MAP);
- *addr = arch_map2vir(vmp, vr->vaddr);
-#endif
+ vr->flags |= VR_PREALLOC_MAP;
+ *addr = vr->vaddr;
return OK;
}
static int rs_memctl_get_prealloc_map(struct vmproc *vmp,
vir_bytes *addr, size_t *len)
{
-#if 0
struct vir_region *vr;
- vr = map_region_lookup_tag(vmp, VRT_PREALLOC_MAP);
+ vr = map_region_lookup_type(vmp, VR_PREALLOC_MAP);
if(!vr) {
*addr = 0;
*len = 0;
}
else {
- *addr = arch_map2vir(vmp, vr->vaddr);
+ *addr = vr->vaddr;
*len = vr->length;
}
-#endif
return OK;
}
#include <minix/syslib.h>
#include <minix/type.h>
#include <minix/bitmap.h>
+#include <minix/rs.h>
#include <string.h>
#include <errno.h>
#include <env.h>
/*===========================================================================*
* swap_proc_dyn_data *
*===========================================================================*/
-int swap_proc_dyn_data(struct vmproc *src_vmp, struct vmproc *dst_vmp)
+int swap_proc_dyn_data(struct vmproc *src_vmp, struct vmproc *dst_vmp,
+ int sys_upd_flags)
{
int is_vm;
int r;
+ struct vir_region *start_vr, *end_vr;
is_vm = (dst_vmp->vm_endpoint == VM_PROC_NR);
- /* For VM, transfer memory regions above the stack first. */
+ /* For VM, transfer memory mapped regions first. */
if(is_vm) {
#if LU_DEBUG
- printf("VM: swap_proc_dyn_data: tranferring regions above the stack from old VM (%d) to new VM (%d)\n",
+ printf("VM: swap_proc_dyn_data: tranferring memory mapped regions from old (%d) to new VM (%d)\n",
src_vmp->vm_endpoint, dst_vmp->vm_endpoint);
#endif
- r = pt_map_in_range(src_vmp, dst_vmp, VM_STACKTOP, 0);
+ r = pt_map_in_range(src_vmp, dst_vmp, VM_OWN_HEAPBASE, VM_OWN_MMAPTOP);
if(r != OK) {
printf("swap_proc_dyn_data: pt_map_in_range failed\n");
return r;
map_setparent(src_vmp);
map_setparent(dst_vmp);
- /* For regular processes, transfer regions above the stack now.
- * In case of rollback, we need to skip this step. To sandbox the
- * new instance and prevent state corruption on rollback, we share all
- * the regions between the two instances as COW.
+ /* Don't transfer mmapped regions if not required. */
+ if(is_vm || (sys_upd_flags & (SF_VM_ROLLBACK|SF_VM_NOMMAP))) {
+ return OK;
+ }
+
+ /* Make sure regions are consistent. */
+ assert(region_search_root(&src_vmp->vm_regions_avl) && region_search_root(&dst_vmp->vm_regions_avl));
+
+ /* Transfer memory mapped regions now. To sandbox the new instance and
+ * prevent state corruption on rollback, we share all the regions
+ * between the two instances as COW.
*/
- if(!is_vm) {
- struct vir_region *vr;
- vr = map_lookup(dst_vmp, VM_STACKTOP, NULL);
- if(vr && !map_lookup(src_vmp, VM_STACKTOP, NULL)) {
+ start_vr = region_search(&dst_vmp->vm_regions_avl, VM_MMAPBASE, AVL_GREATER_EQUAL);
+ end_vr = region_search(&dst_vmp->vm_regions_avl, VM_MMAPTOP, AVL_LESS);
+ if(start_vr) {
#if LU_DEBUG
- printf("VM: swap_proc_dyn_data: tranferring regions above the stack from %d to %d\n",
- src_vmp->vm_endpoint, dst_vmp->vm_endpoint);
+ printf("VM: swap_proc_dyn_data: tranferring memory mapped regions from %d to %d\n",
+ dst_vmp->vm_endpoint, src_vmp->vm_endpoint);
#endif
- r = map_proc_copy_from(src_vmp, dst_vmp, vr);
- if(r != OK) {
- return r;
- }
+ assert(end_vr);
+ r = map_proc_copy_range(src_vmp, dst_vmp, start_vr, end_vr);
+ if(r != OK) {
+ return r;
}
}
return sys_datacopy(SELF, (vir_bytes) &r_usage, m->m_source,
m->m_lc_vm_rusage.addr, (vir_bytes) sizeof(r_usage));
}
+
+/*===========================================================================*
+ * adjust_proc_refs *
+ *===========================================================================*/
+void adjust_proc_refs()
+{
+ struct vmproc *vmp;
+ region_iter iter;
+
+ /* Fix up region parents. */
+ for(vmp = vmproc; vmp < &vmproc[VMP_NR]; vmp++) {
+ struct vir_region *vr;
+ if(!(vmp->vm_flags & VMF_INUSE))
+ continue;
+ region_start_iter_least(&vmp->vm_regions_avl, &iter);
+ while((vr = region_get_iter(&iter))) {
+ USE(vr, vr->parent = vmp;);
+ region_incr_iter(&iter);
+ }
+ }
+}
+
#define VM_MMAPBASE VM_PAGE_SIZE
#endif
+extern char _end;
+#define VM_OWN_HEAPSTART ((vir_bytes) (&_end))
+#define VM_OWN_HEAPBASE roundup(VM_OWN_HEAPSTART, VM_PAGE_SIZE)
+#define VM_OWN_MMAPBASE (VM_OWN_HEAPBASE+1024*1024*1024)
+#define VM_OWN_MMAPTOP (VM_OWN_MMAPBASE+100 * 1024 * 1024)
+
#endif
#define VMF_INUSE 0x001 /* slot contains a process */
#define VMF_EXITING 0x002 /* PM is cleaning up this process */
#define VMF_WATCHEXIT 0x008 /* Store in queryexit table */
+#define VMF_VM_INSTANCE 0x010 /* This is a VM process instance */
#endif