diff --git a/bochs/plex86/kernel/host-linux.c b/bochs/plex86/kernel/host-linux.c
index 8a69d02a5..587c445f6 100644
--- a/bochs/plex86/kernel/host-linux.c
+++ b/bochs/plex86/kernel/host-linux.c
@@ -48,7 +48,7 @@
 
 
 /************************************************************************/
-/* Compatibility macros for older kernels                               */
+/* Compatibility macros & convenience functions for older kernels       */
 /************************************************************************/
 
 #ifndef EXPORT_NO_SYMBOLS
@@ -66,27 +66,30 @@
 #endif
 
 #if LINUX_VERSION_CODE < VERSION_CODE(2,1,0)
-static inline unsigned long copy_from_user(void *to, const void *from, unsigned long n)
+  static inline unsigned long
+copy_from_user(void *to, const void *from, unsigned long n)
 {
-    int i;
-    if ((i = verify_area(VERIFY_READ, from, n)) != 0)
-        return i;
-    memcpy_fromfs(to, from, n);
-    return 0;
+  int i;
+  if ( (i = verify_area(VERIFY_READ, from, n)) != 0 )
+    return i;
+  memcpy_fromfs(to, from, n);
+  return 0;
 }
-static inline unsigned long copy_to_user(void *to, const void *from, unsigned long n)
+  static inline unsigned long
+copy_to_user(void *to, const void *from, unsigned long n)
 {
-    int i;
-    if ((i = verify_area(VERIFY_WRITE, to, n)) != 0)
-        return i;
-    memcpy_tofs(to, from, n);
-    return 0;
+  int i;
+  if ( (i = verify_area(VERIFY_WRITE, to, n)) != 0 )
+    return i;
+  memcpy_tofs(to, from, n);
+  return 0;
 }
 #endif
 
 #if LINUX_VERSION_CODE >= VERSION_CODE(2,1,18) && !defined(THIS_MODULE)
 /* Starting with version 2.1.18, the __this_module symbol is present,
-   but the THIS_MODULE #define was introduced much later ... */
+ * but the THIS_MODULE #define was introduced much later ...
+ */
 #define THIS_MODULE (&__this_module)
 #endif
 
@@ -103,7 +106,7 @@ MODULE_PARM(plex_major, "i");
 MODULE_PARM_DESC(plex_major, "major number (default " __MODULE_STRING(PLEX86_MAJOR) ")");
 #endif
 
-/* The kernel segment base */
+/* The kernel segment base. */
 #if LINUX_VERSION_CODE < VERSION_CODE(2,1,0)
 #  define KERNEL_OFFSET 0xc0000000
 #else
