Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 29 Oct 2009 17:15:22 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r198618 - in stable/7/sys: . amd64/acpica amd64/include contrib/pf dev/acpica i386/acpica i386/include
Message-ID:  <200910291715.n9THFMIq004495@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Thu Oct 29 17:15:22 2009
New Revision: 198618
URL: http://svn.freebsd.org/changeset/base/198618

Log:
  MFC 197439:
  Extract the code to find and map the MADT ACPI table during early kernel
  startup and genericize it so it can be reused to map other tables as well:
  - Add a routine to walk a list of ACPI subtables such as those used in the
    APIC and SRAT tables in the MI acpi(4) driver.
  - Move the routines for mapping and unmapping an ACPI table as well as
    mapping the RSDT or XSDT and searching for a table with a given signature
    out into acpica_machdep.c for both amd64 and i386.

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/amd64/acpica/acpi_machdep.c
  stable/7/sys/amd64/acpica/madt.c
  stable/7/sys/amd64/include/acpica_machdep.h
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/acpica/acpi.c
  stable/7/sys/dev/acpica/acpivar.h
  stable/7/sys/i386/acpica/acpi_machdep.c
  stable/7/sys/i386/acpica/madt.c
  stable/7/sys/i386/include/acpica_machdep.h

Modified: stable/7/sys/amd64/acpica/acpi_machdep.c
==============================================================================
--- stable/7/sys/amd64/acpica/acpi_machdep.c	Thu Oct 29 17:14:18 2009	(r198617)
+++ stable/7/sys/amd64/acpica/acpi_machdep.c	Thu Oct 29 17:15:22 2009	(r198618)
@@ -29,8 +29,12 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/bus.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
 
 #include <contrib/dev/acpica/acpi.h>
+#include <contrib/dev/acpica/actables.h>
+
 #include <dev/acpica/acpivar.h>
 
 static int intr_model = ACPI_INTR_PIC;
@@ -67,3 +71,243 @@ acpi_cpu_c1()
 {
 	__asm __volatile("sti; hlt");
 }
