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