panic: vm_fault: fault on nofualt entry, addr: 81423000

John Baldwin jhb at freebsd.org
Mon Jan 28 15:09:24 PST 2008


On Monday 28 January 2008 01:03:45 pm Pete French wrote:
> o.k., done some investigative work, and I think i have actually tracke
> dodnw what is going wrong, though i do not know how to fix it. mapping
> the header calls madt_map_table, which in turn calls madt_map
> to do the actual mapping:
> 
> 	madt_map called with pa 0x7fec7f40, offset 1, length 60
> 	'off' becomes 3904, and the rounded length 4096
> 	pmap_kenter_temporary called with pa 0x7fec7000, offset 1
> 	gives va of 0x8142300
> 	returns 0x81423f40
> 
> thus the header is ending up in page 0x8142300 if I read that correctly. 
this
> is importnat for later on. meanwhile, back at the table scanning code...
> 
> 	rsdt mapped at 0x81423f40
> 	table offset at 0x81423f64
> 	count is 6
> 	table offset address and their contents
> 	0	0x81423f64	0x7fec7fe8
> 	1	0x81423f68	0x7fec805c
> 	2	0x81423f6c	0x7fec80c4
> 	3	0x81423f70	0x7fec8127
> 	4	0x81423f74	0x7fec8163
> 	5	0x81423f78	0x7fec8195
> 
> so, it probes the first table, held at 0x7fec7fe8 as indicated by
> the address in 0x81423f64. this calls madt_map to map the table
> 
> 	madt_map called with pa 0x7fec7fe8, offset 0, length 36
> 	'off' becomes 4072, and the rounded length 8192
> 	pmap_kenter_temporary called with pa 0x7fec7000, offset 0
> 	pmap_kenter called with va 0x8142300, pa 0x7fec8000
> 	gives va of 0x8142200
> 	returns 0x81422fe8
> 
> code is looking for a signature of 'APIC', but this table has 'FACP', so
> a call is made to madt_unmap before returning
> 
> 	madt_unmap called with data 0x81422fe8, length 36
> 	'off' becomes 4072, and the rounded length 8192
> 	pmap_kremove called with 0x81422000
> 	pmap_kremove called with 0x81423000
> 
> the function then returns 0, and the loop goes round again to look
> at table entry 1. the address of the table is stored at 0x81423f68
> as you can see from the list above, and it is when it tries to access
> that address that it panics.
> 
> now preseumably the panic is correct - 0x81423f68 is in page 0x81423000,
> and didn't we just unmap that ? now I dont really understand this fully,
> but why is page 0x81423000 being touched at all ? shouldnt the mapped
> pages be 0x81421000 and 0x81422000 instead so they don't clash with
> the already mapped 0x81423000 ? The unmap function is quite correctly doing
> the reverse of the map function, but maybe theres something simply going
> wrong in the algorithm working out which pages to map ?

I think the problem is that the header for the FACP table crossed a page 
boundary so we had to map 2 pages to map the header, but the code assumes 
only 1 page is needed so when the second page was mapped, it overlapped with 
the page holding the XSDT.  Here's a fix:

Index: madt.c
===================================================================
RCS file: /usr/cvs/src/sys/i386/acpica/madt.c,v
retrieving revision 1.28
diff -u -r1.28 madt.c
--- madt.c	11 Sep 2007 22:54:09 -0000	1.28
+++ madt.c	28 Jan 2008 21:25:03 -0000
@@ -109,9 +109,11 @@
 /*
  * Code to abuse the crashdump map to map in the tables for the early
  * probe.  We cheat and make the following assumptions about how we
- * use this KVA: page 0 is used to map in the first page of each table
- * found via the RSDT or XSDT and pages 1 to n are used to map in the
- * RSDT or XSDT.  The offset is in pages; the length is in bytes.
+ * use this KVA: pages 0 and 1 are used to map in the header of each
+ * table found via the RSDT or XSDT and pages 2 to n are used to map
+ * in the RSDT or XSDT.  We have to use 2 pages for the table headers
+ * in case a header spans a page boundary.  The offset is in pages;
+ * the length is in bytes.
  */
 static void *
 madt_map(vm_paddr_t pa, int offset, vm_offset_t length)
@@ -232,7 +234,7 @@
 				printf("MADT: RSDP failed extended checksum\n");
 			return (ENXIO);
 		}
-		xsdt = madt_map_table(rsdp->XsdtPhysicalAddress, 1,
+		xsdt = madt_map_table(rsdp->XsdtPhysicalAddress, 2,
 		    ACPI_SIG_XSDT);
 		if (xsdt == NULL) {
 			if (bootverbose)
@@ -246,7 +248,7 @@
 				break;
 		madt_unmap_table(xsdt);
 	} else {
-		rsdt = madt_map_table(rsdp->RsdtPhysicalAddress, 1,
+		rsdt = madt_map_table(rsdp->RsdtPhysicalAddress, 2,
 		    ACPI_SIG_RSDT);
 		if (rsdt == NULL) {
 			if (bootverbose)

-- 
John Baldwin


More information about the freebsd-stable mailing list