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>
        
*** 26,42 ****
--- 26,45 ----
   */
  
  #include <sys/types.h>
  #include <sys/systm.h>
  #include <sys/archsystm.h>
+ #include <sys/framebuffer.h>
  #include <sys/boot_console.h>
  #include <sys/panic.h>
  #include <sys/ctype.h>
+ #include <sys/ascii.h>
  #if defined(__xpv)
  #include <sys/hypervisor.h>
  #endif /* __xpv */
  
+ #include "boot_console_impl.h"
  #include "boot_serial.h"
  #include "boot_vga.h"
  
  #if defined(_BOOT)
  #include <dboot/dboot_asm.h>
*** 55,74 ****
  extern void bcons_putchar_xen(int);
  extern int bcons_getchar_xen(void);
  extern int bcons_ischar_xen(void);
  #endif /* __xpv */
  
! static int cons_color = CONS_COLOR;
  static int console = CONS_SCREEN_TEXT;
  static int tty_num = 0;
  static int tty_addr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
  static char *boot_line;
  static struct boot_env {
          char    *be_env;        /* ends with double ascii nul */
          size_t  be_size;        /* size of the environment, including nul */
  } boot_env;
  
  static int serial_ischar(void);
  static int serial_getchar(void);
  static void serial_putchar(int);
  static void serial_adjust_prop(void);
  
--- 58,103 ----
  extern void bcons_putchar_xen(int);
  extern int bcons_getchar_xen(void);
  extern int bcons_ischar_xen(void);
  #endif /* __xpv */
  
! fb_info_t fb_info;
! static bcons_dev_t bcons_dev;                           /* Device callbacks */
  static int console = CONS_SCREEN_TEXT;
+ static int diag = CONS_INVALID;
  static int tty_num = 0;
  static int tty_addr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
  static char *boot_line;
  static struct boot_env {
          char    *be_env;        /* ends with double ascii nul */
          size_t  be_size;        /* size of the environment, including nul */
  } boot_env;
  
+ /*
+  * Simple console terminal emulator for early boot.
+  * We need this to support kmdb, all other console output is supposed
+  * to be simple text output.
+  */
+ typedef enum btem_state_type {
+         A_STATE_START,
+         A_STATE_ESC,
+         A_STATE_CSI,
+         A_STATE_CSI_QMARK,
+         A_STATE_CSI_EQUAL
+ } btem_state_type_t;
+ 
+ #define BTEM_MAXPARAMS  5
+ typedef struct btem_state {
+         btem_state_type_t btem_state;
+         boolean_t btem_gotparam;
+         int btem_curparam;
+         int btem_paramval;
+         int btem_params[BTEM_MAXPARAMS];
+ } btem_state_t;
+ 
+ static btem_state_t boot_tem;
+ 
  static int serial_ischar(void);
  static int serial_getchar(void);
  static void serial_putchar(int);
  static void serial_adjust_prop(void);
  
*** 90,160 ****
                  *tnum = console_hypervisor_tty_num;
          return (console_hypervisor_device);
  }
  #endif /* __xpv */
  
- /* Clear the screen and initialize VIDEO, XPOS and YPOS. */
- void
- clear_screen(void)
- {
-         /*
-          * XXX should set vga mode so we don't depend on the
-          * state left by the boot loader.  Note that we have to
-          * enable the cursor before clearing the screen since
-          * the cursor position is dependant upon the cursor
-          * skew, which is initialized by vga_cursor_display()
-          */
-         vga_cursor_display();
-         vga_clear(cons_color);
-         vga_setpos(0, 0);
- }
- 
- /* Put the character C on the screen. */
- static void
- screen_putchar(int c)
- {
-         int row, col;
- 
-         vga_getpos(&row, &col);
-         switch (c) {
-         case '\t':
-                 col += 8 - (col % 8);
-                 if (col == VGA_TEXT_COLS)
-                         col = 79;
-                 vga_setpos(row, col);
-                 break;
- 
-         case '\r':
-                 vga_setpos(row, 0);
-                 break;
- 
-         case '\b':
-                 if (col > 0)
-                         vga_setpos(row, col - 1);
-                 break;
- 
-         case '\n':
-                 if (row < VGA_TEXT_ROWS - 1)
-                         vga_setpos(row + 1, col);
-                 else
-                         vga_scroll(cons_color);
-                 break;
- 
-         default:
-                 vga_drawc(c, cons_color);
-                 if (col < VGA_TEXT_COLS -1)
-                         vga_setpos(row, col + 1);
-                 else if (row < VGA_TEXT_ROWS - 1)
-                         vga_setpos(row + 1, 0);
-                 else {
-                         vga_setpos(row, 0);
-                         vga_scroll(cons_color);
-                 }
-                 break;
-         }
- }
- 
  static int port;
  
  static void
  serial_init(void)
  {
--- 119,128 ----
*** 201,217 ****
--- 169,187 ----
  
          /* adjust setting based on tty properties */
          serial_adjust_prop();
  
  #if defined(_BOOT)
+ #if 0
          /*
           * Do a full reset to match console behavior.
           * 0x1B + c - reset everything
           */
          serial_putchar(0x1B);
          serial_putchar('c');
  #endif
+ #endif
  }
  
  /* Advance str pointer past white space */
  #define EAT_WHITE_SPACE(str)    {                       \
          while ((*str != '\0') && ISSPACE(*str))         \