+
+/*
+ * Support for mapping ACPI tables during early boot.  Currently this
+ * uses the crashdump map to map each table.  However, the crashdump
+ * map is created in pmap_bootstrap() right after the direct map, so
+ * we should be able to just use pmap_mapbios() here instead.
+ *
+ * This makes the following assumptions about how we 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.  This has to use 2 pages for the table headers in case a
+ * header spans a page boundary.
+ *
+ * XXX: We don't ensure the table fits in the available address space
+ * in the crashdump map.
+ */
+
+/*
+ * Map some memory using the crashdump map.  'offset' is an offset in
+ * pages into the crashdump map to use for the start of the mapping.
+ */
+static void *
+table_map(vm_paddr_t pa, int offset, vm_offset_t length)
+{
+	vm_offset_t va, off;
+	void *data;
+
+	off = pa & PAGE_MASK;
+	length = roundup(length + off, PAGE_SIZE);
+	pa = pa & PG_FRAME;
+	va = (vm_offset_t)pmap_kenter_temporary(pa, offset) +
+	    (offset * PAGE_SIZE);
+	data = (void *)(va + off);
+	length -= PAGE_SIZE;
+	while (length > 0) {
+		va += PAGE_SIZE;
+		pa += PAGE_SIZE;
+		length -= PAGE_SIZE;
+		pmap_kenter(va, pa);
+		invlpg(va);
+	}
+	return (data);
+}
+
+/* Unmap memory previously mapped with table_map(). */
+static void
+table_unmap(void *data, vm_offset_t length)
+{
+	vm_offset_t va, off;
+
+	va = (vm_offset_t)data;
+	off = va & PAGE_MASK;
+	length = roundup(length + off, PAGE_SIZE);
+	va &= ~PAGE_MASK;
+	while (length > 0) {
+		pmap_kremove(va);
+		invlpg(va);
+		va += PAGE_SIZE;
+		length -= PAGE_SIZE;
+	}
+}
+
+/*
+ * Map a table at a given offset into the crashdump map.  It first
+ * maps the header to determine the table length and then maps the
+ * entire table.
+ */
+static void *
+map_table(vm_paddr_t pa, int offset, const char *sig)
+{
+	ACPI_TABLE_HEADER *header;
+	vm_offset_t length;
+	void *table;
+
+	header = table_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
+	if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) {
+		table_unmap(header, sizeof(ACPI_TABLE_HEADER));
+		return (NULL);
+	}
+	length = header->Length;
+	table_unmap(header, sizeof(ACPI_TABLE_HEADER));
+	table = table_map(pa, offset, length);
+	if (ACPI_FAILURE(AcpiTbChecksum(table, length))) {
+		if (bootverbose)
+			printf("ACPI: Failed checksum for table %s\n", sig);
+		table_unmap(table, length);
+		return (NULL);
+	}
+	return (table);
+}
+
+/*
+ * See if a given ACPI table is the requested table.  Returns the
+ * length of the able if it matches or zero on failure.
+ */
+static int
+probe_table(vm_paddr_t address, const char *sig)
+{
+	ACPI_TABLE_HEADER *table;
+
+	table = table_map(address, 0, sizeof(ACPI_TABLE_HEADER));
+	if (table == NULL) {
+		if (bootverbose)
+			printf("ACPI: Failed to map table at 0x%jx\n",
+			    (uintmax_t)address);
+		return (0);
+	}
+	if (bootverbose)
+		printf("Table '%.4s' at 0x%jx\n", table->Signature,
+		    (uintmax_t)address);
+
+	if (strncmp(table->Signature, sig, ACPI_NAME_SIZE) != 0) {
+		table_unmap(table, sizeof(ACPI_TABLE_HEADER));
+		return (0);
+	}
+	table_unmap(table, sizeof(ACPI_TABLE_HEADER));
+	return (1);
+}
+
+/*
+ * Try to map a table at a given physical address previously returned
+ * by acpi_find_table().
+ */
+void *
+acpi_map_table(vm_paddr_t pa, const char *sig)
+{
+
+	return (map_table(pa, 0, sig));
+}
+
+/* Unmap a table previously mapped via acpi_map_table(). */
+void
+acpi_unmap_table(void *table)
+{
+	ACPI_TABLE_HEADER *header;
+
+	header = (ACPI_TABLE_HEADER *)table;
+	table_unmap(table, header->Length);
+}
+
+/*
+ * Return the physical address of the requested table or zero if one
+ * is not found.
+ */
+vm_paddr_t
+acpi_find_table(const char *sig)
+{
+	ACPI_PHYSICAL_ADDRESS rsdp_ptr;
+	ACPI_TABLE_RSDP *rsdp;
+	ACPI_TABLE_RSDT *rsdt;
+	ACPI_TABLE_XSDT *xsdt;
+	ACPI_TABLE_HEADER *table;
+	vm_paddr_t addr;
+	int i, count;
+
+	if (resource_disabled("acpi", 0))
+		return (0);
+
+	/*
+	 * Map in the RSDP.  Since ACPI uses AcpiOsMapMemory() which in turn
+	 * calls pmap_mapbios() to find the RSDP, we assume that we can use
+	 * pmap_mapbios() to map the RSDP.
+	 */
+	if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
+		return (0);
+	rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
+	if (rsdp == NULL) {
+		if (bootverbose)
+			printf("ACPI: Failed to map RSDP\n");
+		return (0);
+	}
+
+	/*
+	 * For ACPI >= 2.0, use the XSDT if it is available.
+	 * Otherwise, use the RSDT.  We map the XSDT or RSDT at page 2
+	 * in the crashdump area.  Pages 0 and 1 are used to map in the
+	 * headers of candidate ACPI tables.
+	 */
+	addr = 0;
+	if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
+		/*
+		 * AcpiOsGetRootPointer only verifies the checksum for
+		 * the version 1.0 portion of the RSDP.  Version 2.0 has
+		 * an additional checksum that we verify first.
+		 */
+		if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
+			if (bootverbose)
+				printf("ACPI: RSDP failed extended checksum\n");
+			return (0);
+		}
+		xsdt = map_table(rsdp->XsdtPhysicalAddress, 2, ACPI_SIG_XSDT);
+		if (xsdt == NULL) {
+			if (bootverbose)
+				printf("ACPI: Failed to map XSDT\n");
+			return (0);
+		}
+		count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
+		    sizeof(UINT64);
+		for (i = 0; i < count; i++)
+			if (probe_table(xsdt->TableOffsetEntry[i], sig)) {
+				addr = xsdt->TableOffsetEntry[i];
+				break;
+			}
+		acpi_unmap_table(xsdt);
+	} else {
+		rsdt = map_table(rsdp->RsdtPhysicalAddress, 2, ACPI_SIG_RSDT);
+		if (rsdt == NULL) {
+			if (bootverbose)
+				printf("ACPI: Failed to map RSDT\n");
+			return (0);
+		}
+		count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
+		    sizeof(UINT32);
+		for (i = 0; i < count; i++)
+			if (probe_table(rsdt->TableOffsetEntry[i], sig)) {
+				addr = rsdt->TableOffsetEntry[i];
+				break;
+			}
+		acpi_unmap_table(rsdt);
+	}
+	pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP));
+	if (addr == 0) {
+		if (bootverbose)
+			printf("ACPI: No %s table found\n", sig);
+		return (0);
+	}
+	if (bootverbose)
+		printf("%s: Found table at 0x%jx\n", sig, (uintmax_t)addr);
+
+	/*
+	 * Verify that we can map the full table and that its checksum is
+	 * correct, etc.
+	 */
+	table = map_table(addr, 0, sig);
+	if (table == NULL)
+		return (0);
+	acpi_unmap_table(table);
+
+	return (addr);
+}

