1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 5 * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 /* 33 * Copyright 2018 Joyent, Inc. 34 */ 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 #include <sys/types.h> 40 #include <machine/vmm.h> 41 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 46 #include <vmmapi.h> 47 48 #include "acpi.h" 49 #include "bootrom.h" 50 #include "inout.h" 51 #include "pci_emul.h" 52 #include "pci_irq.h" 53 #include "pci_lpc.h" 54 #include "uart_emul.h" 55 56 #define IO_ICU1 0x20 57 #define IO_ICU2 0xA0 58 59 SET_DECLARE(lpc_dsdt_set, struct lpc_dsdt); 60 SET_DECLARE(lpc_sysres_set, struct lpc_sysres); 61 62 #define ELCR_PORT 0x4d0 63 SYSRES_IO(ELCR_PORT, 2); 64 65 #define IO_TIMER1_PORT 0x40 66 67 #define NMISC_PORT 0x61 68 SYSRES_IO(NMISC_PORT, 1); 69 70 static struct pci_devinst *lpc_bridge; 71 72 static const char *romfile; 73 74 #define LPC_UART_NUM 2 75 static struct lpc_uart_softc { 76 struct uart_softc *uart_softc; 77 const char *opts; 78 int iobase; 79 int irq; 80 int enabled; 81 } lpc_uart_softc[LPC_UART_NUM]; 82 83 static const char *lpc_uart_names[LPC_UART_NUM] = { "COM1", "COM2" }; 84 85 /* 86 * LPC device configuration is in the following form: 87 * <lpc_device_name>[,<options>] 88 * For e.g. "com1,stdio" or "bootrom,/var/romfile" 89 */ 90 int 91 lpc_device_parse(const char *opts) 92 { 93 int unit, error; 94 char *str, *cpy, *lpcdev; 95 96 error = -1; 97 str = cpy = strdup(opts); 98 lpcdev = strsep(&str, ","); 99 if (lpcdev != NULL) { 100 if (strcasecmp(lpcdev, "bootrom") == 0) { 101 romfile = str; 102 error = 0; 103 goto done; 104 } 105 for (unit = 0; unit < LPC_UART_NUM; unit++) { 106 if (strcasecmp(lpcdev, lpc_uart_names[unit]) == 0) { 107 lpc_uart_softc[unit].opts = str; 108 error = 0; 109 goto done; 110 } 111 } 112 } 113 114 done: 115 if (error) 116 free(cpy); 117 118 return (error); 119 } 120 121 void 122 lpc_print_supported_devices() 123 { 124 size_t i; 125 126 printf("bootrom\n"); 127 for (i = 0; i < LPC_UART_NUM; i++) 128 printf("%s\n", lpc_uart_names[i]); 129 } 130 131 const char * 132 lpc_bootrom(void) 133 { 134 135 return (romfile); 136 } 137 138 static void 139 lpc_uart_intr_assert(void *arg) 140 { 141 struct lpc_uart_softc *sc = arg; 142 143 assert(sc->irq >= 0); 144 145 vm_isa_pulse_irq(lpc_bridge->pi_vmctx, sc->irq, sc->irq); 146 } 147 148 static void 149 lpc_uart_intr_deassert(void *arg) 150 { 151 /* 152 * The COM devices on the LPC bus generate edge triggered interrupts, 153 * so nothing more to do here. 154 */ 155 } 156 157 static int 158 lpc_uart_io_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 159 uint32_t *eax, void *arg) 160 { 161 int offset; 162 struct lpc_uart_softc *sc = arg; 163 164 offset = port - sc->iobase; 165 166 switch (bytes) { 167 case 1: 168 if (in) 169 *eax = uart_read(sc->uart_softc, offset); 170 else 171 uart_write(sc->uart_softc, offset, *eax); 172 break; 173 case 2: 174 if (in) { 175 *eax = uart_read(sc->uart_softc, offset); 176 *eax |= uart_read(sc->uart_softc, offset + 1) << 8; 177 } else { 178 uart_write(sc->uart_softc, offset, *eax); 179 uart_write(sc->uart_softc, offset + 1, *eax >> 8); 180 } 181 break; 182 #ifndef __FreeBSD__ 183 case 4: 184 if (in) { 185 *eax = uart_read(sc->uart_softc, offset); 186 *eax |= uart_read(sc->uart_softc, offset + 1) << 8; 187 *eax |= uart_read(sc->uart_softc, offset + 2) << 16; 188 *eax |= uart_read(sc->uart_softc, offset + 3) << 24; 189 } else { 190 uart_write(sc->uart_softc, offset, *eax); 191 uart_write(sc->uart_softc, offset + 1, *eax >> 8); 192 uart_write(sc->uart_softc, offset + 2, *eax >> 16); 193 uart_write(sc->uart_softc, offset + 3, *eax >> 24); 194 } 195 break; 196 #endif 197 default: 198 return (-1); 199 } 200 201 return (0); 202 } 203 204 static int 205 lpc_init(struct vmctx *ctx) 206 { 207 struct lpc_uart_softc *sc; 208 struct inout_port iop; 209 const char *name; 210 int unit, error; 211 212 if (romfile != NULL) { 213 error = bootrom_init(ctx, romfile); 214 if (error) 215 return (error); 216 } 217 218 /* COM1 and COM2 */ 219 for (unit = 0; unit < LPC_UART_NUM; unit++) { 220 sc = &lpc_uart_softc[unit]; 221 name = lpc_uart_names[unit]; 222 223 if (uart_legacy_alloc(unit, &sc->iobase, &sc->irq) != 0) { 224 fprintf(stderr, "Unable to allocate resources for " 225 "LPC device %s\n", name); 226 return (-1); 227 } 228 pci_irq_reserve(sc->irq); 229 230 sc->uart_softc = uart_init(lpc_uart_intr_assert, 231 lpc_uart_intr_deassert, sc); 232 233 if (uart_set_backend(sc->uart_softc, sc->opts) != 0) { 234 fprintf(stderr, "Unable to initialize backend '%s' " 235 "for LPC device %s\n", sc->opts, name); 236 return (-1); 237 } 238 239 bzero(&iop, sizeof(struct inout_port)); 240 iop.name = name; 241 iop.port = sc->iobase; 242 iop.size = UART_IO_BAR_SIZE; 243 iop.flags = IOPORT_F_INOUT; 244 iop.handler = lpc_uart_io_handler; 245 iop.arg = sc; 246 247 error = register_inout(&iop); 248 assert(error == 0); 249 sc->enabled = 1; 250 } 251 252 return (0); 253 } 254 255 static void 256 pci_lpc_write_dsdt(struct pci_devinst *pi) 257 { 258 struct lpc_dsdt **ldpp, *ldp; 259 260 dsdt_line(""); 261 dsdt_line("Device (ISA)"); 262 dsdt_line("{"); 263 dsdt_line(" Name (_ADR, 0x%04X%04X)", pi->pi_slot, pi->pi_func); 264 dsdt_line(" OperationRegion (LPCR, PCI_Config, 0x00, 0x100)"); 265 dsdt_line(" Field (LPCR, AnyAcc, NoLock, Preserve)"); 266 dsdt_line(" {"); 267 dsdt_line(" Offset (0x60),"); 268 dsdt_line(" PIRA, 8,"); 269 dsdt_line(" PIRB, 8,"); 270 dsdt_line(" PIRC, 8,"); 271 dsdt_line(" PIRD, 8,"); 272 dsdt_line(" Offset (0x68),"); 273 dsdt_line(" PIRE, 8,"); 274 dsdt_line(" PIRF, 8,"); 275 dsdt_line(" PIRG, 8,"); 276 dsdt_line(" PIRH, 8"); 277 dsdt_line(" }"); 278 dsdt_line(""); 279 280 dsdt_indent(1); 281 SET_FOREACH(ldpp, lpc_dsdt_set) { 282 ldp = *ldpp; 283 ldp->handler(); 284 } 285 286 dsdt_line(""); 287 dsdt_line("Device (PIC)"); 288 dsdt_line("{"); 289 dsdt_line(" Name (_HID, EisaId (\"PNP0000\"))"); 290 dsdt_line(" Name (_CRS, ResourceTemplate ()"); 291 dsdt_line(" {"); 292 dsdt_indent(2); 293 dsdt_fixed_ioport(IO_ICU1, 2); 294 dsdt_fixed_ioport(IO_ICU2, 2); 295 dsdt_fixed_irq(2); 296 dsdt_unindent(2); 297 dsdt_line(" })"); 298 dsdt_line("}"); 299 300 dsdt_line(""); 301 dsdt_line("Device (TIMR)"); 302 dsdt_line("{"); 303 dsdt_line(" Name (_HID, EisaId (\"PNP0100\"))"); 304 dsdt_line(" Name (_CRS, ResourceTemplate ()"); 305 dsdt_line(" {"); 306 dsdt_indent(2); 307 dsdt_fixed_ioport(IO_TIMER1_PORT, 4); 308 dsdt_fixed_irq(0); 309 dsdt_unindent(2); 310 dsdt_line(" })"); 311 dsdt_line("}"); 312 dsdt_unindent(1); 313 314 dsdt_line("}"); 315 } 316 317 static void 318 pci_lpc_sysres_dsdt(void) 319 { 320 struct lpc_sysres **lspp, *lsp; 321 322 dsdt_line(""); 323 dsdt_line("Device (SIO)"); 324 dsdt_line("{"); 325 dsdt_line(" Name (_HID, EisaId (\"PNP0C02\"))"); 326 dsdt_line(" Name (_CRS, ResourceTemplate ()"); 327 dsdt_line(" {"); 328 329 dsdt_indent(2); 330 SET_FOREACH(lspp, lpc_sysres_set) { 331 lsp = *lspp; 332 switch (lsp->type) { 333 case LPC_SYSRES_IO: 334 dsdt_fixed_ioport(lsp->base, lsp->length); 335 break; 336 case LPC_SYSRES_MEM: 337 dsdt_fixed_mem32(lsp->base, lsp->length); 338 break; 339 } 340 } 341 dsdt_unindent(2); 342 343 dsdt_line(" })"); 344 dsdt_line("}"); 345 } 346 LPC_DSDT(pci_lpc_sysres_dsdt); 347 348 static void 349 pci_lpc_uart_dsdt(void) 350 { 351 struct lpc_uart_softc *sc; 352 int unit; 353 354 for (unit = 0; unit < LPC_UART_NUM; unit++) { 355 sc = &lpc_uart_softc[unit]; 356 if (!sc->enabled) 357 continue; 358 dsdt_line(""); 359 dsdt_line("Device (%s)", lpc_uart_names[unit]); 360 dsdt_line("{"); 361 dsdt_line(" Name (_HID, EisaId (\"PNP0501\"))"); 362 dsdt_line(" Name (_UID, %d)", unit + 1); 363 dsdt_line(" Name (_CRS, ResourceTemplate ()"); 364 dsdt_line(" {"); 365 dsdt_indent(2); 366 dsdt_fixed_ioport(sc->iobase, UART_IO_BAR_SIZE); 367 dsdt_fixed_irq(sc->irq); 368 dsdt_unindent(2); 369 dsdt_line(" })"); 370 dsdt_line("}"); 371 } 372 } 373 LPC_DSDT(pci_lpc_uart_dsdt); 374 375 static int 376 pci_lpc_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 377 int coff, int bytes, uint32_t val) 378 { 379 int pirq_pin; 380 381 if (bytes == 1) { 382 pirq_pin = 0; 383 if (coff >= 0x60 && coff <= 0x63) 384 pirq_pin = coff - 0x60 + 1; 385 if (coff >= 0x68 && coff <= 0x6b) 386 pirq_pin = coff - 0x68 + 5; 387 if (pirq_pin != 0) { 388 pirq_write(ctx, pirq_pin, val); 389 pci_set_cfgdata8(pi, coff, pirq_read(pirq_pin)); 390 return (0); 391 } 392 } 393 return (-1); 394 } 395 396 static void 397 pci_lpc_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 398 int baridx, uint64_t offset, int size, uint64_t value) 399 { 400 } 401 402 static uint64_t 403 pci_lpc_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 404 int baridx, uint64_t offset, int size) 405 { 406 return (0); 407 } 408 409 #define LPC_DEV 0x7000 410 #define LPC_VENDOR 0x8086 411 412 static int 413 pci_lpc_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) 414 { 415 416 /* 417 * Do not allow more than one LPC bridge to be configured. 418 */ 419 if (lpc_bridge != NULL) { 420 fprintf(stderr, "Only one LPC bridge is allowed.\n"); 421 return (-1); 422 } 423 424 /* 425 * Enforce that the LPC can only be configured on bus 0. This 426 * simplifies the ACPI DSDT because it can provide a decode for 427 * all legacy i/o ports behind bus 0. 428 */ 429 if (pi->pi_bus != 0) { 430 fprintf(stderr, "LPC bridge can be present only on bus 0.\n"); 431 return (-1); 432 } 433 434 if (lpc_init(ctx) != 0) 435 return (-1); 436 437 /* initialize config space */ 438 pci_set_cfgdata16(pi, PCIR_DEVICE, LPC_DEV); 439 pci_set_cfgdata16(pi, PCIR_VENDOR, LPC_VENDOR); 440 pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE); 441 pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_ISA); 442 443 lpc_bridge = pi; 444 445 return (0); 446 } 447 448 char * 449 lpc_pirq_name(int pin) 450 { 451 char *name; 452 453 if (lpc_bridge == NULL) 454 return (NULL); 455 asprintf(&name, "\\_SB.PC00.ISA.LNK%c,", 'A' + pin - 1); 456 return (name); 457 } 458 459 void 460 lpc_pirq_routed(void) 461 { 462 int pin; 463 464 if (lpc_bridge == NULL) 465 return; 466 467 for (pin = 0; pin < 4; pin++) 468 pci_set_cfgdata8(lpc_bridge, 0x60 + pin, pirq_read(pin + 1)); 469 for (pin = 0; pin < 4; pin++) 470 pci_set_cfgdata8(lpc_bridge, 0x68 + pin, pirq_read(pin + 5)); 471 } 472 473 struct pci_devemu pci_de_lpc = { 474 .pe_emu = "lpc", 475 .pe_init = pci_lpc_init, 476 .pe_write_dsdt = pci_lpc_write_dsdt, 477 .pe_cfgwrite = pci_lpc_cfgwrite, 478 .pe_barwrite = pci_lpc_write, 479 .pe_barread = pci_lpc_read 480 }; 481 PCI_EMUL_SET(pci_de_lpc); 482