*** 603,665 ****
  
          boot_env.be_env = (char *)(uintptr_t)modules[i].bm_addr;
          boot_env.be_size = modules[i].bm_size;
  }
  
  void
  bcons_init(struct xboot_info *xbi)
  {
-         console_value_t *consolep;
-         size_t len, cons_len;
          const char *cons_str;
  #if !defined(_BOOT)
          static char console_text[] = "text";
          extern int post_fastreboot;
  #endif
  
          /* Set up data to fetch properties from commad line and boot env. */
          boot_line = (char *)(uintptr_t)xbi->bi_cmdline;
          bcons_init_env(xbi);
          console = CONS_INVALID;
  
  #if defined(__xpv)
          bcons_init_xen(boot_line);
  #endif /* __xpv */
  
          cons_str = find_boot_prop("console");
          if (cons_str == NULL)
                  cons_str = find_boot_prop("output-device");
  
  #if !defined(_BOOT)
          if (post_fastreboot && strcmp(cons_str, "graphics") == 0)
                  cons_str = console_text;
  #endif
  
!         /*
!          * Go through the console_devices array trying to match the string
!          * we were given.  The string on the command line must end with
!          * a comma or white space.
!          */
!         if (cons_str != NULL) {
!                 int n;
  
-                 cons_len = strlen(cons_str);
-                 for (n = 0; console_devices[n].name != NULL; n++) {
-                         consolep = &console_devices[n];
-                         len = strlen(consolep->name);
-                         if ((len <= cons_len) && ((cons_str[len] == '\0') ||
-                             (cons_str[len] == ',') || (cons_str[len] == '\'') ||
-                             (cons_str[len] == '"') || ISSPACE(cons_str[len])) &&
-                             (strncmp(cons_str, consolep->name, len) == 0)) {
-                                 console = consolep->value;
-                                 if (console == CONS_TTY)
-                                         tty_num = n;
-                                 break;
-                         }
-                 }
-         }
- 
  #if defined(__xpv)
          /*
           * domU's always use the hypervisor regardless of what
           * the console variable may be set to.
           */
--- 573,781 ----
  
          boot_env.be_env = (char *)(uintptr_t)modules[i].bm_addr;
          boot_env.be_size = modules[i].bm_size;
  }
  
