kernel - Expand the x86_64 KVA to 8G
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 6 Feb 2010 17:43:06 +0000 (09:43 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 6 Feb 2010 17:43:06 +0000 (09:43 -0800)
* Our kmem_init() was mapping out the ~6G of KVA below KERNBASE.  KERNBASE
  is at the -2G mark and unlike i386 it does not mark the beginning of KVA.

  Add two more globals, virtual2_start and virtual2_end, adn adjust
  kmem_init() to use that space.  This fixes kernel_map exhaustion issues
  on x86_64.  Before the change only ~600M of KVA was available after a
  fresh boot.

* Populate the PDPs around both KERNBASE and at virtual2_start for
  bootstrapping purposes.

* Adjust kernel_vm_end to start iteration for growkernel purposes at
  VM_MIN_KERNEL_ADDRESS and no longer use it to figure out the end
  of KVM for the minidump.

  In addition, adjust minidump to dump the entire kernel virtual
  address space.

* Remove numerous extranious variables.

* Fix a bug in vm_map_insert() where vm_map->first_free was being
  incorrect set when the map does not begin with reserved space.

sys/platform/pc32/i386/pmap.c
sys/platform/pc64/include/pmap.h
sys/platform/pc64/include/vmparam.h
sys/platform/pc64/x86_64/machdep.c
sys/platform/pc64/x86_64/minidump_machdep.c
sys/platform/pc64/x86_64/mp_machdep.c
sys/platform/pc64/x86_64/pmap.c
sys/platform/vkernel/platform/init.c
sys/vm/pmap.h
sys/vm/vm_kern.c
sys/vm/vm_map.c

index 4721bc5..6c79724 100644 (file)
@@ -155,6 +155,8 @@ vm_paddr_t avail_start;             /* PA of first available physical page */
 vm_paddr_t avail_end;          /* PA of last available physical page */
 vm_offset_t virtual_start;     /* VA of first avail page (after kernel bss) */
 vm_offset_t virtual_end;       /* VA of last avail page (end of kernel AS) */
+vm_offset_t virtual2_start;
+vm_offset_t virtual2_end;
 vm_offset_t KvaStart;          /* VA start of KVA space */
 vm_offset_t KvaEnd;            /* VA end of KVA space (non-inclusive) */
 vm_offset_t KvaSize;           /* max size of kernel virtual address space */
index 87da724..af2a9f6 100644 (file)
        ((unsigned long)(l2) << PDRSHIFT) | \
        ((unsigned long)(l1) << PAGE_SHIFT))
 
-/* Initial number of kernel page tables. */
+/*
+ * Initial number of kernel page tables x 2
+ */
 #ifndef NKPT
-#define        NKPT            32
+#define        NKPT            64
 #endif
 
 #define NKPML4E                1               /* number of kernel PML4 slots */
-#define NKPDPE         howmany(NKPT, NPDEPG)/* number of kernel PDP slots */
+/* NKPDPE defined in vmparam.h */
 
 #define        NUPML4E         (NPML4EPG/2)    /* number of userland PML4 pages */
 #define        NUPDPE          (NUPML4E*NPDPEPG)/* number of userland PDP pages */
index 7522133..f0bf737 100644 (file)
  * page table indexes from pmap.h for precision.
  * Because of the page that is both a PD and PT, it looks a little
  * messy at times, but hey, we'll do anything to save a page :-)
+ *
+ * The kernel address space can be up to (I think) 511 page directory
+ * pages.  Each one represents 1G.  NKPDPE defines the size of the kernel
+ * address space, curently set to 8G.
  */
-
+#define NKPDPE                 8
 #define        VM_MAX_KERNEL_ADDRESS   KVADDR(KPML4I, NPDPEPG-1, NPDEPG-1, NPTEPG-1)
