]> Zhao Yanbai Git Server - minix.git/commitdiff
VM information interface
authorDavid van Moolenbroek <david@minix3.org>
Tue, 19 Jan 2010 21:00:20 +0000 (21:00 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Tue, 19 Jan 2010 21:00:20 +0000 (21:00 +0000)
18 files changed:
etc/system.conf
include/minix/com.h
include/minix/vm.h
lib/syslib/Makefile.in
lib/syslib/vm_ctl.c [deleted file]
lib/syslib/vm_info.c [new file with mode: 0644]
servers/is/Makefile
servers/is/dmp.c
servers/is/dmp_ds.c
servers/is/dmp_vm.c [new file with mode: 0644]
servers/rs/service.c
servers/vm/alloc.c
servers/vm/glo.h
servers/vm/i386/vm.c
servers/vm/main.c
servers/vm/proto.h
servers/vm/region.c
servers/vm/utility.c

index d8d0c9a9fada60d947575948a5dbc2c2ae39b762..276f832b42650f51c2248b49016e2010b25be8f5 100644 (file)
@@ -200,7 +200,7 @@ service is
                SYSCTL          # 44
        ;
        vm
-               CTL
+               INFO
        ;
        uid 0;
 };
index 0386e6c24ece03b2301fa422279a1215b018e030..443e504268fa06be24674afef009a281c49b1978 100644 (file)
 #      define VM_NOTIFY_SIG_ENDPOINT   m1_i1
 #      define VM_NOTIFY_SIG_IPC        m1_i2
 
-#define VM_CTL                 (VM_RQ_BASE+40)
-#define VCTL_WHAT                      m1_i1
-#define VCTL_PARAM                     m1_i2
-
-/* VCTL_PARAMs */
-#define VCTLP_STATS_MEM                        1
-#define VCTLP_STATS_EP                 2
+#define VM_INFO                        (VM_RQ_BASE+40)
+#      define VMI_WHAT                 m2_i1
+#      define VMI_EP                   m2_i2
+#      define VMI_COUNT                m2_i3
+#      define VMI_PTR                  m2_p1
+#      define VMI_NEXT                 m2_l1
+
+/* VMI_WHAT values. */
+#define VMIW_STATS                     1
+#define VMIW_USAGE                     2
+#define VMIW_REGION                    3
 
 /* Total. */
 #define NR_VM_CALLS                            41
index 496abc6622e120c0ee31583e01ad92f3d04b379f..3755dfa96de4567ed00ad9fe74b3e9a4c727cf8f 100644 (file)
@@ -27,5 +27,34 @@ _PROTOTYPE( int vm_ctl, (int what, int param));
 _PROTOTYPE( int vm_set_priv, (int procnr, void *buf));
 _PROTOTYPE( int vm_query_exit, (int *endpt));
 
+struct vm_stats_info {
+  int vsi_pagesize;            /* page size */
+  int vsi_total;               /* total number of memory pages */
+  int vsi_free;                        /* number of free pages */
+  int vsi_largest;             /* largest number of consecutive free pages */
+};
+
+struct vm_usage_info {
+  vir_bytes vui_total;         /* total amount of process memory */
+  vir_bytes vui_common;                /* part of memory mapped in more than once */
+  vir_bytes vui_shared;                /* shared (non-COW) part of common memory */
+};
+
+struct vm_region_info {
+  int vri_seg;                 /* segment of virtual region (T or D) */
+  vir_bytes vri_addr;          /* base address of region */
+  vir_bytes vri_length;                /* length of region */
+  int vri_prot;                        /* protection flags (PROT_) */
+  int vri_flags;               /* memory flags (subset of MAP_) */
+};
+
+#define MAX_VRI_COUNT  64      /* max. number of regions provided at once */
+
+_PROTOTYPE( int vm_info_stats, (struct vm_stats_info *vfi)             );
+_PROTOTYPE( int vm_info_usage, (endpoint_t who,
+       struct vm_usage_info *vui)                                      );
+_PROTOTYPE( int vm_info_region, (endpoint_t who,
+       struct vm_region_info *vri, int count, vir_bytes *next)         );
+
 #endif /* _MINIX_VM_H */
 
