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 */
|