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 <sys/param.h>
31 #include <bootstrap.h>
32 #include <stdbool.h>
33
34 #include <efi.h>
35 #include <efilib.h>
36 #include <efidevp.h>
37 #include <Protocol/IsaIo.h>
38 #include <dev/ic/ns16550.h>
39 #include <uuid.h>
40
41 #ifdef MDE_CPU_X64
42 #include <machine/cpufunc.h>
43 #endif
44
45 EFI_GUID gEfiIsaIoProtocolGuid = EFI_ISA_IO_PROTOCOL_GUID;
46
47 #define COMC_TXWAIT 0x40000 /* transmit timeout */
48 #define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */
49 #define COMC_DIV2BPS(x) (115200 / (x)) /* DLAB divisor to speed */
50
51 #ifndef COMSPEED
52 #define COMSPEED 9600
53 #endif
54
55 #define COM1_IOADDR 0x3f8
56 #define COM2_IOADDR 0x2f8
57 #define COM3_IOADDR 0x3e8
58 #define COM4_IOADDR 0x2e8
59
60 #ifdef MDE_CPU_X64
61 static uint_t io_ports[] = {
62 COM1_IOADDR, COM2_IOADDR, COM3_IOADDR, COM4_IOADDR
63 };
64 #endif
65
66 #define STOP1 0x00
67 #define STOP2 0x04
68
69 #define PARODD 0x00
70 #define PAREN 0x08
71 #define PAREVN 0x10
72 #define PARMARK 0x20
73
74 #define BITS5 0x00 /* 5 bits per char */
75 #define BITS6 0x01 /* 6 bits per char */
76 #define BITS7 0x02 /* 7 bits per char */
77 #define BITS8 0x03 /* 8 bits per char */
78
79 #define PNP0501 0x501 /* 16550A-compatible COM port */
80
81 static void efi_isa_probe(struct console *);
82 static int efi_isa_init(struct console *, int);
83 static void efi_isa_putchar(struct console *, int);
84 static int efi_isa_getchar(struct console *);
85 static int efi_isa_ischar(struct console *);
86 static int efi_isa_ioctl(struct console *, int, void *);
87 static void efi_isa_devinfo(struct console *);
88 static bool efi_isa_setup(struct console *);
89 static char *efi_isa_asprint_mode(struct serial *);
90 static int efi_isa_parse_mode(struct serial *, const char *);
91 static int efi_isa_mode_set(struct env_var *, int, const void *);
92 static int efi_isa_cd_set(struct env_var *, int, const void *);
93 static int efi_isa_rtsdtr_set(struct env_var *, int, const void *);
94
95 extern struct console efi_console;
96
97 static bool
efi_isa_port_is_present(struct serial * sp)98 efi_isa_port_is_present(struct serial *sp)
99 {
100 EFI_STATUS status;
101 #define COMC_TEST 0xbb
102 uint8_t test = COMC_TEST;
103
104 /*
105 * Write byte to scratch register and read it out.
106 */
107 status = sp->io.isa->Io.Write(sp->io.isa,
108 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
109 sp->ioaddr + com_scr, 1, &test);
110 test = 0;
111 if (status == EFI_SUCCESS) {
112 status = sp->io.isa->Io.Read(sp->io.isa,
113 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_scr,
114 1, &test);
115 }
116 return (test == COMC_TEST);
117 #undef COMC_TEST
118 }
119
120 static bool
efi_isa_should_append(const char * name,struct serial * port)121 efi_isa_should_append(const char *name, struct serial *port)
122 {
123 EFI_DEVICE_PATH *node, *dev;
124 EFI_STATUS status;
125 char *buf;
126 size_t sz;
127 bool rv = true;
128
129 if (port->currdev == NULL)
130 return (rv);
131
132 buf = NULL;
133 sz = 0;
134 status = efi_global_getenv(name, buf, &sz);
135 if (status == EFI_BUFFER_TOO_SMALL) {
136 buf = malloc(sz);
137 if (buf == NULL)
138 return (rv);
139 status = efi_global_getenv(name, buf, &sz);
140 }
141 if (EFI_ERROR(status)) {
142 free(buf);
143 return (rv);
144 }
145
146 dev = efi_lookup_devpath(port->currdev);
147 if (dev == NULL) {
148 free(buf);
149 return (rv);
150 }
151
152 node = (EFI_DEVICE_PATH *)buf;
153 /*
154 * We only need to know if this port is first in list.
155 * This is only important when "os_console" is not set.
156 */
157 if (!IsDevicePathEnd(node) && efi_devpath_is_prefix(dev, node))
158 rv = false;
159
160 efi_close_devpath(dev);
161 free(buf);
162 return (rv);
163 }
164
165 static void
efi_isa_setup_env(struct console * tty)166 efi_isa_setup_env(struct console *tty)
167 {
168 struct serial *port = tty->c_private;
169 char name[20];
170 char value[20];
171 char *env;
172
173 (void) snprintf(name, sizeof (name), "%s-mode", tty->c_name);
174 env = getenv(name);
175 if (env != NULL)
176 (void) efi_isa_parse_mode(port, env);
177 env = efi_isa_asprint_mode(port);
178 if (env != NULL) {
179 (void) unsetenv(name);
180 (void) env_setenv(name, EV_VOLATILE, env, efi_isa_mode_set,
181 env_nounset);
182 if (port->is_efi_console) {
183 (void) snprintf(name, sizeof (name), "%s-spcr-mode",
184 tty->c_name);
185 (void) setenv(name, env, 1);
186 free(env);
187
188 /* Add us to console list. */
189 (void) snprintf(name, sizeof (name), "console");
190 env = getenv(name);
191 if (env == NULL) {
192 (void) setenv(name, tty->c_name, 1);
193 } else {
194 char *ptr;
195 int rv;
196
197 /*
198 * we have "text" already in place,
199 * consult ConOut if we need to add
200 * serial console before or after.
201 */
202 if (efi_isa_should_append("ConOut", port))
203 rv = asprintf(&ptr, "%s,%s", env,
204 tty->c_name);
205 else
206 rv = asprintf(&ptr, "%s,%s",
207 tty->c_name, env);
208 if (rv > 0) {
209 (void) setenv(name, ptr, 1);
210 free(ptr);
211 } else {
212 printf("%s: %s\n", __func__,
213 strerror(ENOMEM));
214 }
215 }
216 } else {
217 free(env);
218 }
219 }
220
221 (void) snprintf(name, sizeof (name), "%s-ignore-cd", tty->c_name);
222 env = getenv(name);
223 if (env != NULL) {
224 if (strcmp(env, "true") == 0)
225 port->ignore_cd = 1;
226 else if (strcmp(env, "false") == 0)
227 port->ignore_cd = 0;
228 }
229
230 (void) snprintf(value, sizeof (value), "%s",
231 port->ignore_cd? "true" : "false");
232 (void) unsetenv(name);
233 (void) env_setenv(name, EV_VOLATILE, value, efi_isa_cd_set,
234 env_nounset);
235
236 (void) snprintf(name, sizeof (name), "%s-rts-dtr-off", tty->c_name);
237 env = getenv(name);
238 if (env != NULL) {
239 if (strcmp(env, "true") == 0)
240 port->rtsdtr_off = 1;
241 else if (strcmp(env, "false") == 0)
242 port->rtsdtr_off = 0;
243 }
244
245 (void) snprintf(value, sizeof (value), "%s",
246 port->rtsdtr_off? "true" : "false");
247 (void) unsetenv(name);
248 (void) env_setenv(name, EV_VOLATILE, value, efi_isa_rtsdtr_set,
249 env_nounset);
250 }
251
252 static void
efi_check_and_set_condev(struct serial * port,const char * name)253 efi_check_and_set_condev(struct serial *port, const char *name)
254 {
255 EFI_DEVICE_PATH *node, *dev;
256 EFI_STATUS status;
257 char *buf;
258 size_t sz;
259
260 if (port->currdev == NULL)
261 return;
262
263 buf = NULL;
264 sz = 0;
265 status = efi_global_getenv(name, buf, &sz);
266 if (status == EFI_BUFFER_TOO_SMALL) {
267 buf = malloc(sz);
268 if (buf == NULL)
269 return;
270 status = efi_global_getenv(name, buf, &sz);
271 }
272 if (EFI_ERROR(status)) {
273 free(buf);
274 return;
275 }
276
277 dev = efi_lookup_devpath(port->currdev);
278 if (dev == NULL) {
279 free(buf);
280 return;
281 }
282
283 node = (EFI_DEVICE_PATH *)buf;
284 while (!IsDevicePathEnd(node)) {
285 /* Sanity check the node before moving to the next node. */
286 if (DevicePathNodeLength(node) < sizeof (*node))
287 break;
288
289 if (efi_devpath_is_prefix(dev, node)) {
290 port->is_efi_console = true;
291 break;
292 }
293
294 node = efi_devpath_next_instance(node);
295 }
296
297 efi_close_devpath(dev);
298 free(buf);
299 }
300
301 /*
302 * Return number of ports created (0 or 1).
303 */
304 static uint_t
efi_isa_create_port(EFI_HANDLE handle)305 efi_isa_create_port(EFI_HANDLE handle)
306 {
307 struct serial *port;
308 EFI_ISA_IO_PROTOCOL *io;
309 EFI_STATUS status;
310
311 status = BS->OpenProtocol(handle, &gEfiIsaIoProtocolGuid,
312 (void**)&io, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
313 if (EFI_ERROR(status)) {
314 return (0);
315 }
316
317 /* Is this serial port? */
318 if (io->ResourceList->Device.HID != EISA_PNP_ID(PNP0501))
319 return (0);
320
321 /* We assume I/O port */
322 if (io->ResourceList->ResourceItem->Type != EfiIsaAcpiResourceIo)
323 return (0);
324
325 port = calloc(1, sizeof (*port));
326 if (port == NULL) {
327 return (0);
328 }
329
330 /* Set up port descriptor */
331 port->ignore_cd = true;
332 port->currdev = handle;
333 port->ioaddr = 0;
334 for (uint_t i = 0; io->ResourceList->ResourceItem[i].Type !=
335 EfiIsaAcpiResourceEndOfList; i++) {
336 if (io->ResourceList->ResourceItem[i].Type ==
337 EfiIsaAcpiResourceIo) {
338 port->ioaddr =
339 io->ResourceList->ResourceItem[i].StartRange;
340 break;
341 }
342 }
343 port->guid = &gEfiIsaIoProtocolGuid;
344 port->io.isa = io;
345 /* Use 8,n,1 for defaults */
346 port->databits = 8;
347 port->parity = NoParity;
348 port->stopbits = OneStopBit;
349
350 STAILQ_INSERT_TAIL(&serials, port, next);
351 return (1);
352 }
353
354 #ifdef MDE_CPU_X64
355 static EFI_STATUS
efi_isa_create_io(EFI_ISA_IO_PROTOCOL ** iop)356 efi_isa_create_io(EFI_ISA_IO_PROTOCOL **iop)
357 {
358 EFI_ISA_IO_PROTOCOL *io;
359
360 io = calloc(1, sizeof (*io));
361 if (io == NULL) {
362 return (EFI_OUT_OF_RESOURCES);
363 }
364 io->ResourceList = malloc(sizeof (*io->ResourceList));
365 if (io->ResourceList == NULL) {
366 free(io);
367 return (EFI_OUT_OF_RESOURCES);
368 }
369 io->ResourceList->ResourceItem =
370 calloc(2, sizeof (*io->ResourceList->ResourceItem));
371 if (io->ResourceList == NULL) {
372 free(io->ResourceList);
373 free(io);
374 return (EFI_OUT_OF_RESOURCES);
375 }
376
377 *iop = io;
378 return (EFI_SUCCESS);
379 }
380
381 static EFI_STATUS EFIAPI
_Read(EFI_ISA_IO_PROTOCOL * this __unused,EFI_ISA_IO_PROTOCOL_WIDTH Width __unused,UINT32 Offset,UINTN Count,VOID * Buffer)382 _Read(EFI_ISA_IO_PROTOCOL *this __unused,
383 EFI_ISA_IO_PROTOCOL_WIDTH Width __unused,
384 UINT32 Offset, UINTN Count, VOID *Buffer)
385 {
386 uint8_t *buf = (uint8_t *)Buffer;
387
388 while ((Count--) != 0) {
389 *buf++ = inb(Offset);
390 }
391
392 return (EFI_SUCCESS);
393 }
394
395 static EFI_STATUS EFIAPI
_Write(EFI_ISA_IO_PROTOCOL * this __unused,EFI_ISA_IO_PROTOCOL_WIDTH Width __unused,UINT32 Offset,UINTN Count,VOID * Buffer)396 _Write(EFI_ISA_IO_PROTOCOL *this __unused,
397 EFI_ISA_IO_PROTOCOL_WIDTH Width __unused,
398 UINT32 Offset, UINTN Count, VOID *Buffer)
399 {
400 uint8_t *buf = (uint8_t *)Buffer;
401
402 while ((Count--) != 0) {
403 outb(Offset, *buf++);
404 }
405 return (EFI_SUCCESS);
406 }
407
408 static EFI_STATUS
efi_isa_create_io_ports(void)409 efi_isa_create_io_ports(void)
410 {
411 struct serial *port;
412 EFI_ISA_IO_PROTOCOL *io;
413 EFI_STATUS status = EFI_SUCCESS;
414
415 port = NULL;
416 for (uint_t i = 0; i < nitems(io_ports); i++) {
417 if (port == NULL) {
418 status = efi_isa_create_io(&io);
419 if (EFI_ERROR(status))
420 return (status);
421 io->Io.Read = _Read;
422 io->Io.Write = _Write;
423 io->ResourceList->Device.HID = EISA_PNP_ID(PNP0501);
424 io->ResourceList->ResourceItem[0].Type =
425 EfiIsaAcpiResourceIo;
426 io->ResourceList->ResourceItem[1].Type =
427 EfiIsaAcpiResourceEndOfList;
428
429 port = calloc(1, sizeof (*port));
430 if (port == NULL) {
431 free(io->ResourceList->ResourceItem);
432 free(io->ResourceList);
433 free(io);
434 return (EFI_OUT_OF_RESOURCES);
435 }
436 /* Set up port descriptor */
437 port->io.isa = io;
438 /* Use 8,n,1 for defaults */
439 port->databits = 8;
440 port->parity = NoParity;
441 port->stopbits = OneStopBit;
442 port->ignore_cd = true;
443 port->guid = &gEfiIsaIoProtocolGuid;
444 }
445 io->ResourceList->Device.UID = i;
446 io->ResourceList->ResourceItem[0].StartRange = io_ports[i];
447 port->ioaddr = io_ports[i];
448 if (efi_isa_port_is_present(port)) {
449 STAILQ_INSERT_TAIL(&serials, port, next);
450 port = NULL;
451 }
452 }
453
454 if (port != NULL) {
455 free(io->ResourceList->ResourceItem);
456 free(io->ResourceList);
457 free(io);
458 free(port);
459 }
460 return (status);
461 }
462 #endif /* MDE_CPU_X64 */
463
464 /*
465 * Get IsaIo protocol handles and build port list for us.
466 * returns EFI_SUCCESS or EFI_NOT_FOUND.
467 */
468 static EFI_STATUS
efi_isa_probe_ports(void)469 efi_isa_probe_ports(void)
470 {
471 EFI_STATUS status;
472 EFI_HANDLE *handles;
473 struct serial *port;
474 uint_t count, nhandles, index;
475
476 count = 0;
477 nhandles = 0;
478 handles = NULL;
479 status = efi_get_protocol_handles(&gEfiIsaIoProtocolGuid,
480 &nhandles, &handles);
481 if (!EFI_ERROR(status)) {
482 for (index = 0; index < nhandles; index++) {
483 /* skip if we are iodev for serialio port */
484 STAILQ_FOREACH(port, &serials, next) {
485 if (port->iodev == handles[index])
486 break;
487 }
488 if (port == NULL)
489 count += efi_isa_create_port(handles[index]);
490 }
491 free(handles);
492 if (count == 0)
493 status = EFI_NOT_FOUND;
494 }
495 return (status);
496 }
497
498 /*
499 * Set up list of possible serial consoles.
500 * This function is run very early, so we do not expect to
501 * run out of memory, and on error, we can not print output.
502 *
503 * isaio protocols can include serial ports, parallel ports,
504 * keyboard, mouse. We walk protocol handles, create list of
505 * serial ports, then create console descriptors.
506 */
507 void
efi_isa_ini(void)508 efi_isa_ini(void)
509 {
510 EFI_STATUS status;
511 uint_t c, n;
512 struct console **tmp;
513 struct console *tty;
514 struct serial *port;
515
516 status = efi_isa_probe_ports();
517 #ifdef MDE_CPU_X64
518 if (status == EFI_NOT_FOUND) {
519 /*
520 * We have no IsaIo serial ports. But, as this implementation
521 * is very similar to one used in BIOS comconsole driver,
522 * and in order to avoid using comconsole as last resort
523 * fallback on x86 platform, we implement fake IsaIo.
524 */
525 if (STAILQ_EMPTY(&serials))
526 status = efi_isa_create_io_ports();
527 }
528 #endif
529 if (EFI_ERROR(status))
530 return;
531
532 n = 0;
533 /* Count ports we have */
534 STAILQ_FOREACH(port, &serials, next) {
535 if (uuid_equal((uuid_t *)port->guid,
536 (uuid_t *)&gEfiIsaIoProtocolGuid, NULL) == 1)
537 n++;
538 }
539
540 if (n == 0)
541 return; /* no serial ports here */
542
543 c = cons_array_size();
544 if (c == 0)
545 n++; /* For NULL pointer */
546
547 tmp = realloc(consoles, (c + n) * sizeof (*consoles));
548 if (tmp == NULL) {
549 return;
550 }
551 consoles = tmp;
552 if (c > 0)
553 c--;
554
555 STAILQ_FOREACH(port, &serials, next) {
556 char id;
557
558 if (uuid_equal((uuid_t *)port->guid,
559 (uuid_t *)&gEfiIsaIoProtocolGuid, NULL) == 0) {
560 continue;
561 }
562
563 tty = calloc(1, sizeof (*tty));
564 if (tty == NULL) {
565 /* Out of memory?! */
566 continue;
567 }
568 switch (port->ioaddr) {
569 case 0: /* bad ioaddr */
570 continue;
571 case COM1_IOADDR:
572 id = 'a';
573 break;
574 case COM2_IOADDR:
575 id = 'b';
576 break;
577 case COM3_IOADDR:
578 id = 'c';
579 break;
580 case COM4_IOADDR:
581 id = 'd';
582 break;
583 default:
584 /*
585 * We should not see this happening, but assigning
586 * this id would let us help to identify unexpected
587 * configuration.
588 */
589 id = '0';
590 }
591 /* Set up serial device descriptor */
592 (void) asprintf(&tty->c_name, "tty%c", id);
593 (void) asprintf(&tty->c_desc, "serial port %c", id);
594 tty->c_flags = C_PRESENTIN | C_PRESENTOUT;
595 tty->c_probe = efi_isa_probe;
596 tty->c_init = efi_isa_init;
597 tty->c_out = efi_isa_putchar;
598 tty->c_in = efi_isa_getchar;
599 tty->c_ready = efi_isa_ischar;
600 tty->c_ioctl = efi_isa_ioctl;
601 tty->c_devinfo = efi_isa_devinfo;
602 tty->c_private = port;
603 consoles[c++] = tty;
604
605 /* Reset terminal to initial normal settings with ESC [ 0 m */
606 efi_isa_putchar(tty, 0x1b);
607 efi_isa_putchar(tty, '[');
608 efi_isa_putchar(tty, '0');
609 efi_isa_putchar(tty, 'm');
610 /* drain input from random data */
611 while (efi_isa_getchar(tty) != -1)
612 ;
613 }
614 consoles[c] = NULL;
615 }
616
617 static EFI_STATUS
efi_isa_getspeed(struct serial * sp)618 efi_isa_getspeed(struct serial *sp)
619 {
620 EFI_STATUS status;
621 uint_t divisor;
622 uchar_t dlbh;
623 uchar_t dlbl;
624 uchar_t cfcr;
625 uchar_t c;
626
627 status = sp->io.isa->Io.Read(sp->io.isa,
628 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_cfcr, 1, &cfcr);
629 if (EFI_ERROR(status))
630 return (status);
631 c = CFCR_DLAB | cfcr;
632 status = sp->io.isa->Io.Write(sp->io.isa,
633 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_cfcr, 1, &c);
634 if (EFI_ERROR(status))
635 return (status);
636
637 status = sp->io.isa->Io.Read(sp->io.isa,
638 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_dlbl, 1, &dlbl);
639 if (EFI_ERROR(status))
640 return (status);
641 status = sp->io.isa->Io.Read(sp->io.isa,
642 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_dlbh, 1, &dlbh);
643 if (EFI_ERROR(status))
644 return (status);
645
646 status = sp->io.isa->Io.Write(sp->io.isa,
647 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_cfcr, 1, &cfcr);
648 if (EFI_ERROR(status))
649 return (status);
650
651 divisor = dlbh << 8 | dlbl;
652
653 if (divisor == 0)
654 return (EFI_DEVICE_ERROR);
655
656 sp->baudrate = COMC_DIV2BPS(divisor);
657 return (EFI_SUCCESS);
658 }
659
660 static void
efi_isa_probe(struct console * cp)661 efi_isa_probe(struct console *cp)
662 {
663 struct serial *sp = cp->c_private;
664 EFI_STATUS status;
665 uint8_t lcr;
666
667 if (!efi_isa_port_is_present(sp)) {
668 return;
669 }
670
671 status = efi_isa_getspeed(sp);
672 if (EFI_ERROR(status)) {
673 /* Use fallback value. */
674 sp->baudrate = COMSPEED;
675 }
676 status = sp->io.isa->Io.Read(sp->io.isa,
677 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_lcr,
678 1, &lcr);
679 if (EFI_ERROR(status)) {
680 return;
681 }
682
683 sp->databits = (lcr & BITS8) == BITS8? 8:7;
684 sp->stopbits = (lcr & STOP2) == STOP2? TwoStopBits:OneStopBit;
685 if ((lcr & (PAREN|PAREVN)) == (PAREN|PAREVN))
686 sp->parity = EvenParity;
687 else if ((lcr & PAREN) == PAREN)
688 sp->parity = OddParity;
689 else
690 sp->parity = NoParity;
691
692 /* check if we are listed in ConIn */
693 efi_check_and_set_condev(sp, "ConIn");
694 efi_isa_setup_env(cp);
695 if (!efi_isa_setup(cp))
696 printf("Failed to set up %s\n", cp->c_name);
697 }
698
699 static int
efi_isa_init(struct console * cp,int arg __unused)700 efi_isa_init(struct console *cp, int arg __unused)
701 {
702
703 if (efi_isa_setup(cp))
704 return (CMD_OK);
705
706 cp->c_flags = 0;
707 return (CMD_ERROR);
708 }
709
710 static void
efi_isa_putchar(struct console * cp,int c)711 efi_isa_putchar(struct console *cp, int c)
712 {
713 int wait;
714 EFI_STATUS status;
715 UINTN bufsz = 1;
716 char control, cb = c;
717 struct serial *sp = cp->c_private;
718
719 for (wait = COMC_TXWAIT; wait > 0; wait--) {
720 status = sp->io.isa->Io.Read(sp->io.isa,
721 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_lsr,
722 bufsz, &control);
723 if (EFI_ERROR(status))
724 continue;
725
726 if ((control & LSR_TXRDY) != LSR_TXRDY)
727 continue;
728
729 status = sp->io.isa->Io.Write(sp->io.isa,
730 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_data,
731 bufsz, &cb);
732 if (status != EFI_TIMEOUT)
733 break;
734 }
735 }
736
737 static int
efi_isa_getchar(struct console * cp)738 efi_isa_getchar(struct console *cp)
739 {
740 EFI_STATUS status;
741 UINTN bufsz = 1;
742 char c;
743 struct serial *sp = cp->c_private;
744
745 /*
746 * if this device is also used as ConIn, some firmwares
747 * fail to return all input via SIO protocol.
748 */
749 if (sp->is_efi_console) {
750 return (efi_console.c_in(&efi_console));
751 }
752
753 if (!efi_isa_ischar(cp))
754 return (-1);
755
756 status = sp->io.isa->Io.Read(sp->io.isa,
757 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
758 sp->ioaddr + com_data, bufsz, &c);
759 if (EFI_ERROR(status))
760 return (-1);
761
762 return (c);
763 }
764
765 static int
efi_isa_ischar(struct console * cp)766 efi_isa_ischar(struct console *cp)
767 {
768 EFI_STATUS status;
769 uint8_t control;
770 struct serial *sp = cp->c_private;
771
772 /*
773 * if this device is also used as ConIn, some firmwares
774 * fail to return all input via SIO protocol.
775 */
776 if (sp->is_efi_console) {
777 return (efi_console.c_ready(&efi_console));
778 }
779
780 status = sp->io.isa->Io.Read(sp->io.isa,
781 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
782 sp->ioaddr + com_lsr, 1, &control);
783 if (EFI_ERROR(status))
784 return (0);
785
786 return (control & LSR_RXRDY);
787 }
788
789 static int
efi_isa_ioctl(struct console * cp __unused,int cmd __unused,void * data __unused)790 efi_isa_ioctl(struct console *cp __unused, int cmd __unused,
791 void *data __unused)
792 {
793 return (ENOTTY);
794 }
795
796 static void
efi_isa_devinfo(struct console * cp)797 efi_isa_devinfo(struct console *cp)
798 {
799 struct serial *port = cp->c_private;
800 EFI_DEVICE_PATH *dp;
801 CHAR16 *text;
802
803 if (port->currdev != NULL) {
804 dp = efi_lookup_devpath(port->currdev);
805 if (dp == NULL)
806 return;
807
808 text = efi_devpath_name(dp);
809 if (text == NULL)
810 return;
811
812 printf("\tISA IO device %S", text);
813 efi_free_devpath_name(text);
814 efi_close_devpath(port->currdev);
815 return;
816 }
817
818 if (port->ioaddr != 0) {
819 printf("\tISA IO port %#x", port->ioaddr);
820 }
821 }
822
823 static char *
efi_isa_asprint_mode(struct serial * sp)824 efi_isa_asprint_mode(struct serial *sp)
825 {
826 char par, *buf, *stop;
827
828 if (sp == NULL)
829 return (NULL);
830
831 switch (sp->parity) {
832 case NoParity:
833 par = 'n';
834 break;
835 case EvenParity:
836 par = 'e';
837 break;
838 case OddParity:
839 par = 'o';
840 break;
841 case MarkParity:
842 par = 'm';
843 break;
844 case SpaceParity:
845 par = 's';
846 break;
847 default:
848 par = 'n';
849 break;
850 }
851
852 switch (sp->stopbits) {
853 case OneStopBit:
854 stop = "1";
855 break;
856 case TwoStopBits:
857 stop = "2";
858 break;
859 case OneFiveStopBits:
860 stop = "1.5";
861 break;
862 default:
863 stop = "1";
864 break;
865 }
866
867 (void) asprintf(&buf, "%ju,%d,%c,%s,-", sp->baudrate,
868 sp->databits, par, stop);
869 return (buf);
870 }
871
872 static int
efi_isa_parse_mode(struct serial * sp,const char * value)873 efi_isa_parse_mode(struct serial *sp, const char *value)
874 {
875 unsigned long n;
876 uint64_t baudrate;
877 uint8_t databits;
878 EFI_PARITY_TYPE parity;
879 EFI_STOP_BITS_TYPE stopbits;
880 char *ep;
881
882 if (value == NULL || *value == '\0')
883 return (CMD_ERROR);
884
885 errno = 0;
886 n = strtoul(value, &ep, 10);
887 if (errno != 0 || *ep != ',')
888 return (CMD_ERROR);
889 baudrate = n;
890
891 ep++;
892 n = strtoul(ep, &ep, 10);
893 if (errno != 0 || *ep != ',')
894 return (CMD_ERROR);
895
896 switch (n) {
897 case 5:
898 databits = 5;
899 break;
900 case 6:
901 databits = 6;
902 break;
903 case 7:
904 databits = 7;
905 break;
906 case 8:
907 databits = 8;
908 break;
909 default:
910 return (CMD_ERROR);
911 }
912
913 ep++;
914 switch (*ep++) {
915 case 'n':
916 parity = NoParity;
917 break;
918 case 'e':
919 parity = EvenParity;
920 break;
921 case 'o':
922 parity = OddParity;
923 break;
924 default:
925 return (CMD_ERROR);
926 }
927
928 if (*ep == ',')
929 ep++;
930 else
931 return (CMD_ERROR);
932
933 switch (*ep++) {
934 case '1':
935 stopbits = OneStopBit;
936 break;
937 case '2':
938 stopbits = TwoStopBits;
939 break;
940 default:
941 return (CMD_ERROR);
942 }
943
944 /* handshake is ignored, but we check syntax anyhow */
945 if (*ep == ',')
946 ep++;
947 else
948 return (CMD_ERROR);
949
950 switch (*ep++) {
951 case '-':
952 case 'h':
953 case 's':
954 break;
955 default:
956 return (CMD_ERROR);
957 }
958
959 if (*ep != '\0')
960 return (CMD_ERROR);
961
962 sp->baudrate = baudrate;
963 sp->databits = databits;
964 sp->parity = parity;
965 sp->stopbits = stopbits;
966 return (CMD_OK);
967 }
968
969 /*
970 * CMD_ERROR will cause set/setenv/setprop command to fail,
971 * when used in loader scripts (forth), this will cause processing
972 * of boot scripts to fail, rendering bootloading impossible.
973 * To prevent such unfortunate situation, we return CMD_OK when
974 * there is no such port, or there is invalid value in mode line.
975 */
976 static int
efi_isa_mode_set(struct env_var * ev,int flags,const void * value)977 efi_isa_mode_set(struct env_var *ev, int flags, const void *value)
978 {
979 struct console *cp;
980 char name[15];
981
982 if (value == NULL)
983 return (CMD_ERROR);
984
985 if ((cp = cons_get_console(ev->ev_name)) == NULL)
986 return (CMD_OK);
987
988 /* Do not override serial setup if port is listed in ConIn */
989 (void) snprintf(name, sizeof (name), "%s-spcr-mode", cp->c_name);
990 if (getenv(name) == NULL) {
991 if (efi_isa_parse_mode(cp->c_private, value) == CMD_ERROR) {
992 printf("%s: invalid mode: %s\n", ev->ev_name,
993 (char *)value);
994 return (CMD_OK);
995 }
996
997 (void) efi_isa_setup(cp);
998 (void) env_setenv(ev->ev_name, flags | EV_NOHOOK, value,
999 NULL, NULL);
1000 }
1001
1002 return (CMD_OK);
1003 }
1004
1005 /*
1006 * CMD_ERROR will cause set/setenv/setprop command to fail,
1007 * when used in loader scripts (forth), this will cause processing
1008 * of boot scripts to fail, rendering bootloading impossible.
1009 * To prevent such unfortunate situation, we return CMD_OK when
1010 * there is no such port or invalid value was used.
1011 */
1012 static int
efi_isa_cd_set(struct env_var * ev,int flags,const void * value)1013 efi_isa_cd_set(struct env_var *ev, int flags, const void *value)
1014 {
1015 struct console *cp;
1016 struct serial *sp;
1017
1018 if (value == NULL)
1019 return (CMD_OK);
1020
1021 if ((cp = cons_get_console(ev->ev_name)) == NULL)
1022 return (CMD_OK);
1023
1024 sp = cp->c_private;
1025 if (strcmp(value, "true") == 0) {
1026 sp->ignore_cd = 1;
1027 } else if (strcmp(value, "false") == 0) {
1028 sp->ignore_cd = 0;
1029 } else {
1030 printf("%s: invalid value: %s\n", ev->ev_name,
1031 (char *)value);
1032 return (CMD_OK);
1033 }
1034
1035 (void) efi_isa_setup(cp);
1036
1037 (void) env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
1038
1039 return (CMD_OK);
1040 }
1041
1042 /*
1043 * CMD_ERROR will cause set/setenv/setprop command to fail,
1044 * when used in loader scripts (forth), this will cause processing
1045 * of boot scripts to fail, rendering bootloading impossible.
1046 * To prevent such unfortunate situation, we return CMD_OK when
1047 * there is no such port, or invalid value was used.
1048 */
1049 static int
efi_isa_rtsdtr_set(struct env_var * ev,int flags,const void * value)1050 efi_isa_rtsdtr_set(struct env_var *ev, int flags, const void *value)
1051 {
1052 struct console *cp;
1053 struct serial *sp;
1054
1055 if (value == NULL)
1056 return (CMD_OK);
1057
1058 if ((cp = cons_get_console(ev->ev_name)) == NULL)
1059 return (CMD_OK);
1060
1061 sp = cp->c_private;
1062 if (strcmp(value, "true") == 0) {
1063 sp->rtsdtr_off = 1;
1064 } else if (strcmp(value, "false") == 0) {
1065 sp->rtsdtr_off = 0;
1066 } else {
1067 printf("%s: invalid value: %s\n", ev->ev_name,
1068 (char *)value);
1069 return (CMD_OK);
1070 }
1071
1072 (void) efi_isa_setup(cp);
1073
1074 (void) env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
1075
1076 return (CMD_OK);
1077 }
1078
1079 /*
1080 * In case of error, we also reset ACTIVE flags, so the console
1081 * framefork will try alternate consoles.
1082 */
1083 static bool
efi_isa_setup(struct console * cp)1084 efi_isa_setup(struct console *cp)
1085 {
1086 EFI_STATUS status;
1087 uint8_t data, lcr;
1088 struct serial *sp = cp->c_private;
1089 uint_t tries, try_count = 1000000;
1090
1091 if (sp->baudrate == 0)
1092 return (false);
1093
1094 switch (sp->databits) {
1095 case 8:
1096 lcr = BITS8;
1097 break;
1098 case 7:
1099 lcr = BITS7;
1100 break;
1101 case 6:
1102 lcr = BITS6;
1103 break;
1104 case 5:
1105 lcr = BITS5;
1106 break;
1107 default:
1108 lcr = BITS8;
1109 break;
1110 }
1111
1112 switch (sp->parity) {
1113 case NoParity:
1114 break;
1115 case OddParity:
1116 lcr |= PAREN|PARODD;
1117 break;
1118 case EvenParity:
1119 lcr |= PAREN|PAREVN;
1120 break;
1121 default:
1122 break;
1123 }
1124
1125 switch (sp->stopbits) {
1126 case OneStopBit:
1127 break;
1128 case TwoStopBits:
1129 lcr |= STOP2;
1130 break;
1131 default:
1132 break;
1133 }
1134
1135 data = CFCR_DLAB | lcr;
1136 status = sp->io.isa->Io.Write(sp->io.isa,
1137 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1138 sp->ioaddr + com_cfcr, 1, &data);
1139 if (EFI_ERROR(status))
1140 return (false);
1141 data = COMC_BPS(sp->baudrate) & 0xff;
1142 status = sp->io.isa->Io.Write(sp->io.isa,
1143 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1144 sp->ioaddr + com_dlbl, 1, &data);
1145 if (EFI_ERROR(status))
1146 return (false);
1147 data = COMC_BPS(sp->baudrate) >> 8;
1148 status = sp->io.isa->Io.Write(sp->io.isa,
1149 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1150 sp->ioaddr + com_dlbh, 1, &data);
1151 if (EFI_ERROR(status))
1152 return (false);
1153 status = sp->io.isa->Io.Write(sp->io.isa,
1154 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1155 sp->ioaddr + com_cfcr, 1, &lcr);
1156 if (EFI_ERROR(status))
1157 return (false);
1158 data = sp->rtsdtr_off? ~(MCR_RTS | MCR_DTR) : MCR_RTS | MCR_DTR;
1159 status = sp->io.isa->Io.Write(sp->io.isa,
1160 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1161 sp->ioaddr + com_mcr, 1, &data);
1162 if (EFI_ERROR(status))
1163 return (false);
1164
1165 tries = 0;
1166 do {
1167 status = sp->io.isa->Io.Read(sp->io.isa,
1168 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1169 sp->ioaddr + com_data, 1, &data);
1170 status = sp->io.isa->Io.Read(sp->io.isa,
1171 EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1172 sp->ioaddr + com_lsr, 1, &data);
1173 } while (data & LSR_RXRDY && ++tries < try_count);
1174
1175 if (tries == try_count)
1176 return (false);
1177
1178 /* Mark this port usable. */
1179 cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
1180 return (true);
1181 }
1182