index 9549cc31b578ba9c39296a7bf7979e230cbfd758..34416a6cee3f1bbef008b4ddd30b4d04c60fb7d6 100644 (file)
@@ -80,11 +80,11 @@ libsys_FILES=" \
        taskcall.c \
        ds.c    \
        vm_brk.c \
-       vm_ctl.c \
        vm_exec_newmem.c \
        vm_exit.c \
        vm_notify_sig.c \
        vm_fork.c \
+       vm_info.c \
        vm_map_phys.c \
        vm_umap.c \
        vm_push_sig.c"
diff --git a/lib/syslib/vm_ctl.c b/lib/syslib/vm_ctl.c
deleted file mode 100644 (file)
index 545d5cc..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-
-#include "syslib.h"
-
-#include <minix/vm.h>
-
-/*===========================================================================*
- *                                vm_umap                                   *
- *===========================================================================*/
-PUBLIC int vm_ctl(int what, int param)
-{
-    message m;
-    int result;
-
-    m.VCTL_WHAT = what;
-    m.VCTL_PARAM = param;
-    return _taskcall(VM_PROC_NR, VM_CTL, &m);
-}
-
diff --git a/lib/syslib/vm_info.c b/lib/syslib/vm_info.c
new file mode 100644 (file)
index 0000000..88fdc07
--- /dev/null
@@ -0,0 +1,54 @@
+
+#include "syslib.h"
+
+#include <minix/vm.h>
+
+/*===========================================================================*
+ *                                vm_info_stats                                     *
+ *===========================================================================*/
+PUBLIC int vm_info_stats(struct vm_stats_info *vsi)
+{
+    message m;
+
+    m.VMI_WHAT = VMIW_STATS;
+    m.VMI_PTR = (void *) vsi;
+
+    return _taskcall(VM_PROC_NR, VM_INFO, &m);
+}
+
+/*===========================================================================*
+ *                                vm_info_usage                                     *
+ *===========================================================================*/
+PUBLIC int vm_info_usage(endpoint_t who, struct vm_usage_info *vui)
+{
+    message m;
+
+    m.VMI_WHAT = VMIW_USAGE;
+    m.VMI_EP = who;
+    m.VMI_PTR = (void *) vui;
+
+    return _taskcall(VM_PROC_NR, VM_INFO, &m);
+}
+
+/*===========================================================================*
+ *                                vm_info_region                            *
+ *===========================================================================*/
+PUBLIC int vm_info_region(endpoint_t who, struct vm_region_info *vri,
+       int count, vir_bytes *next)
+{
+    message m;
+    int result;
+
+    m.VMI_WHAT = VMIW_REGION;
+    m.VMI_EP = who;
+    m.VMI_COUNT = count;
+    m.VMI_PTR = (void *) vri;
+    m.VMI_NEXT = *next;
+
+    if ((result = _taskcall(VM_PROC_NR, VM_INFO, &m)) != OK)
+        return result;
+
+    *next = m.VMI_NEXT;
+    return m.VMI_COUNT;
+}
+
index 5edfab3ff3f5b0cdc4148f4d770ef5b730d730fc..59404167ed5b4113d73372488824d464e7287458 100644 (file)
@@ -20,7 +20,7 @@ CFLAGS = $(CPROFILE) $(CPPFLAGS)
 LDFLAGS = -i
 LIBS = -lsys 
 
-OBJ = main.o dmp.o dmp_kernel.o dmp_pm.o dmp_fs.o dmp_rs.o dmp_ds.o 
+OBJ = main.o dmp.o dmp_kernel.o dmp_pm.o dmp_fs.o dmp_rs.o dmp_ds.o dmp_vm.o
 
 # build local binary
 all build:     $(SERVER)
