Print this page
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
    loader: pxe receive cleanup
    9475 libefi: Do not return only if ReceiveFilter
    installboot: should support efi system partition
    8931 boot1.efi: scan all display modes rather than
    loader: spinconsole updates
    loader: gfx experiment to try GOP Blt() function.
    sha1 build test
    loader: add sha1 hash calculation
    common/sha1: update for loader build
    loader: biosdisk rework
    uts: 32-bit kernel FB needs mapping in low memory
    uts: add diag-device
    uts: boot console mirror with diag-device
    uts: enable very early console on ttya
    kmdb: add diag-device as input/output device
    uts: test VGA memory exclusion from mapping
    uts: clear boot mapping and protect boot pages test
    uts: add dboot map debug printf
    uts: need to release FB pages in release_bootstrap()
    uts: add screenmap ioctl
    uts: update sys/queue.h
    loader: add illumos uts/common to include path
    loader: tem/gfx font cleanup
    loader: vbe checks
    uts: gfx_private set KD_TEXT when KD_RESETTEXT is
    uts: gfx 8-bit update
    loader: gfx 8-bit fix
    loader: always set media size from partition.
    uts: MB2 support for 32-bit kernel
    loader: x86 should have tem 80x25
    uts: x86 should have tem 80x25
    uts: font update
    loader: font update
    uts: tem attributes
    loader: tem.c comment added
    uts: use font module
    loader: add font module
    loader: build rules for new font setup
    uts: gfx_private update for new font structure
    uts: early boot update for new font structure
    uts: font update
    uts: font build rules update for new fonts
    uts: tem update to new font structure
    loader: module.c needs to include tem_impl.h
    uts: gfx_private 8x16 font rework
    uts: make font_lookup public
    loader: font rework
    uts: font rework
    9259 libefi: efi_alloc_and_read should check for PMBR
    uts: tem utf-8 support
    loader: implement tem utf-8 support
    loader: tem should be able to display UTF-8
    7784 uts: console input should support utf-8
    7796 uts: ldterm default to utf-8
    uts: do not reset serial console
    uts: set up colors even if tem is not console
    uts: add type for early boot properties
    uts: gfx_private experiment with drm and vga
    uts: gfx_private should use setmode drm callback.
    uts: identify FB types and set up gfx_private based
    loader: replace gop and vesa with framebuffer
    uts: boot needs simple tem to support mdb
    uts: boot_keyboard should emit esc sequences for
    uts: gfx_private FB showuld be written by line
    kmdb: set terminal window size
    uts: gfx_private needs to keep track of early boot FB
    pnglite: move pnglite to usr/src/common
    loader: gfx_fb
    ficl-sys: add gfx primitives
    loader: add illumos.png logo
    ficl: add fb-putimage
    loader: add png support
    loader: add alpha blending for gfx_fb
    loader: use term-drawrect for menu frame
    ficl: add simple gfx words
    uts: provide fb_info via fbgattr dev_specific array.
    uts: gfx_private add alpha blending
    uts: update sys/ascii.h
    uts: tem OSC support (incomplete)
    uts: implement env module support and use data from
    uts: tem get colors from early boot data
    loader: use crc32 from libstand (libz)
    loader: optimize for size
    loader: pass tem info to the environment
    loader: import tem for loader console
    loader: UEFI loader needs to set ISADIR based on
    loader: need UEFI32 support
    8918 loader.efi: add vesa edid support
    uts: tem_safe_pix_clear_prom_output() should only
    uts: tem_safe_pix_clear_entire_screen() should use
    uts: tem_safe_check_first_time() should query cursor
    uts: tem implement cls callback & visual_io v4
    uts: gfx_vgatext use block cursor for vgatext
    uts: gfx_private implement cls callback & visual_io
    uts: gfx_private bitmap framebuffer implementation
    uts: early start frame buffer console support
    uts: font functions should check the input char
    uts: font rendering should support 16/24/32bit depths
    uts: use smallest font as fallback default.
    uts: update terminal dimensions based on selected
    7834 uts: vgatext should use gfx_private
    uts: add spacing property to 8859-1.bdf
    terminfo: add underline for sun-color
    terminfo: sun-color has 16 colors
    uts: add font load callback type
    loader: do not repeat int13 calls with error 0x20 and
    8905 loader: add skein/edonr support
    8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Revert "NEX-16819 loader UEFI support"
