xref: /freebsd-13-stable/usr.sbin/bhyve/pci_lpc.c (revision 3d497e17ebd33fe0f58d773e35ab994d750258d6)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 
30 #include <sys/cdefs.h>
31 #include <sys/types.h>
32 #include <machine/vmm.h>
33 #include <machine/vmm_snapshot.h>
34 
35 #include <err.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include <vmmapi.h>
41 
42 #include "acpi.h"
43 #include "debug.h"
44 #include "bootrom.h"
45 #include "config.h"
46 #include "inout.h"
47 #include "pci_emul.h"
48 #include "pci_irq.h"
49 #include "pci_lpc.h"
50 #include "pci_passthru.h"
51 #include "pctestdev.h"
52 #include "uart_emul.h"
53 
54 #define	IO_ICU1		0x20
55 #define	IO_ICU2		0xA0
56 
57 SET_DECLARE(lpc_dsdt_set, struct lpc_dsdt);
58 SET_DECLARE(lpc_sysres_set, struct lpc_sysres);
59 
60 #define	ELCR_PORT	0x4d0
61 SYSRES_IO(ELCR_PORT, 2);
62 
63 #define	IO_TIMER1_PORT	0x40
64 
65 #define	NMISC_PORT	0x61
66 SYSRES_IO(NMISC_PORT, 1);
67 
68 static struct pci_devinst *lpc_bridge;
69 
70 #define	LPC_UART_NUM	4
71 static struct lpc_uart_softc {
72 	struct uart_softc *uart_softc;
73 	int	iobase;
74 	int	irq;
75 	int	enabled;
76 } lpc_uart_softc[LPC_UART_NUM];
77 
78 static const char *lpc_uart_names[LPC_UART_NUM] = {
79 	"com1", "com2", "com3", "com4"
80 };
81 
82 static const char *lpc_uart_acpi_names[LPC_UART_NUM] = {
83 	"COM1", "COM2", "COM3", "COM4"
84 };
85 
86 /*
87  * LPC device configuration is in the following form:
88  * <lpc_device_name>[,<options>]
89  * For e.g. "com1,stdio" or "bootrom,/var/romfile"
90  */
91 int
lpc_device_parse(const char * opts)92 lpc_device_parse(const char *opts)
93 {
94 	int unit, error;
95 	char *str, *cpy, *lpcdev, *node_name;
96 	const char *romfile, *varfile;
97 
98 	error = -1;
99 	str = cpy = strdup(opts);
100 	lpcdev = strsep(&str, ",");
101 	if (lpcdev != NULL) {
102 		if (strcasecmp(lpcdev, "bootrom") == 0) {
103 			romfile = strsep(&str, ",");
104 			if (romfile == NULL) {
105 				errx(4, "invalid bootrom option \"%s\"", opts);
106 			}
107 			set_config_value("lpc.bootrom", romfile);
108 
109 			varfile = strsep(&str, ",");
110 			if (varfile == NULL) {
111 				error = 0;
112 				goto done;
113 			}
114 			if (strchr(varfile, '=') == NULL) {
115 				set_config_value("lpc.bootvars", varfile);
116 			} else {
117 				/* varfile doesn't exist, it's another config
118 				 * option */
119 				pci_parse_legacy_config(find_config_node("lpc"),
120 				    varfile);
121 			}
122 
123 			pci_parse_legacy_config(find_config_node("lpc"), str);
124 			error = 0;
125 			goto done;
126 		}
127 		for (unit = 0; unit < LPC_UART_NUM; unit++) {
128 			if (strcasecmp(lpcdev, lpc_uart_names[unit]) == 0) {
129 				asprintf(&node_name, "lpc.%s.path",
130 				    lpc_uart_names[unit]);
131 				set_config_value(node_name, str);
132 				free(node_name);
133 				error = 0;
134 				goto done;
135 			}
136 		}
137 		if (strcasecmp(lpcdev, pctestdev_getname()) == 0) {
138 			asprintf(&node_name, "lpc.%s", pctestdev_getname());
139 			set_config_bool(node_name, true);
140 			free(node_name);
141 			error = 0;
142 			goto done;
143 		}
144 	}
145 
146 done:
147 	free(cpy);
148 
149 	return (error);
150 }
151 
152 void
lpc_print_supported_devices(void)153 lpc_print_supported_devices(void)
154 {
155 	size_t i;
156 
157 	printf("bootrom\n");
158 	for (i = 0; i < LPC_UART_NUM; i++)
159 		printf("%s\n", lpc_uart_names[i]);
160 	printf("%s\n", pctestdev_getname());
161 }
162 
163 const char *
lpc_bootrom(void)164 lpc_bootrom(void)
165 {
166 
167 	return (get_config_value("lpc.bootrom"));
168 }
169 
170 const char *
lpc_fwcfg(void)171 lpc_fwcfg(void)
172 {
173 	return (get_config_value("lpc.fwcfg"));
174 }
175 
176 static void
lpc_uart_intr_assert(void * arg)177 lpc_uart_intr_assert(void *arg)
178 {
179 	struct lpc_uart_softc *sc = arg;
180 
181 	assert(sc->irq >= 0);
182 
183 	vm_isa_pulse_irq(lpc_bridge->pi_vmctx, sc->irq, sc->irq);
184 }
185 
186 static void
lpc_uart_intr_deassert(void * arg __unused)187 lpc_uart_intr_deassert(void *arg __unused)
188 {
189 	/*
190 	 * The COM devices on the LPC bus generate edge triggered interrupts,
191 	 * so nothing more to do here.
192 	 */
193 }
194 
195 static int
lpc_uart_io_handler(struct vmctx * ctx __unused,int in,int port,int bytes,uint32_t * eax,void * arg)196 lpc_uart_io_handler(struct vmctx *ctx __unused, int in,
197     int port, int bytes, uint32_t *eax, void *arg)
198 {
199 	int offset;
200 	struct lpc_uart_softc *sc = arg;
201 
202 	offset = port - sc->iobase;
203 
204 	switch (bytes) {
205 	case 1:
206 		if (in)
207 			*eax = uart_read(sc->uart_softc, offset);
208 		else
209 			uart_write(sc->uart_softc, offset, *eax);
210 		break;
211 	case 2:
212 		if (in) {
213 			*eax = uart_read(sc->uart_softc, offset);
214 			*eax |= uart_read(sc->uart_softc, offset + 1) << 8;
215 		} else {
216 			uart_write(sc->uart_softc, offset, *eax);
217 			uart_write(sc->uart_softc, offset + 1, *eax >> 8);
218 		}
219 		break;
220 	default:
221 		return (-1);
222 	}
223 
224 	return (0);
225 }
226 
227 static int
lpc_init(struct vmctx * ctx)228 lpc_init(struct vmctx *ctx)
229 {
230 	struct lpc_uart_softc *sc;
231 	struct inout_port iop;
232 	const char *backend, *name;
233 	char *node_name;
234 	int unit, error;
235 	const nvlist_t *nvl;
236 
237 	nvl = find_config_node("lpc");
238 	if (nvl != NULL && nvlist_exists(nvl, "bootrom")) {
239 		error = bootrom_loadrom(ctx, nvl);
240 		if (error)
241 			return (error);
242 	}
243 
244 	/* COM1 and COM2 */
245 	for (unit = 0; unit < LPC_UART_NUM; unit++) {
246 		sc = &lpc_uart_softc[unit];
247 		name = lpc_uart_names[unit];
248 
249 		if (uart_legacy_alloc(unit, &sc->iobase, &sc->irq) != 0) {
250 			EPRINTLN("Unable to allocate resources for "
251 			    "LPC device %s", name);
252 			return (-1);
253 		}
254 		pci_irq_reserve(sc->irq);
255 
256 		sc->uart_softc = uart_init(lpc_uart_intr_assert,
257 				    lpc_uart_intr_deassert, sc);
258 
259 		asprintf(&node_name, "lpc.%s.path", name);
260 		backend = get_config_value(node_name);
261 		free(node_name);
262 		if (uart_set_backend(sc->uart_softc, backend) != 0) {
263 			EPRINTLN("Unable to initialize backend '%s' "
264 			    "for LPC device %s", backend, name);
265 			return (-1);
266 		}
267 
268 		bzero(&iop, sizeof(struct inout_port));
269 		iop.name = name;
270 		iop.port = sc->iobase;
271 		iop.size = UART_IO_BAR_SIZE;
272 		iop.flags = IOPORT_F_INOUT;
273 		iop.handler = lpc_uart_io_handler;
274 		iop.arg = sc;
275 
276 		error = register_inout(&iop);
277 		assert(error == 0);
278 		sc->enabled = 1;
279 	}
280 
281 	/* pc-testdev */
282 	asprintf(&node_name, "lpc.%s", pctestdev_getname());
283 	if (get_config_bool_default(node_name, false)) {
284 		error = pctestdev_init(ctx);
285 		if (error)
286 			return (error);
287 	}
288 	free(node_name);
289 
290 	return (0);
291 }
292 
293 static void
pci_lpc_write_dsdt(struct pci_devinst * pi)294 pci_lpc_write_dsdt(struct pci_devinst *pi)
295 {
296 	struct lpc_dsdt **ldpp, *ldp;
297 
298 	dsdt_line("");
299 	dsdt_line("Device (ISA)");
300 	dsdt_line("{");
301 	dsdt_line("  Name (_ADR, 0x%04X%04X)", pi->pi_slot, pi->pi_func);
302 	dsdt_line("  OperationRegion (LPCR, PCI_Config, 0x00, 0x100)");
303 	dsdt_line("  Field (LPCR, AnyAcc, NoLock, Preserve)");
304 	dsdt_line("  {");
305 	dsdt_line("    Offset (0x60),");
306 	dsdt_line("    PIRA,   8,");
307 	dsdt_line("    PIRB,   8,");
308 	dsdt_line("    PIRC,   8,");
309 	dsdt_line("    PIRD,   8,");
310 	dsdt_line("    Offset (0x68),");
311 	dsdt_line("    PIRE,   8,");
312 	dsdt_line("    PIRF,   8,");
313 	dsdt_line("    PIRG,   8,");
314 	dsdt_line("    PIRH,   8");
315 	dsdt_line("  }");
316 	dsdt_line("");
317 
318 	dsdt_indent(1);
319 	SET_FOREACH(ldpp, lpc_dsdt_set) {
320 		ldp = *ldpp;
321 		ldp->handler();
322 	}
323 
324 	dsdt_line("");
325 	dsdt_line("Device (PIC)");
326 	dsdt_line("{");
327 	dsdt_line("  Name (_HID, EisaId (\"PNP0000\"))");
328 	dsdt_line("  Name (_CRS, ResourceTemplate ()");
329 	dsdt_line("  {");
330 	dsdt_indent(2);
331 	dsdt_fixed_ioport(IO_ICU1, 2);
332 	dsdt_fixed_ioport(IO_ICU2, 2);
333 	dsdt_fixed_irq(2);
334 	dsdt_unindent(2);
335 	dsdt_line("  })");
336 	dsdt_line("}");
337 
338 	dsdt_line("");
339 	dsdt_line("Device (TIMR)");
340 	dsdt_line("{");
341 	dsdt_line("  Name (_HID, EisaId (\"PNP0100\"))");
342 	dsdt_line("  Name (_CRS, ResourceTemplate ()");
343 	dsdt_line("  {");
344 	dsdt_indent(2);
345 	dsdt_fixed_ioport(IO_TIMER1_PORT, 4);
346 	dsdt_fixed_irq(0);
347 	dsdt_unindent(2);
348 	dsdt_line("  })");
349 	dsdt_line("}");
350 	dsdt_unindent(1);
351 
352 	dsdt_line("}");
353 }
354 
355 static void
pci_lpc_sysres_dsdt(void)356 pci_lpc_sysres_dsdt(void)
357 {
358 	struct lpc_sysres **lspp, *lsp;
359 
360 	dsdt_line("");
361 	dsdt_line("Device (SIO)");
362 	dsdt_line("{");
363 	dsdt_line("  Name (_HID, EisaId (\"PNP0C02\"))");
364 	dsdt_line("  Name (_CRS, ResourceTemplate ()");
365 	dsdt_line("  {");
366 
367 	dsdt_indent(2);
368 	SET_FOREACH(lspp, lpc_sysres_set) {
369 		lsp = *lspp;
370 		switch (lsp->type) {
371 		case LPC_SYSRES_IO:
372 			dsdt_fixed_ioport(lsp->base, lsp->length);
373 			break;
374 		case LPC_SYSRES_MEM:
375 			dsdt_fixed_mem32(lsp->base, lsp->length);
376 			break;
377 		}
378 	}
379 	dsdt_unindent(2);
380 
381 	dsdt_line("  })");
382 	dsdt_line("}");
383 }
384 LPC_DSDT(pci_lpc_sysres_dsdt);
385 
386 static void
pci_lpc_uart_dsdt(void)387 pci_lpc_uart_dsdt(void)
388 {
389 	struct lpc_uart_softc *sc;
390 	int unit;
391 
392 	for (unit = 0; unit < LPC_UART_NUM; unit++) {
393 		sc = &lpc_uart_softc[unit];
394 		if (!sc->enabled)
395 			continue;
396 		dsdt_line("");
397 		dsdt_line("Device (%s)", lpc_uart_acpi_names[unit]);
398 		dsdt_line("{");
399 		dsdt_line("  Name (_HID, EisaId (\"PNP0501\"))");
400 		dsdt_line("  Name (_UID, %d)", unit + 1);
401 		dsdt_line("  Name (_CRS, ResourceTemplate ()");
402 		dsdt_line("  {");
403 		dsdt_indent(2);
404 		dsdt_fixed_ioport(sc->iobase, UART_IO_BAR_SIZE);
405 		dsdt_fixed_irq(sc->irq);
406 		dsdt_unindent(2);
407 		dsdt_line("  })");
408 		dsdt_line("}");
409 	}
410 }
411 LPC_DSDT(pci_lpc_uart_dsdt);
412 
413 static int
pci_lpc_cfgwrite(struct pci_devinst * pi,int coff,int bytes,uint32_t val)414 pci_lpc_cfgwrite(struct pci_devinst *pi, int coff, int bytes, uint32_t val)
415 {
416 	int pirq_pin;
417 
418 	if (bytes == 1) {
419 		pirq_pin = 0;
420 		if (coff >= 0x60 && coff <= 0x63)
421 			pirq_pin = coff - 0x60 + 1;
422 		if (coff >= 0x68 && coff <= 0x6b)
423 			pirq_pin = coff - 0x68 + 5;
424 		if (pirq_pin != 0) {
425 			pirq_write(pi->pi_vmctx, pirq_pin, val);
426 			pci_set_cfgdata8(pi, coff, pirq_read(pirq_pin));
427 			return (0);
428 		}
429 	}
430 	return (-1);
431 }
432 
433 static void
pci_lpc_write(struct pci_devinst * pi __unused,int baridx __unused,uint64_t offset __unused,int size __unused,uint64_t value __unused)434 pci_lpc_write(struct pci_devinst *pi __unused, int baridx __unused,
435     uint64_t offset __unused, int size __unused, uint64_t value __unused)
436 {
437 }
438 
439 static uint64_t
pci_lpc_read(struct pci_devinst * pi __unused,int baridx __unused,uint64_t offset __unused,int size __unused)440 pci_lpc_read(struct pci_devinst *pi __unused, int baridx __unused,
441     uint64_t offset __unused, int size __unused)
442 {
443 	return (0);
444 }
445 
446 #define	LPC_DEV		0x7000
447 #define	LPC_VENDOR	0x8086
448 #define LPC_REVID	0x00
449 #define LPC_SUBVEND_0	0x0000
450 #define LPC_SUBDEV_0	0x0000
451 
452 static int
pci_lpc_get_sel(struct pcisel * const sel)453 pci_lpc_get_sel(struct pcisel *const sel)
454 {
455 	assert(sel != NULL);
456 
457 	memset(sel, 0, sizeof(*sel));
458 
459 	for (uint8_t slot = 0; slot <= PCI_SLOTMAX; ++slot) {
460 		uint8_t max_func = 0;
461 
462 		sel->pc_dev = slot;
463 		sel->pc_func = 0;
464 
465 		if (read_config(sel, PCIR_HDRTYPE, 1) & PCIM_MFDEV)
466 			max_func = PCI_FUNCMAX;
467 
468 		for (uint8_t func = 0; func <= max_func; ++func) {
469 			sel->pc_func = func;
470 
471 			if ((read_config(sel, PCIR_CLASS, 1) == PCIC_BRIDGE) &&
472 			    (read_config(sel, PCIR_SUBCLASS, 1) ==
473 				PCIS_BRIDGE_ISA)) {
474 				return (0);
475 			}
476 		}
477 	}
478 
479 	warnx("%s: Unable to find host selector of LPC bridge.", __func__);
480 
481 	return (-1);
482 }
483 
484 static int
pci_lpc_init(struct pci_devinst * pi,nvlist_t * nvl)485 pci_lpc_init(struct pci_devinst *pi, nvlist_t *nvl)
486 {
487 	struct pcisel sel = { 0 };
488 	struct pcisel *selp = NULL;
489 	uint16_t device, subdevice, subvendor, vendor;
490 	uint8_t revid;
491 
492 	/*
493 	 * Do not allow more than one LPC bridge to be configured.
494 	 */
495 	if (lpc_bridge != NULL) {
496 		EPRINTLN("Only one LPC bridge is allowed.");
497 		return (-1);
498 	}
499 
500 	/*
501 	 * Enforce that the LPC can only be configured on bus 0. This
502 	 * simplifies the ACPI DSDT because it can provide a decode for
503 	 * all legacy i/o ports behind bus 0.
504 	 */
505 	if (pi->pi_bus != 0) {
506 		EPRINTLN("LPC bridge can be present only on bus 0.");
507 		return (-1);
508 	}
509 
510 	if (lpc_init(pi->pi_vmctx) != 0)
511 		return (-1);
512 
513 	if (pci_lpc_get_sel(&sel) == 0)
514 		selp = &sel;
515 
516 	vendor = pci_config_read_reg(selp, nvl, PCIR_VENDOR, 2, LPC_VENDOR);
517 	device = pci_config_read_reg(selp, nvl, PCIR_DEVICE, 2, LPC_DEV);
518 	revid = pci_config_read_reg(selp, nvl, PCIR_REVID, 1, LPC_REVID);
519 	subvendor = pci_config_read_reg(selp, nvl, PCIR_SUBVEND_0, 2,
520 	    LPC_SUBVEND_0);
521 	subdevice = pci_config_read_reg(selp, nvl, PCIR_SUBDEV_0, 2,
522 	    LPC_SUBDEV_0);
523 
524 	/* initialize config space */
525 	pci_set_cfgdata16(pi, PCIR_VENDOR, vendor);
526 	pci_set_cfgdata16(pi, PCIR_DEVICE, device);
527 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE);
528 	pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_ISA);
529 	pci_set_cfgdata8(pi, PCIR_REVID, revid);
530 	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, subvendor);
531 	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, subdevice);
532 
533 	lpc_bridge = pi;
534 
535 	return (0);
536 }
537 
538 char *
lpc_pirq_name(int pin)539 lpc_pirq_name(int pin)
540 {
541 	char *name;
542 
543 	if (lpc_bridge == NULL)
544 		return (NULL);
545 	asprintf(&name, "\\_SB.PC00.ISA.LNK%c,", 'A' + pin - 1);
546 	return (name);
547 }
548 
549 void
lpc_pirq_routed(void)550 lpc_pirq_routed(void)
551 {
552 	int pin;
553 
554 	if (lpc_bridge == NULL)
555 		return;
556 
557  	for (pin = 0; pin < 4; pin++)
558 		pci_set_cfgdata8(lpc_bridge, 0x60 + pin, pirq_read(pin + 1));
559 	for (pin = 0; pin < 4; pin++)
560 		pci_set_cfgdata8(lpc_bridge, 0x68 + pin, pirq_read(pin + 5));
561 }
562 
563 #ifdef BHYVE_SNAPSHOT
564 static int
pci_lpc_snapshot(struct vm_snapshot_meta * meta)565 pci_lpc_snapshot(struct vm_snapshot_meta *meta)
566 {
567 	int unit, ret;
568 	struct uart_softc *sc;
569 
570 	for (unit = 0; unit < LPC_UART_NUM; unit++) {
571 		sc = lpc_uart_softc[unit].uart_softc;
572 
573 		ret = uart_snapshot(sc, meta);
574 		if (ret != 0)
575 			goto done;
576 	}
577 
578 done:
579 	return (ret);
580 }
581 #endif
582 
583 static const struct pci_devemu pci_de_lpc = {
584 	.pe_emu =	"lpc",
585 	.pe_init =	pci_lpc_init,
586 	.pe_write_dsdt = pci_lpc_write_dsdt,
587 	.pe_cfgwrite =	pci_lpc_cfgwrite,
588 	.pe_barwrite =	pci_lpc_write,
589 	.pe_barread =	pci_lpc_read,
590 #ifdef BHYVE_SNAPSHOT
591 	.pe_snapshot =	pci_lpc_snapshot,
592 #endif
593 };
594 PCI_EMUL_SET(pci_de_lpc);
595