index 75618a0f3338183a128363034f3394da29fc91a9..f5d9c782be40ab72573ba51babf7b6ed755a60f3 100644 (file)
@@ -23,7 +23,7 @@ struct hook_entry {
        { F5,   monparams_dmp, "Boot monitor parameters" },
        { F6,   irqtab_dmp, "IRQ hooks and policies" },
        { F7,   kmessages_dmp, "Kernel messages" },
-       { F8,   vm_dmp, "VM status" },
+       { F8,   vm_dmp, "VM status and process maps" },
        { F10,  kenv_dmp, "Kernel parameters" },
        { F11,  timing_dmp, "Timing details (if enabled)" },
        { SF1,  mproc_dmp, "Process manager process table" },
@@ -126,12 +126,3 @@ PUBLIC void mapping_dmp(void)
       printf(" %10s.  %s\n", key_name(hooks[h].key), hooks[h].name);
   printf("\n");
 }
-
-/*===========================================================================*
- *                             vm_dmp                               *
- *===========================================================================*/
-PUBLIC void vm_dmp(void)
-{
-       vm_ctl(VCTLP_STATS_MEM, 0);
-
-}
index 5e9086cd16243ae8051d06cef35852cc048d98f5..8d6769078f814bb98cd645fd9c035659e4bd8cb0 100644 (file)
@@ -1,6 +1,8 @@
 #include "inc.h"
 #include "../ds/store.h"
 
+#define LINES 22
+
 PRIVATE struct data_store ds_store[NR_DS_KEYS];
 
 PUBLIC void data_store_dmp()
@@ -16,7 +18,7 @@ PUBLIC void data_store_dmp()
 
   printf("Data store contents:\n");
   printf("-slot- ------key------ -----owner----- ---type--- ----value---\n");
-  for(i = prev_i; i < NR_DS_KEYS; i++) {
+  for(i = prev_i; i < NR_DS_KEYS && n < LINES; i++) {
        p = &ds_store[i];
        if(!(p->flags & DSF_IN_USE))
                continue;
@@ -43,8 +45,7 @@ PUBLIC void data_store_dmp()
                return;
        }
 
-       if(n++ == 21)
-               break;
+       n++;
   }
 
   if (i >= NR_DS_KEYS) i = 0;