This reverts commit ec06b9fc617b99234e538bf2e7e4d02a24993e0c.
Reverting due to failures in the zfs-tests and the sharefs-tests
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
    loader: pxe receive cleanup
    9475 libefi: Do not return only if ReceiveFilter
    installboot: should support efi system partition
    8931 boot1.efi: scan all display modes rather than
    loader: spinconsole updates
    loader: gfx experiment to try GOP Blt() function.
    sha1 build test
    loader: add sha1 hash calculation
    common/sha1: update for loader build
    loader: biosdisk rework
    uts: 32-bit kernel FB needs mapping in low memory
    uts: add diag-device
    uts: boot console mirror with diag-device
    uts: enable very early console on ttya
    kmdb: add diag-device as input/output device
    uts: test VGA memory exclusion from mapping
    uts: clear boot mapping and protect boot pages test
    uts: add dboot map debug printf
    uts: need to release FB pages in release_bootstrap()
    uts: add screenmap ioctl
    uts: update sys/queue.h
    loader: add illumos uts/common to include path
    loader: tem/gfx font cleanup
    loader: vbe checks
    uts: gfx_private set KD_TEXT when KD_RESETTEXT is
    uts: gfx 8-bit update
    loader: gfx 8-bit fix
    loader: always set media size from partition.
    uts: MB2 support for 32-bit kernel
    loader: x86 should have tem 80x25
    uts: x86 should have tem 80x25
    uts: font update
    loader: font update
    uts: tem attributes
    loader: tem.c comment added
    uts: use font module
    loader: add font module
    loader: build rules for new font setup
    uts: gfx_private update for new font structure
    uts: early boot update for new font structure
    uts: font update
    uts: font build rules update for new fonts
    uts: tem update to new font structure
    loader: module.c needs to include tem_impl.h
    uts: gfx_private 8x16 font rework
    uts: make font_lookup public
    loader: font rework
    uts: font rework
    libefi: efi_alloc_and_read should check for PMBR
    uts: tem utf-8 support
    loader: implement tem utf-8 support
    loader: tem should be able to display UTF-8
    7784 uts: console input should support utf-8
    7796 uts: ldterm default to utf-8
    uts: do not reset serial console
    uts: set up colors even if tem is not console
    uts: add type for early boot properties
    uts: gfx_private experiment with drm and vga
    uts: gfx_private should use setmode drm callback.
    uts: identify FB types and set up gfx_private based
    loader: replace gop and vesa with framebuffer
    uts: boot needs simple tem to support mdb
    uts: boot_keyboard should emit esc sequences for
    uts: gfx_private FB showuld be written by line
    kmdb: set terminal window size
    uts: gfx_private needs to keep track of early boot FB
    pnglite: move pnglite to usr/src/common
    loader: gfx_fb
    ficl-sys: add gfx primitives
    loader: add illumos.png logo
    ficl: add fb-putimage
    loader: add png support
    loader: add alpha blending for gfx_fb
    loader: use term-drawrect for menu frame
    ficl: add simple gfx words
    uts: provide fb_info via fbgattr dev_specific array.
    uts: gfx_private add alpha blending
    uts: update sys/ascii.h
    uts: tem OSC support (incomplete)
    uts: implement env module support and use data from
    uts: tem get colors from early boot data
    loader: use crc32 from libstand (libz)
    loader: optimize for size
    loader: pass tem info to the environment
    loader: import tem for loader console
    loader: UEFI loader needs to set ISADIR based on
    loader: need UEFI32 support
    8918 loader.efi: add vesa edid support
    uts: tem_safe_pix_clear_prom_output() should only
    uts: tem_safe_pix_clear_entire_screen() should use
    uts: tem_safe_check_first_time() should query cursor
    uts: tem implement cls callback & visual_io v4
    uts: gfx_vgatext use block cursor for vgatext
    uts: gfx_private implement cls callback & visual_io
    uts: gfx_private bitmap framebuffer implementation
    uts: early start frame buffer console support
    uts: font functions should check the input char
    uts: font rendering should support 16/24/32bit depths
    uts: use smallest font as fallback default.
    uts: update terminal dimensions based on selected
    7834 uts: vgatext should use gfx_private
    uts: add spacing property to 8859-1.bdf
    terminfo: add underline for sun-color
    terminfo: sun-color has 16 colors
    uts: add font load callback type
    loader: do not repeat int13 calls with error 0x20 and
    8905 loader: add skein/edonr support
    8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>


  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2012 Gary Mills
  23  *
  24  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  25  * Use is subject to license terms.
  26  */
  27 
  28 #include <sys/types.h>
  29 #include <sys/systm.h>
  30 #include <sys/archsystm.h>

  31 #include <sys/boot_console.h>
  32 #include <sys/panic.h>
  33 #include <sys/ctype.h>

  34 #if defined(__xpv)
  35 #include <sys/hypervisor.h>
  36 #endif /* __xpv */
  37 

  38 #include "boot_serial.h"
  39 #include "boot_vga.h"
  40 
  41 #if defined(_BOOT)
  42 #include <dboot/dboot_asm.h>
  43 #include <dboot/dboot_xboot.h>
  44 #else /* _BOOT */
  45 #include <sys/bootconf.h>
  46 #if defined(__xpv)
  47 #include <sys/evtchn_impl.h>
  48 #endif /* __xpv */
  49 static char *defcons_buf;
  50 static char *defcons_cur;
  51 #endif /* _BOOT */
  52 
  53 #if defined(__xpv)
  54 extern void bcons_init_xen(char *);
  55 extern void bcons_putchar_xen(int);
  56 extern int bcons_getchar_xen(void);
  57 extern int bcons_ischar_xen(void);
  58 #endif /* __xpv */
  59 
  60 static int cons_color = CONS_COLOR;

  61 static int console = CONS_SCREEN_TEXT;

  62 static int tty_num = 0;
  63 static int tty_addr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
  64 static char *boot_line;
  65 static struct boot_env {
  66         char    *be_env;        /* ends with double ascii nul */
  67         size_t  be_size;        /* size of the environment, including nul */
  68 } boot_env;
  69 
























  70 static int serial_ischar(void);
  71 static int serial_getchar(void);
  72 static void serial_putchar(int);
  73 static void serial_adjust_prop(void);
  74 
  75 #if !defined(_BOOT)
  76 /* Set if the console or mode are expressed in the boot line */
  77 static int console_set, console_mode_set;
  78 #endif
  79 
  80 #if defined(__xpv)
  81 static int console_hypervisor_redirect = B_FALSE;
  82 static int console_hypervisor_device = CONS_INVALID;
  83 static int console_hypervisor_tty_num = 0;
  84 
  85 /* Obtain the hypervisor console type */
  86 int
  87 console_hypervisor_dev_type(int *tnum)
  88 {
  89         if (tnum != NULL)
  90                 *tnum = console_hypervisor_tty_num;
  91         return (console_hypervisor_device);
  92 }
  93 #endif /* __xpv */
  94 
  95 /* Clear the screen and initialize VIDEO, XPOS and YPOS. */
  96 void
  97 clear_screen(void)
  98 {
  99         /*
 100          * XXX should set vga mode so we don't depend on the
 101          * state left by the boot loader.  Note that we have to
 102          * enable the cursor before clearing the screen since
 103          * the cursor position is dependant upon the cursor
 104          * skew, which is initialized by vga_cursor_display()
 105          */
 106         vga_cursor_display();
 107         vga_clear(cons_color);
 108         vga_setpos(0, 0);
 109 }
 110 
 111 /* Put the character C on the screen. */
 112 static void
 113 screen_putchar(int c)
 114 {
 115         int row, col;
 116 
 117         vga_getpos(&row, &col);
 118         switch (c) {
 119         case '\t':
 120                 col += 8 - (col % 8);
 121                 if (col == VGA_TEXT_COLS)
 122                         col = 79;
 123                 vga_setpos(row, col);
 124                 break;
 125 
 126         case '\r':
 127                 vga_setpos(row, 0);
 128                 break;
 129 
 130         case '\b':
 131                 if (col > 0)
 132                         vga_setpos(row, col - 1);
 133                 break;
 134 
 135         case '\n':
 136                 if (row < VGA_TEXT_ROWS - 1)
 137                         vga_setpos(row + 1, col);
 138                 else
 139                         vga_scroll(cons_color);
 140                 break;
 141 
 142         default:
 143                 vga_drawc(c, cons_color);
 144                 if (col < VGA_TEXT_COLS -1)
 145                         vga_setpos(row, col + 1);
 146                 else if (row < VGA_TEXT_ROWS - 1)
 147                         vga_setpos(row + 1, 0);
 148                 else {
 149                         vga_setpos(row, 0);
 150                         vga_scroll(cons_color);
 151                 }
 152                 break;
 153         }
 154 }
 155 
 156 static int port;
 157 
 158 static void
 159 serial_init(void)
 160 {
 161         port = tty_addr[tty_num];
 162 
 163         outb(port + ISR, 0x20);
 164         if (inb(port + ISR) & 0x20) {
 165                 /*
 166                  * 82510 chip is present
 167                  */
 168                 outb(port + DAT+7, 0x04);       /* clear status */
 169                 outb(port + ISR, 0x40);  /* set to bank 2 */
 170                 outb(port + MCR, 0x08);  /* IMD */
 171                 outb(port + DAT, 0x21);  /* FMD */
 172                 outb(port + ISR, 0x00);  /* set to bank 0 */
 173         } else {
 174                 /*
 175                  * set the UART in FIFO mode if it has FIFO buffers.


 186                         /*
 187                          * no fifo buffers so disable fifos.
 188                          * this is true for 8250's
 189                          */
 190                         outb(port + FIFOR, 0x00);
 191                 }
 192         }
 193 
 194         /* disable interrupts */
 195         outb(port + ICR, 0);
 196 
 197 #if !defined(_BOOT)
 198         if (IN_XPV_PANIC())
 199                 return;
 200 #endif
 201 
 202         /* adjust setting based on tty properties */
 203         serial_adjust_prop();
 204 
 205 #if defined(_BOOT)

 206         /*
 207          * Do a full reset to match console behavior.
 208          * 0x1B + c - reset everything
 209          */
 210         serial_putchar(0x1B);
 211         serial_putchar('c');
 212 #endif

 213 }
 214 
 215 /* Advance str pointer past white space */
 216 #define EAT_WHITE_SPACE(str)    {                       \
 217         while ((*str != '\0') && ISSPACE(*str))         \
 218                 str++;                                  \
 219 }
 220 
 221 /*
 222  * boot_line is set when we call here.  Search it for the argument name,
 223  * and if found, return a pointer to it.
 224  */
 225 static char *
 226 find_boot_line_prop(const char *name)
 227 {
 228         char *ptr;
 229         char *ret = NULL;
 230         char end_char;
 231         size_t len;
 232 


 588 };
 589 
 590 static void
 591 bcons_init_env(struct xboot_info *xbi)
 592 {
 593         uint32_t i;
 594         struct boot_modules *modules;
 595 
 596         modules = (struct boot_modules *)(uintptr_t)xbi->bi_modules;
 597         for (i = 0; i < xbi->bi_module_cnt; i++) {
 598                 if (modules[i].bm_type == BMT_ENV)
 599                         break;
 600         }
 601         if (i == xbi->bi_module_cnt)
 602                 return;
 603 
 604         boot_env.be_env = (char *)(uintptr_t)modules[i].bm_addr;
 605         boot_env.be_size = modules[i].bm_size;
 606 }
 607 






















































































































































 608 void
 609 bcons_init(struct xboot_info *xbi)
 610 {
 611         console_value_t *consolep;
 612         size_t len, cons_len;
 613         const char *cons_str;
 614 #if !defined(_BOOT)
 615         static char console_text[] = "text";
 616         extern int post_fastreboot;
 617 #endif
 618 







 619         /* Set up data to fetch properties from commad line and boot env. */
 620         boot_line = (char *)(uintptr_t)xbi->bi_cmdline;
 621         bcons_init_env(xbi);
 622         console = CONS_INVALID;
 623 



 624 #if defined(__xpv)
 625         bcons_init_xen(boot_line);
 626 #endif /* __xpv */
 627 









 628         cons_str = find_boot_prop("console");
 629         if (cons_str == NULL)
 630                 cons_str = find_boot_prop("output-device");
 631 
 632 #if !defined(_BOOT)
 633         if (post_fastreboot && strcmp(cons_str, "graphics") == 0)
 634                 cons_str = console_text;
 635 #endif
 636 
 637         /*
 638          * Go through the console_devices array trying to match the string
 639          * we were given.  The string on the command line must end with
 640          * a comma or white space.
 641          */
 642         if (cons_str != NULL) {
 643                 int n;
 644 
 645                 cons_len = strlen(cons_str);
 646                 for (n = 0; console_devices[n].name != NULL; n++) {
 647                         consolep = &console_devices[n];
 648                         len = strlen(consolep->name);
 649                         if ((len <= cons_len) && ((cons_str[len] == '\0') ||
 650                             (cons_str[len] == ',') || (cons_str[len] == '\'') ||
 651                             (cons_str[len] == '"') || ISSPACE(cons_str[len])) &&
 652                             (strncmp(cons_str, consolep->name, len) == 0)) {
 653                                 console = consolep->value;
 654                                 if (console == CONS_TTY)
 655                                         tty_num = n;
 656                                 break;
 657                         }
 658                 }
 659         }
 660 
 661 #if defined(__xpv)
 662         /*
 663          * domU's always use the hypervisor regardless of what
 664          * the console variable may be set to.
 665          */
 666         if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
 667                 console = CONS_HYPERVISOR;
 668                 console_hypervisor_redirect = B_TRUE;
 669         }
 670 #endif /* __xpv */
 671 
 672         /*
 673          * If no console device specified, default to text.
 674          * Remember what was specified for second phase.
 675          */
 676         if (console == CONS_INVALID)
 677                 console = CONS_SCREEN_TEXT;
 678 #if !defined(_BOOT)
 679         else
 680                 console_set = 1;


 698                                  * true console mode.  Hence, we're going
 699                                  * to ignore this xen "console" setting.
 700                                  */
 701                                 /*FALLTHROUGH*/
 702                         default:
 703                                 console_hypervisor_device = CONS_INVALID;
 704                 }
 705         }
 706 
 707         /*
 708          * if the hypervisor is using the currently selected serial
 709          * port then default to using the hypervisor as the console
 710          * device.
 711          */
 712         if (console == console_hypervisor_device) {
 713                 console = CONS_HYPERVISOR;
 714                 console_hypervisor_redirect = B_TRUE;
 715         }
 716 #endif /* __xpv */
 717 


 718         switch (console) {
 719         case CONS_TTY:
 720                 serial_init();
 721                 break;
 722 
 723         case CONS_HYPERVISOR:
 724                 break;
 725 
 726 #if !defined(_BOOT)
 727         case CONS_USBSER:
 728                 /*
 729                  * We can't do anything with the usb serial
 730                  * until we have memory management.
 731                  */
 732                 break;
 733 #endif
 734         case CONS_SCREEN_GRAPHICS:
 735                 kb_init();
 736                 break;
 737         case CONS_SCREEN_TEXT:


 738         default:
 739 #if defined(_BOOT)
 740                 clear_screen(); /* clears the grub or xen screen */
 741 #endif /* _BOOT */
 742                 kb_init();
 743                 break;
 744         }
 745 }
 746 
 747 #if !defined(_BOOT)
 748 /*
 749  * 2nd part of console initialization.
 750  * In the kernel (ie. fakebop), this can be used only to switch to
 751  * using a serial port instead of screen based on the contents
 752  * of the bootenv.rc file.
 753  */
 754 /*ARGSUSED*/
 755 void
 756 bcons_init2(char *inputdev, char *outputdev, char *consoledev)
 757 {
 758         int cons = CONS_INVALID;
 759         int ttyn;
 760         char *devnames[] = { consoledev, outputdev, inputdev, NULL };
 761         console_value_t *consolep;


 890         if (lsr & (SERIAL_BREAK | SERIAL_FRAME |
 891             SERIAL_PARITY | SERIAL_OVERRUN)) {
 892                 if (lsr & SERIAL_OVERRUN) {
 893                         return (inb(port + DAT));
 894                 } else {
 895                         /* Toss the garbage */
 896                         (void) inb(port + DAT);
 897                         return (0);
 898                 }
 899         }
 900         return (inb(port + DAT));
 901 }
 902 
 903 static int
 904 serial_ischar(void)
 905 {
 906         return (inb(port + LSR) & RCA);
 907 }
 908 
 909 static void
 910 _doputchar(int c)
 911 {
 912         switch (console) {
















































































































































































 913         case CONS_TTY:
 914                 serial_putchar(c);
 915                 return;
 916         case CONS_SCREEN_TEXT:
 917                 screen_putchar(c);



 918                 return;
 919         case CONS_SCREEN_GRAPHICS:
 920 #if !defined(_BOOT)
 921         case CONS_USBSER:
 922                 defcons_putchar(c);
 923 #endif /* _BOOT */

 924                 return;
 925         }
 926 }
 927 
 928 void
 929 bcons_putchar(int c)
 930 {
 931         static int bhcharpos = 0;
 932 
 933 #if defined(__xpv)
 934         if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
 935             console == CONS_HYPERVISOR) {
 936                 bcons_putchar_xen(c);
 937                 return;
 938         }
 939 #endif /* __xpv */
 940 
 941         if (c == '\t') {
 942                 do {
 943                         _doputchar(' ');
 944                 } while (++bhcharpos % 8);
 945                 return;
 946         } else  if (c == '\n' || c == '\r') {
 947                 bhcharpos = 0;
 948                 _doputchar('\r');
 949                 _doputchar(c);
 950                 return;
 951         } else if (c == '\b') {
 952                 if (bhcharpos)
 953                         bhcharpos--;
 954                 _doputchar(c);
 955                 return;
 956         }
 957 
 958         bhcharpos++;
 959         _doputchar(c);
 960 }
 961 
 962 /*
 963  * kernel character input functions
 964  */
 965 int
 966 bcons_getchar(void)
 967 {
 968 #if defined(__xpv)
 969         if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
 970             console == CONS_HYPERVISOR)
 971                 return (bcons_getchar_xen());
 972 #endif /* __xpv */
 973 
 974         switch (console) {
 975         case CONS_TTY:

 976                 return (serial_getchar());
 977         default:


 978                 return (kb_getchar());
 979         }

 980 }
 981 
 982 #if !defined(_BOOT)
 983 
 984 int
 985 bcons_ischar(void)
 986 {

 987 
 988 #if defined(__xpv)
 989         if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
 990             console == CONS_HYPERVISOR)
 991                 return (bcons_ischar_xen());
 992 #endif /* __xpv */
 993 
 994         switch (console) {
 995         case CONS_TTY:














 996                 return (serial_ischar());




 997         default:
 998                 return (kb_ischar());
 999         }


