1 /* $NetBSD: xen_intr.c,v 1.29 2021/08/09 21:20:50 andvar Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum, and by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: xen_intr.c,v 1.29 2021/08/09 21:20:50 andvar Exp $"); 34 35 #include "opt_multiprocessor.h" 36 #include "opt_pci.h" 37 38 #include <sys/param.h> 39 #include <sys/kernel.h> 40 #include <sys/kmem.h> 41 #include <sys/cpu.h> 42 #include <sys/device.h> 43 44 #include <xen/intr.h> 45 #include <xen/evtchn.h> 46 #include <xen/xenfunc.h> 47 48 #include <uvm/uvm.h> 49 50 #include <machine/cpu.h> 51 #include <machine/intr.h> 52 53 #include "acpica.h" 54 #include "ioapic.h" 55 #include "lapic.h" 56 #include "pci.h" 57 58 #if NACPICA > 0 59 #include <dev/acpi/acpivar.h> 60 #endif 61 62 #if NIOAPIC > 0 || NACPICA > 0 63 #include <machine/i82093var.h> 64 #endif 65 66 #if NLAPIC > 0 67 #include <machine/i82489var.h> 68 #endif 69 70 #if NPCI > 0 71 #include <dev/pci/ppbreg.h> 72 #ifdef __HAVE_PCI_MSI_MSIX 73 #include <x86/pci/msipic.h> 74 #include <x86/pci/pci_msi_machdep.h> 75 #endif 76 #endif 77 78 #if defined(MULTIPROCESSOR) 79 static const char *xen_ipi_names[XEN_NIPIS] = XEN_IPI_NAMES; 80 #endif 81 82 #if !defined(XENPVHVM) 83 void 84 x86_disable_intr(void) 85 { 86 curcpu()->ci_vcpu->evtchn_upcall_mask = 1; 87 x86_lfence(); 88 } 89 90 void 91 x86_enable_intr(void) 92 { 93 volatile struct vcpu_info *_vci = curcpu()->ci_vcpu; 94 __insn_barrier(); 95 _vci->evtchn_upcall_mask = 0; 96 x86_lfence(); /* unmask then check (avoid races) */ 97 if (__predict_false(_vci->evtchn_upcall_pending)) 98 hypervisor_force_callback(); 99 } 100 101 #endif /* !XENPVHVM */ 102 103 u_long 104 xen_read_psl(void) 105 { 106 107 return (curcpu()->ci_vcpu->evtchn_upcall_mask); 108 } 109 110 void 111 xen_write_psl(u_long psl) 112 { 113 struct cpu_info *ci = curcpu(); 114 115 ci->ci_vcpu->evtchn_upcall_mask = psl; 116 xen_rmb(); 117 if (ci->ci_vcpu->evtchn_upcall_pending && psl == 0) { 118 hypervisor_force_callback(); 119 } 120 } 121 122 void * 123 xen_intr_establish(int legacy_irq, struct pic *pic, int pin, 124 int type, int level, int (*handler)(void *), void *arg, 125 bool known_mpsafe) 126 { 127 128 return xen_intr_establish_xname(legacy_irq, pic, pin, type, level, 129 handler, arg, known_mpsafe, "XEN"); 130 } 131 132 void * 133 xen_intr_establish_xname(int legacy_irq, struct pic *pic, int pin, 134 int type, int level, int (*handler)(void *), void *arg, 135 bool known_mpsafe, const char *xname) 136 { 137 const char *intrstr; 138 char intrstr_buf[INTRIDBUF]; 139 140 if (pic->pic_type == PIC_XEN) { 141 struct intrhand *rih; 142 143 intrstr = intr_create_intrid(legacy_irq, pic, pin, intrstr_buf, 144 sizeof(intrstr_buf)); 145 146 rih = event_set_handler(pin, handler, arg, level, 147 intrstr, xname, known_mpsafe, NULL); 148 149 if (rih == NULL) { 150 printf("%s: can't establish interrupt\n", __func__); 151 return NULL; 152 } 153 154 return rih; 155 } /* Else we assume pintr */ 156 157 #if (NPCI > 0 || NISA > 0) && defined(XENPV) /* XXX: support PVHVM pirq */ 158 struct pintrhand *pih; 159 int gsi; 160 int evtchn; 161 /* the hack below is from x86's intr_establish_xname() */ 162 bool mpsafe = (known_mpsafe || level != IPL_VM); 163 164 KASSERTMSG(legacy_irq == -1 || (0 <= legacy_irq && legacy_irq < NUM_XEN_IRQS), 165 "bad legacy IRQ value: %d", legacy_irq); 166 KASSERTMSG(!(legacy_irq == -1 && pic == &i8259_pic), 167 "non-legacy IRQon i8259 "); 168 169 gsi = xen_pic_to_gsi(pic, pin); 170 KASSERTMSG(gsi < NR_EVENT_CHANNELS, "gsi %d >= NR_EVENT_CHANNELS %u", 171 gsi, (int)NR_EVENT_CHANNELS); 172 173 intrstr = intr_create_intrid(gsi, pic, pin, intrstr_buf, 174 sizeof(intrstr_buf)); 175 176 if (irq2port[gsi] == 0) { 177 extern struct cpu_info phycpu_info_primary; /* XXX */ 178 struct cpu_info *ci = &phycpu_info_primary; 179 180 pic->pic_addroute(pic, ci, pin, gsi, type); 181 182 evtchn = bind_pirq_to_evtch(gsi); 183 KASSERT(evtchn > 0); 184 KASSERT(evtchn < NR_EVENT_CHANNELS); 185 irq2port[gsi] = evtchn + 1; 186 xen_atomic_set_bit(&ci->ci_evtmask[0], evtchn); 187 } else { 188 /* 189 * Shared interrupt - we can't rebind. 190 * The port is shared instead. 191 */ 192 evtchn = irq2port[gsi] - 1; 193 } 194 195 pih = pirq_establish(gsi, evtchn, handler, arg, level, 196 intrstr, xname, mpsafe); 197 pih->pic = pic; 198 return pih; 199 #endif /* NPCI > 0 || NISA > 0 */ 200 201 /* FALLTHROUGH */ 202 return NULL; 203 } 204 205 /* 206 * Mask an interrupt source. 207 */ 208 void 209 xen_intr_mask(struct intrhand *ih) 210 { 211 /* XXX */ 212 panic("xen_intr_mask: not yet implemented."); 213 } 214 215 /* 216 * Unmask an interrupt source. 217 */ 218 void 219 xen_intr_unmask(struct intrhand *ih) 220 { 221 /* XXX */ 222 panic("xen_intr_unmask: not yet implemented."); 223 } 224 225 /* 226 * Deregister an interrupt handler. 227 */ 228 void 229 xen_intr_disestablish(struct intrhand *ih) 230 { 231 232 if (ih->ih_pic->pic_type == PIC_XEN) { 233 event_remove_handler(ih->ih_pin, ih->ih_realfun, 234 ih->ih_realarg); 235 /* event_remove_handler frees ih */ 236 return; 237 } 238 #if defined(DOM0OPS) && defined(XENPV) 239 /* 240 * Cache state, to prevent a use after free situation with 241 * ih. 242 */ 243 244 struct pintrhand *pih = (struct pintrhand *)ih; 245 246 int pirq = pih->pirq; 247 int port = pih->evtch; 248 KASSERT(irq2port[pirq] != 0); 249 250 pirq_disestablish(pih); 251 252 if (evtsource[port] == NULL) { 253 /* 254 * Last handler was removed by 255 * event_remove_handler(). 256 * 257 * We can safely unbind the pirq now. 258 */ 259 260 port = unbind_pirq_from_evtch(pirq); 261 KASSERT(port == pih->evtch); 262 irq2port[pirq] = 0; 263 } 264 #endif 265 return; 266 } 267 268 /* MI interface for kern_cpu.c */ 269 void xen_cpu_intr_redistribute(void); 270 271 void 272 xen_cpu_intr_redistribute(void) 273 { 274 KASSERT(mutex_owned(&cpu_lock)); 275 KASSERT(mp_online); 276 277 return; 278 } 279 280 /* MD - called by x86/cpu.c */ 281 #if defined(INTRSTACKSIZE) 282 static inline bool 283 redzone_const_or_false(bool x) 284 { 285 #ifdef DIAGNOSTIC 286 return x; 287 #else 288 return false; 289 #endif /* !DIAGNOSTIC */ 290 } 291 292 static inline int 293 redzone_const_or_zero(int x) 294 { 295 return redzone_const_or_false(true) ? x : 0; 296 } 297 #endif 298 299 void xen_cpu_intr_init(struct cpu_info *); 300 void 301 xen_cpu_intr_init(struct cpu_info *ci) 302 { 303 #if defined(__HAVE_PREEMPTION) 304 x86_init_preempt(ci); 305 #endif 306 x86_intr_calculatemasks(ci); 307 308 #if defined(INTRSTACKSIZE) 309 vaddr_t istack; 310 311 /* 312 * If the red zone is activated, protect both the top and 313 * the bottom of the stack with an unmapped page. 314 */ 315 istack = uvm_km_alloc(kernel_map, 316 INTRSTACKSIZE + redzone_const_or_zero(2 * PAGE_SIZE), 0, 317 UVM_KMF_WIRED|UVM_KMF_ZERO); 318 if (redzone_const_or_false(true)) { 319 pmap_kremove(istack, PAGE_SIZE); 320 pmap_kremove(istack + INTRSTACKSIZE + PAGE_SIZE, PAGE_SIZE); 321 pmap_update(pmap_kernel()); 322 } 323 324 /* 325 * 33 used to be 1. Arbitrarily reserve 32 more register_t's 326 * of space for ddb(4) to examine some subroutine arguments 327 * and to hunt for the next stack frame. 328 */ 329 ci->ci_intrstack = (char *)istack + redzone_const_or_zero(PAGE_SIZE) + 330 INTRSTACKSIZE - 33 * sizeof(register_t); 331 #endif 332 333 #ifdef MULTIPROCESSOR 334 for (int i = 0; i < XEN_NIPIS; i++) 335 evcnt_attach_dynamic(&ci->ci_ipi_events[i], EVCNT_TYPE_MISC, 336 NULL, device_xname(ci->ci_dev), xen_ipi_names[i]); 337 #endif 338 339 ci->ci_idepth = -1; 340 } 341 342 /* 343 * Everything below from here is duplicated from x86/intr.c 344 * When intr.c and xen_intr.c are unified, these will need to be 345 * merged. 346 */ 347 348 u_int xen_cpu_intr_count(struct cpu_info *ci); 349 350 u_int 351 xen_cpu_intr_count(struct cpu_info *ci) 352 { 353 354 KASSERT(ci->ci_nintrhand >= 0); 355 356 return ci->ci_nintrhand; 357 } 358 359 static const char * 360 xen_intr_string(int port, char *buf, size_t len, struct pic *pic) 361 { 362 KASSERT(pic->pic_type == PIC_XEN); 363 364 KASSERT(port >= 0); 365 KASSERT(port < NR_EVENT_CHANNELS); 366 367 snprintf(buf, len, "%s chan %d", pic->pic_name, port); 368 369 return buf; 370 } 371 372 static const char * 373 legacy_intr_string(int ih, char *buf, size_t len, struct pic *pic) 374 { 375 int legacy_irq; 376 377 KASSERT(pic->pic_type == PIC_I8259); 378 #if NLAPIC > 0 379 KASSERT(APIC_IRQ_ISLEGACY(ih)); 380 381 legacy_irq = APIC_IRQ_LEGACY_IRQ(ih); 382 #else 383 legacy_irq = ih; 384 #endif 385 KASSERT(legacy_irq >= 0 && legacy_irq < 16); 386 387 snprintf(buf, len, "%s pin %d", pic->pic_name, legacy_irq); 388 389 return buf; 390 } 391 392 const char * xintr_string(intr_handle_t ih, char *buf, size_t len); 393 394 const char * 395 xintr_string(intr_handle_t ih, char *buf, size_t len) 396 { 397 #if NIOAPIC > 0 398 struct ioapic_softc *pic; 399 #endif 400 401 if (ih == 0) 402 panic("%s: bogus handle 0x%" PRIx64, __func__, ih); 403 404 #if NIOAPIC > 0 405 if (ih & APIC_INT_VIA_APIC) { 406 pic = ioapic_find(APIC_IRQ_APIC(ih)); 407 if (pic != NULL) { 408 snprintf(buf, len, "%s pin %d", 409 device_xname(pic->sc_dev), APIC_IRQ_PIN(ih)); 410 } else { 411 snprintf(buf, len, 412 "apic %d int %d (irq %d)", 413 APIC_IRQ_APIC(ih), 414 APIC_IRQ_PIN(ih), 415 APIC_IRQ_LEGACY_IRQ(ih)); 416 } 417 } else 418 snprintf(buf, len, "irq %d", APIC_IRQ_LEGACY_IRQ(ih)); 419 420 #elif NLAPIC > 0 421 snprintf(buf, len, "irq %d", APIC_IRQ_LEGACY_IRQ(ih)); 422 #else 423 snprintf(buf, len, "irq %d", (int) ih); 424 #endif 425 return buf; 426 427 } 428 429 /* 430 * Create an interrupt id such as "ioapic0 pin 9". This interrupt id is used 431 * by MI code and intrctl(8). 432 */ 433 const char * xen_intr_create_intrid(int legacy_irq, struct pic *pic, 434 int pin, char *buf, size_t len); 435 436 const char * 437 xen_intr_create_intrid(int legacy_irq, struct pic *pic, int pin, char *buf, size_t len) 438 { 439 int ih = 0; 440 441 #if NPCI > 0 && defined(XENPV) 442 #if defined(__HAVE_PCI_MSI_MSIX) 443 if ((pic->pic_type == PIC_MSI) || (pic->pic_type == PIC_MSIX)) { 444 uint64_t pih; 445 int dev, vec; 446 447 dev = msipic_get_devid(pic); 448 vec = pin; 449 pih = __SHIFTIN((uint64_t)dev, MSI_INT_DEV_MASK) 450 | __SHIFTIN((uint64_t)vec, MSI_INT_VEC_MASK) 451 | APIC_INT_VIA_MSI; 452 if (pic->pic_type == PIC_MSI) 453 MSI_INT_MAKE_MSI(pih); 454 else if (pic->pic_type == PIC_MSIX) 455 MSI_INT_MAKE_MSIX(pih); 456 457 return x86_pci_msi_string(NULL, pih, buf, len); 458 } 459 #endif /* __HAVE_PCI_MSI_MSIX */ 460 #endif 461 462 if (pic->pic_type == PIC_XEN) { 463 ih = pin; /* Port == pin */ 464 return xen_intr_string(pin, buf, len, pic); 465 } 466 467 /* 468 * If the device is pci, "legacy_irq" is always -1. Least 8 bit of "ih" 469 * is only used in intr_string() to show the irq number. 470 * If the device is "legacy"(such as floppy), it should not use 471 * intr_string(). 472 */ 473 if (pic->pic_type == PIC_I8259) { 474 ih = legacy_irq; 475 return legacy_intr_string(ih, buf, len, pic); 476 } 477 478 #if NIOAPIC > 0 || NACPICA > 0 479 ih = ((pic->pic_apicid << APIC_INT_APIC_SHIFT) & APIC_INT_APIC_MASK) 480 | ((pin << APIC_INT_PIN_SHIFT) & APIC_INT_PIN_MASK); 481 if (pic->pic_type == PIC_IOAPIC) { 482 ih |= APIC_INT_VIA_APIC; 483 } 484 ih |= pin; 485 return intr_string(ih, buf, len); 486 #endif 487 488 return NULL; /* No pic found! */ 489 } 490 491 static struct intrsource xen_dummy_intrsource; 492 493 struct intrsource * 494 xen_intr_allocate_io_intrsource(const char *intrid) 495 { 496 /* Nothing to do, required by MSI code */ 497 return &xen_dummy_intrsource; 498 } 499 500 void 501 xen_intr_free_io_intrsource(const char *intrid) 502 { 503 /* Nothing to do, required by MSI code */ 504 } 505 506 #if defined(XENPV) 507 __strong_alias(x86_read_psl, xen_read_psl); 508 __strong_alias(x86_write_psl, xen_write_psl); 509 510 __strong_alias(intr_string, xintr_string); 511 __strong_alias(intr_create_intrid, xen_intr_create_intrid); 512 __strong_alias(intr_establish, xen_intr_establish); 513 __strong_alias(intr_establish_xname, xen_intr_establish_xname); 514 __strong_alias(intr_mask, xen_intr_mask); 515 __strong_alias(intr_unmask, xen_intr_unmask); 516 __strong_alias(intr_disestablish, xen_intr_disestablish); 517 __strong_alias(cpu_intr_redistribute, xen_cpu_intr_redistribute); 518 __strong_alias(cpu_intr_count, xen_cpu_intr_count); 519 __strong_alias(cpu_intr_init, xen_cpu_intr_init); 520 __strong_alias(intr_allocate_io_intrsource, xen_intr_allocate_io_intrsource); 521 __strong_alias(intr_free_io_intrsource, xen_intr_free_io_intrsource); 522 #endif /* XENPV */ 523