-#define        VM_MIN_KERNEL_ADDRESS   KVADDR(KPML4I, NPDPEPG-7, 0, 0)
+#define        VM_MIN_KERNEL_ADDRESS   KVADDR(KPML4I, NPDPEPG-NKPDPE, 0, 0)
 
 #define        DMAP_MIN_ADDRESS        KVADDR(DMPML4I, 0, 0, 0)
 #define        DMAP_MAX_ADDRESS        KVADDR(DMPML4I+1, 0, 0, 0)
 #define        KERNBASE                KVADDR(KPML4I, KPDPI, 0, 0)
 #define        PTOV_OFFSET             KERNBASE
 
-#if JG
-#define KPT_MAX_ADDRESS                VADDR(PTDPTDI, KPTDI+NKPT)
-#define KPT_MIN_ADDRESS                VADDR(PTDPTDI, KPTDI)
-#endif
-
 #define UPT_MAX_ADDRESS                KVADDR(PML4PML4I, PML4PML4I, PML4PML4I, PML4PML4I)
 #define UPT_MIN_ADDRESS                KVADDR(PML4PML4I, 0, 0, 0)
 
index bfca8b7..1f7b676 100644 (file)
@@ -148,7 +148,6 @@ SYSINIT(cpu, SI_BOOT2_SMP, SI_ORDER_FIRST, cpu_startup, NULL)
 extern vm_offset_t ksym_start, ksym_end;
 #endif
 
-uint64_t KPTphys;
 uint64_t SMPptpa;
 pt_entry_t *SMPpt;
 
index facacbc..b899e93 100644 (file)
@@ -183,17 +183,22 @@ minidumpsys(struct dumperinfo *di)
        struct mdglobaldata *md;
 
        counter = 0;
-       /* Walk page table pages, set bits in vm_page_dump */
+       /*
+        * Walk page table pages, set bits in vm_page_dump.
+        *
+        * NOTE: kernel_vm_end can actually be below KERNBASE.
+        *       Just use KvaEnd.
+        */
        ptesize = 0;
 
        md = (struct mdglobaldata *)globaldata_find(0);
 
-       kern_end = kernel_vm_end;
+       kern_end = KvaEnd;
        if (kern_end < (vm_offset_t)&(md[ncpus]))
                kern_end = (vm_offset_t)&(md[ncpus]);
 
        pdp = (uint64_t *)PHYS_TO_DMAP(KPDPphys);