diff --git a/servers/is/dmp_vm.c b/servers/is/dmp_vm.c
new file mode 100644 (file)
index 0000000..3201a1f
--- /dev/null
@@ -0,0 +1,119 @@
+/* Debugging dump procedures for the VM server. */
+
+#include "inc.h"
+#include <sys/mman.h>
+#include <minix/vm.h>
+#include <timers.h>
+#include "../../kernel/proc.h"
+
+#define LINES 24
+
+PRIVATE void print_region(struct vm_region_info *vri)
+{
+  char c;
+
+  switch (vri->vri_seg) {
+  case T: c = 'T'; break;
+  case D: c = 'D'; break;
+  default: c = '?';
+  }
+
+  printf("  %c %08lx-%08lx %c%c%c %c (%lu kB)\n", c, 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_SHARED) ? 's' : 'p',
+       vri->vri_length / 1024L);
+}
+
+PUBLIC void vm_dmp()
+{
+  static struct proc proc[NR_TASKS + NR_PROCS];
+  static struct vm_region_info vri[LINES];
+  struct vm_stats_info vsi;
+  struct vm_usage_info vui;
+  static int prev_i = -1;
+  static vir_bytes prev_base = 0;
+  int r, r2, i, j, first, n = 0;
+
+  if (prev_i == -1) {
+       if ((r = vm_info_stats(&vsi)) != OK) {
+               report("IS", "warning: couldn't talk to VM", r);
+               return;
+       }
+
+       printf("Total %u kB, free %u kB, largest free area %u kB\n",    
+               vsi.vsi_total * (vsi.vsi_pagesize / 1024),
+               vsi.vsi_free * (vsi.vsi_pagesize / 1024),
+               vsi.vsi_largest * (vsi.vsi_pagesize / 1024));
+       n++;
+       printf("\n");
+       n++;
+
+       prev_i++;
+  }
+
+  if ((r = sys_getproctab(proc)) != OK) {
+       report("IS", "warning: couldn't get copy of process table", r);
+       return;
+  }
+
+  for (i = prev_i; i < NR_TASKS + NR_PROCS && n < LINES; i++, prev_base = 0) {
+       if (i < NR_TASKS || isemptyp(&proc[i])) continue;
+
+       /* The first batch dump for each process contains a header line. */
+       first = prev_base == 0;
+
+       r = vm_info_region(proc[i].p_endpoint, vri, LINES - first, &prev_base);
+
+       if (r < 0) {
+               printf("Process %d (%s): error %d\n",
+                       proc[i].p_endpoint, proc[i].p_name, r);
+               n++;
+               continue;
+       }
+
+       if (first) {
+               /* The entire batch should fit on the screen. */
+               if (n + 1 + r > LINES) {
+                       prev_base = 0;  /* restart on next page */
+                       break;
+               }
+
+               if ((r2 = vm_info_usage(proc[i].p_endpoint, &vui)) != OK) {
+                       printf("Process %d (%s): error %d\n",
+                               proc[i].p_endpoint, proc[i].p_name, r2);
+                       n++;
+                       continue;
+               }
+
+               printf("Process %d (%s): total %lu kB, common %lu kB, "
+                       "shared %lu kB\n",
+                       proc[i].p_endpoint, proc[i].p_name,
+                       vui.vui_total / 1024L, vui.vui_common / 1024L,
+                       vui.vui_shared / 1024L);
+               n++;
+       }
+
+       for (j = 0; j < r; j++) {
+               print_region(&vri[j]);
+               n++;
+       }
+
+       if (n > LINES) printf("IS: internal error\n");
+       if (n == LINES) break;
+
+       /* This may have to wipe out the "--more--" from below. */
+       printf("        \n");
+       n++;
+  }
+
+  if (i >= NR_TASKS + NR_PROCS) {
+       i = -1;
+       prev_base = 0;
+  }
+  else printf("--more--\r");
+  prev_i = i;
+}
+
index d6d26dc98807dc37c64955dda372705a70f0930a..695ece7b4477121954296b26ebd95328ca50d6d7 100644 (file)
@@ -803,7 +803,7 @@ struct
        { "GETPHYS",            VM_GETPHYS },
        { "GETREFCNT",          VM_GETREF },
        { "QUERYEXIT",          VM_QUERY_EXIT },
-       { "CTL",                VM_CTL },
+       { "INFO",               VM_INFO },
        { NULL,                 0 },
 };
 
index 0af48ed8afce34e8cd4a9481bf41a2a340e80786..5ce525927078b6cde1ddaa8ccaccc67a20b3d13e 100644 (file)
@@ -405,6 +405,8 @@ struct memory *chunks;              /* list of free memory chunks */
 
   addr_init(&addravl);
 
+  total_pages = 0;
+
   /* Use the chunks of physical memory to allocate holes. */
   for (i=NR_MEMS-1; i>=0; i--) {
        if (chunks[i].size > 0) {
@@ -413,6 +415,7 @@ struct memory *chunks;              /* list of free memory chunks */
                if(first || from < mem_low) mem_low = from;
                if(first || to > mem_high) mem_high = to;
                FREE_MEM(chunks[i].base, chunks[i].size);
+               total_pages += chunks[i].size;
                first = 0;
        }
   }
index 0889a8f0666cff5b3842d6abe7d25df82904d1fc..49f82ec82a052623f9c9db6ea83a7f5d6bdb5b72 100644 (file)
@@ -24,6 +24,9 @@ EXTERN int incheck;
 EXTERN long vm_sanitychecklevel;
 #endif
 
+/* total number of memory pages */
+EXTERN int total_pages;
+
 /* vm operation mode state and values */
 EXTERN long vm_paged;
 
