1/* $NetBSD: acpi_machdep.c,v 1.36 2023/10/16 17:27:02 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.36 2023/10/16 17:27:02 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 97ACPI_STATUS 98acpi_md_OsInitialize(void) 99{ 100 return AE_OK; 101} 102 103ACPI_PHYSICAL_ADDRESS 104acpi_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 } 153out: 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 == VM_GUEST_XENPVH) { 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 192struct acpi_md_override { 193 int irq; 194 int pin; 195 int flags; 196}; 197 198#if NIOAPIC > 0 199static ACPI_STATUS 200acpi_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 219ACPI_STATUS 220acpi_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 236void 237acpi_md_OsRemoveInterruptHandler(void *cookie) 238{ 239 intr_disestablish(cookie); 240} 241 242void * 243acpi_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 368void 369acpi_md_intr_mask(void *ih) 370{ 371 intr_mask(ih); 372} 373 374void 375acpi_md_intr_unmask(void *ih) 376{ 377 intr_unmask(ih); 378} 379 380void 381acpi_md_intr_disestablish(void *ih) 382{ 383 intr_disestablish(ih); 384} 385 386ACPI_STATUS 387acpi_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 398void 399acpi_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 405ACPI_STATUS 406acpi_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 419BOOLEAN 420acpi_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 443BOOLEAN 444acpi_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 467void 468acpi_md_OsDisableInterrupt(void) 469{ 470 x86_disable_intr(); 471} 472 473void 474acpi_md_OsEnableInterrupt(void) 475{ 476 x86_enable_intr(); 477} 478 479uint32_t 480acpi_md_ncpus(void) 481{ 482 return kcpuset_countset(kcpuset_attached); 483} 484 485static bool 486acpi_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 551static uint32_t 552acpi_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 564static void 565acpi_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 575static 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 582void 583acpi_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 598int acpi_md_vbios_reset = 0; 599 600void 601device_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