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/param.h> 32 #include <sys/bus.h> 33 #include <sys/kernel.h> 34 35 #include <vm/vm.h> 36 #include <vm/pmap.h> 37 38 #include <machine/machdep.h> 39 40 #include <contrib/dev/acpica/include/acpi.h> 41 #include <contrib/dev/acpica/include/accommon.h> 42 #include <contrib/dev/acpica/include/actables.h> 43 44 #include <dev/acpica/acpivar.h> 45 46 extern struct bus_space memmap_bus; 47 48 int 49 acpi_machdep_init(device_t dev) 50 { 51 52 return (0); 53 } 54 55 int 56 acpi_machdep_quirks(int *quirks) 57 { 58 59 return (0); 60 } 61 62 static void * 63 map_table(vm_paddr_t pa, const char *sig) 64 { 65 ACPI_TABLE_HEADER *header; 66 vm_size_t length; 67 void *table; 68 69 header = pmap_mapbios(pa, sizeof(ACPI_TABLE_HEADER)); 70 if (strncmp(header->Signature, sig, ACPI_NAMESEG_SIZE) != 0) { 71 pmap_unmapbios(header, sizeof(ACPI_TABLE_HEADER)); 72 return (NULL); 73 } 74 length = header->Length; 75 pmap_unmapbios(header, sizeof(ACPI_TABLE_HEADER)); 76 77 table = pmap_mapbios(pa, length); 78 if (ACPI_FAILURE(AcpiUtChecksum(table, length))) { 79 if (bootverbose) 80 printf("ACPI: Failed checksum for table %s\n", sig); 81 #if (ACPI_CHECKSUM_ABORT) 82 pmap_unmapbios(table, length); 83 return (NULL); 84 #endif 85 } 86 return (table); 87 } 88 89 /* 90 * See if a given ACPI table is the requested table. Returns the 91 * length of the table if it matches or zero on failure. 92 */ 93 static int 94 probe_table(vm_paddr_t address, const char *sig) 95 { 96 ACPI_TABLE_HEADER *table; 97 98 table = pmap_mapbios(address, sizeof(ACPI_TABLE_HEADER)); 99 if (table == NULL) { 100 if (bootverbose) 101 printf("ACPI: Failed to map table at 0x%jx\n", 102 (uintmax_t)address); 103 return (0); 104 } 105 106 if (strncmp(table->Signature, sig, ACPI_NAMESEG_SIZE) != 0) { 107 pmap_unmapbios(table, sizeof(ACPI_TABLE_HEADER)); 108 return (0); 109 } 110 pmap_unmapbios(table, sizeof(ACPI_TABLE_HEADER)); 111 return (1); 112 } 113 114 /* Unmap a table previously mapped via acpi_map_table(). */ 115 void 116 acpi_unmap_table(void *table) 117 { 118 ACPI_TABLE_HEADER *header; 119 120 header = (ACPI_TABLE_HEADER *)table; 121 pmap_unmapbios(table, header->Length); 122 } 123 124 /* 125 * Try to map a table at a given physical address previously returned 126 * by acpi_find_table(). 127 */ 128 void * 129 acpi_map_table(vm_paddr_t pa, const char *sig) 130 { 131 132 return (map_table(pa, sig)); 133 } 134 135 /* 136 * Return the physical address of the requested table or zero if one 137 * is not found. 138 */ 139 vm_paddr_t 140 acpi_find_table(const char *sig) 141 { 142 ACPI_PHYSICAL_ADDRESS rsdp_ptr; 143 ACPI_TABLE_RSDP *rsdp; 144 ACPI_TABLE_XSDT *xsdt; 145 ACPI_TABLE_HEADER *table; 146 vm_paddr_t addr; 147 int i, count; 148 149 if (resource_disabled("acpi", 0)) 150 return (0); 151 152 /* 153 * Map in the RSDP. Since ACPI uses AcpiOsMapMemory() which in turn 154 * calls pmap_mapbios() to find the RSDP, we assume that we can use 155 * pmap_mapbios() to map the RSDP. 156 */ 157 if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0) 158 return (0); 159 rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP)); 160 if (rsdp == NULL) { 161 printf("ACPI: Failed to map RSDP\n"); 162 return (0); 163 } 164 165 addr = 0; 166 if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) { 167 /* 168 * AcpiOsGetRootPointer only verifies the checksum for 169 * the version 1.0 portion of the RSDP. Version 2.0 has 170 * an additional checksum that we verify first. 171 */ 172 if (AcpiUtChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) { 173 printf("ACPI: RSDP failed extended checksum\n"); 174 pmap_unmapbios(rsdp, sizeof(ACPI_TABLE_RSDP)); 175 return (0); 176 } 177 xsdt = map_table(rsdp->XsdtPhysicalAddress, ACPI_SIG_XSDT); 178 if (xsdt == NULL) { 179 printf("ACPI: Failed to map XSDT\n"); 180 pmap_unmapbios(rsdp, sizeof(ACPI_TABLE_RSDP)); 181 return (0); 182 } 183 count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) / 184 sizeof(UINT64); 185 for (i = 0; i < count; i++) 186 if (probe_table(xsdt->TableOffsetEntry[i], sig)) { 187 addr = xsdt->TableOffsetEntry[i]; 188 break; 189 } 190 acpi_unmap_table(xsdt); 191 } else { 192 printf("ACPI: Unsupported RSDP version %d and XSDT %#lx\n", 193 rsdp->Revision, rsdp->XsdtPhysicalAddress); 194 } 195 pmap_unmapbios(rsdp, sizeof(ACPI_TABLE_RSDP)); 196 197 if (addr == 0) 198 return (0); 199 200 /* 201 * Verify that we can map the full table and that its checksum is 202 * correct, etc. 203 */ 204 table = map_table(addr, sig); 205 if (table == NULL) 206 return (0); 207 acpi_unmap_table(table); 208 209 return (addr); 210 } 211 212 int 213 acpi_map_addr(struct acpi_generic_address *addr, bus_space_tag_t *tag, 214 bus_space_handle_t *handle, bus_size_t size) 215 { 216 bus_addr_t phys; 217 218 /* Check if the device is Memory mapped */ 219 if (addr->SpaceId != 0) 220 return (ENXIO); 221 222 phys = addr->Address; 223 *tag = &memmap_bus; 224 225 return (bus_space_map(*tag, phys, size, 0, handle)); 226 } 227 228 #if MAXMEMDOM > 1 229 static void 230 parse_pxm_tables(void *dummy) 231 { 232 uint64_t mmfr0, parange; 233 234 /* Only parse ACPI tables when booting via ACPI */ 235 if (arm64_bus_method != ARM64_BUS_ACPI) 236 return; 237 238 if (!get_kernel_reg(ID_AA64MMFR0_EL1, &mmfr0)) { 239 /* chosen arbitrarily */ 240 mmfr0 = ID_AA64MMFR0_PARange_1T; 241 } 242 243 switch (ID_AA64MMFR0_PARange_VAL(mmfr0)) { 244 case ID_AA64MMFR0_PARange_4G: 245 parange = (vm_paddr_t)4 << 30 /* GiB */; 246 break; 247 case ID_AA64MMFR0_PARange_64G: 248 parange = (vm_paddr_t)64 << 30 /* GiB */; 249 break; 250 case ID_AA64MMFR0_PARange_1T: 251 parange = (vm_paddr_t)1 << 40 /* TiB */; 252 break; 253 case ID_AA64MMFR0_PARange_4T: 254 parange = (vm_paddr_t)4 << 40 /* TiB */; 255 break; 256 case ID_AA64MMFR0_PARange_16T: 257 parange = (vm_paddr_t)16 << 40 /* TiB */; 258 break; 259 case ID_AA64MMFR0_PARange_256T: 260 parange = (vm_paddr_t)256 << 40 /* TiB */; 261 break; 262 case ID_AA64MMFR0_PARange_4P: 263 parange = (vm_paddr_t)4 << 50 /* PiB */; 264 break; 265 default: 266 /* chosen arbitrarily */ 267 parange = (vm_paddr_t)1 << 40 /* TiB */; 268 printf("Unknown value for PARange in mmfr0 (%#lx)\n", mmfr0); 269 break; 270 } 271 272 acpi_pxm_init(MAXCPU, parange); 273 acpi_pxm_parse_tables(); 274 acpi_pxm_set_mem_locality(); 275 } 276 SYSINIT(parse_pxm_tables, SI_SUB_VM - 1, SI_ORDER_FIRST, parse_pxm_tables, 277 NULL); 278 #endif 279