-       for (va = KERNBASE; va < kern_end; va += NBPDR) {
+       for (va = VM_MIN_KERNEL_ADDRESS; va < kern_end; va += NBPDR) {
                i = (va >> PDPSHIFT) & ((1ul << NPDPEPGSHIFT) - 1);
                /*
                 * We always write a page, even if it is zero. Each
@@ -265,7 +270,7 @@ minidumpsys(struct dumperinfo *di)
        mdhdr.msgbufsize = msgbufp->msg_size;
        mdhdr.bitmapsize = vm_page_dump_size;
        mdhdr.ptesize = ptesize;
-       mdhdr.kernbase = KERNBASE;
+       mdhdr.kernbase = VM_MIN_KERNEL_ADDRESS;
        mdhdr.dmapbase = DMAP_MIN_ADDRESS;
        mdhdr.dmapend = DMAP_MAX_ADDRESS;
 
@@ -300,7 +305,7 @@ minidumpsys(struct dumperinfo *di)
 
        /* Dump kernel page table pages */
        pdp = (uint64_t *)PHYS_TO_DMAP(KPDPphys);
-       for (va = KERNBASE; va < kern_end; va += NBPDR) {
+       for (va = VM_MIN_KERNEL_ADDRESS; va < kern_end; va += NBPDR) {
                i = (va >> PDPSHIFT) & ((1ul << NPDPEPGSHIFT) - 1);
                /* We always write a page, even if it is zero */
                if ((pdp[i] & PG_V) == 0) {
index 8778d02..0b48164 100644 (file)
@@ -258,9 +258,6 @@ int     apic_id_to_logical[NAPICID];
 char *bootSTK;
 static int bootAP;
 
-/* Hotwire a 0->4MB V==P mapping */
-extern pt_entry_t *KPTphys;
-
 /*
  * SMP page table page.  Setup by locore to point to a page table
  * page from which we allocate per-cpu privatespace areas io_apics,
index d2d86c9..583a7a1 100644 (file)
@@ -149,6 +149,8 @@ static TAILQ_HEAD(,pmap)    pmap_list = TAILQ_HEAD_INITIALIZER(pmap_list);
 
 vm_paddr_t avail_start;                /* PA of first available physical page */
 vm_paddr_t avail_end;          /* PA of last available physical page */
+vm_offset_t virtual2_start;    /* cutout free area prior to kernel start */
+vm_offset_t virtual2_end;
 vm_offset_t virtual_start;     /* VA of first avail page (after kernel bss) */
 vm_offset_t virtual_end;       /* VA of last avail page (end of kernel AS) */
 vm_offset_t KvaStart;          /* VA start of KVA space */
@@ -163,11 +165,14 @@ static vm_object_t kptobj;
 static int ndmpdp;
 static vm_paddr_t dmaplimit;
 static int nkpt;
-vm_offset_t kernel_vm_end;
+vm_offset_t kernel_vm_end = VM_MIN_KERNEL_ADDRESS;
 
+static uint64_t KPTbase;
+static uint64_t KPTphys;
 static uint64_t        KPDphys;        /* phys addr of kernel level 2 */
-uint64_t               KPDPphys;       /* phys addr of kernel level 3 */
-uint64_t               KPML4phys;      /* phys addr of kernel level 4 */
+static uint64_t        KPDbase;        /* phys addr of kernel level 2 @ KERNBASE */
+uint64_t KPDPphys;     /* phys addr of kernel level 3 */
+uint64_t KPML4phys;    /* phys addr of kernel level 4 */
 
 static uint64_t        DMPDphys;       /* phys addr of direct mapped level 2 */
 static uint64_t        DMPDPphys;      /* phys addr of direct mapped level 3 */
@@ -196,7 +201,6 @@ struct msgbuf *msgbufp=0;
 static pt_entry_t *pt_crashdumpmap;
 static caddr_t crashdumpmap;
 
-extern uint64_t KPTphys;
 extern pt_entry_t *SMPpt;
 extern uint64_t SMPptpa;
 
@@ -426,10 +430,18 @@ create_pagetables(vm_paddr_t *firstaddr)
        /* we are running (mostly) V=P at this point */
 
        /* Allocate pages */
+       KPTbase = allocpages(firstaddr, NKPT);
        KPTphys = allocpages(firstaddr, NKPT);
        KPML4phys = allocpages(firstaddr, 1);
        KPDPphys = allocpages(firstaddr, NKPML4E);
+
+       /*
+        * Calculate the page directory base for KERNBASE,
+        * that is where we start populating the page table pages.
+        * Basically this is the end - 2.
+        */
        KPDphys = allocpages(firstaddr, NKPDPE);
+       KPDbase = KPDphys + ((NKPDPE - (NPDPEPG - KPDPI)) << PAGE_SHIFT);
 
        ndmpdp = (ptoa(Maxmem) + NBPDP - 1) >> PDPSHIFT;
        if (ndmpdp < 4)         /* Minimum 4GB of dirmap */
@@ -439,32 +451,52 @@ create_pagetables(vm_paddr_t *firstaddr)
                DMPDphys = allocpages(firstaddr, ndmpdp);
        dmaplimit = (vm_paddr_t)ndmpdp << PDPSHIFT;
 
-       /* Fill in the underlying page table pages */
-       /* Read-only from zero to physfree */
-       /* XXX not fully used, underneath 2M pages */
+       /*
+        * Fill in the underlying page table pages for the area around
+        * KERNBASE.  This remaps low physical memory to KERNBASE.
+        *
+        * Read-only from zero to physfree
+        * XXX not fully used, underneath 2M pages
+        */
        for (i = 0; (i << PAGE_SHIFT) < *firstaddr; i++) {
-               ((pt_entry_t *)KPTphys)[i] = i << PAGE_SHIFT;
-               ((pt_entry_t *)KPTphys)[i] |= PG_RW | PG_V | PG_G;
+               ((pt_entry_t *)KPTbase)[i] = i << PAGE_SHIFT;
+               ((pt_entry_t *)KPTbase)[i] |= PG_RW | PG_V | PG_G;
        }
 
-       /* Now map the page tables at their location within PTmap */
+       /*
+        * Now map the initial kernel page tables.  One block of page
+        * tables is placed at the beginning of kernel virtual memory,
+        * and another block is placed at KERNBASE to map the kernel binary,
+        * data, bss, and initial pre-allocations.
+        */
+       for (i = 0; i < NKPT; i++) {
+               ((pd_entry_t *)KPDbase)[i] = KPTbase + (i << PAGE_SHIFT);
+               ((pd_entry_t *)KPDbase)[i] |= PG_RW | PG_V;
+       }
        for (i = 0; i < NKPT; i++) {
                ((pd_entry_t *)KPDphys)[i] = KPTphys + (i << PAGE_SHIFT);
                ((pd_entry_t *)KPDphys)[i] |= PG_RW | PG_V;
        }
 
-       /* Map from zero to end of allocations under 2M pages */
-       /* This replaces some of the KPTphys entries above */
+       /*
+        * Map from zero to end of allocations using 2M pages as an
+        * optimization.  This will bypass some of the KPTBase pages
+        * above in the KERNBASE area.
+        */
        for (i = 0; (i << PDRSHIFT) < *firstaddr; i++) {
-               ((pd_entry_t *)KPDphys)[i] = i << PDRSHIFT;
-               ((pd_entry_t *)KPDphys)[i] |= PG_RW | PG_V | PG_PS | PG_G;
+               ((pd_entry_t *)KPDbase)[i] = i << PDRSHIFT;
+               ((pd_entry_t *)KPDbase)[i] |= PG_RW | PG_V | PG_PS | PG_G;
        }
 
-       /* And connect up the PD to the PDP */
+       /*
+        * And connect up the PD to the PDP.  The kernel pmap is expected
+        * to pre-populate all of its PDs.  See NKPDPE in vmparam.h.
+        */
        for (i = 0; i < NKPDPE; i++) {
-               ((pdp_entry_t *)KPDPphys)[i + KPDPI] = KPDphys +
-                   (i << PAGE_SHIFT);
-               ((pdp_entry_t *)KPDPphys)[i + KPDPI] |= PG_RW | PG_V | PG_U;
+               ((pdp_entry_t *)KPDPphys)[NPDPEPG - NKPDPE + i] =
+                               KPDphys + (i << PAGE_SHIFT);
+               ((pdp_entry_t *)KPDPphys)[NPDPEPG - NKPDPE + i] |=
+                               PG_RW | PG_V | PG_U;
        }
 
        /* Now set up the direct map space using either 2MB or 1GB pages */
@@ -538,6 +570,9 @@ pmap_bootstrap(vm_paddr_t *firstaddr)
         */
        create_pagetables(firstaddr);
 
+       virtual2_start = KvaStart;
+       virtual2_end = PTOV_OFFSET;
+
        virtual_start = (vm_offset_t) PTOV_OFFSET + *firstaddr;
        virtual_start = pmap_kmem_choose(virtual_start);
 
@@ -1816,7 +1851,7 @@ pmap_growkernel(vm_offset_t addr)
 
        crit_enter();
        if (kernel_vm_end == 0) {
-               kernel_vm_end = KERNBASE;
+               kernel_vm_end = VM_MIN_KERNEL_ADDRESS;
                nkpt = 0;
                while ((*pmap_pde(&kernel_pmap, kernel_vm_end) & PG_V) != 0) {
                        kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) & ~(PAGE_SIZE * NPTEPG - 1);
index f2fabd1..be9e5cf 100644 (file)
@@ -91,6 +91,8 @@ vm_offset_t KvaEnd;
 vm_offset_t KvaSize;
 vm_offset_t virtual_start;
 vm_offset_t virtual_end;
+vm_offset_t virtual2_start;
+vm_offset_t virtual2_end;
 vm_offset_t kernel_vm_end;
 vm_offset_t crashdumpmap;
 vm_offset_t clean_sva;
index 02242f8..e360186 100644 (file)
@@ -118,6 +118,8 @@ extern vm_offset_t KvaEnd;
 extern vm_offset_t KvaSize;
 extern vm_offset_t virtual_start;
 extern vm_offset_t virtual_end;
+extern vm_offset_t virtual2_start;
+extern vm_offset_t virtual2_end;
 extern vm_paddr_t phys_avail[];        
 
 /*
index e66b4a0..792eef5 100644 (file)
@@ -357,6 +357,9 @@ kmem_free_wakeup(vm_map_t map, vm_offset_t addr, vm_size_t size)
  *     allocated or reserved thus far.  That is, the area (KvaStart,start)
  *     and (end,KvaEnd) must be marked as allocated.
  *
+ *     virtual2_start/end is a cutout Between KvaStart and start,
+ *     for x86_64 due to the location of KERNBASE (at -2G).
+ *
  *     We could use a min_offset of 0 instead of KvaStart, but since the
  *     min_offset is not used for any calculations other then a bounds check
  *     it does not effect readability.  KvaStart is more appropriate.
@@ -366,6 +369,7 @@ kmem_free_wakeup(vm_map_t map, vm_offset_t addr, vm_size_t size)
 void
 kmem_init(vm_offset_t start, vm_offset_t end)
 {
+       vm_offset_t addr;
        vm_map_t m;
        int count;
 
@@ -374,16 +378,28 @@ kmem_init(vm_offset_t start, vm_offset_t end)
        /* N.B.: cannot use kgdb to debug, starting with this assignment ... */
        m->system_map = 1;
        count = vm_map_entry_reserve(MAP_RESERVE_COUNT);
-       if (KvaStart != start) {
+       addr = KvaStart;
+       if (virtual2_start) {
+               if (addr < virtual2_start) {
+                       vm_map_insert(m, &count, NULL, (vm_offset_t) 0,
+                                     addr, virtual2_start,
+                                     VM_MAPTYPE_NORMAL,
+                                     VM_PROT_ALL, VM_PROT_ALL,
+                                     0);
+               }
+               addr = virtual2_end;
+       }
+       if (addr < start) {
                vm_map_insert(m, &count, NULL, (vm_offset_t) 0,
-                             KvaStart, start,
+                             addr, start,
                              VM_MAPTYPE_NORMAL,
                              VM_PROT_ALL, VM_PROT_ALL,
                              0);
        }
-       if (KvaEnd != end) {
+       addr = end;
+       if (addr < KvaEnd) {
                vm_map_insert(m, &count, NULL, (vm_offset_t) 0,
-                             end, KvaEnd,
+                             addr, KvaEnd,
                              VM_MAPTYPE_NORMAL,
                              VM_PROT_ALL, VM_PROT_ALL,
                              0);
index 4982f14..bf7b2b8 100644 (file)
@@ -925,10 +925,12 @@ vm_map_insert(vm_map_t map, int *countp,
        map->size += new_entry->end - new_entry->start;
 
        /*
-        * Update the free space hint
+        * Update the free space hint.  Entries cannot overlap.
+        * An exact comparison is needed to avoid matching
+        * against the map->header.
         */
        if ((map->first_free == prev_entry) &&
-           (prev_entry->end >= new_entry->start)) {
+           (prev_entry->end == new_entry->start)) {
                map->first_free = new_entry;
        }