1000 }
1001 
1002 #endif /* _BOOT */


  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2012 Gary Mills
  23  *
  24  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  25  * Use is subject to license terms.
  26  */
  27 
  28 #include <sys/types.h>
  29 #include <sys/systm.h>
  30 #include <sys/archsystm.h>
  31 #include <sys/framebuffer.h>
  32 #include <sys/boot_console.h>
  33 #include <sys/panic.h>
  34 #include <sys/ctype.h>
  35 #include <sys/ascii.h>
  36 #if defined(__xpv)
  37 #include <sys/hypervisor.h>
  38 #endif /* __xpv */
  39 
  40 #include "boot_console_impl.h"
  41 #include "boot_serial.h"
  42 #include "boot_vga.h"
  43 
  44 #if defined(_BOOT)
  45 #include <dboot/dboot_asm.h>
  46 #include <dboot/dboot_xboot.h>
  47 #else /* _BOOT */
  48 #include <sys/bootconf.h>
  49 #if defined(__xpv)
  50 #include <sys/evtchn_impl.h>
  51 #endif /* __xpv */
  52 static char *defcons_buf;
  53 static char *defcons_cur;
  54 #endif /* _BOOT */
  55 
  56 #if defined(__xpv)
  57 extern void bcons_init_xen(char *);
  58 extern void bcons_putchar_xen(int);
  59 extern int bcons_getchar_xen(void);
  60 extern int bcons_ischar_xen(void);
  61 #endif /* __xpv */
  62 
  63 fb_info_t fb_info;
  64 static bcons_dev_t bcons_dev;                           /* Device callbacks */
  65 static int console = CONS_SCREEN_TEXT;
  66 static int diag = CONS_INVALID;
  67 static int tty_num = 0;
  68 static int tty_addr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
  69 static char *boot_line;
  70 static struct boot_env {
  71         char    *be_env;        /* ends with double ascii nul */
  72         size_t  be_size;        /* size of the environment, including nul */
  73 } boot_env;
  74 
  75 /*
  76  * Simple console terminal emulator for early boot.
  77  * We need this to support kmdb, all other console output is supposed
  78  * to be simple text output.
  79  */
  80 typedef enum btem_state_type {
  81         A_STATE_START,
  82         A_STATE_ESC,
  83         A_STATE_CSI,
  84         A_STATE_CSI_QMARK,
  85         A_STATE_CSI_EQUAL
  86 } btem_state_type_t;
  87 
  88 #define BTEM_MAXPARAMS  5
  89 typedef struct btem_state {
  90         btem_state_type_t btem_state;
  91         boolean_t btem_gotparam;
  92         int btem_curparam;
  93         int btem_paramval;
  94         int btem_params[BTEM_MAXPARAMS];
  95 } btem_state_t;
  96 
  97 static btem_state_t boot_tem;
  98 
  99 static int serial_ischar(void);
 100 static int serial_getchar(void);
 101 static void serial_putchar(int);
 102 static void serial_adjust_prop(void);
 103 
 104 #if !defined(_BOOT)
 105 /* Set if the console or mode are expressed in the boot line */
 106 static int console_set, console_mode_set;
 107 #endif
 108 
 109 #if defined(__xpv)
 110 static int console_hypervisor_redirect = B_FALSE;
 111 static int console_hypervisor_device = CONS_INVALID;
 112 static int console_hypervisor_tty_num = 0;
 113 
 114 /* Obtain the hypervisor console type */
 115 int
 116 console_hypervisor_dev_type(int *tnum)
 117 {
 118         if (tnum != NULL)
 119                 *tnum = console_hypervisor_tty_num;
 120         return (console_hypervisor_device);
 121 }
 122 #endif /* __xpv */
 123 





























































 124 static int port;
 125 
 126 static void
 127 serial_init(void)
 128 {
 129         port = tty_addr[tty_num];
 130 
 131         outb(port + ISR, 0x20);
 132         if (inb(port + ISR) & 0x20) {
 133                 /*
 134                  * 82510 chip is present
 135                  */
 136                 outb(port + DAT+7, 0x04);       /* clear status */
 137                 outb(port + ISR, 0x40);  /* set to bank 2 */
 138                 outb(port + MCR, 0x08);  /* IMD */
 139                 outb(port + DAT, 0x21);  /* FMD */
 140                 outb(port + ISR, 0x00);  /* set to bank 0 */
 141         } else {
 142                 /*
 143                  * set the UART in FIFO mode if it has FIFO buffers.


 154                         /*
 155                          * no fifo buffers so disable fifos.
 156                          * this is true for 8250's
 157                          */
 158                         outb(port + FIFOR, 0x00);
 159                 }
 160         }
 161 
 162         /* disable interrupts */
 163         outb(port + ICR, 0);
 164 
 165 #if !defined(_BOOT)
 166         if (IN_XPV_PANIC())
 167                 return;
 168 #endif
 169 
 170         /* adjust setting based on tty properties */
 171         serial_adjust_prop();
 172 
 173 #if defined(_BOOT)
 174 #if 0
 175         /*
 176          * Do a full reset to match console behavior.
 177          * 0x1B + c - reset everything
 178          */
 179         serial_putchar(0x1B);
 180         serial_putchar('c');
 181 #endif
 182 #endif
 183 }
 184 
 185 /* Advance str pointer past white space */
 186 #define EAT_WHITE_SPACE(str)    {                       \
 187         while ((*str != '\0') && ISSPACE(*str))         \
 188                 str++;                                  \
 189 }
 190 
 191 /*
 192  * boot_line is set when we call here.  Search it for the argument name,
 193  * and if found, return a pointer to it.
 194  */
 195 static char *
 196 find_boot_line_prop(const char *name)
 197 {
 198         char *ptr;
 199         char *ret = NULL;
 200         char end_char;
 201         size_t len;
 202 


 558 };
 559 
 560 static void
 561 bcons_init_env(struct xboot_info *xbi)
 562 {
 563         uint32_t i;
 564         struct boot_modules *modules;
 565 
 566         modules = (struct boot_modules *)(uintptr_t)xbi->bi_modules;
 567         for (i = 0; i < xbi->bi_module_cnt; i++) {
 568                 if (modules[i].bm_type == BMT_ENV)
 569                         break;
 570         }
 571         if (i == xbi->bi_module_cnt)
 572                 return;
 573 
 574         boot_env.be_env = (char *)(uintptr_t)modules[i].bm_addr;
 575         boot_env.be_size = modules[i].bm_size;
 576 }
 577 
 578 int
 579 boot_fb(struct xboot_info *xbi, int console)
 580 {
 581         if (xbi_fb_init(xbi, &bcons_dev) == B_FALSE)
 582                 return (console);
 583 
 584         /* FB address is not set, fall back to serial terminal. */
 585         if (fb_info.paddr == 0) {
 586                 return (CONS_TTY);
 587         }
 588 
 589         fb_info.terminal.x = VGA_TEXT_COLS;
 590         fb_info.terminal.y = VGA_TEXT_ROWS;
 591         boot_fb_init(CONS_FRAMEBUFFER);
 592 
 593         if (console == CONS_SCREEN_TEXT)
 594                 return (CONS_FRAMEBUFFER);
 595         return (console);
 596 }
 597 
 598 /*
 599  * TODO.
 600  * quick and dirty local atoi. Perhaps should build with strtol, but
 601  * dboot & early boot mix does overcomplicate things much.
 602  * Stolen from libc anyhow.
 603  */
 604 static int
 605 atoi(const char *p)
 606 {
 607         int n, c, neg = 0;
 608         unsigned char *up = (unsigned char *)p;
 609 
 610         if (!isdigit(c = *up)) {
 611                 while (isspace(c))
 612                         c = *++up;
 613                 switch (c) {
 614                 case '-':
 615                         neg++;
 616                         /* FALLTHROUGH */
 617                 case '+':
 618                         c = *++up;
 619                 }
 620                 if (!isdigit(c))
 621                         return (0);
 622         }
 623         for (n = '0' - c; isdigit(c = *++up); ) {
 624                 n *= 10; /* two steps to avoid unnecessary overflow */
 625                 n += '0' - c; /* accum neg to avoid surprises at MAX */
 626         }
 627         return (neg ? n : -n);
 628 }
 629 
 630 static void
 631 bcons_init_fb(void)
 632 {
 633         const char *propval;
 634         int intval;
 635 
 636         /* initialize with explicit default values */
 637         fb_info.fg_color = CONS_COLOR;
 638         fb_info.bg_color = 0;
 639         fb_info.inverse = B_FALSE;
 640         fb_info.inverse_screen = B_FALSE;
 641 
 642         /* color values are 0 - 7 */
 643         propval = find_boot_prop("tem.fg_color");
 644         if (propval != NULL) {
 645                 intval = atoi(propval);
 646                 if (intval >= 0 && intval <= 7)
 647                         fb_info.fg_color = intval;
 648         }
 649 
 650         /* color values are 0 - 7 */
 651         propval = find_boot_prop("tem.bg_color");
 652         if (propval != NULL && ISDIGIT(*propval)) {
 653                 intval = atoi(propval);
 654                 if (intval >= 0 && intval <= 7)
 655                         fb_info.bg_color = intval;
 656         }
 657 
 658         /* get inverses. allow 0, 1, true, false */
 659         propval = find_boot_prop("tem.inverse");
 660         if (propval != NULL) {
 661                 if (*propval == '1' || MATCHES(propval, "true"))
 662                         fb_info.inverse = B_TRUE;
 663         }
 664 
 665         propval = find_boot_prop("tem.inverse-screen");
 666         if (propval != NULL) {
 667                 if (*propval == '1' || MATCHES(propval, "true"))
 668                         fb_info.inverse_screen = B_TRUE;
 669         }
 670 
 671 #if defined(_BOOT)
 672         /*
 673          * Load cursor position from bootloader only in dboot,
 674          * dboot will pass cursor position to kernel via xboot info.
 675          */
 676         propval = find_boot_prop("tem.cursor.row");
 677         if (propval != NULL) {
 678                 intval = atoi(propval);
 679                 if (intval >= 0 && intval <= 0xFFFF)
 680                         fb_info.cursor.pos.y = intval;
 681         }
 682 
 683         propval = find_boot_prop("tem.cursor.col");
 684         if (propval != NULL) {
 685                 intval = atoi(propval);
 686                 if (intval >= 0 && intval <= 0xFFFF)
 687                         fb_info.cursor.pos.x = intval;
 688         }
 689 #endif
 690 }
 691 
 692 /*
 693  * Go through the console_devices array trying to match the string
 694  * we were given.  The string on the command line must end with
 695  * a comma or white space.
 696  *
 697  * Eventually we need to rework this to process dual console setup.
 698  * This function does set tty_num as an side effect.
 699  */
 700 static int
 701 lookup_console_devices(const char *cons_str)
 702 {
 703         int n, cons;
 704         size_t len, cons_len;
 705         console_value_t *consolep;
 706 
 707         cons = CONS_INVALID;
 708         if (cons_str != NULL) {
 709 
 710                 cons_len = strlen(cons_str);
 711                 for (n = 0; console_devices[n].name != NULL; n++) {
 712                         consolep = &console_devices[n];
 713                         len = strlen(consolep->name);
 714                         if ((len <= cons_len) && ((cons_str[len] == '\0') ||
 715                             (cons_str[len] == ',') || (cons_str[len] == '\'') ||
 716                             (cons_str[len] == '"') || ISSPACE(cons_str[len])) &&
 717                             (strncmp(cons_str, consolep->name, len) == 0)) {
 718                                 cons = consolep->value;
 719                                 if (cons == CONS_TTY)
 720                                         tty_num = n;
 721                                 break;
 722                         }
 723                 }
 724         }
 725         return (cons);
 726 }
 727 
 728 void
 729 bcons_init(struct xboot_info *xbi)
 730 {


 731         const char *cons_str;
 732 #if !defined(_BOOT)
 733         static char console_text[] = "text";
 734         extern int post_fastreboot;
 735 #endif
 736 
 737         if (xbi == NULL) {
 738                 /* This is very early dboot console, set up ttya. */
 739                 console = CONS_TTY;
 740                 serial_init();
 741                 return;
 742         }
 743 
 744         /* Set up data to fetch properties from commad line and boot env. */
 745         boot_line = (char *)(uintptr_t)xbi->bi_cmdline;
 746         bcons_init_env(xbi);
 747         console = CONS_INVALID;
 748 
 749         /* set up initial fb_info */
 750         bcons_init_fb();
 751 
 752 #if defined(__xpv)
 753         bcons_init_xen(boot_line);
 754 #endif /* __xpv */
 755 
 756         /*
 757          * First check for diag-device.
 758          */
 759         cons_str = find_boot_prop("diag-device");
 760         if (cons_str != NULL) {
 761                 diag = lookup_console_devices(cons_str);
 762                 serial_init();
 763         }
 764 
 765         cons_str = find_boot_prop("console");
 766         if (cons_str == NULL)
 767                 cons_str = find_boot_prop("output-device");
 768 
 769 #if !defined(_BOOT)
 770         if (post_fastreboot && strcmp(cons_str, "graphics") == 0)
 771                 cons_str = console_text;
 772 #endif
 773 
 774         if (cons_str != NULL)
 775                 console = lookup_console_devices(cons_str);





 776 
















 777 #if defined(__xpv)
 778         /*
 779          * domU's always use the hypervisor regardless of what
 780          * the console variable may be set to.
 781          */
 782         if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
 783                 console = CONS_HYPERVISOR;
 784                 console_hypervisor_redirect = B_TRUE;
 785         }
 786 #endif /* __xpv */
 787 
 788         /*
 789          * If no console device specified, default to text.
 790          * Remember what was specified for second phase.
 791          */
 792         if (console == CONS_INVALID)
 793                 console = CONS_SCREEN_TEXT;
 794 #if !defined(_BOOT)
 795         else
 796                 console_set = 1;


 814                                  * true console mode.  Hence, we're going
 815                                  * to ignore this xen "console" setting.
 816                                  */
 817                                 /*FALLTHROUGH*/
 818                         default:
 819                                 console_hypervisor_device = CONS_INVALID;
 820                 }
 821         }
 822 
 823         /*
 824          * if the hypervisor is using the currently selected serial
 825          * port then default to using the hypervisor as the console
 826          * device.
 827          */
 828         if (console == console_hypervisor_device) {
 829                 console = CONS_HYPERVISOR;
 830                 console_hypervisor_redirect = B_TRUE;
 831         }
 832 #endif /* __xpv */
 833 
 834         /* make sure the FB is set up if present */
 835         console = boot_fb(xbi, console);
 836         switch (console) {
 837         case CONS_TTY:
 838                 serial_init();
 839                 break;
 840 
 841         case CONS_HYPERVISOR:
 842                 break;
 843 
 844 #if !defined(_BOOT)
 845         case CONS_USBSER:
 846                 /*
 847                  * We can't do anything with the usb serial
 848                  * until we have memory management.
 849                  */
 850                 break;
 851 #endif
 852         case CONS_SCREEN_GRAPHICS:
 853                 kb_init();
 854                 break;
 855         case CONS_SCREEN_TEXT:
 856                 boot_vga_init(&bcons_dev);
 857                 /* Fall through */
 858         default:



 859                 kb_init();
 860                 break;
 861         }
 862 }
 863 
 864 #if !defined(_BOOT)
 865 /*
 866  * 2nd part of console initialization.
 867  * In the kernel (ie. fakebop), this can be used only to switch to
 868  * using a serial port instead of screen based on the contents
 869  * of the bootenv.rc file.
 870  */
 871 /*ARGSUSED*/
 872 void
 873 bcons_init2(char *inputdev, char *outputdev, char *consoledev)
 874 {
 875         int cons = CONS_INVALID;
 876         int ttyn;
 877         char *devnames[] = { consoledev, outputdev, inputdev, NULL };
 878         console_value_t *consolep;


1007         if (lsr & (SERIAL_BREAK | SERIAL_FRAME |
1008             SERIAL_PARITY | SERIAL_OVERRUN)) {
1009                 if (lsr & SERIAL_OVERRUN) {
1010                         return (inb(port + DAT));
1011                 } else {
1012                         /* Toss the garbage */
1013                         (void) inb(port + DAT);
1014                         return (0);
1015                 }
1016         }
1017         return (inb(port + DAT));
1018 }
1019 
1020 static int
1021 serial_ischar(void)
1022 {
1023         return (inb(port + LSR) & RCA);
1024 }
1025 
1026 static void
1027 btem_control(btem_state_t *btem, int c)
1028 {
1029         int y, rows, cols;
1030 
1031         rows = fb_info.cursor.pos.y;
1032         cols = fb_info.cursor.pos.x;
1033 
1034         btem->btem_state = A_STATE_START;
1035         switch (c) {
1036         case A_BS:
1037                 bcons_dev.bd_setpos(rows, cols - 1);
1038                 break;
1039 
1040         case A_HT:
1041                 cols += 8 - (cols % 8);
1042                 if (cols == fb_info.terminal.x)
1043                         cols = fb_info.terminal.x - 1;
1044                 bcons_dev.bd_setpos(rows, cols);
1045                 break;
1046 
1047         case A_CR:
1048                 bcons_dev.bd_setpos(rows, 0);
1049                 break;
1050 
1051         case A_FF:
1052                 for (y = 0; y < fb_info.terminal.y; y++) {
1053                         bcons_dev.bd_setpos(y, 0);
1054                         bcons_dev.bd_eraseline();
1055                 }
1056                 bcons_dev.bd_setpos(0, 0);
1057                 break;
1058 
1059         case A_ESC:
1060                 btem->btem_state = A_STATE_ESC;
1061                 break;
1062 
1063         default:
1064                 bcons_dev.bd_putchar(c);
1065                 break;
1066         }
1067 }
1068 
1069 /*
1070  * if parameters [0..count - 1] are not set, set them to the value
1071  * of newparam.
1072  */
1073 static void
1074 btem_setparam(btem_state_t *btem, int count, int newparam)
1075 {
1076         int i;
1077 
1078         for (i = 0; i < count; i++) {
1079                 if (btem->btem_params[i] == -1)
1080                         btem->btem_params[i] = newparam;
1081         }
1082 }
1083 
1084 static void
1085 btem_chkparam(btem_state_t *btem, int c)
1086 {
1087         int rows, cols;
1088 
1089         rows = fb_info.cursor.pos.y;
1090         cols = fb_info.cursor.pos.x;
1091         switch (c) {
1092         case '@':                       /* insert char */
1093                 btem_setparam(btem, 1, 1);
1094                 bcons_dev.bd_shift(btem->btem_params[0]);
1095                 break;
1096 
1097         case 'A':                       /* cursor up */
1098                 btem_setparam(btem, 1, 1);
1099                 bcons_dev.bd_setpos(rows - btem->btem_params[0], cols);
1100                 break;
1101 
1102         case 'B':                       /* cursor down */
1103                 btem_setparam(btem, 1, 1);
1104                 bcons_dev.bd_setpos(rows + btem->btem_params[0], cols);
1105                 break;
1106 
1107         case 'C':                       /* cursor right */
1108                 btem_setparam(btem, 1, 1);
1109                 bcons_dev.bd_setpos(rows, cols + btem->btem_params[0]);
1110                 break;
1111 
1112         case 'D':                       /* cursor left */
1113                 btem_setparam(btem, 1, 1);
1114                 bcons_dev.bd_setpos(rows, cols - btem->btem_params[0]);
1115                 break;
1116 
1117         case 'K':
1118                 bcons_dev.bd_eraseline();
1119                 break;
1120         default:
1121                 /* bcons_dev.bd_putchar(c); */
1122                 break;
1123         }
1124         btem->btem_state = A_STATE_START;
1125 }
1126 
1127 static void
1128 btem_getparams(btem_state_t *btem, int c)
1129 {
1130         if (c >= '0' && c <= '9') {
1131                 btem->btem_paramval = btem->btem_paramval * 10 + c - '0';
1132                 btem->btem_gotparam = B_TRUE;
1133                 return;
1134         }
1135 
1136         if (btem->btem_curparam < BTEM_MAXPARAMS) {
1137                 if (btem->btem_gotparam == B_TRUE) {
1138                         btem->btem_params[btem->btem_curparam] =
1139                             btem->btem_paramval;
1140                 }
1141                 btem->btem_curparam++;
1142         }
1143 
1144         if (c == ';') {
1145                 /* Restart parameter search */
1146                 btem->btem_gotparam = B_FALSE;
1147                 btem->btem_paramval = 0;
1148         } else {
1149                 btem_chkparam(btem, c);
1150         }
1151 }
1152 
1153 /* Simple boot terminal parser. */
1154 static void
1155 btem_parse(btem_state_t *btem, int c)
1156 {
1157         int i;
1158 
1159         /* Normal state? */
1160         if (btem->btem_state == A_STATE_START) {
1161                 if (c == A_CSI || c < ' ')
1162                         btem_control(btem, c);
1163                 else
1164                         bcons_dev.bd_putchar(c);
1165                 return;
1166         }
1167 
1168         /* In <ESC> sequence */
1169         if (btem->btem_state != A_STATE_ESC) {
1170                 btem_getparams(btem, c);
1171                 return;
1172         }
1173 
1174         /* Previous char was <ESC> */
1175         switch (c) {
1176         case '[':
1177                 btem->btem_curparam = 0;
1178                 btem->btem_paramval = 0;
1179                 btem->btem_gotparam = B_FALSE;
1180                 /* clear the parameters */
1181                 for (i = 0; i < BTEM_MAXPARAMS; i++)
1182                         btem->btem_params[i] = -1;
1183                 btem->btem_state = A_STATE_CSI;
1184                 return;
1185 
1186         case 'Q':       /* <ESC>Q */
1187         case 'C':       /* <ESC>C */
1188                 btem->btem_state = A_STATE_START;
1189                 return;
1190 
1191         default:
1192                 btem->btem_state = A_STATE_START;
1193                 break;
1194         }
1195 
1196         if (c < ' ')
1197                 btem_control(btem, c);
1198         else
1199                 bcons_dev.bd_putchar(c);
1200 }
1201 
1202 static void
1203 _doputchar(int device, int c)
1204 {
1205         switch (device) {
1206         case CONS_TTY:
1207                 serial_putchar(c);
1208                 return;
1209         case CONS_SCREEN_TEXT:
1210         case CONS_FRAMEBUFFER:
1211                 bcons_dev.bd_cursor(B_FALSE);
1212                 btem_parse(&boot_tem, c);
1213                 bcons_dev.bd_cursor(B_TRUE);
1214                 return;
1215         case CONS_SCREEN_GRAPHICS:
1216 #if !defined(_BOOT)
1217         case CONS_USBSER:
1218                 defcons_putchar(c);
1219 #endif /* _BOOT */
1220         default:
1221                 return;
1222         }
1223 }
1224 
1225 void
1226 bcons_putchar(int c)
1227 {


1228 #if defined(__xpv)
1229         if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
1230             console == CONS_HYPERVISOR) {
1231                 bcons_putchar_xen(c);
1232                 return;
1233         }
1234 #endif /* __xpv */
1235 
1236         if (c == '\n') {
1237                 _doputchar(console, '\r');
1238                 if (diag != console)
1239                         _doputchar(diag, '\r');











1240         }
1241         _doputchar(console, c);
1242         if (diag != console)
1243                 _doputchar(diag, c);
1244 }
1245 
1246 /*
1247  * kernel character input functions
1248  */
1249 int
1250 bcons_getchar(void)
1251 {
1252 #if defined(__xpv)
1253         if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
1254             console == CONS_HYPERVISOR)
1255                 return (bcons_getchar_xen());
1256 #endif /* __xpv */
1257 
1258         for (;;) {
1259                 if (console == CONS_TTY || diag == CONS_TTY) {
1260                         if (serial_ischar())
1261                                 return (serial_getchar());
1262                 }
1263                 if (console != CONS_INVALID || diag != CONS_INVALID) {
1264                         if (kb_ischar())
1265                                 return (kb_getchar());
1266                 }
1267         }
1268 }
1269 
1270 #if !defined(_BOOT)
1271 
1272 int
1273 bcons_ischar(void)
1274 {
1275         int c = 0;
1276 
1277 #if defined(__xpv)
1278         if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
1279             console == CONS_HYPERVISOR)
1280                 return (bcons_ischar_xen());
1281 #endif /* __xpv */
1282 
1283         switch (console) {
1284         case CONS_TTY:
1285                 c = serial_ischar();
1286                 break;
1287 
1288         case CONS_INVALID:
1289                 break;
1290 
1291         default:
1292                 c = kb_ischar();
1293         }
1294         if (c != 0)
1295                 return (c);
1296 
1297         switch (diag) {
1298         case CONS_TTY:
1299                 return (serial_ischar());
1300 
1301         case CONS_INVALID:
1302                 break;
1303 
1304         default:
1305                 return (kb_ischar());
1306         }
1307 
1308         return (c);
1309 }
1310 
1311 #endif /* _BOOT */