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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 790 efi_isa_ioctl(struct console *cp __unused, int cmd __unused, 791 void *data __unused) 792 { 793 return (ENOTTY); 794 } 795 796 static void 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 * 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 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 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 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 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 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