Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/usermode Start NetBSD/usermode's pmap. Its using a ...



details:   https://anonhg.NetBSD.org/src/rev/477318dabc27
branches:  trunk
changeset: 768606:477318dabc27
user:      reinoud <reinoud%NetBSD.org@localhost>
date:      Mon Aug 22 15:36:23 2011 +0000

description:
Start NetBSD/usermode's pmap. Its using a temp file as a physical memory
backup and that should be documented in the code. A physical address is thus a
file offset(!) and a virtual address is a `normal' accesible address.

Still to do: various misc functions and pmap_extract() in special.

Credits also go to Ben Harris for his work on the Acorn26 pmap that followed
the Daemon Book recommendation for systems without real page tables on wich
this implementation is modelled after.

diffstat:

 sys/arch/usermode/include/pmap.h    |    9 +-
 sys/arch/usermode/include/vmparam.h |   24 +-
 sys/arch/usermode/usermode/pmap.c   |  444 +++++++++++++++++++++++++++++++++--
 3 files changed, 432 insertions(+), 45 deletions(-)

diffs (truncated from 629 to 300 lines):

diff -r 24bf812384a8 -r 477318dabc27 sys/arch/usermode/include/pmap.h
--- a/sys/arch/usermode/include/pmap.h  Mon Aug 22 15:30:16 2011 +0000
+++ b/sys/arch/usermode/include/pmap.h  Mon Aug 22 15:36:23 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.3 2011/01/18 23:02:36 haad Exp $ */
+/* $NetBSD: pmap.h,v 1.4 2011/08/22 15:36:23 reinoud Exp $ */
 
 /*-
  * Copyright (c) 2007 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -30,10 +30,7 @@
 #define _ARCH_USERMODE_INCLUDE_PMAP_H
 
 #define        PMAP_GROWKERNEL         1
-#define PMAP_MAP_POOLPAGE(x)   (x)
-#define PMAP_UNMAP_POOLPAGE(x) (x)
-
-struct pmap {
-};
+//#define PMAP_MAP_POOLPAGE(x) (x)
+//#define PMAP_UNMAP_POOLPAGE(x)       (x)
 
 #endif /* !_ARCH_USERMODE_INCLUDE_PMAP_H */
diff -r 24bf812384a8 -r 477318dabc27 sys/arch/usermode/include/vmparam.h
--- a/sys/arch/usermode/include/vmparam.h       Mon Aug 22 15:30:16 2011 +0000
+++ b/sys/arch/usermode/include/vmparam.h       Mon Aug 22 15:36:23 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: vmparam.h,v 1.3 2009/10/21 16:06:59 snj Exp $ */
+/* $NetBSD: vmparam.h,v 1.4 2011/08/22 15:36:23 reinoud Exp $ */
 
 /*-
  * Copyright (c) 2007 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -30,21 +30,27 @@
 #define _ARCH_USERMODE_INCLUDE_VMPARAM_H
 
 #include </usr/include/machine/vmparam.h>
+#include <machine/pmap.h>
 #include "opt_memsize.h"
 
-#undef VM_MIN_ADDRESS
-#define VM_MIN_ADDRESS 0
-
-#undef VM_MAX_ADDRESS
-#define VM_MAX_ADDRESS (MEMSIZE*1024)
+extern paddr_t kmem_k_start, kmem_k_end;
+extern paddr_t kmem_data_start, kmem_data_end;
+extern paddr_t kmem_ext_start, kmem_ext_end;
+extern paddr_t kmem_user_start, kmem_user_end;
 
 #undef VM_MIN_KERNEL_ADDRESS
-#define VM_MIN_KERNEL_ADDRESS  0
+#define VM_MIN_KERNEL_ADDRESS  kmem_k_start
 
 #undef VM_MAX_KERNEL_ADDRESS
-#define VM_MAX_KERNEL_ADDRESS (MEMSIZE*1024)
+#define VM_MAX_KERNEL_ADDRESS  kmem_ext_end
+
+#undef VM_MIN_ADDRESS
+#define VM_MIN_ADDRESS         kmem_k_start
+
+#undef VM_MAX_ADDRESS
+#define VM_MAX_ADDRESS         kmem_user_end
 
 #undef VM_MAXUSER_ADDRESS
-#define VM_MAXUSER_ADDRESS (MEMSIZE*1024)
+#define VM_MAXUSER_ADDRESS     kmem_user_end
 
 #endif /* !_ARCH_USERMODE_INCLUDE_VMPARAM_H */
diff -r 24bf812384a8 -r 477318dabc27 sys/arch/usermode/usermode/pmap.c
--- a/sys/arch/usermode/usermode/pmap.c Mon Aug 22 15:30:16 2011 +0000
+++ b/sys/arch/usermode/usermode/pmap.c Mon Aug 22 15:36:23 2011 +0000
@@ -1,7 +1,7 @@
-/* $NetBSD: pmap.c,v 1.8 2011/08/13 10:31:24 jmcneill Exp $ */
+/* $NetBSD: pmap.c,v 1.9 2011/08/22 15:36:23 reinoud Exp $ */
 
 /*-
- * Copyright (c) 2007 Jared D. McNeill <jmcneill%invisible.ca@localhost>
+ * Copyright (c) 2011 Reinoud Zandijk <reinoud%NetBSD.org@localhost>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,49 +27,254 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.8 2011/08/13 10:31:24 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.9 2011/08/22 15:36:23 reinoud Exp $");
+
+#include "opt_uvmhist.h"
+#include "opt_memsize.h"
+#include "opt_kmempages.h"
 
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/mutex.h>
 #include <sys/buf.h>
+#include <machine/thunk.h>
 
+#include <uvm/uvm.h>
+#include <uvm/uvm_stat.h>
 #include <uvm/uvm_page.h>
 #include <uvm/uvm_pmap.h>
 
-#include "opt_memsize.h"
 
-extern void * calloc(size_t, size_t);
+struct pv_entry {
+       struct  pv_entry *pv_next;
+       pmap_t  pv_pmap;
+       int     pv_ppn;         /* physical page number */
+       int     pv_lpn;         /* logical page number  */
+       vm_prot_t       pv_prot;        /* logical protection */
+       int             pv_mmap_ppl;    /* programmed protection */
+       uint8_t         pv_vflags;      /* per mapping flags */
+#define PV_WIRED       0x01            /* wired mapping */
+#define PV_UNMANAGED   0x02            /* entered by pmap_kenter_ */
+       uint8_t         pv_pflags;      /* per phys page flags */
+#define PV_REFERENCED  0x01
+#define PV_MODIFIED    0x02
+};
 
+/* this is a guesstimate of 16KB/process on amd64, or around 680+ mappings */
+#define PM_MIN_NENTRIES ((int) (16*1024 / sizeof(pv_entry)))
+struct pmap {
+       int     pm_count;
+       int     pm_flags;
+#define PM_ACTIVE 0x01
+       struct  pmap_statistics pm_stats;
+       struct  pv_entry **pm_entries;
+};
+
+static struct pv_entry *pv_table;
 static struct pmap     pmap_kernel_store;
 struct pmap * const    kernel_pmap_ptr = &pmap_kernel_store;
 
-static uint8_t *pmap_memory;
-static vsize_t pmap_memory_size = 1024 * MEMSIZE;
-static vaddr_t virtual_avail, virtual_end;
-static vaddr_t pmap_maxkvaddr;
+static char mem_name[20] = "";
+static int mem_fh;
+
+static int phys_npages = 0;
+static int pm_nentries = 0;
+static uint64_t pm_entries_size = 0;
 
+/* forwards */
 void           pmap_bootstrap(void);
+static void    pmap_page_activate(struct pv_entry *pv);
+static void    pv_update(struct pv_entry *pv);
+static void    pmap_update_page(int ppn);
+static struct pv_entry *pv_get(pmap_t pmap, int ppn, int lpn);
+
+/* exposed to signal handler */
+vaddr_t kmem_k_start, kmem_k_end;
+vaddr_t kmem_data_start, kmem_data_end;
+vaddr_t kmem_ext_start, kmem_ext_end;
+vaddr_t kmem_user_start, kmem_user_end;
+vaddr_t kmem_ext_cur_start, kmem_ext_cur_end;
 
 void
 pmap_bootstrap(void)
 {
-       pmap_memory = calloc(1, pmap_memory_size);
-       if (pmap_memory == NULL)
-               panic("pmap_bootstrap: no memory");
+       struct pmap *pmap;
+       ssize_t fpos, file_len;
+       ssize_t pv_fpos, pm_fpos;
+       ssize_t wlen;
+       uint64_t pv_table_size;
+       paddr_t free_start, free_end;
+       paddr_t pa;
+       vaddr_t va;
+       void *addr;
+       char dummy;
+       int pg, err;
+
+       extern void _init(void);        /* start of kernel               */
+       extern int etext;               /* end of the kernel             */
+       extern int edata;               /* end of the init. data segment */
+       extern int end;                 /* end of bss                    */
+
+       aprint_debug("Information retrieved from elf image\n");
+       aprint_debug("start kernel        at %p\n", _init);
+       aprint_debug("  end kernel        at %p\n", &etext);
+       aprint_debug("  end of init. data at %p\n", &edata);
+       aprint_debug("1st end of data     at %p\n", &end);
+       aprint_debug("CUR end data        at %p\n", thunk_sbrk(0));
+       assert(&end == thunk_sbrk(0));
+
+       /* calculate sections of the kernel (R+X) */
+       kmem_k_start = (paddr_t) PAGE_SIZE * (atop(_init)   );
+       kmem_k_end   = (paddr_t) PAGE_SIZE * (atop(&etext) + 1);
+
+       /* read only section (for userland R, kernel RW) */
+       kmem_data_start = (paddr_t) PAGE_SIZE * (atop(&etext));
+       kmem_data_end   = (paddr_t) PAGE_SIZE * (atop(&end) + 1);
+
+#ifdef DIAGNOSTIC
+       if (kmem_k_end >= kmem_data_start) {
+               printf("end of kernel and kernel exec could clash\n");
+               printf("   kmem_k_end = %p, kmem_data_start = %p\n",
+                       (void *) kmem_k_end, (void *) kmem_data_start);
+               printf("fixing\n");
+       }
+#endif
+       /* on clash move RO segment so that all code is executable */
+       if (kmem_k_end >= kmem_data_start)
+               kmem_data_start = kmem_k_end;
+
+       /* claim an area for kernel data space growth (over dim) */
+       kmem_ext_start   = kmem_data_end;
+       kmem_ext_end     = kmem_ext_start + NKMEMPAGES * PAGE_SIZE;
+
+       /* claim an area for userland */
+       kmem_user_start = kmem_ext_end;
+       kmem_user_end   = kmem_user_start + 1024 * MEMSIZE;
+       /* TODO make a better user space size estimate */
+
+       if (kmem_user_end < kmem_user_start)
+               panic("pmap_bootstrap: to small memorysize specified");
+
+       aprint_debug("\nMemory summary\n");
+       aprint_debug("\tkmem_k_start\t%p\n",    (void *) kmem_k_start);
+       aprint_debug("\tkmem_k_end\t%p\n",      (void *) kmem_k_end);
+       aprint_debug("\tkmem_data_start\t%p\n", (void *) kmem_data_start);
+       aprint_debug("\tkmem_data_end\t%p\n",   (void *) kmem_data_end);
+       aprint_debug("\tkmem_ext_start\t%p\n",  (void *) kmem_ext_start);
+       aprint_debug("\tkmem_ext_end\t%p\n",    (void *) kmem_ext_end);
+       aprint_debug("\tkmem_user_start\t%p\n", (void *) kmem_user_start);
+       aprint_debug("\tkmem_user_end\t%p\n",   (void *) kmem_user_end);
+       aprint_debug("\n\n\n");
+
+       aprint_debug("Creating memory mapped backend\n");
+
+       /* create memory file since mmap/maccess only can be on files */
+       strlcpy(mem_name, "/tmp/netbsd.XXXXX", sizeof(mem_name));
+       mem_fh = thunk_mkstemp(mem_name);
+       if (mem_fh < 0)
+               panic("pmap_bootstrap: can't create memory file\n");
+
+       /* file_len is the backing store length, nothing to do with placement */
+       file_len = 1024 * MEMSIZE;
+       wlen = thunk_pwrite(mem_fh, &dummy, 1, file_len - 1);
+       if (wlen != 1)
+               panic("pmap_bootstrap: can't grow file\n");
 
-       virtual_avail = (vaddr_t)pmap_memory;
-       virtual_end = virtual_avail + pmap_memory_size;
+       /* (un)protect the current kernel and data sections */
+       /* XXX kernel stack? */
+       err = thunk_mprotect((void *) kmem_k_start, kmem_k_end - kmem_k_start,
+               PROT_READ | PROT_EXEC);
+       assert(err == 0);
+       err = thunk_mprotect((void *) kmem_k_end, kmem_data_end - kmem_k_end,
+               PROT_READ | PROT_WRITE);
+       assert(err == 0);
+
+       /* set up pv_table; bootstrap problem! */
+       fpos = 0;
+       free_start = fpos;     /* in physical space ! */
+       free_end   = file_len; /* in physical space ! */
+
+       phys_npages = (free_end - free_start) / PAGE_SIZE;
+       pv_table_size = round_page(phys_npages * sizeof(struct pv_entry));
+       aprint_debug("claiming %"PRIu64" KB of pv_table for "
+               "%d pages of physical memory\n", pv_table_size/1024, phys_npages);
+
+       kmem_ext_cur_start = kmem_ext_start;
+       pv_fpos = fpos;
+       pv_table = (struct pv_entry *) kmem_ext_cur_start;
+       addr = thunk_mmap(pv_table, pv_table_size,
+               PROT_READ | PROT_WRITE,
+               MAP_FILE | MAP_FIXED,
+               mem_fh, pv_fpos);
+       if (addr != (void *) kmem_ext_start)
+               panic("pmap_bootstrap: can't map in pv table\n");
+
+       memset(pv_table, 0, pv_table_size);     /* test and clear */
+
+       aprint_debug("pv_table initialiased correctly, mmap works\n");
+
+       /* advance */
+       kmem_ext_cur_start += pv_table_size;
+       fpos += pv_table_size;
+
+       /* set up kernel pmap */
+       pm_nentries = (kmem_user_end - kmem_k_start) / PAGE_SIZE;
+       pm_entries_size = round_page(pm_nentries * sizeof(struct pv_entry *));
+       aprint_debug("pmap va->pa lookup table is %"PRIu64" KB for %d logical pages\n",
+               pm_entries_size/1024, pm_nentries);
 
-       uvm_page_physload(atop(virtual_avail),
-           atop(virtual_end),
-           atop(virtual_avail + PAGE_SIZE),
-           atop(virtual_end), 
+        pmap = pmap_kernel(); 
+        memset(pmap, 0, sizeof(*pmap)); 
+       pmap->pm_count = 1;             /* reference */
+       pmap->pm_flags = PM_ACTIVE;     /* kernel pmap is allways active */



Home | Main Index | Thread Index | Old Index