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