+ int
+ boot_fb(struct xboot_info *xbi, int console)
+ {
+         if (xbi_fb_init(xbi, &bcons_dev) == B_FALSE)
+                 return (console);
+ 
+         /* FB address is not set, fall back to serial terminal. */
+         if (fb_info.paddr == 0) {
+                 return (CONS_TTY);
+         }
+ 
+         fb_info.terminal.x = VGA_TEXT_COLS;
+         fb_info.terminal.y = VGA_TEXT_ROWS;
+         boot_fb_init(CONS_FRAMEBUFFER);
+ 
+         if (console == CONS_SCREEN_TEXT)
+                 return (CONS_FRAMEBUFFER);
+         return (console);
+ }
+ 
+ /*
+  * TODO.
+  * quick and dirty local atoi. Perhaps should build with strtol, but
+  * dboot & early boot mix does overcomplicate things much.
+  * Stolen from libc anyhow.
+  */
+ static int
+ atoi(const char *p)
+ {
+         int n, c, neg = 0;
+         unsigned char *up = (unsigned char *)p;
+ 
+         if (!isdigit(c = *up)) {
+                 while (isspace(c))
+                         c = *++up;
+                 switch (c) {
+                 case '-':
+                         neg++;
+                         /* FALLTHROUGH */
+                 case '+':
+                         c = *++up;
+                 }
+                 if (!isdigit(c))
+                         return (0);
+         }
+         for (n = '0' - c; isdigit(c = *++up); ) {
+                 n *= 10; /* two steps to avoid unnecessary overflow */
+                 n += '0' - c; /* accum neg to avoid surprises at MAX */
+         }
+         return (neg ? n : -n);
+ }
+ 
+ static void
+ bcons_init_fb(void)
+ {
+         const char *propval;
+         int intval;
+ 
+         /* initialize with explicit default values */
+         fb_info.fg_color = CONS_COLOR;
+         fb_info.bg_color = 0;
+         fb_info.inverse = B_FALSE;
+         fb_info.inverse_screen = B_FALSE;
+ 
+         /* color values are 0 - 7 */
+         propval = find_boot_prop("tem.fg_color");
+         if (propval != NULL) {
+                 intval = atoi(propval);
+                 if (intval >= 0 && intval <= 7)
+                         fb_info.fg_color = intval;
+         }
+ 
+         /* color values are 0 - 7 */
+         propval = find_boot_prop("tem.bg_color");
+         if (propval != NULL && ISDIGIT(*propval)) {
+                 intval = atoi(propval);
+                 if (intval >= 0 && intval <= 7)
+                         fb_info.bg_color = intval;
+         }
+ 
+         /* get inverses. allow 0, 1, true, false */
+         propval = find_boot_prop("tem.inverse");
+         if (propval != NULL) {
+                 if (*propval == '1' || MATCHES(propval, "true"))
+                         fb_info.inverse = B_TRUE;
+         }
+ 
+         propval = find_boot_prop("tem.inverse-screen");
+         if (propval != NULL) {
+                 if (*propval == '1' || MATCHES(propval, "true"))
+                         fb_info.inverse_screen = B_TRUE;
+         }
+ 
+ #if defined(_BOOT)
+         /*
+          * Load cursor position from bootloader only in dboot,
+          * dboot will pass cursor position to kernel via xboot info.
+          */
+         propval = find_boot_prop("tem.cursor.row");
+         if (propval != NULL) {
+                 intval = atoi(propval);
+                 if (intval >= 0 && intval <= 0xFFFF)
+                         fb_info.cursor.pos.y = intval;
+         }
+ 
+         propval = find_boot_prop("tem.cursor.col");
+         if (propval != NULL) {
+                 intval = atoi(propval);
+                 if (intval >= 0 && intval <= 0xFFFF)
+                         fb_info.cursor.pos.x = intval;
+         }
+ #endif
+ }
+ 
+ /*
+  * Go through the console_devices array trying to match the string
+  * we were given.  The string on the command line must end with
+  * a comma or white space.
+  *
+  * Eventually we need to rework this to process dual console setup.
+  * This function does set tty_num as an side effect.
+  */
+ static int
+ lookup_console_devices(const char *cons_str)
+ {
+         int n, cons;
+         size_t len, cons_len;
+         console_value_t *consolep;
+ 
+         cons = CONS_INVALID;
+         if (cons_str != NULL) {
+ 
+                 cons_len = strlen(cons_str);
+                 for (n = 0; console_devices[n].name != NULL; n++) {
+                         consolep = &console_devices[n];
+                         len = strlen(consolep->name);
+                         if ((len <= cons_len) && ((cons_str[len] == '\0') ||
+                             (cons_str[len] == ',') || (cons_str[len] == '\'') ||
+                             (cons_str[len] == '"') || ISSPACE(cons_str[len])) &&
+                             (strncmp(cons_str, consolep->name, len) == 0)) {
+                                 cons = consolep->value;
+                                 if (cons == CONS_TTY)
+                                         tty_num = n;
+                                 break;
+                         }
+                 }
+         }
+         return (cons);
+ }
+ 
  void
  bcons_init(struct xboot_info *xbi)
  {
          const char *cons_str;
  #if !defined(_BOOT)
          static char console_text[] = "text";
          extern int post_fastreboot;
  #endif
  
+         if (xbi == NULL) {
+                 /* This is very early dboot console, set up ttya. */
+                 console = CONS_TTY;
+                 serial_init();
+                 return;
+         }
+ 
          /* Set up data to fetch properties from commad line and boot env. */
          boot_line = (char *)(uintptr_t)xbi->bi_cmdline;
          bcons_init_env(xbi);
          console = CONS_INVALID;
  
+         /* set up initial fb_info */
+         bcons_init_fb();
+ 
  #if defined(__xpv)
          bcons_init_xen(boot_line);
  #endif /* __xpv */
  
+         /*
+          * First check for diag-device.
+          */
+         cons_str = find_boot_prop("diag-device");
+         if (cons_str != NULL) {
+                 diag = lookup_console_devices(cons_str);
+                 serial_init();
+         }
+ 
          cons_str = find_boot_prop("console");
          if (cons_str == NULL)
                  cons_str = find_boot_prop("output-device");
  
  #if !defined(_BOOT)
          if (post_fastreboot && strcmp(cons_str, "graphics") == 0)
                  cons_str = console_text;
  #endif
  
!         if (cons_str != NULL)
!                 console = lookup_console_devices(cons_str);
  
  #if defined(__xpv)
          /*
           * domU's always use the hypervisor regardless of what
           * the console variable may be set to.
           */
*** 713,722 ****
--- 829,840 ----
                  console = CONS_HYPERVISOR;
                  console_hypervisor_redirect = B_TRUE;
          }
  #endif /* __xpv */
  