index 0f4be46ead74680a1dcdf6c314586bee7fdf01c7..f23534e7a211df4a59ed5318c06cc45e46458802 100644 (file)
@@ -61,6 +61,36 @@ PUBLIC char *arch_map2str(struct vmproc *vmp, vir_bytes addr)
        return bufstr;
 }
 
+/*===========================================================================*
+ *                             arch_map2info                                *
+ *===========================================================================*/
+PUBLIC vir_bytes arch_map2info(struct vmproc *vmp, vir_bytes addr, int *seg,
+       int *prot)
+{
+       vir_bytes textstart = CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys);
+       vir_bytes textend = textstart +
+               CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_len);
+       vir_bytes datastart = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys);
+
+       /* The protection to be returned here is that of the segment. */
+       if(addr < textstart) {
+               *seg = D;
+               *prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+               return addr;
+       } else if(addr < datastart) {
+               *seg = T;
+               *prot = PROT_READ | PROT_EXEC;
+               return addr - textstart;
+       } else {
+               *seg = D;
+               if (textstart == textend)       /* common I&D? */
+                       *prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+               else
+                       *prot = PROT_READ | PROT_WRITE;
+               return addr - datastart;
+       }
+}
+
 /*===========================================================================*
  *                             arch_addrok                                  *
  *===========================================================================*/
index fcf0976667f8ca397f138b3ceef58b021829538c..c734f6c0e698146b06ac050d5f680ae17668a2d2 100644 (file)
@@ -347,7 +347,7 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
        CALLMAP(VM_GETPHYS, do_get_phys);
        CALLMAP(VM_SHM_UNMAP, do_shared_unmap);
        CALLMAP(VM_GETREF, do_get_refcount);
-       CALLMAP(VM_CTL, do_ctl);
+       CALLMAP(VM_INFO, do_info);
        CALLMAP(VM_QUERY_EXIT, do_query_exit);
 
        /* Sanity checks */
index daf6ac983a33698fb16fb8cf14c4ee7d5b15b0d8..d7d296d8404fab4547efe8ddc4abf50cdc51ae67 100644 (file)
@@ -10,6 +10,7 @@ struct phys_region;
 #include <minix/ipc.h>
 #include <minix/endpoint.h>
 #include <minix/safecopies.h>
+#include <minix/vm.h>
 #include <timers.h>
 #include <stdio.h>
 #include <pagetable.h>
@@ -42,7 +43,7 @@ _PROTOTYPE( void reserve_proc_mem, (struct memory *mem_chunks,
         struct mem_map *map_ptr));
 _PROTOTYPE( int vm_isokendpt, (endpoint_t ep, int *proc)            );
 _PROTOTYPE( int get_stack_ptr, (int proc_nr, vir_bytes *sp)             );
-_PROTOTYPE( int do_ctl, (message *)             );
+_PROTOTYPE( int do_info, (message *)                                   );
 
 /* exit.c */
 _PROTOTYPE( void clear_proc, (struct vmproc *vmp)                      );
@@ -168,16 +169,22 @@ _PROTOTYPE(int map_copy_ph_block, (struct vmproc *vmp,
        struct vir_region *region, struct phys_region *ph));
 _PROTOTYPE(void pb_unreferenced, (struct vir_region *region,
        struct phys_region *pr));
+_PROTOTYPE(void get_usage_info, (struct vmproc *vmp,
+       struct vm_usage_info *vui));
+_PROTOTYPE(int get_region_info, (struct vmproc *vmp,
+       struct vm_region_info *vri, int count, vir_bytes *nextp));
 #if SANITYCHECKS
 _PROTOTYPE(void map_sanitycheck,(char *file, int line));
 #endif
 
 /* $(ARCH)/vm.c */
