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>