xref: /illumos-gate/usr/src/boot/efi/libefi/efiserialio.c (revision 4ac2186d79f65de18b11f2693e78f73b27d5308b)
1 /*
2  * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #include <sys/cdefs.h>
27 
28 #include <stand.h>
29 #include <sys/errno.h>
30 #include <bootstrap.h>
31 #include <stdbool.h>
32 
33 #include <efi.h>
34 #include <efilib.h>
35 #include <efidevp.h>
36 #include <Protocol/SerialIo.h>
37 #include <Protocol/SuperIo.h>
38 #include <Protocol/IsaIo.h>
39 
40 EFI_GUID gEfiSerialIoProtocolGuid = SERIAL_IO_PROTOCOL;
41 EFI_GUID gEfiSerialTerminalDeviceTypeGuid = \
42 	EFI_SERIAL_TERMINAL_DEVICE_TYPE_GUID;
43 EFI_GUID gEfiSioProtocolGuid = EFI_SIO_PROTOCOL_GUID;
44 
45 #define	COMC_TXWAIT	0x40000		/* transmit timeout */
46 #define	COM1_IOADDR	0x3f8
47 #define	COM2_IOADDR	0x2f8
48 #define	COM3_IOADDR	0x3e8
49 #define	COM4_IOADDR	0x2e8
50 
51 #define	PNP0501		0x501		/* 16550A-compatible COM port */
52 
53 /* List of serial ports, set up by efi_serial_ini() */
54 serial_list_t serials = STAILQ_HEAD_INITIALIZER(serials);
55 
56 static void	efi_serial_probe(struct console *);
57 static int	efi_serial_init(struct console *, int);
58 static void	efi_serial_putchar(struct console *, int);
59 static int	efi_serial_getchar(struct console *);
60 static int	efi_serial_ischar(struct console *);
61 static int	efi_serial_ioctl(struct console *, int, void *);
62 static void	efi_serial_devinfo(struct console *);
63 static bool	efi_serial_setup(struct console *);
64 static char	*efi_serial_asprint_mode(struct serial *);
65 static int	efi_serial_parse_mode(struct serial *, const char *);
66 static int	efi_serial_mode_set(struct env_var *, int, const void *);
67 static int	efi_serial_cd_set(struct env_var *, int, const void *);
68 static int	efi_serial_rtsdtr_set(struct env_var *, int, const void *);
69 
70 extern struct console efi_console;
71 
72 static bool
efi_serial_should_append(struct serial * port)73 efi_serial_should_append(struct serial *port)
74 {
75 	EFI_DEVICE_PATH *node, *dev;
76 	EFI_STATUS status;
77 	const char *name;
78 	char *buf;
79 	size_t sz;
80 	bool rv = true;
81 
82 	if (port->currdev == NULL)
83 		return (rv);
84 
85 	buf = NULL;
86 	sz = 0;
87 	name = "ConOut";
88 	status = efi_global_getenv(name, buf, &sz);
89 	/* Some systems do not provide ConOut, also check ConIn */
90 	if (EFI_ERROR(status) && status != EFI_BUFFER_TOO_SMALL) {
91 		name = "ConIn";
92 		status = efi_global_getenv(name, buf, &sz);
93 	}
94 	if (status == EFI_BUFFER_TOO_SMALL) {
95 		buf = malloc(sz);
96 		if (buf == NULL)
97 			return (rv);
98 		status = efi_global_getenv(name, buf, &sz);
99 	}
100 	if (EFI_ERROR(status)) {
101 		free(buf);
102 		return (rv);
103 	}
104 
105 	dev = efi_lookup_devpath(port->currdev);
106 	if (dev == NULL) {
107 		free(buf);
108 		return (rv);
109 	}
110 
111 	node = (EFI_DEVICE_PATH *)buf;
112 	/*
113 	 * We only need to know if this port is first in list.
114 	 * This is only important when "os_console" is not set.
115 	 */
116 	if (!IsDevicePathEnd(node) && efi_devpath_is_prefix(dev, node))
117 		rv = false;
118 
119 	efi_close_devpath(dev);
120 	free(buf);
121 	return (rv);
122 }
123 
124 static void
efi_serial_setup_env(struct console * tty)125 efi_serial_setup_env(struct console *tty)
126 {
127 	struct serial *port = tty->c_private;
128 	char name[20];
129 	char value[20];
130 	char *env;
131 
132 	(void) snprintf(name, sizeof (name), "%s-mode", tty->c_name);
133 	env = getenv(name);
134 	if (env != NULL)
135 		(void) efi_serial_parse_mode(port, env);
136 	env = efi_serial_asprint_mode(port);
137 	if (env != NULL) {
138 		(void) unsetenv(name);
139 		(void) env_setenv(name, EV_VOLATILE, env, efi_serial_mode_set,
140 		    env_nounset);
141 		if (port->is_efi_console) {
142 			(void) snprintf(name, sizeof (name), "%s-spcr-mode",
143 			    tty->c_name);
144 			(void) setenv(name, env, 1);
145 			free(env);
146 
147 			/* Add us to console list. */
148 			(void) snprintf(name, sizeof (name), "console");
149 			env = getenv(name);
150 			if (env == NULL) {
151 				(void) setenv(name, tty->c_name, 1);
152 			} else {
153 				char *ptr;
154 				int rv;
155 
156 				/*
157 				 * we have "text" already in place,
158 				 * check if we need to add
159 				 * serial console before or after.
160 				 */
161 				if (efi_serial_should_append(port))
162 					rv = asprintf(&ptr, "%s,%s", env,
163 					    tty->c_name);
164 				else
165 					rv = asprintf(&ptr, "%s,%s",
166 					    tty->c_name, env);
167 				if (rv > 0) {
168 					(void) setenv(name, ptr, 1);
169 					free(ptr);
170 				} else {
171 					printf("%s: %s\n", __func__,
172 					    strerror(ENOMEM));
173 				}
174 			}
175 		} else {
176 			free(env);
177 		}
178 	}
179 
180 	(void) snprintf(name, sizeof (name), "%s-ignore-cd", tty->c_name);
181 	env = getenv(name);
182 	if (env != NULL) {
183 		if (strcmp(env, "true") == 0)
184 			port->ignore_cd = 1;
185 		else if (strcmp(env, "false") == 0)
186 			port->ignore_cd = 0;
187 	}
188 
189 	(void) snprintf(value, sizeof (value), "%s",
190 	    port->ignore_cd? "true" : "false");
191 	(void) unsetenv(name);
192 	(void) env_setenv(name, EV_VOLATILE, value, efi_serial_cd_set,
193 	    env_nounset);
194 
195 	(void) snprintf(name, sizeof (name), "%s-rts-dtr-off", tty->c_name);
196 	env = getenv(name);
197 	if (env != NULL) {
198 		if (strcmp(env, "true") == 0)
199 			port->rtsdtr_off = 1;
200 		else if (strcmp(env, "false") == 0)
201 			port->rtsdtr_off = 0;
202 	}
203 
204 	(void) snprintf(value, sizeof (value), "%s",
205 	    port->rtsdtr_off? "true" : "false");
206 	(void) unsetenv(name);
207 	(void) env_setenv(name, EV_VOLATILE, value, efi_serial_rtsdtr_set,
208 	    env_nounset);
209 }
210 
211 static void
efi_check_and_set_condev(struct serial * port,const char * name)212 efi_check_and_set_condev(struct serial *port, const char *name)
213 {
214 	EFI_DEVICE_PATH *node, *dev;
215 	EFI_STATUS status;
216 	char *buf;
217 	size_t sz;
218 
219 	if (port->currdev == NULL)
220 		return;
221 
222 	buf = NULL;
223 	sz = 0;
224 	status = efi_global_getenv(name, buf, &sz);
225 	if (status == EFI_BUFFER_TOO_SMALL) {
226 		buf = malloc(sz);
227 		if (buf == NULL)
228 			return;
229 		status = efi_global_getenv(name, buf, &sz);
230 	}
231 	if (EFI_ERROR(status)) {
232 		free(buf);
233 		return;
234 	}
235 
236 	dev = efi_lookup_devpath(port->currdev);
237 	if (dev == NULL) {
238 		free(buf);
239 		return;
240 	}
241 
242 	node = (EFI_DEVICE_PATH *)buf;
243 	while (!IsDevicePathEnd(node)) {
244 		/* Sanity check the node before moving to the next node. */
245 		if (DevicePathNodeLength(node) < sizeof (*node))
246 			break;
247 
248 		if (efi_devpath_is_prefix(dev, node)) {
249 			port->is_efi_console = true;
250 			break;
251 		}
252 
253 		node = efi_devpath_next_instance(node);
254 	}
255 
256 	efi_close_devpath(dev);
257 	free(buf);
258 }
259 
260 /*
261  * Get list of super io handles, get device path and check if this
262  * sio device path is parent of serial io device.
263  */
264 static EFI_STATUS
efi_get_io_handle(EFI_HANDLE * handles,uint_t nhandles,EFI_DEVICE_PATH * dp,EFI_HANDLE * hp)265 efi_get_io_handle(EFI_HANDLE *handles, uint_t nhandles, EFI_DEVICE_PATH *dp,
266     EFI_HANDLE *hp)
267 {
268 	EFI_HANDLE h;
269 	EFI_DEVICE_PATH *parent;
270 
271 	h = NULL;
272 	for (uint_t i = 0; i < nhandles; i++) {
273 		parent = efi_lookup_devpath(handles[i]);
274 		if (parent == NULL)
275 			continue;
276 		if (efi_devpath_is_prefix(parent, dp)) {
277 			h = handles[i];
278 			efi_close_devpath(h);
279 			break;
280 		}
281 		efi_close_devpath(handles[i]);
282 	}
283 
284 	if (h == NULL)
285 		return (EFI_NOT_FOUND);
286 	*hp = h;
287 	return (EFI_SUCCESS);
288 }
289 
290 /*
291  * Use this super io protocol instance to identify serial port.
292  */
293 static EFI_STATUS
efi_get_sio_serial_name(EFI_HANDLE handle,char * id)294 efi_get_sio_serial_name(EFI_HANDLE handle, char *id)
295 {
296 	EFI_STATUS status;
297 	EFI_SIO_PROTOCOL *sio;
298 	ACPI_RESOURCE_HEADER_PTR rl;
299 	EFI_ACPI_IO_PORT_DESCRIPTOR *io;
300 	EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *fixedio;
301 	EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *as;
302 	UINT64 base_address = 0;
303 	char name;
304 
305 	status = BS->OpenProtocol(handle, &gEfiSioProtocolGuid,
306 	    (void **)&sio, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
307 	if (!EFI_ERROR(status)) {
308 		status = sio->GetResources(sio, &rl);
309 		(void) BS->CloseProtocol(handle, &gEfiSioProtocolGuid,
310 		    IH, NULL);
311 	}
312 
313 	if (EFI_ERROR(status)) {
314 		return (status);
315 	}
316 
317 	while (rl.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR &&
318 	    base_address == 0) {
319 		switch (rl.SmallHeader->Byte) {
320 		case ACPI_IO_PORT_DESCRIPTOR:
321 			io = (EFI_ACPI_IO_PORT_DESCRIPTOR *)rl.SmallHeader;
322 			if (io->Length != 0)
323 				base_address = io->BaseAddressMin;
324 			break;
325 
326 		case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:
327 			fixedio =
328 			    (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *)
329 			    rl.SmallHeader;
330 			if (fixedio->Length != 0)
331 				base_address = fixedio->BaseAddress;
332 			break;
333 
334 		case ACPI_ADDRESS_SPACE_DESCRIPTOR:
335 			as = (void *)rl.SmallHeader;
336 			if (as->AddrLen != 0)
337 				base_address = as->AddrRangeMin;
338 			break;
339 		}
340 
341 		if (rl.SmallHeader->Bits.Type == 0) {
342 			rl.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *)
343 			    ((UINT8 *)rl.SmallHeader +
344 			    rl.SmallHeader->Bits.Length +
345 			    sizeof (rl.SmallHeader));
346 		} else {
347 			rl.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *)
348 			    ((UINT8 *)rl.LargeHeader +
349 			    rl.LargeHeader->Length +
350 			    sizeof (rl.LargeHeader));
351 		}
352 	}
353 
354 	/*
355 	 * On x86, we name COM1-COM4 as ttya-ttyd.
356 	 */
357 	switch (base_address) {
358 	case COM1_IOADDR:
359 		name = 'a';
360 		break;
361 
362 	case COM2_IOADDR:
363 		name = 'b';
364 		break;
365 
366 	case COM3_IOADDR:
367 		name = 'c';
368 		break;
369 
370 	case COM4_IOADDR:
371 		name = 'd';
372 		break;
373 
374 	default:
375 		return (EFI_NOT_FOUND);
376 	}
377 
378 	*id = name;
379 	return (status);
380 }
381 
382 /*
383  * Use this ISA io protocol instance to identify serial port.
384  */
385 static EFI_STATUS
efi_get_isaio_serial_name(EFI_HANDLE handle,char * id)386 efi_get_isaio_serial_name(EFI_HANDLE handle, char *id)
387 {
388 	EFI_STATUS status;
389 	EFI_ISA_IO_PROTOCOL *io;
390 	UINT32 StartRange = 0;
391 	char name;
392 
393 	status = BS->OpenProtocol(handle, &gEfiIsaIoProtocolGuid,
394 	    (void **)&io, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
395 	if (EFI_ERROR(status))
396 		return (status);
397 
398 	for (uint_t i = 0;
399 	    io->ResourceList->ResourceItem[i].Type !=
400 	    EfiIsaAcpiResourceEndOfList;
401 	    i++) {
402 		switch (io->ResourceList->ResourceItem[i].Type) {
403 		case EfiIsaAcpiResourceIo:
404 			StartRange =
405 			    io->ResourceList->ResourceItem[i].StartRange;
406 			break;
407 		default:
408 			break;
409 		}
410 	}
411 	(void) BS->CloseProtocol(handle, &gEfiIsaIoProtocolGuid, IH, NULL);
412 
413 	switch (StartRange) {
414 	case COM1_IOADDR:
415 		name = 'a';
416 		break;
417 
418 	case COM2_IOADDR:
419 		name = 'b';
420 		break;
421 
422 	case COM3_IOADDR:
423 		name = 'c';
424 		break;
425 
426 	case COM4_IOADDR:
427 		name = 'd';
428 		break;
429 
430 	default:
431 		return (EFI_NOT_FOUND);
432 	}
433 
434 	*id = name;
435 	return (status);
436 }
437 
438 /*
439  * Return UID from ACPI_EXTENDED_HID_DEVICE_PATH.
440  */
441 uint32_t
efi_get_acpiex_uid(ACPI_EXTENDED_HID_DEVICE_PATH * acpiex)442 efi_get_acpiex_uid(ACPI_EXTENDED_HID_DEVICE_PATH *acpiex)
443 {
444 	char *_HIDSTR, *_UIDSTR;
445 	unsigned long tmp;
446 	char *end;
447 
448 	_HIDSTR = (char *)acpiex + 16;
449 	_UIDSTR = _HIDSTR + strlen(_HIDSTR) + 1;
450 
451 	if (*_UIDSTR != '\0') {
452 		errno = 0;
453 		tmp = strtoul(_UIDSTR, &end, 0);
454 		if (errno == 0) {
455 			return (tmp);
456 		}
457 		/*
458 		 * in case of error, we have option to panic
459 		 * or return UID. There is no screen output yet.
460 		 */
461 	}
462 
463 	return (acpiex->UID);
464 }
465 
466 /*
467  * walk device path and check each node.
468  * if node is ACPI dp for serial port, use UID to set name.
469  */
470 static EFI_STATUS
efi_get_acpi_name(EFI_DEVICE_PATH * dp,char * id)471 efi_get_acpi_name(EFI_DEVICE_PATH *dp, char *id)
472 {
473 	ACPI_HID_DEVICE_PATH *acpi;
474 	ACPI_EXTENDED_HID_DEVICE_PATH *acpiex;
475 	EFI_STATUS status;
476 	char *_HIDSTR;
477 
478 	status = EFI_NOT_FOUND;
479 	acpiex = NULL;
480 	_HIDSTR = NULL;
481 
482 	while (!IsDevicePathEnd(dp)) {
483 		if (DevicePathType(dp) == ACPI_DEVICE_PATH) {
484 			acpi = (ACPI_HID_DEVICE_PATH *)dp;
485 			if (DevicePathSubType(dp) == ACPI_DP &&
486 			    acpi->HID == EISA_PNP_ID(PNP0501)) {
487 				*id = 'a' + acpi->UID;
488 				status = EFI_SUCCESS;
489 				break;
490 			}
491 
492 			acpiex = (ACPI_EXTENDED_HID_DEVICE_PATH *)dp;
493 			/*
494 			 * acpi extended structure may additionally have
495 			 * _HIDSTR, _UIDSTR, _CIDSTR string data,
496 			 * if present, they override HID, UID and CID
497 			 * fields. Either HID or _HIDSTR must be present.
498 			 */
499 			_HIDSTR = (char *)dp + 16;
500 			/*
501 			 * From note in ACPICA source (AcpiNsRepair_HID()),
502 			 * there are many machines with ID starting with
503 			 * asterisk. We use same approach here as in acpica.
504 			 * Note: I have no idea if UEFI device path creation
505 			 * already handles this, but lets play safe.
506 			 */
507 			if (*_HIDSTR == '*')
508 				_HIDSTR++;
509 
510 			if (DevicePathSubType(dp) == ACPI_EXTENDED_DP &&
511 			    (acpiex->HID == EISA_PNP_ID(PNP0501) ||
512 			    acpiex->CID == EISA_PNP_ID(PNP0501) ||
513 			    strncmp(_HIDSTR, "UART", 4) == 0)) {
514 				*id = 'a' + efi_get_acpiex_uid(acpiex);
515 				status = EFI_SUCCESS;
516 				break;
517 			}
518 		}
519 		dp = NextDevicePathNode(dp);
520 	}
521 
522 	return (status);
523 }
524 
525 /*
526  * SERIAL IO protocol is abstraction on top of actual device
527  */
528 static void
efi_set_serial_name(struct console * tty)529 efi_set_serial_name(struct console *tty)
530 {
531 	struct serial *p, *port = tty->c_private;
532 	EFI_DEVICE_PATH *dp;
533 	EFI_STATUS status;
534 	EFI_HANDLE *handles, handle;
535 	uint_t nhandles;
536 
537 	dp = efi_lookup_devpath(port->currdev);
538 	if (dp != NULL) {
539 		/* Try to detect actual IO protocol */
540 		status = efi_get_protocol_handles(&gEfiSioProtocolGuid,
541 		    &nhandles, &handles);
542 		if (!EFI_ERROR(status)) {
543 			status = efi_get_io_handle(handles, nhandles,
544 			    dp, &handle);
545 			free(handles);
546 			if (!EFI_ERROR(status)) {
547 				port->iodev = handle;
548 				status = efi_get_sio_serial_name(handle,
549 				    &port->name);
550 				/* It is SIO serial device, we are done. */
551 				goto done;
552 			}
553 		}
554 
555 		status = efi_get_protocol_handles(&gEfiIsaIoProtocolGuid,
556 		    &nhandles, &handles);
557 		if (!EFI_ERROR(status)) {
558 			status = efi_get_io_handle(handles, nhandles,
559 			    dp, &handle);
560 			free(handles);
561 			if (!EFI_ERROR(status)) {
562 				port->iodev = handle;
563 				status = efi_get_isaio_serial_name(handle,
564 				    &port->name);
565 				/* It is ISAIO serial device, we are done. */
566 				goto done;
567 			}
568 		}
569 
570 		/*
571 		 * Still nothing? check, if we have ACPI device path.
572 		 */
573 		status = efi_get_acpi_name(dp, &port->name);
574 done:
575 		if (EFI_ERROR(status)) {
576 			/*
577 			 * We have serial port but unknown hw driver.
578 			 * If we do not have serial ports registered,
579 			 * start from ttya, otherwise from tty0.
580 			 * Other option would be to do this only in case of
581 			 * VenHw device path.
582 			 */
583 			if (STAILQ_EMPTY(&serials))
584 				port->name = 'a';
585 			else
586 				port->name = '0';
587 
588 			STAILQ_FOREACH(p, &serials, next) {
589 				if (p->name == port->name)
590 					port->name++;
591 			}
592 		}
593 		efi_close_devpath(dp);
594 	}
595 
596 	(void) asprintf(&tty->c_name, "tty%c", port->name);
597 	(void) asprintf(&tty->c_desc, "serial port %c", port->name);
598 }
599 
600 static uint_t
efi_serial_create_port(uint_t c,EFI_HANDLE handle)601 efi_serial_create_port(uint_t c, EFI_HANDLE handle)
602 {
603 	struct console *tty;
604 	struct serial *port;
605 	EFI_STATUS status;
606 
607 	tty = calloc(1, sizeof (*tty));
608 	if (tty == NULL) {
609 		/* Out of memory?! can not continue */
610 		consoles[c] = tty;
611 		return (c);
612 	}
613 	port = calloc(1, sizeof (*port));
614 	if (port == NULL) {
615 		free(tty);
616 		consoles[c] = NULL;
617 		return (c);
618 	}
619 
620 	/* Set up port descriptor */
621 	port->currdev = handle;
622 	status = BS->OpenProtocol(handle, &gEfiSerialIoProtocolGuid,
623 	    (void **)&port->io.sio, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
624 	if (EFI_ERROR(status)) {
625 		free(tty);
626 		free(port);
627 		consoles[c] = NULL;
628 		return (c);
629 	}
630 
631 	port->guid = &gEfiSerialIoProtocolGuid;
632 	port->baudrate = port->io.sio->Mode->BaudRate;
633 	port->timeout = port->io.sio->Mode->Timeout;
634 	port->receivefifodepth = port->io.sio->Mode->ReceiveFifoDepth;
635 	port->databits = port->io.sio->Mode->DataBits;
636 	port->parity = port->io.sio->Mode->Parity;
637 	port->stopbits = port->io.sio->Mode->StopBits;
638 	port->ignore_cd = true;		/* ignore cd */
639 	port->rtsdtr_off = false;	/* rts-dtr is on */
640 
641 	/* Set up serial device descriptor */
642 	tty->c_private = port;
643 	efi_set_serial_name(tty);
644 	tty->c_flags = C_PRESENTIN | C_PRESENTOUT;
645 	tty->c_probe = efi_serial_probe;
646 	tty->c_init = efi_serial_init;
647 	tty->c_out = efi_serial_putchar;
648 	tty->c_in = efi_serial_getchar;
649 	tty->c_ready = efi_serial_ischar;
650 	tty->c_ioctl = efi_serial_ioctl;
651 	tty->c_devinfo = efi_serial_devinfo;
652 	STAILQ_INSERT_TAIL(&serials, port, next);
653 	consoles[c++] = tty;
654 	consoles[c] = NULL;
655 
656 	/* Reset terminal to initial normal settings with ESC [ 0 m */
657 	efi_serial_putchar(tty, 0x1b);
658 	efi_serial_putchar(tty, '[');
659 	efi_serial_putchar(tty, '0');
660 	efi_serial_putchar(tty, 'm');
661 	/* drain input from random data */
662 	while (efi_serial_getchar(tty) != -1)
663 		;
664 
665 	/* check if we are listed in ConIn */
666 	efi_check_and_set_condev(port, "ConIn");
667 	efi_serial_setup_env(tty);
668 	return (c);
669 }
670 
671 /*
672  * Set up list of possible serial consoles.
673  * This function is run very early, so we do not expect to
674  * run out of memory, and on error, we can not print output.
675  */
676 void
efi_serial_ini(void)677 efi_serial_ini(void)
678 {
679 	EFI_STATUS status;
680 	EFI_HANDLE *handles;
681 	uint_t c, n, index, nhandles;
682 	struct console **tmp;
683 
684 	status = efi_get_protocol_handles(&gEfiSerialIoProtocolGuid, &nhandles,
685 	    &handles);
686 	if (EFI_ERROR(status))
687 		return;
688 
689 	if (nhandles == 0)
690 		return;
691 
692 	n = nhandles;
693 	c = cons_array_size();
694 	if (c == 0)
695 		n++;	/* For NULL pointer */
696 
697 	tmp = realloc(consoles, (c + n) * sizeof (*consoles));
698 	if (tmp == NULL) {
699 		free(handles);
700 		return;
701 	}
702 	consoles = tmp;
703 	if (c > 0)
704 		c--;
705 
706 	for (index = 0; index < nhandles; index++) {
707 		c = efi_serial_create_port(c, handles[index]);
708 	}
709 	free(handles);
710 }
711 
712 static void
efi_serial_probe(struct console * cp)713 efi_serial_probe(struct console *cp)
714 {
715 	cp->c_flags = C_PRESENTIN | C_PRESENTOUT;
716 }
717 
718 static int
efi_serial_init(struct console * cp,int arg __unused)719 efi_serial_init(struct console *cp, int arg __unused)
720 {
721 
722 	if (efi_serial_setup(cp))
723 		return (CMD_OK);
724 
725 	cp->c_flags = 0;
726 	return (CMD_ERROR);
727 }
728 
729 static void
efi_serial_putchar(struct console * cp,int c)730 efi_serial_putchar(struct console *cp, int c)
731 {
732 	int wait;
733 	EFI_STATUS status;
734 	UINTN bufsz = 1;
735 	char cb = c;
736 	struct serial *sp = cp->c_private;
737 
738 	if (sp->io.sio == NULL)
739 		return;
740 
741 	for (wait = COMC_TXWAIT; wait > 0; wait--) {
742 		status = sp->io.sio->Write(sp->io.sio, &bufsz, &cb);
743 		if (status != EFI_TIMEOUT)
744 			break;
745 	}
746 }
747 
748 static int
efi_serial_getchar(struct console * cp)749 efi_serial_getchar(struct console *cp)
750 {
751 	EFI_STATUS status;
752 	UINTN bufsz = 1;
753 	char c;
754 	struct serial *sp = cp->c_private;
755 
756 	/*
757 	 * if this device is also used as ConIn, some firmwares
758 	 * fail to return all input via SIO protocol.
759 	 */
760 	if (sp->is_efi_console) {
761 		return (efi_console.c_in(&efi_console));
762 	}
763 
764 	if (sp->io.sio == NULL || !efi_serial_ischar(cp))
765 		return (-1);
766 
767 	status = sp->io.sio->Read(sp->io.sio, &bufsz, &c);
768 	if (EFI_ERROR(status) || bufsz == 0)
769 		return (-1);
770 
771 	return (c);
772 }
773 
774 static int
efi_serial_ischar(struct console * cp)775 efi_serial_ischar(struct console *cp)
776 {
777 	EFI_STATUS status;
778 	uint32_t control;
779 	struct serial *sp = cp->c_private;
780 
781 	/*
782 	 * if this device is also used as ConIn, some firmwares
783 	 * fail to return all input via SIO protocol.
784 	 */
785 	if (sp->is_efi_console) {
786 		return (efi_console.c_ready(&efi_console));
787 	}
788 
789 	if (sp->io.sio == NULL)
790 		return (0);
791 
792 	status = sp->io.sio->GetControl(sp->io.sio, &control);
793 	if (EFI_ERROR(status))
794 		return (0);
795 
796 	return (!(control & EFI_SERIAL_INPUT_BUFFER_EMPTY));
797 }
798 
799 static int
efi_serial_ioctl(struct console * cp __unused,int cmd __unused,void * data __unused)800 efi_serial_ioctl(struct console *cp __unused, int cmd __unused,
801     void *data __unused)
802 {
803 	return (ENOTTY);
804 }
805 
806 static void
efi_serial_devinfo(struct console * cp)807 efi_serial_devinfo(struct console *cp)
808 {
809 	struct serial *port = cp->c_private;
810 	EFI_DEVICE_PATH *dp;
811 	CHAR16 *text;
812 
813 	if (port->currdev == NULL) {
814 		printf("\tdevice is not present");
815 		return;
816 	}
817 
818 	dp = efi_lookup_devpath(port->currdev);
819 	if (dp == NULL)
820 		return;
821 
822 	text = efi_devpath_name(dp);
823 	if (text == NULL)
824 		return;
825 
826 	printf("\t%S", text);
827 	efi_free_devpath_name(text);
828 	efi_close_devpath(port->currdev);
829 }
830 
831 static char *
efi_serial_asprint_mode(struct serial * sp)832 efi_serial_asprint_mode(struct serial *sp)
833 {
834 	char par, *buf;
835 	char *stop;
836 
837 	if (sp == NULL)
838 		return (NULL);
839 
840 	switch (sp->parity) {
841 	case NoParity:
842 		par = 'n';
843 		break;
844 	case EvenParity:
845 		par = 'e';
846 		break;
847 	case OddParity:
848 		par = 'o';
849 		break;
850 	case MarkParity:
851 		par = 'm';
852 		break;
853 	case SpaceParity:
854 		par = 's';
855 		break;
856 	default:
857 		par = 'n';
858 		break;
859 	}
860 
861 	switch (sp->stopbits) {
862 	case OneStopBit:
863 		stop = "1";
864 		break;
865 	case TwoStopBits:
866 		stop = "2";
867 		break;
868 	case OneFiveStopBits:
869 		stop = "1.5";
870 		break;
871 	default:
872 		stop = "1";
873 		break;
874 	}
875 
876 	(void) asprintf(&buf, "%ju,%d,%c,%s,-", sp->baudrate, sp->databits,
877 	    par, stop);
878 	return (buf);
879 }
880 
881 static int
efi_serial_parse_mode(struct serial * sp,const char * value)882 efi_serial_parse_mode(struct serial *sp, const char *value)
883 {
884 	unsigned long n;
885 	uint64_t baudrate;
886 	uint8_t databits = 8;
887 	int parity = NoParity;
888 	int stopbits = OneStopBit;
889 	char *ep;
890 
891 	if (value == NULL || *value == '\0')
892 		return (CMD_ERROR);
893 
894 	errno = 0;
895 	n = strtoul(value, &ep, 10);
896 	if (errno != 0 || *ep != ',')
897 		return (CMD_ERROR);
898 	baudrate = n;
899 
900 	ep++;
901 	n = strtoul(ep, &ep, 10);
902 	if (errno != 0 || *ep != ',')
903 		return (CMD_ERROR);
904 
905 	switch (n) {
906 	case 5: databits = 5;
907 		break;
908 	case 6: databits = 6;
909 		break;
910 	case 7: databits = 7;
911 		break;
912 	case 8: databits = 8;
913 		break;
914 	default:
915 		return (CMD_ERROR);
916 	}
917 
918 	ep++;
919 	switch (*ep++) {
920 	case 'n': parity = NoParity;
921 		break;
922 	case 'e': parity = EvenParity;
923 		break;
924 	case 'o': parity = OddParity;
925 		break;
926 	case 'm': parity = MarkParity;
927 		break;
928 	case 's': parity = SpaceParity;
929 		break;
930 	default:
931 		return (CMD_ERROR);
932 	}
933 
934 	if (*ep == ',')
935 		ep++;
936 	else
937 		return (CMD_ERROR);
938 
939 	switch (*ep++) {
940 	case '1': stopbits = OneStopBit;
941 		if (ep[0] == '.' && ep[1] == '5') {
942 			ep += 2;
943 			stopbits = OneFiveStopBits;
944 		}
945 		break;
946 	case '2': stopbits = TwoStopBits;
947 		break;
948 	default:
949 		return (CMD_ERROR);
950 	}
951 
952 	/* handshake is ignored, but we check syntax anyhow */
953 	if (*ep == ',')
954 		ep++;
955 	else
956 		return (CMD_ERROR);
957 
958 	switch (*ep++) {
959 	case '-':
960 	case 'h':
961 	case 's':
962 		break;
963 	default:
964 		return (CMD_ERROR);
965 	}
966 
967 	if (*ep != '\0')
968 		return (CMD_ERROR);
969 
970 	sp->baudrate = baudrate;
971 	sp->databits = databits;
972 	sp->parity = parity;
973 	sp->stopbits = stopbits;
974 	return (CMD_OK);
975 }
976 
977 static int
efi_serial_mode_set(struct env_var * ev,int flags,const void * value)978 efi_serial_mode_set(struct env_var *ev, int flags, const void *value)
979 {
980 	struct console *cp;
981 
982 	if (value == NULL)
983 		return (CMD_ERROR);
984 
985 	if ((cp = cons_get_console(ev->ev_name)) == NULL)
986 		return (CMD_ERROR);
987 
988 	if (efi_serial_parse_mode(cp->c_private, value) == CMD_ERROR)
989 		return (CMD_ERROR);
990 
991 	(void) efi_serial_setup(cp);
992 
993 	(void) env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
994 
995 	return (CMD_OK);
996 }
997 
998 static int
efi_serial_cd_set(struct env_var * ev,int flags,const void * value)999 efi_serial_cd_set(struct env_var *ev, int flags, const void *value)
1000 {
1001 	struct console *cp;
1002 	struct serial *sp;
1003 
1004 	if (value == NULL)
1005 		return (CMD_OK);
1006 
1007 	if ((cp = cons_get_console(ev->ev_name)) == NULL)
1008 		return (CMD_OK);
1009 
1010 	sp = cp->c_private;
1011 	if (strcmp(value, "true") == 0)
1012 		sp->ignore_cd = true;
1013 	else if (strcmp(value, "false") == 0)
1014 		sp->ignore_cd = false;
1015 	else
1016 		return (CMD_OK);
1017 
1018 	(void) efi_serial_setup(cp);
1019 
1020 	(void) env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
1021 
1022 	return (CMD_OK);
1023 }
1024 
1025 static int
efi_serial_rtsdtr_set(struct env_var * ev,int flags,const void * value)1026 efi_serial_rtsdtr_set(struct env_var *ev, int flags, const void *value)
1027 {
1028 	struct console *cp;
1029 	struct serial *sp;
1030 
1031 	if (value == NULL)
1032 		return (CMD_OK);
1033 
1034 	if ((cp = cons_get_console(ev->ev_name)) == NULL)
1035 		return (CMD_OK);
1036 
1037 	sp = cp->c_private;
1038 	if (strcmp(value, "true") == 0)
1039 		sp->rtsdtr_off = true;
1040 	else if (strcmp(value, "false") == 0)
1041 		sp->rtsdtr_off = false;
1042 	else
1043 		return (CMD_OK);
1044 
1045 	(void) efi_serial_setup(cp);
1046 
1047 	(void) env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
1048 
1049 	return (CMD_OK);
1050 }
1051 
1052 /*
1053  * In case of error, we also reset ACTIVE flags, so the console
1054  * framefork will try alternate consoles.
1055  */
1056 static bool
efi_serial_setup(struct console * cp)1057 efi_serial_setup(struct console *cp)
1058 {
1059 	EFI_STATUS status;
1060 	UINT32 control, new_control;
1061 	struct serial *sp = cp->c_private;
1062 	uint64_t baudrate;
1063 	uint32_t timeout, receivefifodepth, databits;
1064 	EFI_PARITY_TYPE parity;
1065 	EFI_STOP_BITS_TYPE stopbits;
1066 	bool change = false;
1067 
1068 	/* port is not usable */
1069 	if (sp->io.sio == NULL)
1070 		return (false);
1071 
1072 	if (sp->io.sio->Reset != NULL) {
1073 		status = sp->io.sio->Reset(sp->io.sio);
1074 		if (EFI_ERROR(status))
1075 			return (false);
1076 	}
1077 
1078 	if (sp->baudrate == sp->io.sio->Mode->BaudRate) {
1079 		baudrate = 0;
1080 	} else {
1081 		baudrate = sp->baudrate;
1082 		change = true;
1083 	}
1084 	if (sp->receivefifodepth == sp->io.sio->Mode->ReceiveFifoDepth) {
1085 		receivefifodepth = 0;
1086 	} else {
1087 		receivefifodepth = sp->receivefifodepth;
1088 		change = true;
1089 	}
1090 	if (sp->timeout == sp->io.sio->Mode->Timeout) {
1091 		timeout = 0;
1092 	} else {
1093 		timeout = sp->timeout;
1094 		change = true;
1095 	}
1096 	if (sp->parity == sp->io.sio->Mode->Parity) {
1097 		parity = DefaultParity;
1098 	} else {
1099 		parity = sp->parity;
1100 		change = true;
1101 	}
1102 	if (sp->databits == sp->io.sio->Mode->DataBits) {
1103 		databits = 0;
1104 	} else {
1105 		databits = sp->databits;
1106 		change = true;
1107 	}
1108 	if (sp->stopbits == sp->io.sio->Mode->StopBits) {
1109 		stopbits = DefaultStopBits;
1110 	} else {
1111 		stopbits = sp->stopbits;
1112 		change = true;
1113 	}
1114 
1115 	if (change && sp->io.sio->SetAttributes != NULL) {
1116 		status = sp->io.sio->SetAttributes(sp->io.sio, baudrate,
1117 		    receivefifodepth, timeout, parity, databits, stopbits);
1118 		if (EFI_ERROR(status))
1119 			return (false);
1120 	}
1121 
1122 	/*
1123 	 * Perform SetControl() only in case there was change in settings.
1124 	 */
1125 	control = new_control = 0;
1126 	status = sp->io.sio->GetControl(sp->io.sio, &control);
1127 	if (!EFI_ERROR(status)) {
1128 		new_control = control;
1129 		if (sp->rtsdtr_off) {
1130 			new_control &= ~(EFI_SERIAL_REQUEST_TO_SEND |
1131 			    EFI_SERIAL_DATA_TERMINAL_READY);
1132 		} else {
1133 			new_control |= EFI_SERIAL_REQUEST_TO_SEND;
1134 		}
1135 	}
1136 
1137 	if (control != new_control)
1138 		(void) sp->io.sio->SetControl(sp->io.sio, new_control);
1139 
1140 	/* Mark this port usable. */
1141 	cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
1142 	return (true);
1143 }
1144