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