1 /* $NetBSD: acpi_machdep.c,v 1.32 2021/05/12 23:22:33 thorpej Exp $ */ 2 3 /* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 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 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * Machine-dependent routines for ACPICA. 40 */ 41 42 #include <sys/cdefs.h> 43 __KERNEL_RCSID(0, "$NetBSD: acpi_machdep.c,v 1.32 2021/05/12 23:22:33 thorpej Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/bus.h> 48 #include <sys/cpu.h> 49 #include <sys/device.h> 50 51 #include <uvm/uvm_extern.h> 52 53 #include <machine/cpufunc.h> 54 #include <machine/bootinfo.h> 55 #include <machine/autoconf.h> 56 57 #include <dev/acpi/acpica.h> 58 #include <dev/acpi/acpivar.h> 59 #include <dev/acpi/acpi_mcfg.h> 60 61 #include <machine/acpi_machdep.h> 62 #include <machine/mpbiosvar.h> 63 #include <machine/mpacpi.h> 64 #include <machine/i82093reg.h> 65 #include <machine/i82093var.h> 66 #include <machine/pic.h> 67 68 #include <x86/efi.h> 69 70 #include <dev/pci/pcivar.h> 71 72 #include <dev/isa/isareg.h> 73 #include <dev/isa/isavar.h> 74 75 #include "ioapic.h" 76 77 #include "acpica.h" 78 #include "opt_mpbios.h" 79 #include "opt_acpi.h" 80 #include "opt_vga.h" 81 82 #ifdef XEN 83 #include <xen/hypervisor.h> 84 #endif 85 86 /* 87 * Default VBIOS reset method for non-HW accelerated VGA drivers. 88 */ 89 #ifdef VGA_POST 90 # define VBIOS_RESET_DEFAULT 2 91 #else 92 # define VBIOS_RESET_DEFAULT 1 93 #endif 94 95 ACPI_STATUS 96 acpi_md_OsInitialize(void) 97 { 98 return AE_OK; 99 } 100 101 ACPI_PHYSICAL_ADDRESS 102 acpi_md_OsGetRootPointer(void) 103 { 104 ACPI_PHYSICAL_ADDRESS PhysicalAddress; 105 ACPI_STATUS Status; 106 107 #ifdef XENPV 108 /* 109 * Obtain the ACPI RSDP from the hypervisor. 110 * This is the only way to go if Xen booted from EFI: the 111 * Extended BIOS Data Area (EBDA) is not mapped, and Xen 112 * does not pass an EFI SystemTable to the kernel. 113 */ 114 struct xen_platform_op op = { 115 .cmd = XENPF_firmware_info, 116 .u.firmware_info = { 117 .type = XEN_FW_EFI_INFO, 118 .index = XEN_FW_EFI_CONFIG_TABLE 119 } 120 }; 121 union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info; 122 123 if (HYPERVISOR_platform_op(&op) == 0) { 124 struct efi_cfgtbl *ct; 125 int i; 126 127 ct = AcpiOsMapMemory(info->cfg.addr, 128 sizeof(*ct) * info->cfg.nent); 129 130 for (i = 0; i < info->cfg.nent; i++) { 131 if (memcmp(&ct[i].ct_uuid, 132 &EFI_UUID_ACPI20, sizeof(EFI_UUID_ACPI20)) == 0) { 133 PhysicalAddress = (ACPI_PHYSICAL_ADDRESS) 134 (uintptr_t)ct[i].ct_data; 135 if (PhysicalAddress) 136 goto out; 137 138 } 139 } 140 141 for (i = 0; i < info->cfg.nent; i++) { 142 if (memcmp(&ct[i].ct_uuid, 143 &EFI_UUID_ACPI10, sizeof(EFI_UUID_ACPI10)) == 0) { 144 PhysicalAddress = (ACPI_PHYSICAL_ADDRESS) 145 (uintptr_t)ct[i].ct_data; 146 if (PhysicalAddress) 147 goto out; 148 149 } 150 } 151 out: 152 AcpiOsUnmapMemory(ct, sizeof(*ct) * info->cfg.nent); 153 154 if (PhysicalAddress) 155 return PhysicalAddress; 156 } 157 #else 158 #ifdef XEN 159 if (vm_guest == VM_GUEST_XENPVH) { 160 PhysicalAddress = hvm_start_info->rsdp_paddr; 161 if (PhysicalAddress) 162 return PhysicalAddress; 163 } 164 #endif 165 /* 166 * Get the ACPI RSDP from EFI SystemTable. This works when the 167 * kernel was loaded from EFI bootloader. 168 */ 169 if (efi_probe()) { 170 PhysicalAddress = efi_getcfgtblpa(&EFI_UUID_ACPI20); 171 if (!PhysicalAddress) 172 PhysicalAddress = efi_getcfgtblpa(&EFI_UUID_ACPI10); 173 if (PhysicalAddress) 174 return PhysicalAddress; 175 } 176 177 #endif 178 /* 179 * Find ACPI RSDP from Extended BIOS Data Area (EBDA). This 180 * works when the kernel was started from BIOS bootloader, 181 * or for Xen PV when Xen was started from BIOS bootloader. 182 */ 183 Status = AcpiFindRootPointer(&PhysicalAddress); 184 if (ACPI_FAILURE(Status)) 185 PhysicalAddress = 0; 186 187 return PhysicalAddress; 188 } 189 190 struct acpi_md_override { 191 int irq; 192 int pin; 193 int flags; 194 }; 195 196 #if NIOAPIC > 0 197 static ACPI_STATUS 198 acpi_md_findoverride(ACPI_SUBTABLE_HEADER *hdrp, void *aux) 199 { 200 ACPI_MADT_INTERRUPT_OVERRIDE *iop; 201 struct acpi_md_override *ovrp; 202 203 if (hdrp->Type != ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) { 204 return AE_OK; 205 } 206 207 iop = (void *)hdrp; 208 ovrp = aux; 209 if (iop->SourceIrq == ovrp->irq) { 210 ovrp->pin = iop->GlobalIrq; 211 ovrp->flags = iop->IntiFlags; 212 } 213 return AE_OK; 214 } 215 #endif 216 217 ACPI_STATUS 218 acpi_md_OsInstallInterruptHandler(uint32_t InterruptNumber, 219 ACPI_OSD_HANDLER ServiceRoutine, void *Context, void **cookiep, 220 const char *xname) 221 { 222 void *ih; 223 224 ih = acpi_md_intr_establish(InterruptNumber, IPL_TTY, IST_LEVEL, 225 (int (*)(void *))ServiceRoutine, Context, false, xname); 226 if (ih == NULL) 227 return AE_NO_MEMORY; 228 229 *cookiep = ih; 230 231 return AE_OK; 232 } 233 234 void 235 acpi_md_OsRemoveInterruptHandler(void *cookie) 236 { 237 intr_disestablish(cookie); 238 } 239 240 void * 241 acpi_md_intr_establish(uint32_t InterruptNumber, int ipl, int type, 242 int (*handler)(void *), void *arg, bool mpsafe, const char *xname) 243 { 244 void *ih; 245 struct pic *pic; 246 int irq = InterruptNumber, pin; 247 #if NIOAPIC > 0 248 struct ioapic_softc *ioapic; 249 struct acpi_md_override ovr; 250 struct mp_intr_map tmpmap, *mip, **mipp = NULL; 251 intr_handle_t mpih; 252 int redir, mpflags; 253 254 /* 255 * ACPI interrupts default to level-triggered active-low. 256 */ 257 258 mpflags = (MPS_INTTR_LEVEL << 2) | MPS_INTPO_ACTLO; 259 redir = IOAPIC_REDLO_LEVEL | IOAPIC_REDLO_ACTLO; 260 261 /* 262 * Apply any MADT override setting. 263 */ 264 265 ovr.irq = irq; 266 ovr.pin = -1; 267 if (acpi_madt_map() == AE_OK) { 268 acpi_madt_walk(acpi_md_findoverride, &ovr); 269 acpi_madt_unmap(); 270 } else { 271 aprint_debug("acpi_madt_map() failed, can't check for MADT override\n"); 272 } 273 274 if (ovr.pin != -1) { 275 bool sci = irq == AcpiGbl_FADT.SciInterrupt; 276 int polarity = ovr.flags & ACPI_MADT_POLARITY_MASK; 277 int trigger = ovr.flags & ACPI_MADT_TRIGGER_MASK; 278 279 irq = ovr.pin; 280 if (polarity == ACPI_MADT_POLARITY_ACTIVE_HIGH || 281 (!sci && polarity == ACPI_MADT_POLARITY_CONFORMS)) { 282 mpflags &= ~MPS_INTPO_ACTLO; 283 mpflags |= MPS_INTPO_ACTHI; 284 redir &= ~IOAPIC_REDLO_ACTLO; 285 } 286 if (trigger == ACPI_MADT_TRIGGER_EDGE || 287 (!sci && trigger == ACPI_MADT_TRIGGER_CONFORMS)) { 288 type = IST_EDGE; 289 mpflags &= ~(MPS_INTTR_LEVEL << 2); 290 mpflags |= (MPS_INTTR_EDGE << 2); 291 redir &= ~IOAPIC_REDLO_LEVEL; 292 } 293 } 294 295 pic = NULL; 296 pin = irq; 297 298 /* 299 * If the interrupt is handled via IOAPIC, update the map. 300 * If the map isn't set up yet, install a temporary one. 301 * Identify ISA & EISA interrupts 302 */ 303 if (mp_busses != NULL) { 304 if (intr_find_mpmapping(mp_isa_bus, irq, &mpih) == 0 || 305 intr_find_mpmapping(mp_eisa_bus, irq, &mpih) == 0) { 306 if (!APIC_IRQ_ISLEGACY(mpih)) { 307 pin = APIC_IRQ_PIN(mpih); 308 ioapic = ioapic_find(APIC_IRQ_APIC(mpih)); 309 if (ioapic != NULL) 310 pic = &ioapic->sc_pic; 311 } 312 } 313 } 314 315 if (pic == NULL) { 316 /* 317 * If the interrupt is handled via IOAPIC, update the map. 318 * If the map isn't set up yet, install a temporary one. 319 */ 320 ioapic = ioapic_find_bybase(irq); 321 if (ioapic != NULL) { 322 pic = &ioapic->sc_pic; 323 324 if (pic->pic_type == PIC_IOAPIC) { 325 pin = irq - pic->pic_vecbase; 326 irq = -1; 327 } else { 328 pin = irq; 329 } 330 331 mip = ioapic->sc_pins[pin].ip_map; 332 if (mip) { 333 mip->flags &= ~0xf; 334 mip->flags |= mpflags; 335 mip->redir &= ~(IOAPIC_REDLO_LEVEL | 336 IOAPIC_REDLO_ACTLO); 337 mip->redir |= redir; 338 } else { 339 mipp = &ioapic->sc_pins[pin].ip_map; 340 *mipp = &tmpmap; 341 tmpmap.redir = redir; 342 tmpmap.flags = mpflags; 343 } 344 } 345 } 346 347 if (pic == NULL) 348 #endif 349 { 350 pic = &i8259_pic; 351 pin = irq; 352 } 353 354 ih = intr_establish_xname(irq, pic, pin, type, ipl, 355 handler, arg, mpsafe, xname); 356 357 #if NIOAPIC > 0 358 if (mipp) { 359 *mipp = NULL; 360 } 361 #endif 362 363 return ih; 364 } 365 366 void 367 acpi_md_intr_mask(void *ih) 368 { 369 intr_mask(ih); 370 } 371 372 void 373 acpi_md_intr_unmask(void *ih) 374 { 375 intr_unmask(ih); 376 } 377 378 void 379 acpi_md_intr_disestablish(void *ih) 380 { 381 intr_disestablish(ih); 382 } 383 384 ACPI_STATUS 385 acpi_md_OsMapMemory(ACPI_PHYSICAL_ADDRESS PhysicalAddress, 386 uint32_t Length, void **LogicalAddress) 387 { 388 int rv; 389 390 rv = _x86_memio_map(x86_bus_space_mem, PhysicalAddress, 391 Length, 0, (bus_space_handle_t *)LogicalAddress); 392 393 return (rv != 0) ? AE_NO_MEMORY : AE_OK; 394 } 395 396 void 397 acpi_md_OsUnmapMemory(void *LogicalAddress, uint32_t Length) 398 { 399 (void) _x86_memio_unmap(x86_bus_space_mem, 400 (bus_space_handle_t)LogicalAddress, Length, NULL); 401 } 402 403 ACPI_STATUS 404 acpi_md_OsGetPhysicalAddress(void *LogicalAddress, 405 ACPI_PHYSICAL_ADDRESS *PhysicalAddress) 406 { 407 paddr_t pa; 408 409 if (pmap_extract(pmap_kernel(), (vaddr_t) LogicalAddress, &pa)) { 410 *PhysicalAddress = pa; 411 return AE_OK; 412 } 413 414 return AE_ERROR; 415 } 416 417 BOOLEAN 418 acpi_md_OsReadable(void *Pointer, uint32_t Length) 419 { 420 BOOLEAN rv = TRUE; 421 vaddr_t sva, eva; 422 pt_entry_t *pte; 423 424 sva = trunc_page((vaddr_t) Pointer); 425 eva = round_page((vaddr_t) Pointer + Length); 426 427 if (sva < VM_MIN_KERNEL_ADDRESS) 428 return FALSE; 429 430 for (; sva < eva; sva += PAGE_SIZE) { 431 pte = kvtopte(sva); 432 if ((*pte & PTE_P) == 0) { 433 rv = FALSE; 434 break; 435 } 436 } 437 438 return rv; 439 } 440 441 BOOLEAN 442 acpi_md_OsWritable(void *Pointer, uint32_t Length) 443 { 444 BOOLEAN rv = TRUE; 445 vaddr_t sva, eva; 446 pt_entry_t *pte; 447 448 sva = trunc_page((vaddr_t) Pointer); 449 eva = round_page((vaddr_t) Pointer + Length); 450 451 if (sva < VM_MIN_KERNEL_ADDRESS) 452 return FALSE; 453 454 for (; sva < eva; sva += PAGE_SIZE) { 455 pte = kvtopte(sva); 456 if ((*pte & (PTE_P|PTE_W)) != (PTE_P|PTE_W)) { 457 rv = FALSE; 458 break; 459 } 460 } 461 462 return rv; 463 } 464 465 void 466 acpi_md_OsDisableInterrupt(void) 467 { 468 x86_disable_intr(); 469 } 470 471 void 472 acpi_md_OsEnableInterrupt(void) 473 { 474 x86_enable_intr(); 475 } 476 477 uint32_t 478 acpi_md_ncpus(void) 479 { 480 return kcpuset_countset(kcpuset_attached); 481 } 482 483 static bool 484 acpi_md_mcfg_validate(uint64_t addr, int bus_start, int *bus_end) 485 { 486 struct btinfo_memmap *bim; 487 uint64_t size, mapaddr, mapsize; 488 uint32_t type; 489 int i, n; 490 491 #ifndef XENPV 492 if (lookup_bootinfo(BTINFO_EFIMEMMAP) != NULL) 493 bim = efi_get_e820memmap(); 494 else 495 #endif 496 bim = lookup_bootinfo(BTINFO_MEMMAP); 497 if (bim == NULL) 498 return false; 499 500 size = *bus_end - bus_start + 1; 501 size *= ACPIMCFG_SIZE_PER_BUS; 502 for (i = 0; i < bim->num; i++) { 503 mapaddr = bim->entry[i].addr; 504 mapsize = bim->entry[i].size; 505 type = bim->entry[i].type; 506 507 aprint_debug("MCFG: MEMMAP: 0x%016" PRIx64 508 "-0x%016" PRIx64 ", size=0x%016" PRIx64 509 ", type=%d(%s)\n", 510 mapaddr, mapaddr + mapsize - 1, mapsize, type, 511 (type == BIM_Memory) ? "Memory" : 512 (type == BIM_Reserved) ? "Reserved" : 513 (type == BIM_ACPI) ? "ACPI" : 514 (type == BIM_NVS) ? "NVS" : 515 (type == BIM_PMEM) ? "Persistent" : 516 (type == BIM_PRAM) ? "Persistent (Legacy)" : 517 "unknown"); 518 519 switch (type) { 520 case BIM_ACPI: 521 case BIM_Reserved: 522 if (addr < mapaddr || addr >= mapaddr + mapsize) 523 break; 524 525 /* full map */ 526 if (addr + size <= mapaddr + mapsize) 527 return true; 528 529 /* partial map */ 530 n = (mapsize - (addr - mapaddr)) / 531 ACPIMCFG_SIZE_PER_BUS; 532 /* bus_start == bus_end is not allowed. */ 533 if (n > 1) { 534 *bus_end = bus_start + n - 1; 535 return true; 536 } 537 aprint_debug("MCFG: bus %d-%d, address 0x%016" PRIx64 538 ": invalid size: request 0x%016" PRIx64 ", " 539 "actual 0x%016" PRIx64 "\n", 540 bus_start, *bus_end, addr, size, mapsize); 541 break; 542 } 543 } 544 aprint_debug("MCFG: bus %d-%d, address 0x%016" PRIx64 ": " 545 "no valid region\n", bus_start, *bus_end, addr); 546 return false; 547 } 548 549 static uint32_t 550 acpi_md_mcfg_read(bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t addr) 551 { 552 vaddr_t va = bsh + addr; 553 uint32_t data = (uint32_t) -1; 554 555 KASSERT(bst == x86_bus_space_mem); 556 557 __asm("movl %1, %0" : "=a" (data) : "m" (*(volatile uint32_t *)va)); 558 559 return data; 560 } 561 562 static void 563 acpi_md_mcfg_write(bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t addr, 564 uint32_t data) 565 { 566 vaddr_t va = bsh + addr; 567 568 KASSERT(bst == x86_bus_space_mem); 569 570 __asm("movl %1, %0" : "=m" (*(volatile uint32_t *)va) : "a" (data)); 571 } 572 573 static const struct acpimcfg_ops acpi_md_mcfg_ops = { 574 .ao_validate = acpi_md_mcfg_validate, 575 576 .ao_read = acpi_md_mcfg_read, 577 .ao_write = acpi_md_mcfg_write, 578 }; 579 580 void 581 acpi_md_callback(struct acpi_softc *sc) 582 { 583 #ifdef MPBIOS 584 if (!mpbios_scanned) 585 #endif 586 mpacpi_find_interrupts(sc); 587 588 #ifndef XENPV 589 acpi_md_sleep_init(); 590 #endif 591 592 acpimcfg_init(x86_bus_space_mem, &acpi_md_mcfg_ops); 593 } 594 595 #ifndef XENPV 596 void 597 device_acpi_register(device_t dev, void *aux) 598 { 599 device_t parent; 600 bool device_is_vga, device_is_pci, device_is_isa; 601 602 parent = device_parent(dev); 603 if (parent == NULL) 604 return; 605 606 device_is_vga = device_is_a(dev, "vga") || device_is_a(dev, "genfb"); 607 device_is_pci = device_is_a(parent, "pci"); 608 device_is_isa = device_is_a(parent, "isa"); 609 610 if (device_is_vga && (device_is_pci || device_is_isa)) { 611 extern int acpi_md_vbios_reset; 612 613 acpi_md_vbios_reset = VBIOS_RESET_DEFAULT; 614 } 615 } 616 #endif 617