Modified: stable/7/sys/amd64/acpica/madt.c
==============================================================================
--- stable/7/sys/amd64/acpica/madt.c	Thu Oct 29 17:14:18 2009	(r198617)
+++ stable/7/sys/amd64/acpica/madt.c	Thu Oct 29 17:15:22 2009	(r198618)
@@ -36,25 +36,19 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/smp.h>
-
 #include <vm/vm.h>
-#include <vm/vm_param.h>
 #include <vm/pmap.h>
 
 #include <machine/apicreg.h>
-#include <machine/frame.h>
 #include <machine/intr_machdep.h>
 #include <machine/apicvar.h>
-#include <machine/md_var.h>
-#include <machine/specialreg.h>
 
 #include <contrib/dev/acpica/acpi.h>
 #include <contrib/dev/acpica/actables.h>
+
 #include <dev/acpica/acpivar.h>
 #include <dev/pci/pcivar.h>
 
-typedef	void madt_entry_handler(ACPI_SUBTABLE_HEADER *entry, void *arg);
-
 /* These two arrays are indexed by APIC IDs. */
 struct ioapic_info {
 	void *io_apic;
@@ -77,8 +71,6 @@ static enum intr_polarity interrupt_pola
 static enum intr_trigger interrupt_trigger(UINT16 IntiFlags, UINT8 Source);
 static int	madt_find_cpu(u_int acpi_id, u_int *apic_id);
 static int	madt_find_interrupt(int intr, void **apic, u_int *pin);
-static void	*madt_map(vm_paddr_t pa, int offset, vm_offset_t length);
-static void	*madt_map_table(vm_paddr_t pa, int offset, const char *sig);
 static void	madt_parse_apics(ACPI_SUBTABLE_HEADER *entry, void *arg);
 static void	madt_parse_interrupt_override(
 		    ACPI_MADT_INTERRUPT_OVERRIDE *intr);
@@ -90,13 +82,10 @@ static int	madt_probe(void);
 static int	madt_probe_cpus(void);
 static void	madt_probe_cpus_handler(ACPI_SUBTABLE_HEADER *entry,
 		    void *arg __unused);
-static int	madt_probe_table(vm_paddr_t address);
 static void	madt_register(void *dummy);
 static int	madt_setup_local(void);
 static int	madt_setup_io(void);
-static void	madt_unmap(void *data, vm_offset_t length);
-static void	madt_unmap_table(void *table);
-static void	madt_walk_table(madt_entry_handler *handler, void *arg);
+static void	madt_walk_table(acpi_subtable_handler *handler, void *arg);
 
 static struct apic_enumerator madt_enumerator = {
 	"MADT",
@@ -107,224 +96,30 @@ static struct apic_enumerator madt_enume
 };
 
 /*
- * 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: 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)
-{
-	vm_offset_t va, off;
-	void *data;
-
-	off = pa & PAGE_MASK;
-	length = roundup(length + off, PAGE_SIZE);
-	pa = pa & PG_FRAME;
-	va = (vm_offset_t)pmap_kenter_temporary(pa, offset) +
-	    (offset * PAGE_SIZE);
-	data = (void *)(va + off);
-	length -= PAGE_SIZE;
-	while (length > 0) {
-		va += PAGE_SIZE;
-		pa += PAGE_SIZE;
-		length -= PAGE_SIZE;
-		pmap_kenter(va, pa);
-		invlpg(va);
-	}
-	return (data);
-}
-
-static void
-madt_unmap(void *data, vm_offset_t length)
-{
-	vm_offset_t va, off;
-
-	va = (vm_offset_t)data;
-	off = va & PAGE_MASK;
-	length = roundup(length + off, PAGE_SIZE);
-	va &= ~PAGE_MASK;
-	while (length > 0) {
-		pmap_kremove(va);
-		invlpg(va);
-		va += PAGE_SIZE;
-		length -= PAGE_SIZE;
-	}
-}
-
-static void *
-madt_map_table(vm_paddr_t pa, int offset, const char *sig)
-{
-	ACPI_TABLE_HEADER *header;
-	vm_offset_t length;
-	void *table;
-
-	header = madt_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
-	if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) {
-		madt_unmap(header, sizeof(ACPI_TABLE_HEADER));
-		return (NULL);
-	}
-	length = header->Length;
-	madt_unmap(header, sizeof(ACPI_TABLE_HEADER));
-	table = madt_map(pa, offset, length);
-	if (ACPI_FAILURE(AcpiTbChecksum(table, length))) {
-		if (bootverbose)
-			printf("MADT: Failed checksum for table %s\n", sig);
-		madt_unmap(table, length);
-		return (NULL);
-	}
-	return (table);
-}
-
-static void
-madt_unmap_table(void *table)
-{
-	ACPI_TABLE_HEADER *header;
-
-	header = (ACPI_TABLE_HEADER *)table;
-	madt_unmap(table, header->Length);
-}
-
-/*
  * Look for an ACPI Multiple APIC Description Table ("APIC")
  */
 static int
 madt_probe(void)
 {
-	ACPI_PHYSICAL_ADDRESS rsdp_ptr;
-	ACPI_TABLE_RSDP *rsdp;
-	ACPI_TABLE_RSDT *rsdt;
-	ACPI_TABLE_XSDT *xsdt;
-	int i, count;
-
-	if (resource_disabled("acpi", 0))
-		return (ENXIO);
-
-	/*
-	 * Map in the RSDP.  Since ACPI uses AcpiOsMapMemory() which in turn
-	 * calls pmap_mapbios() to find the RSDP, we assume that we can use
-	 * pmap_mapbios() to map the RSDP.
-	 */
-	if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
-		return (ENXIO);
-	rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
-	if (rsdp == NULL) {
-		if (bootverbose)
-			printf("MADT: Failed to map RSDP\n");
-		return (ENXIO);
-	}
-
-	/*
-	 * For ACPI >= 2.0, use the XSDT if it is available.
-	 * Otherwise, use the RSDT.  We map the XSDT or RSDT at page 1
-	 * in the crashdump area.  Page 0 is used to map in the
-	 * headers of candidate ACPI tables.
-	 */
-	if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
-		/*
-		 * AcpiOsGetRootPointer only verifies the checksum for
-		 * the version 1.0 portion of the RSDP.  Version 2.0 has
-		 * an additional checksum that we verify first.
-		 */
-		if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
-			if (bootverbose)
-				printf("MADT: RSDP failed extended checksum\n");
-			return (ENXIO);
-		}
-		xsdt = madt_map_table(rsdp->XsdtPhysicalAddress, 2,
-		    ACPI_SIG_XSDT);
-		if (xsdt == NULL) {
-			if (bootverbose)
-				printf("MADT: Failed to map XSDT\n");
-			return (ENXIO);
-		}
-		count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
-		    sizeof(UINT64);
-		for (i = 0; i < count; i++)
-			if (madt_probe_table(xsdt->TableOffsetEntry[i]))
-				break;
-		madt_unmap_table(xsdt);
-	} else {
-		rsdt = madt_map_table(rsdp->RsdtPhysicalAddress, 2,
-		    ACPI_SIG_RSDT);
-		if (rsdt == NULL) {
-			if (bootverbose)
-				printf("MADT: Failed to map RSDT\n");
-			return (ENXIO);
-		}
-		count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
-		    sizeof(UINT32);
-		for (i = 0; i < count; i++)
-			if (madt_probe_table(rsdt->TableOffsetEntry[i]))
-				break;
-		madt_unmap_table(rsdt);
-	}
-	pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP));
-	if (madt_physaddr == 0) {
-		if (bootverbose)
-			printf("MADT: No MADT table found\n");
-		return (ENXIO);
-	}
-	if (bootverbose)
-		printf("MADT: Found table at 0x%jx\n",
-		    (uintmax_t)madt_physaddr);
 