-_PROTOTYPE( vir_bytes, arch_map2vir(struct vmproc *vmp, vir_bytes addr));
-_PROTOTYPE( char *, arch_map2str(struct vmproc *vmp, vir_bytes addr));
-_PROTOTYPE( vir_bytes, arch_vir2map(struct vmproc *vmp, vir_bytes addr));
-_PROTOTYPE( vir_bytes, arch_vir2map_text(struct vmproc *vmp, vir_bytes addr));
-_PROTOTYPE( vir_bytes, arch_addrok(struct vmproc *vmp, vir_bytes addr));
+_PROTOTYPE( vir_bytes arch_map2vir, (struct vmproc *vmp, vir_bytes addr));
+_PROTOTYPE( char *arch_map2str, (struct vmproc *vmp, vir_bytes addr));
+_PROTOTYPE( vir_bytes arch_map2info, (struct vmproc *vmp, vir_bytes addr,
+       int *space, int *prot));
+_PROTOTYPE( vir_bytes arch_vir2map, (struct vmproc *vmp, vir_bytes addr));
+_PROTOTYPE( vir_bytes arch_vir2map_text, (struct vmproc *vmp, vir_bytes addr));
+_PROTOTYPE( vir_bytes arch_addrok, (struct vmproc *vmp, vir_bytes addr));
 
 /* rs.c */
 _PROTOTYPE(int do_rs_set_priv, (message *m));
index 33768ada77abfe764bf4efdc60716df00ce5d2c7..616c5c51e9e7b7b89544df41fb733b29d532bcac 100644 (file)
@@ -1455,6 +1455,76 @@ PUBLIC int map_get_ref(struct vmproc *vmp, vir_bytes addr, u8_t *cnt)
        return OK;
 }
 
+/*========================================================================*
+ *                             get_usage_info                            *
+ *========================================================================*/
+PUBLIC void get_usage_info(struct vmproc *vmp, struct vm_usage_info *vui)
+{
+       struct vir_region *vr;
+       physr_iter iter;
+       struct phys_region *ph;
+       vir_bytes len;
+
+       memset(vui, 0, sizeof(*vui));
+
+       for(vr = vmp->vm_regions; vr; vr = vr->next) {
+               physr_start_iter_least(vr->phys, &iter);
+               while((ph = physr_get_iter(&iter))) {
+                       len = ph->ph->length;
+
+                       /* All present pages are counted towards the total. */
+                       vui->vui_total += len;
+
+                       if (ph->ph->refcount > 1) {
+                               /* Any page with a refcount > 1 is common. */
+                               vui->vui_common += len;
+       
+                               /* Any common, non-COW page is shared. */
+                               if (vr->flags & VR_SHARED ||
+                                       ph->ph->share_flag == PBSH_SMAP)
+                                       vui->vui_shared += len;
+                       }
+                       physr_incr_iter(&iter);
+               }
+       }
+}
+
+/*===========================================================================*
+ *                             get_region_info                              *
+ *===========================================================================*/
+PUBLIC int get_region_info(struct vmproc *vmp, struct vm_region_info *vri,
+       int max, vir_bytes *nextp)
+{
+       struct vir_region *vr;
+       vir_bytes next;
+       int count;
+
+       next = *nextp;
+
+       if (!max) return 0;
+
+       for(vr = vmp->vm_regions; vr; vr = vr->next)
+               if (vr->vaddr >= next) break;
+
+       if (!vr) return 0;
+
+       for(count = 0; vr && count < max; vr = vr->next, count++, vri++) {
+               vri->vri_addr = arch_map2info(vmp, vr->vaddr, &vri->vri_seg,
+                       &vri->vri_prot);
+               vri->vri_length = vr->length;
+
+               /* "AND" the provided protection with per-page protection. */
+               if (!(vr->flags & VR_WRITABLE))
+                       vri->vri_prot &= ~PROT_WRITE;
+
+               vri->vri_flags = (vr->flags & VR_SHARED) ? MAP_SHARED : 0;
+
+               next = vr->vaddr + vr->length;
+       }
+
+       *nextp = next;
+       return count;
+}
 
 /*========================================================================*
  *                             regionprintstats                          *
index a9d4182b65299b1c61f54b8e7c0d8794615cb67e..bebf9fb51be086f96d1cc6c419042b061aa7b6c1 100644 (file)
@@ -122,7 +122,7 @@ PUBLIC int vm_isokendpt(endpoint_t endpoint, int *proc)
 {
         *proc = _ENDPOINT_P(endpoint);
         if(*proc < 0 || *proc >= NR_PROCS)
-               vm_panic("crazy slot number", *proc); 
+               return EINVAL;
         if(*proc >= 0 && endpoint != vmproc[*proc].vm_endpoint)
                 return EDEADSRCDST;
         if(*proc >= 0 && !(vmproc[*proc].vm_flags & VMF_INUSE))
@@ -166,27 +166,82 @@ char *brk_addr;
 }
 
 /*===========================================================================*
- *                              do_ctl                                        *
+ *                              do_info                                      *
  *===========================================================================*/
