shithub: riscv

Download patch

ref: b2c7a8d84a0075fea104009115d0c34bffc39e06
parent: 6118d778581b44e5c41a04a60d4aa8e6cad4a37c
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Jun 28 14:12:13 EDT 2019

pc64: preallocate mmupool page tables

preallocate 2% of user pages for page tables and MMU structures
and keep them mapped in the VMAP range. this leaves more space
in the KZERO window and avoids running out of kernel memory on
machines with large amounts of memory.

--- a/sys/src/9/pc64/fns.h
+++ b/sys/src/9/pc64/fns.h
@@ -157,6 +157,7 @@
 void	(*_pcmspecialclose)(int);
 void	pcmunmap(int, PCMmap*);
 void	pmap(uintptr *, uintptr, uintptr, vlong);
+void	preallocpages(void);
 void	procrestore(Proc*);
 void	procsave(Proc*);
 void	procsetup(Proc*);
--- a/sys/src/9/pc64/main.c
+++ b/sys/src/9/pc64/main.c
@@ -103,45 +103,6 @@
 	}
 }
 
-/*
- * The palloc.pages array can be a large chunk out of the 2GB
- * window above KZERO, so we allocate the array from
- * upages and map in the VMAP window before pageinit()
- */
-static void
-preallocpages(void)
-{
-	Pallocmem *pm;
-	uintptr va, base, top;
-	vlong size;
-	ulong np;
-	int i;
-
-	np = 0;
-	for(i=0; i<nelem(palloc.mem); i++){
-		pm = &palloc.mem[i];
-		np += pm->npage;
-	}
-	size = (uvlong)np * BY2PG;
-	size += sizeof(Page) + BY2PG;	/* round up */
-	size = (size / (sizeof(Page) + BY2PG)) * sizeof(Page);
-	size = ROUND(size, PGLSZ(1));
-
-	for(i=0; i<nelem(palloc.mem); i++){
-		pm = &palloc.mem[i];
-		base = ROUND(pm->base, PGLSZ(1));
-		top = pm->base + (uvlong)pm->npage * BY2PG;
-		if((base + size) <= VMAPSIZE && (vlong)(top - base) >= size){
-			va = base + VMAP;
-			pmap(m->pml4, base | PTEGLOBAL|PTEWRITE|PTEVALID, va, size);
-			palloc.pages = (Page*)va;
-			pm->base = base + size;
-			pm->npage = (top - pm->base)/BY2PG;
-			break;
-		}
-	}
-}
-
 void
 machinit(void)
 {
--- a/sys/src/9/pc64/mmu.c
+++ b/sys/src/9/pc64/mmu.c
@@ -271,7 +271,11 @@
 		if(pte & PTEVALID){
 			if(pte & PTESIZE)
 				return 0;
-			table = KADDR(PPN(pte));
+			pte = PPN(pte);
+			if(pte >= (uintptr)-KZERO)
+				table = (void*)(pte + VMAP);
+			else
+				table = (void*)(pte + KZERO);
 		} else {
 			if(!create)
 				return 0;
@@ -568,5 +572,64 @@
 		mask = l == 0 ? 3<<3 | 1<<7 : 3<<3 | 1<<12;
 		attr = (((PATWC&3)<<3) | ((PATWC&4)<<5) | ((PATWC&4)<<10));
 		*pte = (*pte & ~mask) | (attr & mask);
+	}
+}
+
+/*
+ * The palloc.pages array and mmupool can be a large chunk
+ * out of the 2GB window above KZERO, so we allocate from
+ * upages and map in the VMAP window before pageinit()
+ */
+void
+preallocpages(void)
+{
+	Pallocmem *pm;
+	uintptr va, base, top;
+	vlong tsize, psize;
+	ulong np, nt;
+	int i;
+
+	np = 0;
+	for(i=0; i<nelem(palloc.mem); i++){
+		pm = &palloc.mem[i];
+		np += pm->npage;
+	}
+	nt = np / 50;	/* 2% for mmupool */
+	np -= nt;
+
+	nt = (uvlong)nt*BY2PG / (sizeof(MMU)+PTSZ);
+	tsize = (uvlong)nt * (sizeof(MMU)+PTSZ);
+
+	psize = (uvlong)np * BY2PG;
+	psize += sizeof(Page) + BY2PG;
+	psize = (psize / (sizeof(Page)+BY2PG)) * sizeof(Page);
+
+	psize += tsize;
+	psize = ROUND(psize, PGLSZ(1));
+
+	for(i=0; i<nelem(palloc.mem); i++){
+		pm = &palloc.mem[i];
+		base = ROUND(pm->base, PGLSZ(1));
+		top = pm->base + (uvlong)pm->npage * BY2PG;
+		if((base + psize) <= VMAPSIZE && (vlong)(top - base) >= psize){
+			pm->base = base + psize;
+			pm->npage = (top - pm->base)/BY2PG;
+
+			va = base + VMAP;
+			pmap(m->pml4, base | PTEGLOBAL|PTEWRITE|PTEVALID, va, psize);
+
+			palloc.pages = (void*)(va + tsize);
+
+			mmupool.nfree = mmupool.nalloc = nt;
+			mmupool.free = (void*)(va + (uvlong)nt*PTSZ);
+			for(i=0; i<nt; i++){
+				mmupool.free[i].page = (uintptr*)va;
+				mmupool.free[i].next = &mmupool.free[i+1];
+				va += PTSZ;
+			}
+			mmupool.free[i-1].next = nil;
+
+			break;
+		}
 	}
 }