+         /* make sure the FB is set up if present */
+         console = boot_fb(xbi, console);
          switch (console) {
          case CONS_TTY:
                  serial_init();
                  break;
  
*** 733,746 ****
  #endif
          case CONS_SCREEN_GRAPHICS:
                  kb_init();
                  break;
          case CONS_SCREEN_TEXT:
          default:
- #if defined(_BOOT)
-                 clear_screen(); /* clears the grub or xen screen */
- #endif /* _BOOT */
                  kb_init();
                  break;
          }
  }
  
--- 851,863 ----
  #endif
          case CONS_SCREEN_GRAPHICS:
                  kb_init();
                  break;
          case CONS_SCREEN_TEXT:
+                 boot_vga_init(&bcons_dev);
+                 /* Fall through */
          default:
                  kb_init();
                  break;
          }
  }
  
*** 905,964 ****
  {
          return (inb(port + LSR) & RCA);
  }
  
  static void
! _doputchar(int c)
  {
!         switch (console) {
          case CONS_TTY:
                  serial_putchar(c);
                  return;
          case CONS_SCREEN_TEXT:
!                 screen_putchar(c);
                  return;
          case CONS_SCREEN_GRAPHICS:
  #if !defined(_BOOT)
          case CONS_USBSER:
                  defcons_putchar(c);
  #endif /* _BOOT */
                  return;
          }
  }
  
  void
  bcons_putchar(int c)
  {
-         static int bhcharpos = 0;
- 
  #if defined(__xpv)
          if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
              console == CONS_HYPERVISOR) {
                  bcons_putchar_xen(c);
                  return;
          }
  #endif /* __xpv */
  
!         if (c == '\t') {
!                 do {
!                         _doputchar(' ');
!                 } while (++bhcharpos % 8);
!                 return;
!         } else  if (c == '\n' || c == '\r') {
!                 bhcharpos = 0;
!                 _doputchar('\r');
!                 _doputchar(c);
!                 return;
!         } else if (c == '\b') {
!                 if (bhcharpos)
!                         bhcharpos--;
!                 _doputchar(c);
!                 return;
          }
! 
!         bhcharpos++;
!         _doputchar(c);
  }
  
  /*
   * kernel character input functions
   */
--- 1022,1248 ----
  {
          return (inb(port + LSR) & RCA);
  }
  
  static void