-PUBLIC int do_ctl(message *m)
+PUBLIC int do_info(message *m)
 {
-       int pages, nodes;
-       int pr;
+       struct vm_stats_info vsi;
+       struct vm_usage_info vui;
+       static struct vm_region_info vri[MAX_VRI_COUNT];
        struct vmproc *vmp;
+       vir_bytes addr, size, next, ptr;
+       int r, pr, dummy, count;
 
-       switch(m->VCTL_WHAT) {
-               case VCTLP_STATS_MEM:
-                       printmemstats();
-                       break;
-               case VCTLP_STATS_EP:
-                       if(vm_isokendpt(m->VCTL_PARAM, &pr) != OK)
-                               return EINVAL;
-                       printregionstats(&vmproc[pr]);
-                       break;
-               default:
+       if (vm_isokendpt(m->m_source, &pr) != OK)
+               return EINVAL;
+       vmp = &vmproc[pr];
+
+       ptr = (vir_bytes) m->VMI_PTR;
+
+       switch(m->VMI_WHAT) {
+       case VMIW_STATS:
+               vsi.vsi_pagesize = VM_PAGE_SIZE;
+               vsi.vsi_total = total_pages;
+               memstats(&dummy, &vsi.vsi_free, &vsi.vsi_largest);
+
+               addr = (vir_bytes) &vsi;
+               size = sizeof(vsi);
+
+               break;
+
+       case VMIW_USAGE:
+               if (vm_isokendpt(m->VMI_EP, &pr) != OK)
+                       return EINVAL;
+
+               get_usage_info(&vmproc[pr], &vui);
+
+               addr = (vir_bytes) &vui;
+               size = sizeof(vui);
+
+               break;
+
+       case VMIW_REGION:
+               if (vm_isokendpt(m->VMI_EP, &pr) != OK)
                        return EINVAL;
+
+               count = MIN(m->VMI_COUNT, MAX_VRI_COUNT);
+               next = m->VMI_NEXT;
+
+               count = get_region_info(&vmproc[pr], vri, count, &next);
+
+               m->VMI_COUNT = count;
+               m->VMI_NEXT = next;
+
+               addr = (vir_bytes) vri;
+               size = sizeof(vri[0]) * count;
+
+               break;
+
+       default:
+               return EINVAL;
        }
 
-       return OK;
+       if (size == 0)
+               return OK;
+
+       /* Make sure that no page faults can occur while copying out. A page
+        * fault would cause the kernel to send a notify to us, while we would
+        * be waiting for the result of the copy system call, resulting in a
+        * deadlock. Note that no memory mapping can be undone without the
+        * involvement of VM, so we are safe until we're done.
+        */
+       r = handle_memory(vmp, arch_vir2map(vmp, ptr), size, 1 /*wrflag*/);
+       if (r != OK) return r;
+
+       /* Now that we know the copy out will succeed, perform the actual copy
+        * operation.
+        */
+       return sys_datacopy(SELF, addr,
+               (vir_bytes) vmp->vm_endpoint, ptr, size);
 }