1 /*- 2 * Copyright (c) 2001 Mitsuru IWASAKI 3 * Copyright (c) 2015 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * This software was developed by Andrew Turner under 7 * sponsorship from the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/bus.h> 36 #include <sys/kernel.h> 37 38 #include <vm/vm.h> 39 #include <vm/pmap.h> 40 41 #include <contrib/dev/acpica/include/acpi.h> 42 #include <contrib/dev/acpica/include/accommon.h> 43 #include <contrib/dev/acpica/include/actables.h> 44 45 #include <dev/acpica/acpivar.h> 46 47 int 48 acpi_machdep_init(device_t dev) 49 { 50 51 return (0); 52 } 53 54 int 55 acpi_machdep_quirks(int *quirks) 56 { 57 58 return (0); 59 } 60 61 static void * 62 map_table(vm_paddr_t pa, int offset, const char *sig) 63 { 64 ACPI_TABLE_HEADER *header; 65 vm_offset_t length; 66 void *table; 67 68 header = pmap_mapbios(pa, sizeof(ACPI_TABLE_HEADER)); 69 if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) { 70 pmap_unmapbios((vm_offset_t)header, sizeof(ACPI_TABLE_HEADER)); 71 return (NULL); 72 } 73 length = header->Length; 74 pmap_unmapbios((vm_offset_t)header, sizeof(ACPI_TABLE_HEADER)); 75 76 table = pmap_mapbios(pa, length); 77 if (ACPI_FAILURE(AcpiTbChecksum(table, length))) { 78 if (bootverbose) 79 printf("ACPI: Failed checksum for table %s\n", sig); 80 #if (ACPI_CHECKSUM_ABORT) 81 pmap_unmapbios(table, length); 82 return (NULL); 83 #endif 84 } 85 return (table); 86 } 87 88 /* 89 * See if a given ACPI table is the requested table. Returns the 90 * length of the able if it matches or zero on failure. 91 */ 92 static int 93 probe_table(vm_paddr_t address, const char *sig) 94 { 95 ACPI_TABLE_HEADER *table; 96 97 table = pmap_mapbios(address, sizeof(ACPI_TABLE_HEADER)); 98 if (table == NULL) { 99 if (bootverbose) 100 printf("ACPI: Failed to map table at 0x%jx\n", 101 (uintmax_t)address); 102 return (0); 103 } 104 if (bootverbose) 105 printf("Table '%.4s' at 0x%jx\n", table->Signature, 106 (uintmax_t)address); 107 108 if (strncmp(table->Signature, sig, ACPI_NAME_SIZE) != 0) { 109 pmap_unmapbios((vm_offset_t)table, sizeof(ACPI_TABLE_HEADER)); 110 return (0); 111 } 112 pmap_unmapbios((vm_offset_t)table, sizeof(ACPI_TABLE_HEADER)); 113 return (1); 114 } 115 116 /* Unmap a table previously mapped via acpi_map_table(). */ 117 void 118 acpi_unmap_table(void *table) 119 { 120 ACPI_TABLE_HEADER *header; 121 122 header = (ACPI_TABLE_HEADER *)table; 123 pmap_unmapbios((vm_offset_t)table, header->Length); 124 } 125 126 /* 127 * Try to map a table at a given physical address previously returned 128 * by acpi_find_table(). 129 */ 130 void * 131 acpi_map_table(vm_paddr_t pa, const char *sig) 132 { 133 134 return (map_table(pa, 0, sig)); 135 } 136 137 /* 138 * Return the physical address of the requested table or zero if one 139 * is not found. 140 */ 141 vm_paddr_t 142 acpi_find_table(const char *sig) 143 { 144 ACPI_PHYSICAL_ADDRESS rsdp_ptr; 145 ACPI_TABLE_RSDP *rsdp; 146 ACPI_TABLE_XSDT *xsdt; 147 ACPI_TABLE_HEADER *table; 148 vm_paddr_t addr; 149 int i, count; 150 151 if (resource_disabled("acpi", 0)) 152 return (0); 153 154 /* 155 * Map in the RSDP. Since ACPI uses AcpiOsMapMemory() which in turn 156 * calls pmap_mapbios() to find the RSDP, we assume that we can use 157 * pmap_mapbios() to map the RSDP. 158 */ 159 if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0) 160 return (0); 161 rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP)); 162 if (rsdp == NULL) { 163 if (bootverbose) 164 printf("ACPI: Failed to map RSDP\n"); 165 return (0); 166 } 167 168 addr = 0; 169 if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) { 170 /* 171 * AcpiOsGetRootPointer only verifies the checksum for 172 * the version 1.0 portion of the RSDP. Version 2.0 has 173 * an additional checksum that we verify first. 174 */ 175 if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) { 176 if (bootverbose) 177 printf("ACPI: RSDP failed extended checksum\n"); 178 return (0); 179 } 180 xsdt = map_table(rsdp->XsdtPhysicalAddress, 2, ACPI_SIG_XSDT); 181 if (xsdt == NULL) { 182 if (bootverbose) 183 printf("ACPI: Failed to map XSDT\n"); 184 pmap_unmapbios((vm_offset_t)rsdp, 185 sizeof(ACPI_TABLE_RSDP)); 186 return (0); 187 } 188 count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) / 189 sizeof(UINT64); 190 for (i = 0; i < count; i++) 191 if (probe_table(xsdt->TableOffsetEntry[i], sig)) { 192 addr = xsdt->TableOffsetEntry[i]; 193 break; 194 } 195 acpi_unmap_table(xsdt); 196 } 197 pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP)); 198 199 if (addr == 0) { 200 if (bootverbose) 201 printf("ACPI: No %s table found\n", sig); 202 return (0); 203 } 204 if (bootverbose) 205 printf("%s: Found table at 0x%jx\n", sig, (uintmax_t)addr); 206 207 /* 208 * Verify that we can map the full table and that its checksum is 209 * correct, etc. 210 */ 211 table = map_table(addr, 0, sig); 212 if (table == NULL) 213 return (0); 214 acpi_unmap_table(table); 215 216 return (addr); 217 } 218