@@ -111,26 +114,28 @@ MODULE_PARM_DESC(plex_major, "major number (default " __MODULE_STRING(PLEX86_MAJ
 #endif
 
 
-/* File operations */
-static int plex86_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+/* File operations. */
+static int plex86_ioctl(struct inode *, struct file *, unsigned int,
+                        unsigned long);
 static int plex86_open(struct inode *, struct file *);
 
 #if LINUX_VERSION_CODE >= VERSION_CODE(2,1,31)
-    static int plex86_release(struct inode *, struct file *);
+static int plex86_release(struct inode *, struct file *);
 #else
-    static void plex86_release(struct inode *, struct file *);
+static void plex86_release(struct inode *, struct file *);
 #endif
 
 #if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)
-    static int plex86_mmap(struct file * file, struct vm_area_struct * vma);
+static int plex86_mmap(struct file * file, struct vm_area_struct * vma);
 #else
-    static int plex86_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma);
+static int plex86_mmap(struct inode * inode, struct file * file,
+                       struct vm_area_struct * vma);
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
-/* New License scheme */
+/* New License scheme. */
 #ifdef MODULE_LICENSE
-MODULE_LICENSE("GPL"); /* Close enough. */
+MODULE_LICENSE("GPL"); /* Close enough.  Keeps kernel from complaining. */
 #endif
 #endif
 
@@ -140,12 +145,12 @@ MODULE_LICENSE("GPL"); /* Close enough. */
 /* Structures / Variables                                               */
 /************************************************************************/
 
-static int retrieve_vm_pages(Bit32u *page, int max_pages, void *addr, unsigned size);
-static unsigned retrieve_phy_pages(Bit32u *page, int max_pages, void *addr, unsigned size);
+static int retrieve_vm_pages(Bit32u *page, int max_pages, void *addr,
+                             unsigned size);
+static unsigned retrieve_phy_pages(Bit32u *page, int max_pages, void *addr,
+                                   unsigned size);
 static int retrieve_monitor_pages(void);
 
-monitor_pages_t monitor_pages;
-extern unsigned intRedirCount[];
 
 
 static struct file_operations plex86_fops = {
@@ -173,14 +178,14 @@ int plex86_read_procmem(char *, char **, off_t, int, int);
 
 #if LINUX_VERSION_CODE < VERSION_CODE(2,3,25)
 static struct proc_dir_entry plex86_proc_entry = {
-    0,                  /* dynamic inode */
-    6, "driver/plex86",     /* len, name */
-    S_IFREG | S_IRUGO,  /* mode */
-    1, 0, 0,
-    0,
-    NULL,
-    &plex86_read_procmem,  /* read function */
-};
+  0,                  /* dynamic inode */
+  6, "driver/plex86",     /* len, name */
+  S_IFREG | S_IRUGO,  /* mode */
+  1, 0, 0,
+  0,
+  NULL,
+  &plex86_read_procmem,  /* read function */
+  };
 #endif
 
 
@@ -191,95 +196,95 @@ static struct proc_dir_entry plex86_proc_entry = {
   int
 init_module(void)
 {
-    int err;
+  int err;
 
-    /* clear uninitialised structures */
-    memset(&monitor_pages, 0, sizeof(monitor_pages));
+  /* Clear uninitialised structures. */
+  memset(&monitor_pages, 0, sizeof(monitor_pages));
 
-    /* register the device with the kernel */
-    err = register_chrdev(plex_major, "plex86", &plex86_fops);
-    if (err < 0) {
-        printk(KERN_WARNING "plex86: can't get major %d\n", plex_major);
-        return(err);
-        }
-    /* If this was a dynamic allocation, save the major for
-     * the release code
-     */
-    if(!plex_major)
-      plex_major = err;
+  /* Register the device with the kernel. */
+  err = register_chrdev(plex_major, "plex86", &plex86_fops);
+  if (err < 0) {
+    printk(KERN_WARNING "plex86: can't get major %d\n", plex_major);
+    return(err);
+    }
+  /* If this was a dynamic allocation, save the major for
+   * the release code
+   */
+  if(!plex_major)
+    plex_major = err;
 
-    /* register the /proc entry */
+  /* Register the /proc entry. */
 #ifdef CONFIG_PROC_FS
 #if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
-    if (!create_proc_info_entry("driver/plex86", 0, NULL, plex86_read_procmem))
-      printk(KERN_ERR "plex86: registering /proc/driver/plex86 failed\n");
+  if (!create_proc_info_entry("driver/plex86", 0, NULL, plex86_read_procmem))
+    printk(KERN_ERR "plex86: registering /proc/driver/plex86 failed\n");
 #else
-    proc_register_dynamic(&proc_root, &plex86_proc_entry);
+  proc_register_dynamic(&proc_root, &plex86_proc_entry);
 #endif
 #endif
 
-    /* register /dev/misc/plex86 with devfs */
+  /* Register /dev/misc/plex86 with devfs. */
 #ifdef CONFIG_DEVFS_FS
-    my_devfs_entry = devfs_register(NULL, "misc/plex86", 
-                                    DEVFS_FL_DEFAULT, 
-                                    plex_major, 0 /* minor mode*/, 
-                                    S_IFCHR | 0666, &plex86_fops,
-                                    NULL /* "info" */);
-    if (!my_devfs_entry)
-      printk(KERN_ERR "plex86: registering misc/plex86 devfs entry failed\n");
+  my_devfs_entry = devfs_register(NULL, "misc/plex86", 
+                                  DEVFS_FL_DEFAULT, 
+                                  plex_major, 0 /* minor mode*/, 
+                                  S_IFCHR | 0666, &plex86_fops,
+                                  NULL /* "info" */);
+  if (!my_devfs_entry)
+    printk(KERN_ERR "plex86: registering misc/plex86 devfs entry failed\n");
 #endif
 
-    /* retrieve the monitor physical pages */
-    if (!retrieve_monitor_pages()) {
-      printk(KERN_ERR "plex86: retrieve_monitor_pages returned error\n");
-      err = -EINVAL;
-      goto fail_retrieve_pages;
-      }
+  /* Retrieve the monitor physical pages. */
+  if ( !retrieve_monitor_pages() ) {
+    printk(KERN_ERR "plex86: retrieve_monitor_pages returned error\n");
+    err = -EINVAL;
+    goto fail_retrieve_pages;
+    }
 
-    /* Kernel independent code to be run when kernel module is loaded. */
-    if ( !genericModuleInit() ) {
-      printk(KERN_ERR "plex86: genericModuleInit returned error\n");
-      err = -EINVAL;
-      goto fail_cpu_capabilities;
-      }
+  /* Kernel independent code to be run when kernel module is loaded. */
+  if ( !genericModuleInit() ) {
+    printk(KERN_ERR "plex86: genericModuleInit returned error\n");
+    err = -EINVAL;
+    goto fail_cpu_capabilities;
+    }
 
-    /* success */
-    EXPORT_NO_SYMBOLS;
-    return(0);
+  /* Success. */
+  EXPORT_NO_SYMBOLS;
+  return(0);
 
 fail_cpu_capabilities:
 fail_retrieve_pages:
-    /* unregister /proc entry */
+  /* Unregister /proc entry. */
 #ifdef CONFIG_PROC_FS
 #if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
-    remove_proc_entry("driver/plex86", NULL);
+  remove_proc_entry("driver/plex86", NULL);
 #else
-    proc_unregister(&proc_root, plex86_proc_entry.low_ino);
+  proc_unregister(&proc_root, plex86_proc_entry.low_ino);
 #endif
 #endif
 
-    /* unregister device */
-    unregister_chrdev(plex_major, "plex86");
-    return err;
+  /* Unregister device. */
+  unregister_chrdev(plex_major, "plex86");
+  return err;
 }
 
-void
+  void
 cleanup_module(void)
 {
-    /* unregister device */
-    unregister_chrdev(plex_major, "plex86");
+  /* Unregister device. */
+  unregister_chrdev(plex_major, "plex86");
 
-    /* unregister /proc entry */
+  /* Unregister /proc entry. */
 #ifdef CONFIG_PROC_FS
 #if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
-    remove_proc_entry("driver/plex86", NULL);
+  remove_proc_entry("driver/plex86", NULL);
 #else
-    proc_unregister(&proc_root, plex86_proc_entry.low_ino);
+  proc_unregister(&proc_root, plex86_proc_entry.low_ino);
 #endif
 #endif
 
 #ifdef CONFIG_DEVFS_FS
-    devfs_unregister(my_devfs_entry);
+  devfs_unregister(my_devfs_entry);
 #endif
 }
 
@@ -298,7 +303,7 @@ plex86_open(struct inode *inode, struct file *filp)
 #endif
 
   /* Allocate a VM structure. */
-  if ( (vm = vmalloc(sizeof(vm_t))) == NULL )
+  if ( (vm = hostAllocZeroedMem(sizeof(vm_t))) == NULL )
     return -ENOMEM;
   filp->private_data = vm;
   
@@ -316,28 +321,27 @@ plex86_open(struct inode *inode, struct file *filp)
 #endif
 plex86_release(struct inode *inode, struct file *filp)
 {
-    vm_t *vm = (vm_t *)filp->private_data;
-    filp->private_data = NULL;
+  vm_t *vm = (vm_t *)filp->private_data;
+  filp->private_data = NULL;
 
-    /* Free the virtual memory. */
-    hostUnreserveGuestPages( vm );
-    unallocVmPages( vm );
+  /* Free the virtual memory. */
+  unreserveGuestPhyPages(vm);
+  unallocVmPages( vm );
 
-    /* Free the VM structure. */
-    memset( vm, 0, sizeof(*vm) );
-    vfree( vm );
+  /* Free the VM structure. */
+  memset( vm, 0, sizeof(*vm) );
+  vfree( vm );
 
 #if LINUX_VERSION_CODE < VERSION_CODE(2,4,0)
-    MOD_DEC_USE_COUNT;
+  MOD_DEC_USE_COUNT;
 #endif
 
 #if LINUX_VERSION_CODE >= VERSION_CODE(2,1,31)
-    return(0);
+  return(0);
 #endif
 }
 
 
-
   int
 plex86_ioctl(struct inode *inode, struct file *filp,
              unsigned int cmd, unsigned long arg)
@@ -359,116 +363,98 @@ plex86_ioctl(struct inode *inode, struct file *filp,
 }
 
 
-int
+  int
 #if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)
 plex86_mmap(struct file * file, struct vm_area_struct * vma)
 #else
 plex86_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
 #endif
 {
-    vm_t *vm = (vm_t *)file->private_data;
-    int i, firstpage, nr_pages;
-    Bit32u *pagesArray;
-    unsigned stateMask;
+  vm_t *vm = (vm_t *)file->private_data;
+  int firstpage, pagesN;
+#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)
+  void *inode = NULL; /* Not used; for consistency of passing args. */
+#endif
+  int ret;
 
-    /* Must have memory allocated */
-    if (!vm->pages.guest_n_pages) {
-      printk(KERN_WARNING "plex86: device not initialized\n");
-      return -EACCES;
-      }
-
-    /* Private mappings make no sense ... */
-    if ( !(vma->vm_flags & VM_SHARED) ) {
-      printk(KERN_WARNING "plex86: private mapping\n");
-      return -EINVAL;
-      }
+  /* Private mappings make no sense ... */
+  if ( !(vma->vm_flags & VM_SHARED) ) {
+    printk(KERN_WARNING "plex86: private mapping\n");
+    return -EINVAL;
+    }
 
 #if LINUX_VERSION_CODE < VERSION_CODE(2,3,25)
-    /* To simplify things, allow only page-aligned offsets */
-    if ( vma->vm_offset & (PAGE_SIZE - 1) ) {
-      printk(KERN_WARNING "plex86: unaligned offset %08lx\n", vma->vm_offset);
-      return -EINVAL;
-      }
+  /* To simplify things, allow only page-aligned offsets */
+  if ( vma->vm_offset & (PAGE_SIZE - 1) ) {
+    printk(KERN_WARNING "plex86: unaligned offset %08lx\n", vma->vm_offset);
+    return -EINVAL;
+    }
 #endif
 
 
-    /* Map all requested pages in ... */
 #if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
-    firstpage = vma->vm_pgoff;
+  firstpage = vma->vm_pgoff;
 #else
-    firstpage = vma->vm_offset >> PAGE_SHIFT;
+  firstpage = vma->vm_offset >> PAGE_SHIFT;
 #endif
-    nr_pages  = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+  pagesN  = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
 
-    /* The memory map:
-     *   guest physical memory (guest_n_pages)
-     *   log_buffer            (1)
-     *   guest_cpu             (1)
-     */
-    if ( firstpage == 0 ) {
-      if (nr_pages != vm->pages.guest_n_pages) {
-        printk(KERN_WARNING "plex86: mmap of guest phy mem, "
-              "nr_pages of %u != guest_n_pages of %u\n",
-              nr_pages, vm->pages.guest_n_pages);
-        return -EINVAL;
-        }
-      /* printk(KERN_WARNING "plex86: found mmap of guest phy memory.\n"); */
-      pagesArray = &vm->pages.guest[0];
-      stateMask = VMStateMMapPhyMem;
-      }
-    else if ( firstpage == (vm->pages.guest_n_pages+0) ) {
-      if (nr_pages != 1) {
-        printk(KERN_WARNING "plex86: mmap of log_buffer, pages>1.\n");
-        return -EINVAL;
-        }
-      /* printk(KERN_WARNING "plex86: found mmap of log_buffer.\n"); */
-      pagesArray = &vm->pages.log_buffer[0];
-      stateMask = VMStateMMapPrintBuffer;
-      }
-    else if ( firstpage == (vm->pages.guest_n_pages+1) ) {
-      if (nr_pages != 1) {
-        printk(KERN_WARNING "plex86: mmap of guest_cpu, pages>1.\n");
-        return -EINVAL;
-        }
-      /* printk(KERN_WARNING "plex86: found mmap of guest_cpu.\n"); */
-      pagesArray = &vm->pages.guest_cpu;
-      stateMask = VMStateMMapGuestCPU;
-      }
-    else {
-      printk(KERN_WARNING "plex86: mmap with firstpage of 0x%x.\n", firstpage);
-      return -EINVAL;
-      }
+  ret = genericMMap(vm, inode, file, vma, firstpage, pagesN);
+  return( - hostConvertPlex86Errno(ret) );
+}
 
-    /* Sanity check */
+
+  int
+hostMMap(vm_t *vm, void *iV, void *fV, void *vmaV, 
+         unsigned pagesN, Bit32u *pagesArray)
+{
+#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)
+  void *inode = NULL;
+#else
+  struct inode * inode = (struct inode *) iV;
+#endif
+  struct file * file = (struct file *) fV;
+  struct vm_area_struct * vma = (struct vm_area_struct *) vmaV;
+  unsigned i;
+
+  UNUSED(file);
+
+  /* Note: this function returns Plex86Errno style errors, since
+   * it reports to the hostOS-independent logic.
+   */
+
+  /* Sanity check. */
 #if LINUX_VERSION_CODE >= VERSION_CODE(2,3,25)
-    if ( ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) > nr_pages ) {
-      printk(KERN_WARNING "plex86: mmap sanity checks failed.\n");
-      return -EINVAL;
-      }
+  if ( ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) > pagesN ) {
+    printk(KERN_WARNING "plex86: mmap sanity checks failed.\n");
+    return Plex86ErrnoEINVAL;
+    }
 #else
-    if ( (vma->vm_end - vma->vm_start) > (nr_pages << PAGE_SHIFT) ) {
-      printk(KERN_WARNING "plex86: mmap sanity checks failed.\n");
-      return -EINVAL;
-      }
+  if ( (vma->vm_end - vma->vm_start) > (pagesN << PAGE_SHIFT) ) {
+    printk(KERN_WARNING "plex86: mmap sanity checks failed.\n");
+    return Plex86ErrnoEINVAL;
+    }
 #endif
 
-    for ( i = 0; i < nr_pages; i++ ) {
-      if ( remap_page_range(vma->vm_start + (i << PAGE_SHIFT),
-                            pagesArray[i] << 12,
-                            PAGE_SIZE,
-                            vma->vm_page_prot ) )
-        /* xxx What about fixing partial remaps? */
-        return -EAGAIN;
-        }
+  for (i = 0; i < pagesN; i++) {
+    if ( remap_page_range(vma->vm_start + (i << PAGE_SHIFT),
+                          pagesArray[i] << 12,
+                          PAGE_SIZE,
+                          vma->vm_page_prot) )
+      /* xxx What about fixing partial remaps? */
+      return Plex86ErrnoEAGAIN;
+    }
 
 #if LINUX_VERSION_CODE < VERSION_CODE(2,1,0)
-    /* Enter our inode into the VMA; no need to change the default ops */
-    vma->vm_inode = inode;
-    if (!inode->i_count)
-      inode->i_count++;
+  /* Enter our inode into the VMA; no need to change the default ops. */
+  vma->vm_inode = inode;
+  if (!inode->i_count)
+    inode->i_count++;
+#else
+  UNUSED(inode);
 #endif
-    vm->vmState |= stateMask;
-    return 0;
+
+  return 0; /* OK. */
 }
 
 