! btem_control(btem_state_t *btem, int c)
  {
!         int y, rows, cols;
! 
!         rows = fb_info.cursor.pos.y;
!         cols = fb_info.cursor.pos.x;
! 
!         btem->btem_state = A_STATE_START;
!         switch (c) {
!         case A_BS:
!                 bcons_dev.bd_setpos(rows, cols - 1);
!                 break;
! 
!         case A_HT:
!                 cols += 8 - (cols % 8);
!                 if (cols == fb_info.terminal.x)
!                         cols = fb_info.terminal.x - 1;
!                 bcons_dev.bd_setpos(rows, cols);
!                 break;
! 
!         case A_CR:
!                 bcons_dev.bd_setpos(rows, 0);
!                 break;
! 
!         case A_FF:
!                 for (y = 0; y < fb_info.terminal.y; y++) {
!                         bcons_dev.bd_setpos(y, 0);
!                         bcons_dev.bd_eraseline();
!                 }
!                 bcons_dev.bd_setpos(0, 0);
!                 break;
! 
!         case A_ESC:
!                 btem->btem_state = A_STATE_ESC;
!                 break;
! 
!         default:
!                 bcons_dev.bd_putchar(c);
!                 break;
!         }
! }
! 
! /*
!  * if parameters [0..count - 1] are not set, set them to the value
!  * of newparam.
!  */
! static void
! btem_setparam(btem_state_t *btem, int count, int newparam)
! {
!         int i;
! 
!         for (i = 0; i < count; i++) {
!                 if (btem->btem_params[i] == -1)
!                         btem->btem_params[i] = newparam;
!         }
! }
! 
! static void
! btem_chkparam(btem_state_t *btem, int c)
! {
!         int rows, cols;
! 
!         rows = fb_info.cursor.pos.y;
!         cols = fb_info.cursor.pos.x;
!         switch (c) {
!         case '@':                       /* insert char */
!                 btem_setparam(btem, 1, 1);
!                 bcons_dev.bd_shift(btem->btem_params[0]);
!                 break;
! 
!         case 'A':                       /* cursor up */
!                 btem_setparam(btem, 1, 1);
!                 bcons_dev.bd_setpos(rows - btem->btem_params[0], cols);
!                 break;
! 
!         case 'B':                       /* cursor down */
!                 btem_setparam(btem, 1, 1);
!                 bcons_dev.bd_setpos(rows + btem->btem_params[0], cols);
!                 break;
! 
!         case 'C':                       /* cursor right */
!                 btem_setparam(btem, 1, 1);
!                 bcons_dev.bd_setpos(rows, cols + btem->btem_params[0]);
!                 break;
! 
!         case 'D':                       /* cursor left */
!                 btem_setparam(btem, 1, 1);
!                 bcons_dev.bd_setpos(rows, cols - btem->btem_params[0]);
!                 break;
! 
!         case 'K':
!                 bcons_dev.bd_eraseline();
!                 break;
!         default:
!                 /* bcons_dev.bd_putchar(c); */
!                 break;
!         }
!         btem->btem_state = A_STATE_START;
! }
! 
! static void
! btem_getparams(btem_state_t *btem, int c)
! {
!         if (c >= '0' && c <= '9') {
!                 btem->btem_paramval = btem->btem_paramval * 10 + c - '0';
!                 btem->btem_gotparam = B_TRUE;
!                 return;
!         }
! 
!         if (btem->btem_curparam < BTEM_MAXPARAMS) {
!                 if (btem->btem_gotparam == B_TRUE) {
!                         btem->btem_params[btem->btem_curparam] =
!                             btem->btem_paramval;
!                 }
!                 btem->btem_curparam++;
!         }
! 
!         if (c == ';') {
!                 /* Restart parameter search */
!                 btem->btem_gotparam = B_FALSE;
!                 btem->btem_paramval = 0;
!         } else {
!                 btem_chkparam(btem, c);
!         }
! }
! 
! /* Simple boot terminal parser. */
! static void
! btem_parse(btem_state_t *btem, int c)
! {
!         int i;
! 
!         /* Normal state? */
!         if (btem->btem_state == A_STATE_START) {
!                 if (c == A_CSI || c < ' ')
!                         btem_control(btem, c);
!                 else
!                         bcons_dev.bd_putchar(c);
!                 return;
!         }
! 
!         /* In <ESC> sequence */
!         if (btem->btem_state != A_STATE_ESC) {
!                 btem_getparams(btem, c);
!                 return;
!         }
! 
!         /* Previous char was <ESC> */
!         switch (c) {
!         case '[':
!                 btem->btem_curparam = 0;
!                 btem->btem_paramval = 0;
!                 btem->btem_gotparam = B_FALSE;
!                 /* clear the parameters */
!                 for (i = 0; i < BTEM_MAXPARAMS; i++)
!                         btem->btem_params[i] = -1;
!                 btem->btem_state = A_STATE_CSI;
!                 return;
! 
!         case 'Q':       /* <ESC>Q */
!         case 'C':       /* <ESC>C */
!                 btem->btem_state = A_STATE_START;
!                 return;
! 
!         default:
!                 btem->btem_state = A_STATE_START;
!                 break;
!         }
! 
!         if (c < ' ')
!                 btem_control(btem, c);
!         else
!                 bcons_dev.bd_putchar(c);
! }
! 
! static void
! _doputchar(int device, int c)
! {
!         switch (device) {
          case CONS_TTY:
                  serial_putchar(c);
                  return;
          case CONS_SCREEN_TEXT:
!         case CONS_FRAMEBUFFER:
!                 bcons_dev.bd_cursor(B_FALSE);
!                 btem_parse(&boot_tem, c);
!                 bcons_dev.bd_cursor(B_TRUE);
                  return;
          case CONS_SCREEN_GRAPHICS:
  #if !defined(_BOOT)
          case CONS_USBSER:
                  defcons_putchar(c);
  #endif /* _BOOT */
+         default:
                  return;
          }
  }
  
  void
  bcons_putchar(int c)
  {
  #if defined(__xpv)
          if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
              console == CONS_HYPERVISOR) {
                  bcons_putchar_xen(c);
                  return;
          }
  #endif /* __xpv */
  