-	/*
-	 * Verify that we can map the full table and that its checksum is
-	 * correct, etc.
-	 */
-	madt = madt_map_table(madt_physaddr, 0, ACPI_SIG_MADT);
-	if (madt == NULL)
+	madt_physaddr = acpi_find_table(ACPI_SIG_MADT);
+	if (madt_physaddr == 0)
 		return (ENXIO);
-	madt_unmap_table(madt);
-	madt = NULL;
-
 	return (0);
 }
 
 /*
- * See if a given ACPI table is the MADT.
- */
-static int
-madt_probe_table(vm_paddr_t address)
-{
-	ACPI_TABLE_HEADER *table;
-
-	table = madt_map(address, 0, sizeof(ACPI_TABLE_HEADER));
-	if (table == NULL) {
-		if (bootverbose)
-			printf("MADT: Failed to map table at 0x%jx\n",
-			    (uintmax_t)address);
-		return (0);
-	}
-	if (bootverbose)
-		printf("Table '%.4s' at 0x%jx\n", table->Signature,
-		    (uintmax_t)address);
-
-	if (strncmp(table->Signature, ACPI_SIG_MADT, ACPI_NAME_SIZE) != 0) {
-		madt_unmap(table, sizeof(ACPI_TABLE_HEADER));
-		return (0);
-	}
-	madt_physaddr = address;
-	madt_length = table->Length;
-	madt_unmap(table, sizeof(ACPI_TABLE_HEADER));
-	return (1);
-}
-
-/*
  * Run through the MP table enumerating CPUs.
  */
 static int
 madt_probe_cpus(void)
 {
 
-	madt = madt_map_table(madt_physaddr, 0, ACPI_SIG_MADT);
+	madt = acpi_map_table(madt_physaddr, ACPI_SIG_MADT);
+	madt_length = madt->Header.Length;
 	KASSERT(madt != NULL, ("Unable to re-map MADT"));
 	madt_walk_table(madt_probe_cpus_handler, NULL);
-	madt_unmap_table(madt);
+	acpi_unmap_table(madt);
 	madt = NULL;
 	return (0);
 }
