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 <stand.h>
27 #include <sys/errno.h>
28 #include <bootstrap.h>
29 #include <stdbool.h>
30
31 #include <efi.h>
32 #include <efilib.h>
33 #include <Protocol/SerialIo.h>
34
35 static EFI_GUID serial = EFI_SERIAL_IO_PROTOCOL_GUID;
36
37 #define COMC_TXWAIT 0x40000 /* transmit timeout */
38
39 #define PNP0501 0x501 /* 16550A-compatible COM port */
40
41 struct serial {
42 uint64_t newbaudrate;
43 uint64_t baudrate;
44 uint32_t timeout;
45 uint32_t receivefifodepth;
46 uint32_t databits;
47 EFI_PARITY_TYPE parity;
48 EFI_STOP_BITS_TYPE stopbits;
49 int ioaddr; /* index in handles array */
50 EFI_HANDLE currdev; /* current serial device */
51 EFI_HANDLE condev; /* EFI Console device */
52 SERIAL_IO_INTERFACE *sio;
53 };
54
55 static void comc_probe(struct console *);
56 static int comc_init(int);
57 static void comc_putchar(int);
58 static int comc_getchar(void);
59 static int comc_ischar(void);
60 static bool comc_setup(void);
61 static int comc_parse_intval(const char *, unsigned *);
62 static int comc_port_set(struct env_var *, int, const void *);
63 static int comc_speed_set(struct env_var *, int, const void *);
64
65 static struct serial *comc_port;
66 extern struct console efi_console;
67
68 struct console eficom = {
69 .c_name = "eficom",
70 .c_desc = "serial port",
71 .c_flags = 0,
72 .c_probe = comc_probe,
73 .c_init = comc_init,
74 .c_out = comc_putchar,
75 .c_in = comc_getchar,
76 .c_ready = comc_ischar,
77 };
78
79 #if defined(__aarch64__) && __FreeBSD_version < 1500000
80 static void comc_probe_compat(struct console *);
81 struct console comconsole = {
82 .c_name = "comconsole",
83 .c_desc = "serial port",
84 .c_flags = 0,
85 .c_probe = comc_probe_compat,
86 .c_init = comc_init,
87 .c_out = comc_putchar,
88 .c_in = comc_getchar,
89 .c_ready = comc_ischar,
90 };
91 #endif
92
93 static EFI_STATUS
efi_serial_init(EFI_HANDLE ** handlep,int * nhandles)94 efi_serial_init(EFI_HANDLE **handlep, int *nhandles)
95 {
96 UINTN bufsz = 0;
97 EFI_STATUS status;
98 EFI_HANDLE *handles;
99
100 /*
101 * get buffer size
102 */
103 *nhandles = 0;
104 handles = NULL;
105 status = BS->LocateHandle(ByProtocol, &serial, NULL, &bufsz, handles);
106 if (status != EFI_BUFFER_TOO_SMALL)
107 return (status);
108
109 if ((handles = malloc(bufsz)) == NULL)
110 return (ENOMEM);
111
112 *nhandles = (int)(bufsz / sizeof (EFI_HANDLE));
113 /*
114 * get handle array
115 */
116 status = BS->LocateHandle(ByProtocol, &serial, NULL, &bufsz, handles);
117 if (EFI_ERROR(status)) {
118 free(handles);
119 *nhandles = 0;
120 } else
121 *handlep = handles;
122 return (status);
123 }
124
125 /*
126 * Find serial device number from device path.
127 * Return -1 if not found.
128 */
129 static int
efi_serial_get_index(EFI_DEVICE_PATH * devpath,int idx)130 efi_serial_get_index(EFI_DEVICE_PATH *devpath, int idx)
131 {
132 ACPI_HID_DEVICE_PATH *acpi;
133 CHAR16 *text;
134
135 while (!IsDevicePathEnd(devpath)) {
136 if (DevicePathType(devpath) == MESSAGING_DEVICE_PATH &&
137 DevicePathSubType(devpath) == MSG_UART_DP)
138 return (idx);
139
140 if (DevicePathType(devpath) == ACPI_DEVICE_PATH &&
141 (DevicePathSubType(devpath) == ACPI_DP ||
142 DevicePathSubType(devpath) == ACPI_EXTENDED_DP)) {
143
144 acpi = (ACPI_HID_DEVICE_PATH *)devpath;
145 if (acpi->HID == EISA_PNP_ID(PNP0501)) {
146 return (acpi->UID);
147 }
148 }
149
150 devpath = NextDevicePathNode(devpath);
151 }
152 return (-1);
153 }
154
155 /*
156 * The order of handles from LocateHandle() is not known, we need to
157 * iterate handles, pick device path for handle, and check the device
158 * number.
159 */
160 static EFI_HANDLE
efi_serial_get_handle(int port,EFI_HANDLE condev)161 efi_serial_get_handle(int port, EFI_HANDLE condev)
162 {
163 EFI_STATUS status;
164 EFI_HANDLE *handles, handle;
165 EFI_DEVICE_PATH *devpath;
166 int index, nhandles;
167
168 if (port == -1)
169 return (NULL);
170
171 handles = NULL;
172 nhandles = 0;
173 status = efi_serial_init(&handles, &nhandles);
174 if (EFI_ERROR(status))
175 return (NULL);
176
177 /*
178 * We have console handle, set ioaddr for it.
179 */
180 if (condev != NULL) {
181 for (index = 0; index < nhandles; index++) {
182 if (condev == handles[index]) {
183 devpath = efi_lookup_devpath(condev);
184 comc_port->ioaddr =
185 efi_serial_get_index(devpath, index);
186 efi_close_devpath(condev);
187 free(handles);
188 return (condev);
189 }
190 }
191 }
192
193 handle = NULL;
194 for (index = 0; handle == NULL && index < nhandles; index++) {
195 devpath = efi_lookup_devpath(handles[index]);
196 if (port == efi_serial_get_index(devpath, index))
197 handle = (handles[index]);
198 efi_close_devpath(handles[index]);
199 }
200
201 /*
202 * In case we did fail to identify the device by path, use port as
203 * array index. Note, we did check port == -1 above.
204 */
205 if (port < nhandles && handle == NULL)
206 handle = handles[port];
207
208 free(handles);
209 return (handle);
210 }
211
212 static EFI_HANDLE
comc_get_con_serial_handle(const char * name)213 comc_get_con_serial_handle(const char *name)
214 {
215 EFI_HANDLE handle;
216 EFI_DEVICE_PATH *node;
217 EFI_STATUS status;
218 char *buf, *ep;
219 size_t sz;
220
221 buf = NULL;
222 sz = 0;
223 status = efi_global_getenv(name, buf, &sz);
224 if (status == EFI_BUFFER_TOO_SMALL) {
225 buf = malloc(sz);
226 if (buf == NULL)
227 return (NULL);
228 status = efi_global_getenv(name, buf, &sz);
229 }
230 if (status != EFI_SUCCESS) {
231 free(buf);
232 return (NULL);
233 }
234
235 ep = buf + sz;
236 node = (EFI_DEVICE_PATH *)buf;
237 while ((char *)node < ep) {
238 status = BS->LocateDevicePath(&serial, &node, &handle);
239 if (status == EFI_SUCCESS) {
240 free(buf);
241 return (handle);
242 }
243
244 /* Sanity check the node before moving to the next node. */
245 if (DevicePathNodeLength(node) < sizeof(*node))
246 break;
247
248 /* Start of next device path in list. */
249 node = NextDevicePathNode(node);
250 }
251 free(buf);
252 return (NULL);
253 }
254
255 /*
256 * Called from cons_probe() to see if this device is available.
257 * Return immediately on x86, except for hyperv, since it interferes with
258 * common configurations otherwise (yes, this is just firewalling the bug).
259 */
260 static void
comc_probe(struct console * sc)261 comc_probe(struct console *sc)
262 {
263 EFI_STATUS status;
264 EFI_HANDLE handle;
265 char name[20];
266 char value[20];
267 unsigned val;
268 char *env, *buf, *ep;
269 size_t sz;
270
271 #ifdef __amd64__
272 /*
273 * This driver tickles issues on a number of different firmware loads.
274 * It is only required for HyperV, and is only known to work on HyperV,
275 * so only allow it on HyperV.
276 */
277 env = getenv("smbios.bios.version");
278 if (env == NULL || strncmp(env, "Hyper-V", 7) != 0) {
279 return;
280 }
281 #endif
282
283 if (comc_port == NULL) {
284 comc_port = calloc(1, sizeof (struct serial));
285 if (comc_port == NULL)
286 return;
287 }
288
289 /* Use defaults from firmware */
290 comc_port->databits = 8;
291 comc_port->parity = DefaultParity;
292 comc_port->stopbits = DefaultStopBits;
293
294 handle = NULL;
295 env = getenv("efi_com_port");
296 if (comc_parse_intval(env, &val) == CMD_OK) {
297 comc_port->ioaddr = val;
298 } else {
299 /*
300 * efi_com_port is not set, we need to select default.
301 * First, we consult ConOut variable to see if
302 * we have serial port redirection. If not, we just
303 * pick first device.
304 */
305 handle = comc_get_con_serial_handle("ConOut");
306 comc_port->condev = handle;
307 }
308
309 handle = efi_serial_get_handle(comc_port->ioaddr, handle);
310 if (handle != NULL) {
311 comc_port->currdev = handle;
312 status = BS->OpenProtocol(handle, &serial,
313 (void**)&comc_port->sio, IH, NULL,
314 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
315
316 if (EFI_ERROR(status)) {
317 comc_port->sio = NULL;
318 } else {
319 comc_port->newbaudrate =
320 comc_port->baudrate = comc_port->sio->Mode->BaudRate;
321 comc_port->timeout = comc_port->sio->Mode->Timeout;
322 comc_port->receivefifodepth =
323 comc_port->sio->Mode->ReceiveFifoDepth;
324 comc_port->databits = comc_port->sio->Mode->DataBits;
325 comc_port->parity = comc_port->sio->Mode->Parity;
326 comc_port->stopbits = comc_port->sio->Mode->StopBits;
327 }
328 }
329
330 /*
331 * If there's no sio, then the device isn't there, so just return since
332 * the present flags aren't yet set.
333 */
334 if (comc_port->sio == NULL) {
335 free(comc_port);
336 comc_port = NULL;
337 return;
338 }
339
340 if (env != NULL)
341 unsetenv("efi_com_port");
342 snprintf(value, sizeof (value), "%u", comc_port->ioaddr);
343 env_setenv("efi_com_port", EV_VOLATILE, value,
344 comc_port_set, env_nounset);
345
346 env = getenv("efi_com_speed");
347 if (env == NULL)
348 /* fallback to comconsole setting */
349 env = getenv("comconsole_speed");
350
351 if (comc_parse_intval(env, &val) == CMD_OK)
352 comc_port->newbaudrate = val;
353
354 if (env != NULL)
355 unsetenv("efi_com_speed");
356 snprintf(value, sizeof (value), "%ju", (uintmax_t)comc_port->baudrate);
357 env_setenv("efi_com_speed", EV_VOLATILE, value,
358 comc_speed_set, env_nounset);
359
360 if (comc_setup()) {
361 sc->c_flags = C_PRESENTIN | C_PRESENTOUT;
362 } else {
363 sc->c_flags &= ~(C_PRESENTIN | C_PRESENTOUT);
364 free(comc_port);
365 comc_port = NULL;
366 }
367 }
368
369 #if defined(__aarch64__) && __FreeBSD_version < 1500000
370 static void
comc_probe_compat(struct console * sc)371 comc_probe_compat(struct console *sc)
372 {
373 comc_probe(&eficom);
374 if (eficom.c_flags & (C_PRESENTIN | C_PRESENTOUT)) {
375 printf("comconsole: comconsole device name is deprecated, switch to eficom\n");
376 }
377 /*
378 * Note: We leave the present bits unset in sc to avoid ghosting.
379 */
380 }
381 #endif
382
383 /*
384 * Called when the console is selected in cons_change. If we didn't detect the
385 * device, comc_port will be NULL, and comc_setup will fail. It may be called
386 * even when the device isn't present as a 'fallback' console or when listed
387 * specifically in console env, so we have to reset the c_flags in those case to
388 * say it's not present.
389 */
390 static int
comc_init(int arg __unused)391 comc_init(int arg __unused)
392 {
393 if (comc_setup())
394 return (0);
395
396 eficom.c_flags &= ~(C_ACTIVEIN | C_ACTIVEOUT);
397 return (1);
398 }
399
400 static void
comc_putchar(int c)401 comc_putchar(int c)
402 {
403 int wait;
404 EFI_STATUS status;
405 UINTN bufsz = 1;
406 char cb = c;
407
408 if (comc_port->sio == NULL)
409 return;
410
411 for (wait = COMC_TXWAIT; wait > 0; wait--) {
412 status = comc_port->sio->Write(comc_port->sio, &bufsz, &cb);
413 if (status != EFI_TIMEOUT)
414 break;
415 }
416 }
417
418 static int
comc_getchar(void)419 comc_getchar(void)
420 {
421 EFI_STATUS status;
422 UINTN bufsz = 1;
423 char c;
424
425
426 /*
427 * if this device is also used as ConIn, some firmwares
428 * fail to return all input via SIO protocol.
429 */
430 if (comc_port->currdev == comc_port->condev) {
431 if ((efi_console.c_flags & C_ACTIVEIN) == 0)
432 return (efi_console.c_in());
433 return (-1);
434 }
435
436 if (comc_port->sio == NULL)
437 return (-1);
438
439 status = comc_port->sio->Read(comc_port->sio, &bufsz, &c);
440 if (EFI_ERROR(status) || bufsz == 0)
441 return (-1);
442
443 return (c);
444 }
445
446 static int
comc_ischar(void)447 comc_ischar(void)
448 {
449 EFI_STATUS status;
450 uint32_t control;
451
452 /*
453 * if this device is also used as ConIn, some firmwares
454 * fail to return all input via SIO protocol.
455 */
456 if (comc_port->currdev == comc_port->condev) {
457 if ((efi_console.c_flags & C_ACTIVEIN) == 0)
458 return (efi_console.c_ready());
459 return (0);
460 }
461
462 if (comc_port->sio == NULL)
463 return (0);
464
465 status = comc_port->sio->GetControl(comc_port->sio, &control);
466 if (EFI_ERROR(status))
467 return (0);
468
469 return (!(control & EFI_SERIAL_INPUT_BUFFER_EMPTY));
470 }
471
472 static int
comc_parse_intval(const char * value,unsigned * valp)473 comc_parse_intval(const char *value, unsigned *valp)
474 {
475 unsigned n;
476 char *ep;
477
478 if (value == NULL || *value == '\0')
479 return (CMD_ERROR);
480
481 errno = 0;
482 n = strtoul(value, &ep, 10);
483 if (errno != 0 || *ep != '\0')
484 return (CMD_ERROR);
485 *valp = n;
486
487 return (CMD_OK);
488 }
489
490 static int
comc_port_set(struct env_var * ev,int flags,const void * value)491 comc_port_set(struct env_var *ev, int flags, const void *value)
492 {
493 unsigned port;
494 SERIAL_IO_INTERFACE *sio;
495 EFI_HANDLE handle;
496 EFI_STATUS status;
497
498 if (value == NULL || comc_port == NULL)
499 return (CMD_ERROR);
500
501 if (comc_parse_intval(value, &port) != CMD_OK)
502 return (CMD_ERROR);
503
504 handle = efi_serial_get_handle(port, NULL);
505 if (handle == NULL) {
506 printf("no handle\n");
507 return (CMD_ERROR);
508 }
509
510 status = BS->OpenProtocol(handle, &serial,
511 (void**)&sio, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
512
513 if (EFI_ERROR(status)) {
514 printf("OpenProtocol: %lu\n", DECODE_ERROR(status));
515 return (CMD_ERROR);
516 }
517
518 comc_port->currdev = handle;
519 comc_port->ioaddr = port;
520 comc_port->sio = sio;
521
522 (void) comc_setup();
523
524 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
525 return (CMD_OK);
526 }
527
528 static int
comc_speed_set(struct env_var * ev,int flags,const void * value)529 comc_speed_set(struct env_var *ev, int flags, const void *value)
530 {
531 unsigned speed;
532
533 if (value == NULL || comc_port == NULL)
534 return (CMD_ERROR);
535
536 if (comc_parse_intval(value, &speed) != CMD_OK)
537 return (CMD_ERROR);
538
539 comc_port->newbaudrate = speed;
540 if (comc_setup())
541 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
542
543 return (CMD_OK);
544 }
545
546 /*
547 * In case of error, we also reset ACTIVE flags, so the console
548 * framefork will try alternate consoles.
549 */
550 static bool
comc_setup(void)551 comc_setup(void)
552 {
553 EFI_STATUS status;
554 char *ev;
555
556 /*
557 * If the device isn't active, or there's no port present.
558 */
559 if ((eficom.c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) == 0 || comc_port == NULL)
560 return (false);
561
562 if (comc_port->sio->Reset != NULL) {
563 status = comc_port->sio->Reset(comc_port->sio);
564 if (EFI_ERROR(status))
565 return (false);
566 }
567
568 /*
569 * Avoid setting the baud rate on Hyper-V. Also, only set the baud rate
570 * if the baud rate has changed from the default. And pass in '0' or
571 * DefaultFoo when we're not changing those values. Some EFI
572 * implementations get cranky when you set things to the values reported
573 * back even when they are unchanged.
574 */
575 if (comc_port->sio->SetAttributes != NULL &&
576 comc_port->newbaudrate != comc_port->baudrate) {
577 ev = getenv("smbios.bios.version");
578 if (ev != NULL && strncmp(ev, "Hyper-V", 7) != 0) {
579 status = comc_port->sio->SetAttributes(comc_port->sio,
580 comc_port->newbaudrate, 0, 0, DefaultParity, 0,
581 DefaultStopBits);
582 if (EFI_ERROR(status))
583 return (false);
584 comc_port->baudrate = comc_port->newbaudrate;
585 }
586 }
587
588 #ifdef EFI_FORCE_RTS
589 if (comc_port->sio->GetControl != NULL && comc_port->sio->SetControl != NULL) {
590 UINT32 control;
591
592 status = comc_port->sio->GetControl(comc_port->sio, &control);
593 if (EFI_ERROR(status))
594 return (false);
595 control |= EFI_SERIAL_REQUEST_TO_SEND;
596 (void) comc_port->sio->SetControl(comc_port->sio, control);
597 }
598 #endif
599 /* Mark this port usable. */
600 eficom.c_flags |= (C_PRESENTIN | C_PRESENTOUT);
601 return (true);
602 }
603