shithub: riscv

Download patch

ref: 639f9e8de7ad75f1c985d2cec2ef8b39b3d73070
parent: 128525d431e18e0f3f1849c97dfec05d3c35cc7f
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Apr 27 16:09:12 EDT 2025

pc64: don't panic when running out of page-tables

We used to just panic if we'r out of kernel memory
for MMU page tables.

Instead, call flushmmu() and retry, waiting until
we can allocate the memory.

--- a/sys/src/9/pc64/mmu.c
+++ b/sys/src/9/pc64/mmu.c
@@ -179,10 +179,12 @@
 			n = 256;
 			p = malloc(n * sizeof(MMU));
 			if(p == nil)
-				panic("mmualloc: out of memory for MMU");
+				return nil;
 			p->page = mallocalign(n * PTSZ, BY2PG, 0, 0);
-			if(p->page == nil)
-				panic("mmualloc: out of memory for MMU pages");
+			if(p->page == nil){
+				free(p);
+				return nil;
+			}
 			for(i=1; i<n; i++){
 				p[i].page = p[i-1].page + (1<<PTSHIFT);
 				p[i-1].next = &p[i];
@@ -210,8 +212,8 @@
 	if(va < VMAP){
 		assert(up != nil);
 		assert((va < USTKTOP) || (va >= KMAP && va < KMAP+KMAPSIZE));
-
-		p = mmualloc();
+		if((p = mmualloc()) == nil)
+			return nil;
 		p->index = index;
 		p->level = level;
 		if(va < USTKTOP){
@@ -246,7 +248,7 @@
 }
 
 uintptr*
-mmuwalk(uintptr* table, uintptr va, int level, int create)
+mmuwalk(uintptr *table, uintptr va, int level, int create)
 {
 	uintptr pte;
 	int i, x;
@@ -256,7 +258,7 @@
 		pte = table[x];
 		if(pte & PTEVALID){
 			if(pte & PTESIZE)
-				return 0;
+				return nil;
 			pte = PPN(pte);
 			if(pte >= (uintptr)-KZERO)
 				table = (void*)(pte + VMAP);
@@ -264,8 +266,10 @@
 				table = (void*)(pte + KZERO);
 		} else {
 			if(!create)
-				return 0;
+				return nil;
 			table = mmucreate(table, va, i, x);
+			if(table == nil)
+				return nil;
 		}
 		x = PTLX(va, i);
 	}
@@ -272,6 +276,22 @@
 	return &table[x];
 }
 
+static uintptr*
+getpte(uintptr va)
+{
+	uintptr *pte;
+
+	if((pte = mmuwalk(m->pml4, va, 0, 1)) == nil){
+		flushmmu();
+		while((pte = mmuwalk(m->pml4, va, 0, 1)) == nil){
+			int x = spllo();
+			resrcwait("out of MMU pages");
+			splx(x);
+		}
+	}
+	return pte;
+}
+
 static int
 ptecount(uintptr va, int level)
 {
@@ -500,9 +520,7 @@
 	int x;
 
 	x = splhi();
-	pte = mmuwalk(m->pml4, va, 0, 1);
-	if(pte == 0)
-		panic("putmmu: bug: va=%#p pa=%#p", va, pa);
+	pte = getpte(va);
 	old = *pte;
 	*pte = pa | PTEACCESSED|PTEDIRTY|PTEUSER;
 	splx(x);
@@ -522,7 +540,7 @@
 
 	x = splhi();
 	pte = mmuwalk(m->pml4, va, 0, 0);
-	if(pte == 0 || ((old = *pte) & PTEVALID) == 0 || PPN(old) == pa){
+	if(pte == nil || ((old = *pte) & PTEVALID) == 0 || PPN(old) == pa){
 		splx(x);
 		return;
 	}
@@ -550,8 +568,8 @@
 
 	x = splhi();
 	va = KMAP + (((uintptr)up->kmapindex++ << PGSHIFT) & (KMAPSIZE-1));
-	pte = mmuwalk(m->pml4, va, 0, 1);
-	if(pte == 0 || (*pte & PTEVALID) != 0)
+	pte = getpte(va);
+	if((*pte & PTEVALID) != 0)
 		panic("kmap: pa=%#p va=%#p", pa, va);
 	*pte = pa | PTEACCESSED|PTEDIRTY|PTEWRITE|PTENOEXEC|PTEVALID;
 	splx(x);
@@ -571,7 +589,7 @@
 
 	x = splhi();
 	pte = mmuwalk(m->pml4, va, 0, 0);
-	if(pte == 0 || (*pte & PTEVALID) == 0)
+	if(pte == nil || (*pte & PTEVALID) == 0)
 		panic("kunmap: va=%#p", va);
 	*pte = 0;
 	splx(x);
@@ -632,9 +650,9 @@
 	for(va = (uintptr)a; n > 0; n -= z, va += z){
 		l = 0;
 		pte = mmuwalk(m->pml4, va, l, 0);
-		if(pte == 0)
+		if(pte == nil)
 			pte = mmuwalk(m->pml4, va, ++l, 0);
-		if(pte == 0 || (*pte & PTEVALID) == 0)
+		if(pte == nil || (*pte & PTEVALID) == 0)
 			panic("patwc: va=%#p", va);
 		z = PGLSZ(l);
 		z -= va & (z-1);
--