@@ -415,17 +210,11 @@ SYSINIT(madt_register, SI_SUB_TUNABLES -
  * Call the handler routine for each entry in the MADT table.
  */
 static void
-madt_walk_table(madt_entry_handler *handler, void *arg)
+madt_walk_table(acpi_subtable_handler *handler, void *arg)
 {
-	ACPI_SUBTABLE_HEADER *entry;
-	u_char *p, *end;
 
-	end = (u_char *)(madt) + madt->Header.Length;
-	for (p = (u_char *)(madt + 1); p < end; ) {
-		entry = (ACPI_SUBTABLE_HEADER *)p;
-		handler(entry, arg);
-		p += entry->Length;
-	}
+	acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
+	    handler, arg);
 }
 
 static void

Modified: stable/7/sys/amd64/include/acpica_machdep.h
==============================================================================
--- stable/7/sys/amd64/include/acpica_machdep.h	Thu Oct 29 17:14:18 2009	(r198617)
+++ stable/7/sys/amd64/include/acpica_machdep.h	Thu Oct 29 17:15:22 2009	(r198618)
@@ -77,5 +77,8 @@ extern int	acpi_release_global_lock(uint
 
 void	acpi_SetDefaultIntrModel(int model);
 void	acpi_cpu_c1(void);
+void	*acpi_map_table(vm_paddr_t pa, const char *sig);
+void	acpi_unmap_table(void *table);
+vm_paddr_t acpi_find_table(const char *sig);
 
 #endif /* __ACPICA_MACHDEP_H__ */

Modified: stable/7/sys/dev/acpica/acpi.c
==============================================================================
--- stable/7/sys/dev/acpica/acpi.c	Thu Oct 29 17:14:18 2009	(r198617)
+++ stable/7/sys/dev/acpica/acpi.c	Thu Oct 29 17:15:22 2009	(r198618)
@@ -2166,6 +2166,28 @@ acpi_SetIntrModel(int model)
 }
 
 /*
+ * Walk subtables of a table and call a callback routine for each
+ * subtable.  The caller should provide the first subtable and a
+ * pointer to the end of the table.  This can be used to walk tables
+ * such as MADT and SRAT that use subtable entries.
+ */
+void
+acpi_walk_subtables(void *first, void *end, acpi_subtable_handler *handler,
+    void *arg)
+{
+    ACPI_SUBTABLE_HEADER *entry;
+
+    for (entry = first; (void *)entry < end; ) {
+	/* Avoid an infinite loop if we hit a bogus entry. */
+	if (entry->Length < sizeof(ACPI_SUBTABLE_HEADER))
+	    return;
+
+	handler(entry, arg);
+	entry = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, entry, entry->Length);
+    }
+}
+
+/*
  * DEPRECATED.  This interface has serious deficiencies and will be
  * removed.
  *

Modified: stable/7/sys/dev/acpica/acpivar.h
==============================================================================
--- stable/7/sys/dev/acpica/acpivar.h	Thu Oct 29 17:14:18 2009	(r198617)
+++ stable/7/sys/dev/acpica/acpivar.h	Thu Oct 29 17:15:22 2009	(r198618)
@@ -307,6 +307,9 @@ void		acpi_EnterDebugger(void);
 	ACPI_DEVINFO_PRESENT(x, ACPI_STA_PRESENT | ACPI_STA_FUNCTIONAL | \
 	    ACPI_STA_BATT_PRESENT)
 
+/* Callback function type for walking subtables within a table. */
+typedef void acpi_subtable_handler(ACPI_SUBTABLE_HEADER *, void *);
+
 BOOLEAN		acpi_DeviceIsPresent(device_t dev);
 BOOLEAN		acpi_BatteryIsPresent(device_t dev);
 ACPI_STATUS	acpi_GetHandleInScope(ACPI_HANDLE parent, char *path,
@@ -339,6 +342,8 @@ void		acpi_UserNotify(const char *subsys
 int		acpi_bus_alloc_gas(device_t dev, int *type, int *rid,
 		    ACPI_GENERIC_ADDRESS *gas, struct resource **res,
 		    u_int flags);
+void		acpi_walk_subtables(void *first, void *end,
+		    acpi_subtable_handler *handler, void *arg);
 
 struct acpi_parse_resource_set {
     void	(*set_init)(device_t dev, void *arg, void **context);

Modified: stable/7/sys/i386/acpica/acpi_machdep.c
==============================================================================
--- stable/7/sys/i386/acpica/acpi_machdep.c	Thu Oct 29 17:14:18 2009	(r198617)
+++ stable/7/sys/i386/acpica/acpi_machdep.c	Thu Oct 29 17:15:22 2009	(r198618)
@@ -41,6 +41,8 @@ __FBSDID("$FreeBSD$");
 #include <vm/pmap.h>
 
 #include <contrib/dev/acpica/acpi.h>
+#include <contrib/dev/acpica/actables.h>
+
 #include <dev/acpica/acpivar.h>
 #include <dev/acpica/acpiio.h>
 
@@ -549,3 +551,241 @@ acpi_cpu_c1()
 {
 	__asm __volatile("sti; hlt");
 }
+
+/*
+ * Support for mapping ACPI tables during early boot.  This abuses the
+ * crashdump map because the kernel cannot allocate KVA in
+ * pmap_mapbios() when this is used.  This makes the following
+ * assumptions about how we 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.  This has to use
+ * 2 pages for the table headers in case a header spans a page
+ * boundary.
+ *
+ * XXX: We don't ensure the table fits in the available address space
+ * in the crashdump map.
+ */
+
+/*
+ * Map some memory using the crashdump map.  'offset' is an offset in
+ * pages into the crashdump map to use for the start of the mapping.
+ */
+static void *
+table_map(vm_paddr_t pa, int offset, vm_offset_t length)
+{
+	vm_offset_t va, off;
+	void *data;
+
+	off = pa & PAGE_MASK;
+	length = roundup(length + off, PAGE_SIZE);
+	pa = pa & PG_FRAME;
+	va = (vm_offset_t)pmap_kenter_temporary(pa, offset) +
+	    (offset * PAGE_SIZE);
+	data = (void *)(va + off);
+	length -= PAGE_SIZE;
+	while (length > 0) {
+		va += PAGE_SIZE;
+		pa += PAGE_SIZE;
+		length -= PAGE_SIZE;
+		pmap_kenter(va, pa);
+		invlpg(va);
+	}
+	return (data);
+}
+
+/* Unmap memory previously mapped with table_map(). */
+static void
+table_unmap(void *data, vm_offset_t length)
+{
+	vm_offset_t va, off;
+
+	va = (vm_offset_t)data;
+	off = va & PAGE_MASK;
+	length = roundup(length + off, PAGE_SIZE);
+	va &= ~PAGE_MASK;
+	while (length > 0) {
+		pmap_kremove(va);
+		invlpg(va);
+		va += PAGE_SIZE;
+		length -= PAGE_SIZE;
+	}
+}
+
+/*
+ * Map a table at a given offset into the crashdump map.  It first
+ * maps the header to determine the table length and then maps the
+ * entire table.
+ */
+static void *
+map_table(vm_paddr_t pa, int offset, const char *sig)
+{
+	ACPI_TABLE_HEADER *header;
+	vm_offset_t length;
+	void *table;
+
+	header = table_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
+	if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) {
+		table_unmap(header, sizeof(ACPI_TABLE_HEADER));
+		return (NULL);
+	}
+	length = header->Length;
+	table_unmap(header, sizeof(ACPI_TABLE_HEADER));
+	table = table_map(pa, offset, length);
+	if (ACPI_FAILURE(AcpiTbChecksum(table, length))) {
+		if (bootverbose)
+			printf("ACPI: Failed checksum for table %s\n", sig);
+		table_unmap(table, length);
+		return (NULL);
+	}
+	return (table);
+}
+
+/*
+ * See if a given ACPI table is the requested table.  Returns the
+ * length of the able if it matches or zero on failure.
+ */
+static int
+probe_table(vm_paddr_t address, const char *sig)
+{
+	ACPI_TABLE_HEADER *table;
+
+	table = table_map(address, 0, sizeof(ACPI_TABLE_HEADER));
+	if (table == NULL) {
+		if (bootverbose)
+			printf("ACPI: Failed to map table at 0x%jx\n",
+			    (uintmax_t)address);
+		return (0);
+	}
+	if (bootverbose)
+		printf("Table '%.4s' at 0x%jx\n", table->Signature,
+		    (uintmax_t)address);
+
+	if (strncmp(table->Signature, sig, ACPI_NAME_SIZE) != 0) {
+		table_unmap(table, sizeof(ACPI_TABLE_HEADER));
+		return (0);
+	}
+	table_unmap(table, sizeof(ACPI_TABLE_HEADER));
+	return (1);
+}
+
+/*
+ * Try to map a table at a given physical address previously returned
+ * by acpi_find_table().
+ */
+void *
+acpi_map_table(vm_paddr_t pa, const char *sig)
+{
+
+	return (map_table(pa, 0, sig));
+}
+
+/* Unmap a table previously mapped via acpi_map_table(). */
+void
+acpi_unmap_table(void *table)
+{
+	ACPI_TABLE_HEADER *header;
+
+	header = (ACPI_TABLE_HEADER *)table;
+	table_unmap(table, header->Length);
+}
+
+/*
+ * Return the physical address of the requested table or zero if one
+ * is not found.
+ */
+vm_paddr_t
+acpi_find_table(const char *sig)
+{
+	ACPI_PHYSICAL_ADDRESS rsdp_ptr;
+	ACPI_TABLE_RSDP *rsdp;
+	ACPI_TABLE_RSDT *rsdt;
+	ACPI_TABLE_XSDT *xsdt;
+	ACPI_TABLE_HEADER *table;
+	vm_paddr_t addr;
+	int i, count;
+
+	if (resource_disabled("acpi", 0))
+		return (0);
+
+	/*
+	 * Map in the RSDP.  Since ACPI uses AcpiOsMapMemory() which in turn
+	 * calls pmap_mapbios() to find the RSDP, we assume that we can use
+	 * pmap_mapbios() to map the RSDP.
+	 */
+	if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
+		return (0);
+	rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
+	if (rsdp == NULL) {
+		if (bootverbose)
+			printf("ACPI: Failed to map RSDP\n");
+		return (0);
+	}
+
+	/*
+	 * For ACPI >= 2.0, use the XSDT if it is available.
+	 * Otherwise, use the RSDT.  We map the XSDT or RSDT at page 2
+	 * in the crashdump area.  Pages 0 and 1 are used to map in the
+	 * headers of candidate ACPI tables.
+	 */
+	addr = 0;
+	if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
+		/*
+		 * AcpiOsGetRootPointer only verifies the checksum for
+		 * the version 1.0 portion of the RSDP.  Version 2.0 has
+		 * an additional checksum that we verify first.
+		 */
+		if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
+			if (bootverbose)
+				printf("ACPI: RSDP failed extended checksum\n");
+			return (0);
+		}
+		xsdt = map_table(rsdp->XsdtPhysicalAddress, 2, ACPI_SIG_XSDT);
+		if (xsdt == NULL) {
+			if (bootverbose)
+				printf("ACPI: Failed to map XSDT\n");
+			return (0);
+		}
+		count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
+		    sizeof(UINT64);
+		for (i = 0; i < count; i++)
+			if (probe_table(xsdt->TableOffsetEntry[i], sig)) {
+				addr = xsdt->TableOffsetEntry[i];
+				break;
+			}
+		acpi_unmap_table(xsdt);
+	} else {
+		rsdt = map_table(rsdp->RsdtPhysicalAddress, 2, ACPI_SIG_RSDT);
+		if (rsdt == NULL) {
+			if (bootverbose)
+				printf("ACPI: Failed to map RSDT\n");
+			return (0);
+		}
+		count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
+		    sizeof(UINT32);
+		for (i = 0; i < count; i++)
+			if (probe_table(rsdt->TableOffsetEntry[i], sig)) {
+				addr = rsdt->TableOffsetEntry[i];
+				break;
+			}
+		acpi_unmap_table(rsdt);
+	}
+	pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP));
+	if (addr == 0) {
+		if (bootverbose)
+			printf("ACPI: No %s table found\n", sig);
+		return (0);
+	}
+	if (bootverbose)
+		printf("%s: Found table at 0x%jx\n", sig, (uintmax_t)addr);
+
+	/*
+	 * Verify that we can map the full table and that its checksum is
+	 * correct, etc.
+	 */
+	table = map_table(addr, 0, sig);
+	if (table == NULL)
+		return (0);
+	acpi_unmap_table(table);
+
+	return (addr);
+}