!         if (c == '\n') {
!                 _doputchar(console, '\r');
!                 if (diag != console)
!                         _doputchar(diag, '\r');
          }
!         _doputchar(console, c);
!         if (diag != console)
!                 _doputchar(diag, c);
  }
  
  /*
   * kernel character input functions
   */
*** 969,1002 ****
          if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
              console == CONS_HYPERVISOR)
                  return (bcons_getchar_xen());
  #endif /* __xpv */
  
!         switch (console) {
!         case CONS_TTY:
                  return (serial_getchar());
!         default:
                  return (kb_getchar());
          }
  }
  
  #if !defined(_BOOT)
  
  int
  bcons_ischar(void)
  {
  
  #if defined(__xpv)
          if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
              console == CONS_HYPERVISOR)
                  return (bcons_ischar_xen());
  #endif /* __xpv */
  
          switch (console) {
          case CONS_TTY:
                  return (serial_ischar());
          default:
                  return (kb_ischar());
          }
  }
  
  #endif /* _BOOT */
--- 1253,1311 ----
          if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
              console == CONS_HYPERVISOR)
                  return (bcons_getchar_xen());
  #endif /* __xpv */
  
!         for (;;) {
!                 if (console == CONS_TTY || diag == CONS_TTY) {
!                         if (serial_ischar())
                                  return (serial_getchar());
!                 }
!                 if (console != CONS_INVALID || diag != CONS_INVALID) {
!                         if (kb_ischar())
                                  return (kb_getchar());
                  }
+         }
  }
  
  #if !defined(_BOOT)
  
  int
  bcons_ischar(void)
  {
+         int c = 0;
  
  #if defined(__xpv)
          if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
              console == CONS_HYPERVISOR)
                  return (bcons_ischar_xen());
  #endif /* __xpv */
  
          switch (console) {
          case CONS_TTY:
+                 c = serial_ischar();
+                 break;
+ 
+         case CONS_INVALID:
+                 break;
+ 
+         default:
+                 c = kb_ischar();
+         }
+         if (c != 0)
+                 return (c);
+ 
+         switch (diag) {
+         case CONS_TTY:
                  return (serial_ischar());
+ 
+         case CONS_INVALID:
+                 break;
+ 
          default:
                  return (kb_ischar());
          }
+ 
+         return (c);
  }
  
  #endif /* _BOOT */