@@ -480,235 +466,220 @@ plex86_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vm
   int
 plex86_read_procmem(char *buf, char **start, off_t offset,
 #if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
-                 int len
+                    int len
 #else
-                 int len, int unused
+                    int len, int unused
 #endif
-                 )
+                    )
 {
-    unsigned i;
-    len = 0;
-    len += sprintf(buf, "monitor-->host interrupt reflection counts\n");
-    for (i=0; i<256; i++) {
+  unsigned i;
+  len = 0;
+  len += sprintf(buf, "monitor-->host interrupt reflection counts\n");
+  for (i=0; i<256; i++) {
     if (intRedirCount[i])
-        len += sprintf(buf+len, "  0x%2x:%10u\n", i, intRedirCount[i]);
+      len += sprintf(buf+len, "  0x%2x:%10u\n", i, intRedirCount[i]);
     }
-    return(len);
+  return(len);
 }
 
 
+#warning "Consolidate retrieve_XYZ() functions?"
+  int
+retrieve_monitor_pages(void)
+{
+  /* 
+   * Retrieve start address and size of this module.
+   *
+   * Note that with old kernels, we cannot access the module info (size),
+   * hence we rely on the fact that Linux lets at least one page of 
+   * virtual address space unused after the end of the module.
+   */
+#ifdef THIS_MODULE
+  void *start_addr = THIS_MODULE;
+  unsigned size    = THIS_MODULE->size;
+#else
+  void *start_addr = &mod_use_count_;
+  unsigned size    = 0x10000000;  /* Actual size determined below */
+#endif
+
+  int n_pages;
+
+  n_pages = retrieve_vm_pages(monitor_pages.page, PLEX86_MAX_MONITOR_PAGES,
+                              start_addr, size);
+  if (n_pages == 0) {
+    printk(KERN_ERR "plex86: retrieve_vm_pages returned error.\n");
+    return( 0 ); /* Error. */
+    }
+  printk(KERN_WARNING "plex86: %u monitor pages located\n", n_pages);
+
+  monitor_pages.startOffset = (Bit32u)start_addr;
+  monitor_pages.startOffsetPageAligned = monitor_pages.startOffset & 0xfffff000;
+  monitor_pages.n_pages    = n_pages;
+  return( n_pages );
+}
+
   int
 retrieve_vm_pages(Bit32u *page, int max_pages, void *addr, unsigned size)
 {
-    /*  
-     * Grrr.  There doesn't seem to be an exported mechanism to retrieve
-     * the physical pages underlying a vmalloc()'ed area.  We do it the
-     * hard way ... 
-     */
-    pageEntry_t *host_pgd;
-    Bit32u host_cr3;
-    Bit32u start_addr;
-    int n_pages;
-    int i;
+  /*  
+   * Grrr.  There doesn't seem to be an exported mechanism to retrieve
+   * the physical pages underlying a vmalloc()'ed area.  We do it the
+   * hard way ... 
+   */
+  pageEntry_t *host_pgd;
+  Bit32u host_cr3;
+  Bit32u start_addr;
+  int n_pages;
+  int i;
 
-    start_addr = ((Bit32u)addr) & 0xfffff000;
-    n_pages = BytesToPages( (((Bit32u)addr) - start_addr) + size );
+  start_addr = ((Bit32u)addr) & 0xfffff000;
+  n_pages = BytesToPages( (((Bit32u)addr) - start_addr) + size );
 
-    if (!addr) {
-      printk(KERN_WARNING "plex86: retrieve_vm_pages: addr NULL!\n");
-      return 0;
-      }
-
-    if ( n_pages > max_pages ) {
-      printk(KERN_WARNING "plex86: retrieve_vm_pages: not enough pages!\n");
-      printk(KERN_WARNING "plex86: npages(%u) > max_pages(%u)\n",
-             n_pages, max_pages);
-      return 0;
-      }
-
-    asm volatile ("movl %%cr3, %0" : "=r" (host_cr3));
-    host_pgd = (pageEntry_t *)(phys_to_virt(host_cr3 & ~0xfff));
-
-    for (i = 0; i < n_pages; i++)
-    {
-        Bit32u virt_addr = start_addr + i*PAGESIZE + KERNEL_OFFSET;
-        pageEntry_t *pde = host_pgd + (virt_addr >> 22);
-        pageEntry_t *pte = (pageEntry_t *)phys_to_virt(pde->fields.base << 12)
-                         + ((virt_addr >> 12) & 0x3ff);
-
-        /* If page isn't present, assume end of area */
-        if ( !pde->fields.P || ! pte->fields.P )
-        {
-            n_pages = i;
-            break;
-        }
-        
-        /* Abort if our page list is too small */
-        if (i >= max_pages)
-        {
-            printk(KERN_WARNING "plex86: page list is too small!\n");
-            printk(KERN_WARNING "plex86: n_pages=%u, max_pages=%u\n",
-                   n_pages, max_pages);
-            return 0;
-        }
-
-        page[i] = pte->fields.base;
+  if (!addr) {
+    printk(KERN_WARNING "plex86: retrieve_vm_pages: addr NULL!\n");
+    return 0;
     }
 
-    return n_pages;
-}
+  if ( n_pages > max_pages ) {
+    printk(KERN_WARNING "plex86: retrieve_vm_pages: not enough pages!\n");
+    printk(KERN_WARNING "plex86: npages(%u) > max_pages(%u)\n",
+           n_pages, max_pages);
+    return 0;
+    }
 
-  int
-retrieve_monitor_pages(void)
-{
-    /* 
-     * Retrieve start address and size of this module.
-     *
-     * Note that with old kernels, we cannot access the module info (size),
-     * hence we rely on the fact that Linux lets at least one page of 
-     * virtual address space unused after the end of the module.
-     */
-#ifdef THIS_MODULE
-    void *start_addr = THIS_MODULE;
-    unsigned size    = THIS_MODULE->size;
-#else
-    void *start_addr = &mod_use_count_;
-    unsigned size    = 0x10000000;  /* Actual size determined below */
-#endif
+  asm volatile ("movl %%cr3, %0" : "=r" (host_cr3));
+  host_pgd = (pageEntry_t *)(phys_to_virt(host_cr3 & ~0xfff));
 
-    int n_pages;
+  for (i = 0; i < n_pages; i++) {
+    Bit32u virt_addr = start_addr + i*PAGESIZE + KERNEL_OFFSET;
+    pageEntry_t *pde = host_pgd + (virt_addr >> 22);
+    pageEntry_t *pte = (pageEntry_t *)phys_to_virt(pde->fields.base << 12)
+                       + ((virt_addr >> 12) & 0x3ff);
 
-    n_pages = retrieve_vm_pages(monitor_pages.page, PLEX86_MAX_MONITOR_PAGES,
-                                    start_addr, size);
-    if (n_pages == 0) {
-      printk(KERN_ERR "plex86: retrieve_vm_pages returned error.\n");
-      return( 0 ); /* Error. */
+    /* If page isn't present, assume end of area. */
+    if ( !pde->fields.P || ! pte->fields.P ) {
+      n_pages = i;
+      break;
+      }
+    
+    /* Abort if our page list is too small */
+    if (i >= max_pages) {
+      printk(KERN_WARNING "plex86: page list is too small!\n");
+      printk(KERN_WARNING "plex86: n_pages=%u, max_pages=%u\n",
+           n_pages, max_pages);
+      return 0;
       }
-    printk(KERN_WARNING "plex86: %u monitor pages located\n", n_pages);
 
-    monitor_pages.startOffset = (Bit32u)start_addr;
-    monitor_pages.startOffsetPageAligned =
-        monitor_pages.startOffset & 0xfffff000;
-    monitor_pages.n_pages    = n_pages;
-    return( n_pages );
+    page[i] = pte->fields.base;
+    }
+
+  return n_pages;
 }
 
-  void
-hostReserveGuestPages(vm_t *vm)
-{
-    vm_pages_t *pg = &vm->pages;
-    unsigned p;
-
-    /*
-     * As we want to map these pages to user space, we need to mark
-     * them as 'reserved' pages by setting the PG_reserved bit.
-     *
-     * This has the effect that:
-     *  - remap_page_range accepts them as candidates for remapping
-     *  - the swapper does *not* try to swap these pages out, even
-     *    after they are mapped to user space
-     */
-
-#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
-    for (p = 0; p < pg->guest_n_pages; p++)
-      set_bit(PG_reserved, &((mem_map + pg->guest[p])->flags));
-    set_bit(PG_reserved, &((mem_map + pg->log_buffer[0])->flags));
-    set_bit(PG_reserved, &((mem_map + pg->guest_cpu)->flags));
-#else
-    for (p = 0; p < pg->guest_n_pages; p++)
-      mem_map_reserve(pg->guest[p]);
-    mem_map_reserve(pg->log_buffer[0]);
-    mem_map_reserve(pg->guest_cpu);
-#endif
-}
-
-  void
-hostUnreserveGuestPages(vm_t *vm)
-{
-    vm_pages_t *pg = &vm->pages;
-    unsigned p;
-
-    /* Remove the PG_reserved flags before returning the pages */
-#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
-    for (p = 0; p < pg->guest_n_pages; p++)
-      clear_bit(PG_reserved, &((mem_map + pg->guest[p])->flags));
-    clear_bit(PG_reserved, &((mem_map + pg->log_buffer[0])->flags));
-    clear_bit(PG_reserved, &((mem_map + pg->guest_cpu)->flags));
-#else
-    for (p = 0; p < pg->guest_n_pages; p++)
-      mem_map_unreserve(pg->guest[p]);
-    mem_map_unreserve(pg->log_buffer[0]);
-    mem_map_unreserve(pg->guest_cpu);
-#endif
-}
-
-
   unsigned
 retrieve_phy_pages(Bit32u *page, int max_pages, void *addr_v, unsigned size)
 {
-    /*  
-     * Grrr.  There doesn't seem to be an exported mechanism to retrieve
-     * the physical pages underlying a vmalloc()'ed area.  We do it the
-     * hard way ... 
-     */
-    pageEntry_t *host_pgd;
-    Bit32u host_cr3;
-    /*Bit32u start_addr = (Bit32u)addr & ~(PAGESIZE-1); */
-    /*int n_pages = ((Bit32u)addr + size - start_addr + PAGESIZE-1) >> 12; */
-    int i;
-    Bit8u *addr;
-    unsigned n_pages;
+  /*  
+   * Grrr.  There doesn't seem to be an exported mechanism to retrieve
+   * the physical pages underlying a vmalloc()'ed area.  We do it the
+   * hard way ... 
+   */
+  pageEntry_t *host_pgd;
+  Bit32u host_cr3;
+  /*Bit32u start_addr = (Bit32u)addr & ~(PAGESIZE-1); */
+  /*int n_pages = ((Bit32u)addr + size - start_addr + PAGESIZE-1) >> 12; */
+  int i;
+  Bit8u *addr;
+  unsigned n_pages;
 
-    addr = (Bit8u *) addr_v;
-    if ( ((Bit32u)addr) & 0xfff ) {
-      printk(KERN_ERR "plex86: retrieve_phy_pages: not aligned!\n");
+  addr = (Bit8u *) addr_v;
+  if ( ((Bit32u)addr) & 0xfff ) {
+    printk(KERN_ERR "plex86: retrieve_phy_pages: not aligned!\n");
+    return 0;
+    }
+  n_pages = BytesToPages(size);
+  if (!addr) {
+    printk(KERN_ERR "plex86: retrieve_phy_pages: addr NULL!\n");
+    return 0;
+    }
+
+  if ( n_pages > max_pages ) {
+    printk(KERN_ERR "plex86: retrieve_phy_pages: n=%u > max=%u\n",
+       n_pages, max_pages);
+    return 0;
+    }
+
+  asm volatile ("movl %%cr3, %0" : "=r" (host_cr3));
+  host_pgd = (pageEntry_t *)(phys_to_virt(host_cr3 & ~0xfff));
+
+  for (i = 0; i < n_pages; i++) {
+    Bit32u laddr;
+    pageEntry_t *pde;
+    pageEntry_t *pte;
+
+    laddr = KERNEL_OFFSET + ((Bit32u) addr);
+    pde = host_pgd + (laddr >> 22);
+    pte = ((pageEntry_t *)phys_to_virt(pde->fields.base << 12))
+          + ((laddr >> 12) & 0x3ff);
+    if ( !pde->fields.P ) {
+      printk(KERN_ERR "plex86: retrieve_phy_pages: "
+                      "PDE.P==0: i=%u, n=%u laddr=0x%x\n", i, n_pages, laddr);
       return 0;
       }
-    n_pages = BytesToPages(size);
-    if (!addr) {
-      printk(KERN_ERR "plex86: retrieve_phy_pages: addr NULL!\n");
+    if ( !pte->fields.P ) {
+      printk(KERN_ERR "plex86: retrieve_phy_pages: "
+                      "PTE.P==0: i=%u, n=%u laddr=0x%x\n", i, n_pages, laddr);
       return 0;
       }
-
-    if ( n_pages > max_pages ) {
-      printk(KERN_ERR "plex86: retrieve_phy_pages: n=%u > max=%u\n",
-             n_pages, max_pages);
-      return 0;
-      }
-
-    asm volatile ("movl %%cr3, %0" : "=r" (host_cr3));
-    host_pgd = (pageEntry_t *)(phys_to_virt(host_cr3 & ~0xfff));
-
-    for (i = 0; i < n_pages; i++) {
-      Bit32u laddr;
-      pageEntry_t *pde;
-      pageEntry_t *pte;
-
-      laddr = KERNEL_OFFSET + ((Bit32u) addr);
-      pde = host_pgd + (laddr >> 22);
-      pte = ((pageEntry_t *)phys_to_virt(pde->fields.base << 12))
-                         + ((laddr >> 12) & 0x3ff);
-      if ( !pde->fields.P ) {
-        printk(KERN_ERR "plex86: retrieve_phy_pages: PDE.P==0: i=%u, n=%u laddr=0x%x\n",
-               i, n_pages, laddr);
-        return 0;
-        }
-      if ( !pte->fields.P ) {
-        printk(KERN_ERR "plex86: retrieve_phy_pages: PTE.P==0: i=%u, n=%u laddr=0x%x\n",
-               i, n_pages, laddr);
-        return 0;
-        }
-      page[i] = pte->fields.base;
-      addr += 4096;
-      }
-    return(n_pages);
+    page[i] = pte->fields.base;
+    addr += 4096;
+    }
+  return(n_pages);
 }
 
 
 
-/************************************************************************/
-/* The requisite host-specific functions.                               */
-/************************************************************************/
+/************************************************************************
+ * The requisite host-specific functions.  An implementation of each of
+ * these functions needs to be offered for each host-XYZ.c file.
+ ************************************************************************/
+
+  void
+hostReservePhyPages(vm_t *vm, Bit32u *hostPhyPages, unsigned nPages)
+{
+  unsigned p;
+
+  /*
+   * As we want to map these pages to user space, we need to mark
+   * them as 'reserved' pages by setting the PG_reserved bit.
+   *
+   * This has the effect that:
+   *  - remap_page_range accepts them as candidates for remapping
+   *  - the swapper does *not* try to swap these pages out, even
+   *    after they are mapped to user space
+   */
+
+  for (p = 0; p < nPages; p++)
+#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
+    set_bit(PG_reserved, &((mem_map + hostPhyPages[p])->flags));
+#else
+    mem_map_reserve(hostPhyPages[p]);
+#endif
+}
+
+  void
+hostUnreservePhyPages(vm_t *vm, Bit32u *hostPhyPages, unsigned nPages)
+{
+  unsigned p;
+
+  /* Remove the PG_reserved flags before returning the pages. */
+  for (p = 0; p < nPages; p++)
+#if LINUX_VERSION_CODE >= VERSION_CODE(2,4,0)
+    clear_bit(PG_reserved, &((mem_map + hostPhyPages[p])->flags));
+#else
+    mem_map_unreserve(hostPhyPages[p]);
+#endif
+}
 
   unsigned
 hostIdle(void)
@@ -800,6 +771,8 @@ hostConvertPlex86Errno(unsigned ret)
     case Plex86ErrnoENOMEM: return(ENOMEM);
     case Plex86ErrnoEFAULT: return(EFAULT);
     case Plex86ErrnoEINVAL: return(EINVAL);
+    case Plex86ErrnoEACCES: return(EACCES);
+    case Plex86ErrnoEAGAIN: return(EAGAIN);
     default:
       printk(KERN_ERR "plex86: ioctlAllocVPhys: case %u\n", ret);
       return(EINVAL);
diff --git a/bochs/plex86/kernel/host-null.c b/bochs/plex86/kernel/host-null.c
index dfb56d369..eabbb879b 100644
--- a/bochs/plex86/kernel/host-null.c
+++ b/bochs/plex86/kernel/host-null.c
@@ -56,12 +56,12 @@ main(int argc, char *argv[])
 }
 
   void
-hostReserveGuestPages(vm_t *vm)
+hostReservePhyPages(vm_t *vm, Bit32u *hostPhyPages, unsigned nPages)
 {
 }
 
   void
-hostUnreserveGuestPages(vm_t *vm)
+hostUnreservePhyPages(vm_t *vm, Bit32u *hostPhyPages, unsigned nPages)
 {
 }
 
diff --git a/bochs/plex86/kernel/include/monitor.h b/bochs/plex86/kernel/include/monitor.h
index e2e1dd98a..31183f87e 100644
--- a/bochs/plex86/kernel/include/monitor.h
+++ b/bochs/plex86/kernel/include/monitor.h
@@ -36,6 +36,11 @@
 #include "eflags.h"
 #include "guest_context.h"
 
+#ifndef UNUSED
+#  define UNUSED(x) ((void)(x))
+#endif
+
+
 /* Method1: push event info (CPU pushes error code before) */
 typedef struct 
 {
@@ -481,6 +486,7 @@ typedef struct {
 
 extern monitor_pages_t monitor_pages;
 extern cpuid_info_t cpuid_info;
+extern unsigned intRedirCount[];
 
 
 
@@ -566,6 +572,8 @@ vm_rdtsc(void) {
 #define Plex86ErrnoENOMEM     2
 #define Plex86ErrnoEFAULT     3
 #define Plex86ErrnoEINVAL     4
+#define Plex86ErrnoEACCES     5
+#define Plex86ErrnoEAGAIN     6
 
 #define vm_save_flags(x) \
   asm volatile("pushfl ; popl %0": "=g" (x): :"memory")
@@ -588,6 +596,10 @@ int      ioctlGeneric(vm_t *vm, void *inode, void *filp,
 int      ioctlExecute(vm_t *vm, plex86IoctlExecute_t *executeMsg);
 unsigned ioctlAllocVPhys(vm_t *vm, unsigned long arg);
 void     copyGuestStateToUserSpace(vm_t *vm);
+void     unreserveGuestPhyPages(vm_t *vm);
+void     reserveGuestPhyPages(vm_t *vm);
+int      genericMMap(vm_t *vm, void *inode, void *file, void *vma,
+                     unsigned firstPage, unsigned pagesN);
 
 /* These are the functions that the host-OS-specific file of the
  * plex86 device driver must define.
@@ -602,13 +614,15 @@ unsigned hostGetAllocedMemPhyPages(Bit32u *page, int max_pages, void *ptr,
 Bit32u   hostGetAllocedPagePhyPage(void *ptr);
 void     hostPrint(char *fmt, ...);
 Bit32u   hostKernelOffset(void);
-void     hostReserveGuestPages(vm_t *vm);
-void     hostUnreserveGuestPages(vm_t *vm);
+void     hostReservePhyPages(vm_t *vm, Bit32u *hostPhyPages, unsigned nPages);
+void     hostUnreservePhyPages(vm_t *vm, Bit32u *hostPhyPages, unsigned nPages);
 int      hostConvertPlex86Errno(unsigned ret);
 unsigned hostMMapCheck(void *i, void *f);
 void     hostModuleCountReset(vm_t *vm, void *inode, void *filp);
 unsigned long hostCopyFromUser(void *to, void *from, unsigned long len);
 unsigned long hostCopyToUser(void *to, void *from, unsigned long len);
+int      hostMMap(vm_t *vm, void *iV, void *fV, void *vmaV,
+                  unsigned pagesN, Bit32u *pagesArray);
 
 #endif  /* HOST Space */
 
diff --git a/bochs/plex86/kernel/monitor-host.c b/bochs/plex86/kernel/monitor-host.c
index 88ef3423b..8bd3c51d4 100644
--- a/bochs/plex86/kernel/monitor-host.c
+++ b/bochs/plex86/kernel/monitor-host.c
@@ -25,14 +25,15 @@
 #define IN_HOST_SPACE
 #include "monitor.h"
 
+monitor_pages_t monitor_pages;
 /* Instrumentation of how many hardware interrupts were redirected
  * to the host, while the VM was running.
  */
+#warning "Check for SMP issues on these globals"
 unsigned intRedirCount[256];
-
-
 cpuid_info_t hostCpuIDInfo;
 
+
 static int  initIDTSlot(vm_t *vm, unsigned vec, int type);
 static void mapMonPages(vm_t *vm, Bit32u *, unsigned, Bit32u *, page_t *,
                           unsigned user, unsigned writable, char *name);
@@ -744,7 +745,8 @@ ioctlGeneric(vm_t *vm, void *inode, void *filp,
        */
       vm->vmState &= ~VMStateMMapAll;
 
-      hostUnreserveGuestPages(vm);
+#warning "Add check before calling unreserveGuestPhyPages()"
+      unreserveGuestPhyPages(vm);
       unallocVmPages(vm);
 
       /* Reset state to only FD opened. */
@@ -769,6 +771,7 @@ ioctlGeneric(vm_t *vm, void *inode, void *filp,
       return ret;
       }
 
+#warning "PLEX86_RESET should only conditionally compiled for debugging."
     /*
      * For debugging, when the module gets hosed, this is a way
      * to reset the in-use count, so we can rmmod it.
@@ -1262,11 +1265,11 @@ hostPrint("plex86: vm_t size is %u\n", sizeof(vm_t));
     }
 
   /* Mark guest pages as reserved (for mmap()). */
-  hostReserveGuestPages( vm );
+  reserveGuestPhyPages(vm);
 
   /* Initialize the guests physical memory. */
   if ( initGuestPhyMem(vm) ) {
-    hostUnreserveGuestPages(vm);
+    unreserveGuestPhyPages(vm);
     unallocVmPages(vm);
     return -Plex86ErrnoEFAULT;
     }
@@ -1274,7 +1277,7 @@ hostPrint("plex86: vm_t size is %u\n", sizeof(vm_t));
   /* Initialize the monitor. */
   if ( !initMonitor(vm) ||
        !mapMonitor(vm) ) {
-    hostUnreserveGuestPages(vm);
+    unreserveGuestPhyPages(vm);
     unallocVmPages(vm);
     return -Plex86ErrnoEFAULT;
     }
@@ -1688,4 +1691,86 @@ initShadowPaging(vm_t *vm)
       xxxpanic(vm, "monPagingRemap: BadUsage4PDir\n");
     }
 #endif
+}
+
+  void
+reserveGuestPhyPages(vm_t *vm)
+{
+  /* Mark guest pages as reserved (for mmap()). */
+  hostReservePhyPages(vm, vm->pages.guest, vm->pages.guest_n_pages);
+  hostReservePhyPages(vm, vm->pages.log_buffer, LOG_BUFF_PAGES);
+  hostReservePhyPages(vm, &vm->pages.guest_cpu, 1);
+}
+
+  void
+unreserveGuestPhyPages(vm_t *vm)
+{
+  hostUnreservePhyPages(vm, vm->pages.guest, vm->pages.guest_n_pages);
+  hostUnreservePhyPages(vm, vm->pages.log_buffer, LOG_BUFF_PAGES);
+  hostUnreservePhyPages(vm, &vm->pages.guest_cpu, 1);
+}
+
+  int
+genericMMap(vm_t *vm, void *inode, void *file, void *vma, unsigned firstPage,
+            unsigned pagesN)
+{
+  unsigned stateMask;
+  Bit32u *pagesArray;
+  int ret;
+
+  /* The memory map:
+   *   guest physical memory (guest_n_pages)
+   *   log_buffer      (1)
+   *   guest_cpu       (1)
+   */
+
+  /* Must have memory allocated. */
+  if (!vm->pages.guest_n_pages) {
+    hostPrint("plex86: genericMMap: device not initialized\n");
+    return Plex86ErrnoEACCES;
+    }
+
+  if ( firstPage == 0 ) {
+    if (pagesN != vm->pages.guest_n_pages) {
+      hostPrint("plex86: mmap of guest phy mem, "
+                "pagesN of %u != guest_n_pages of %u\n",
+                pagesN, vm->pages.guest_n_pages);
+      return Plex86ErrnoEINVAL;
+      }
+    /* hostPrint("plex86: found mmap of guest phy memory.\n"); */
+    pagesArray = &vm->pages.guest[0];
+    stateMask = VMStateMMapPhyMem;
+    }
+  else if ( firstPage == (vm->pages.guest_n_pages+0) ) {
+    if (pagesN != 1) {
+      hostPrint("plex86: mmap of log_buffer, pages>1.\n");
+      return Plex86ErrnoEINVAL;
+      }
+    /* hostPrint("plex86: found mmap of log_buffer.\n"); */
+    pagesArray = &vm->pages.log_buffer[0];
+    stateMask = VMStateMMapPrintBuffer;
+    }
+  else if ( firstPage == (vm->pages.guest_n_pages+1) ) {
+    if (pagesN != 1) {
+      hostPrint("plex86: mmap of guest_cpu, pages>1.\n");
+      return Plex86ErrnoEINVAL;
+      }
+    /* hostPrint("plex86: found mmap of guest_cpu.\n"); */
+    pagesArray = &vm->pages.guest_cpu;
+    stateMask = VMStateMMapGuestCPU;
+    }
+  else {
+    hostPrint("plex86: mmap with firstPage of 0x%x.\n", firstPage);
+    return Plex86ErrnoEINVAL;
+    }
+
+  /* Call the hostOS-specific mmap code. */
+  ret = hostMMap(vm, inode, file, vma, pagesN, pagesArray);
+  if (ret != 0) {
+    /* Host-specific mmap code returned an error.  Return that. */
+    return( ret );
+    }
+
+  vm->vmState |= stateMask;
+  return 0; /* OK. */
 }