x86: Make an editable copy of the MP tables

I have a machine that appears to have some bad entries.  I'd like to
just edit the table in place, but there's no guarantee the tables are in
actual RAM.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/arch/x86/mp.c b/kern/arch/x86/mp.c
index 2bb8b49..caa9009 100644
--- a/kern/arch/x86/mp.c
+++ b/kern/arch/x86/mp.c
@@ -59,6 +59,10 @@
 	{"ISA   ", IPhigh, TMedge,},
 };
 
+/* Editable version of the MP tables so we can fix botched entries.  Kmalloced,
+ * never freed.  Might be NULL if pcmp checks failed.*/
+static PCMP *pcmp;
+
 static Mpbus *mpbus[Nbus];
 int mpisabusno = -1;
 #define MP_VERBOSE_DEBUG 0
@@ -420,12 +424,22 @@
 //  return sigscan(KADDR(0xa0000 - 1024), 1024, signature);
 }
 
+static PCMP *copy_pcmp(PCMP *pcmp)
+{
+	PCMP *new_pcmp;
+	size_t n = l16get(pcmp->length) + l16get(pcmp->xlength);
+
+	new_pcmp = kmalloc(n, MEM_ATOMIC);
+	assert(new_pcmp);
+	memcpy(new_pcmp, pcmp, n);
+	return new_pcmp;
+}
+
 int mpsinit(int maxcores)
 {
 	uint8_t *p;
-	int i, n;
+	int i;
 	_MP_ *mp;
-	PCMP *pcmp;
 
 	if ((mp = sigsearch("_MP_")) == NULL) {
 		printk("No mp tables found, might have issues!\n");
@@ -448,14 +462,16 @@
 	if ((pcmp = KADDR_NOCHECK(l32get(mp->addr))) == NULL)
 		return maxcores;
 	if (pcmp->revision != 1 && pcmp->revision != 4) {
+		pcmp = NULL;
 		return maxcores;
 	}
-	n = l16get(pcmp->length) + l16get(pcmp->xlength);
-	if ((pcmp = KADDR_NOCHECK(l32get(mp->addr))) == NULL)
-		return maxcores;
 	if (sigchecksum(pcmp, l16get(pcmp->length)) != 0) {
+		pcmp = NULL;
 		return maxcores;
 	}
+
+	pcmp = copy_pcmp(pcmp);
+
 	if (MP_VERBOSE_DEBUG) {
 		printk("PCMP @ %#p length %p revision %d\n",
 			   pcmp, l16get(pcmp->length), pcmp->revision);