Modified: stable/7/sys/i386/acpica/madt.c
==============================================================================
--- stable/7/sys/i386/acpica/madt.c	Thu Oct 29 17:14:18 2009	(r198617)
+++ stable/7/sys/i386/acpica/madt.c	Thu Oct 29 17:15:22 2009	(r198618)
@@ -36,25 +36,19 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/smp.h>
-
 #include <vm/vm.h>
-#include <vm/vm_param.h>
 #include <vm/pmap.h>
 
 #include <machine/apicreg.h>
-#include <machine/frame.h>
 #include <machine/intr_machdep.h>
 #include <machine/apicvar.h>
-#include <machine/md_var.h>
-#include <machine/specialreg.h>
 
 #include <contrib/dev/acpica/acpi.h>
 #include <contrib/dev/acpica/actables.h>
+
 #include <dev/acpica/acpivar.h>
 #include <dev/pci/pcivar.h>
 
-typedef	void madt_entry_handler(ACPI_SUBTABLE_HEADER *entry, void *arg);
-
 /* These two arrays are indexed by APIC IDs. */
 struct ioapic_info {
 	void *io_apic;
@@ -77,8 +71,6 @@ static enum intr_polarity interrupt_pola
 static enum intr_trigger interrupt_trigger(UINT16 IntiFlags, UINT8 Source);
 static int	madt_find_cpu(u_int acpi_id, u_int *apic_id);
 static int	madt_find_interrupt(int intr, void **apic, u_int *pin);
-static void	*madt_map(vm_paddr_t pa, int offset, vm_offset_t length);
-static void	*madt_map_table(vm_paddr_t pa, int offset, const char *sig);
 static void	madt_parse_apics(ACPI_SUBTABLE_HEADER *entry, void *arg);
 static void	madt_parse_interrupt_override(
 		    ACPI_MADT_INTERRUPT_OVERRIDE *intr);
@@ -90,13 +82,10 @@ static int	madt_probe(void);
 static int	madt_probe_cpus(void);
 static void	madt_probe_cpus_handler(ACPI_SUBTABLE_HEADER *entry,
 		    void *arg __unused);
-static int	madt_probe_table(vm_paddr_t address);
 static void	madt_register(void *dummy);
 static int	madt_setup_local(void);
 static int	madt_setup_io(void);
-static void	madt_unmap(void *data, vm_offset_t length);
-static void	madt_unmap_table(void *table);
-static void	madt_walk_table(madt_entry_handler *handler, void *arg);
+static void	madt_walk_table(acpi_subtable_handler *handler, void *arg);
 
 static struct apic_enumerator madt_enumerator = {
 	"MADT",
@@ -106,87 +95,6 @@ static struct apic_enumerator madt_enume
 	madt_setup_io
 };
 
-/*
- * 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: 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)
-{
-	vm_offset_t va, off;
-	void *data;
-
-	off = pa & PAGE_MASK;
-	length = roundup(length + off, PAGE_SIZE);
-	pa = pa & PG_FRAME;
-	va = (vm_offset_t)pmap_kenter_temporary(pa, offset) +
-	    (offset * PAGE_SIZE);
-	data = (void *)(va + off);
-	length -= PAGE_SIZE;
-	while (length > 0) {
-		va += PAGE_SIZE;
-		pa += PAGE_SIZE;
-		length -= PAGE_SIZE;
-		pmap_kenter(va, pa);
-		invlpg(va);
-	}
-	return (data);
-}
-
-static void
-madt_unmap(void *data, vm_offset_t length)
-{
-	vm_offset_t va, off;
-
-	va = (vm_offset_t)data;
-	off = va & PAGE_MASK;
-	length = roundup(length + off, PAGE_SIZE);
-	va &= ~PAGE_MASK;
-	while (length > 0) {
-		pmap_kremove(va);
-		invlpg(va);
-		va += PAGE_SIZE;
-		length -= PAGE_SIZE;
-	}
-}
-
-static void *
-madt_map_table(vm_paddr_t pa, int offset, const char *sig)
-{
-	ACPI_TABLE_HEADER *header;
-	vm_offset_t length;
-	void *table;
-
-	header = madt_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
-	if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) {
-		madt_unmap(header, sizeof(ACPI_TABLE_HEADER));
-		return (NULL);
-	}
-	length = header->Length;
-	madt_unmap(header, sizeof(ACPI_TABLE_HEADER));
-	table = madt_map(pa, offset, length);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200910291715.n9THFMIq004495>