Changeset View
Changeset View
Standalone View
Standalone View
head/sys/i386/acpica/acpi_machdep.c
Show First 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | acpi_machdep_quirks(int *quirks) | ||||
*/ | */ | ||||
if (year > 90 && year < 99) | if (year > 90 && year < 99) | ||||
*quirks = ACPI_Q_BROKEN; | *quirks = ACPI_Q_BROKEN; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Support for mapping ACPI tables during early boot. This abuses the | * Map a table. First map the header to determine the table length and then map | ||||
* crashdump map because the kernel cannot allocate KVA in | * the entire table. | ||||
* 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 * | static void * | ||||
table_map(vm_paddr_t pa, int offset, vm_offset_t length) | map_table(vm_paddr_t pa, const char *sig) | ||||
{ | { | ||||
vm_offset_t va, off; | |||||
void *data; | |||||
off = pa & PAGE_MASK; | |||||
length = round_page(length + off); | |||||
pa = pmap_pg_frame(pa); | |||||
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 = round_page(length + off); | |||||
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; | ACPI_TABLE_HEADER *header; | ||||
vm_offset_t length; | vm_offset_t length; | ||||
void *table; | void *table; | ||||
header = table_map(pa, offset, sizeof(ACPI_TABLE_HEADER)); | header = pmap_mapbios(pa, sizeof(ACPI_TABLE_HEADER)); | ||||
if (strncmp(header->Signature, sig, ACPI_NAMESEG_SIZE) != 0) { | if (strncmp(header->Signature, sig, ACPI_NAMESEG_SIZE) != 0) { | ||||
table_unmap(header, sizeof(ACPI_TABLE_HEADER)); | pmap_unmapbios((vm_offset_t)header, sizeof(ACPI_TABLE_HEADER)); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
length = header->Length; | length = header->Length; | ||||
table_unmap(header, sizeof(ACPI_TABLE_HEADER)); | pmap_unmapbios((vm_offset_t)header, sizeof(ACPI_TABLE_HEADER)); | ||||
table = table_map(pa, offset, length); | table = pmap_mapbios(pa, length); | ||||
if (ACPI_FAILURE(AcpiTbChecksum(table, length))) { | if (ACPI_FAILURE(AcpiTbChecksum(table, length))) { | ||||
if (bootverbose) | if (bootverbose) | ||||
printf("ACPI: Failed checksum for table %s\n", sig); | printf("ACPI: Failed checksum for table %s\n", sig); | ||||
#if (ACPI_CHECKSUM_ABORT) | #if (ACPI_CHECKSUM_ABORT) | ||||
table_unmap(table, length); | pmap_unmapbios((vm_offset_t)table, length); | ||||
return (NULL); | return (NULL); | ||||
#endif | #endif | ||||
} | } | ||||
return (table); | return (table); | ||||
} | } | ||||
/* | /* | ||||
* See if a given ACPI table is the requested table. Returns the | * See if a given ACPI table is the requested table. Returns the | ||||
* length of the able if it matches or zero on failure. | * length of the able if it matches or zero on failure. | ||||
*/ | */ | ||||
static int | static int | ||||
probe_table(vm_paddr_t address, const char *sig) | probe_table(vm_paddr_t address, const char *sig) | ||||
{ | { | ||||
ACPI_TABLE_HEADER *table; | ACPI_TABLE_HEADER *table; | ||||
int ret; | |||||
table = table_map(address, 0, sizeof(ACPI_TABLE_HEADER)); | table = pmap_mapbios(address, sizeof(ACPI_TABLE_HEADER)); | ||||
if (table == NULL) { | ret = strncmp(table->Signature, sig, ACPI_NAMESEG_SIZE) == 0; | ||||
if (bootverbose) | pmap_unmapbios((vm_offset_t)table, sizeof(ACPI_TABLE_HEADER)); | ||||
printf("ACPI: Failed to map table at 0x%jx\n", | return (ret); | ||||
(uintmax_t)address); | |||||
return (0); | |||||
} | } | ||||
if (strncmp(table->Signature, sig, ACPI_NAMESEG_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 | * Try to map a table at a given physical address previously returned | ||||
* by acpi_find_table(). | * by acpi_find_table(). | ||||
*/ | */ | ||||
void * | void * | ||||
acpi_map_table(vm_paddr_t pa, const char *sig) | acpi_map_table(vm_paddr_t pa, const char *sig) | ||||
{ | { | ||||
return (map_table(pa, 0, sig)); | return (map_table(pa, sig)); | ||||
} | } | ||||
/* Unmap a table previously mapped via acpi_map_table(). */ | /* Unmap a table previously mapped via acpi_map_table(). */ | ||||
void | void | ||||
acpi_unmap_table(void *table) | acpi_unmap_table(void *table) | ||||
{ | { | ||||
ACPI_TABLE_HEADER *header; | ACPI_TABLE_HEADER *header; | ||||
header = (ACPI_TABLE_HEADER *)table; | header = (ACPI_TABLE_HEADER *)table; | ||||
table_unmap(table, header->Length); | pmap_unmapbios((vm_offset_t)table, header->Length); | ||||
} | } | ||||
/* | /* | ||||
* Return the physical address of the requested table or zero if one | * Return the physical address of the requested table or zero if one | ||||
* is not found. | * is not found. | ||||
*/ | */ | ||||
vm_paddr_t | vm_paddr_t | ||||
acpi_find_table(const char *sig) | acpi_find_table(const char *sig) | ||||
Show All 20 Lines | acpi_find_table(const char *sig) | ||||
if (rsdp == NULL) { | if (rsdp == NULL) { | ||||
if (bootverbose) | if (bootverbose) | ||||
printf("ACPI: Failed to map RSDP\n"); | printf("ACPI: Failed to map RSDP\n"); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* For ACPI >= 2.0, use the XSDT if it is available. | * For ACPI >= 2.0, use the XSDT if it is available. | ||||
* Otherwise, use the RSDT. We map the XSDT or RSDT at page 2 | * Otherwise, use the RSDT. | ||||
* in the crashdump area. Pages 0 and 1 are used to map in the | |||||
* headers of candidate ACPI tables. | |||||
*/ | */ | ||||
addr = 0; | addr = 0; | ||||
if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) { | if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) { | ||||
/* | /* | ||||
* AcpiOsGetRootPointer only verifies the checksum for | * AcpiOsGetRootPointer only verifies the checksum for | ||||
* the version 1.0 portion of the RSDP. Version 2.0 has | * the version 1.0 portion of the RSDP. Version 2.0 has | ||||
* an additional checksum that we verify first. | * an additional checksum that we verify first. | ||||
*/ | */ | ||||
if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) { | if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) { | ||||
if (bootverbose) | if (bootverbose) | ||||
printf("ACPI: RSDP failed extended checksum\n"); | printf("ACPI: RSDP failed extended checksum\n"); | ||||
return (0); | return (0); | ||||
} | } | ||||
xsdt = map_table(rsdp->XsdtPhysicalAddress, 2, ACPI_SIG_XSDT); | xsdt = map_table(rsdp->XsdtPhysicalAddress, ACPI_SIG_XSDT); | ||||
if (xsdt == NULL) { | if (xsdt == NULL) { | ||||
if (bootverbose) | if (bootverbose) | ||||
printf("ACPI: Failed to map XSDT\n"); | printf("ACPI: Failed to map XSDT\n"); | ||||
return (0); | return (0); | ||||
} | } | ||||
count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) / | count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) / | ||||
sizeof(UINT64); | sizeof(UINT64); | ||||
for (i = 0; i < count; i++) | for (i = 0; i < count; i++) | ||||
if (probe_table(xsdt->TableOffsetEntry[i], sig)) { | if (probe_table(xsdt->TableOffsetEntry[i], sig)) { | ||||
addr = xsdt->TableOffsetEntry[i]; | addr = xsdt->TableOffsetEntry[i]; | ||||
break; | break; | ||||
} | } | ||||
acpi_unmap_table(xsdt); | acpi_unmap_table(xsdt); | ||||
} else { | } else { | ||||
rsdt = map_table(rsdp->RsdtPhysicalAddress, 2, ACPI_SIG_RSDT); | rsdt = map_table(rsdp->RsdtPhysicalAddress, ACPI_SIG_RSDT); | ||||
if (rsdt == NULL) { | if (rsdt == NULL) { | ||||
if (bootverbose) | if (bootverbose) | ||||
printf("ACPI: Failed to map RSDT\n"); | printf("ACPI: Failed to map RSDT\n"); | ||||
return (0); | return (0); | ||||
} | } | ||||
count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) / | count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) / | ||||
sizeof(UINT32); | sizeof(UINT32); | ||||
for (i = 0; i < count; i++) | for (i = 0; i < count; i++) | ||||
if (probe_table(rsdt->TableOffsetEntry[i], sig)) { | if (probe_table(rsdt->TableOffsetEntry[i], sig)) { | ||||
addr = rsdt->TableOffsetEntry[i]; | addr = rsdt->TableOffsetEntry[i]; | ||||
break; | break; | ||||
} | } | ||||
acpi_unmap_table(rsdt); | acpi_unmap_table(rsdt); | ||||
} | } | ||||
pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP)); | pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP)); | ||||
if (addr == 0) | if (addr == 0) | ||||
return (0); | return (0); | ||||
/* | /* | ||||
* Verify that we can map the full table and that its checksum is | * Verify that we can map the full table and that its checksum is | ||||
* correct, etc. | * correct, etc. | ||||
*/ | */ | ||||
table = map_table(addr, 0, sig); | table = map_table(addr, sig); | ||||
if (table == NULL) | if (table == NULL) | ||||
return (0); | return (0); | ||||
acpi_unmap_table(table); | acpi_unmap_table(table); | ||||
return (addr); | return (addr); | ||||
} | } | ||||
/* | /* | ||||
Show All 38 Lines |