efi_console.c revision 294445
1/*- 2 * Copyright (c) 2000 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/10/sys/boot/efi/libefi/efi_console.c 294445 2016-01-20 16:53:38Z emaste $"); 29 30#include <efi.h> 31#include <efilib.h> 32 33#include "bootstrap.h" 34 35static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; 36static SIMPLE_INPUT_INTERFACE *conin; 37 38#ifdef TERM_EMU 39#define DEFAULT_FGCOLOR EFI_LIGHTGRAY 40#define DEFAULT_BGCOLOR EFI_BLACK 41 42#define MAXARGS 8 43static int args[MAXARGS], argc; 44static int fg_c, bg_c, curx, cury; 45static int esc; 46 47void get_pos(int *x, int *y); 48void curs_move(int *_x, int *_y, int x, int y); 49static void CL(int); 50#endif 51 52static void efi_cons_probe(struct console *); 53static int efi_cons_init(int); 54void efi_cons_putchar(int); 55int efi_cons_getchar(void); 56void efi_cons_efiputchar(int); 57int efi_cons_poll(void); 58 59struct console efi_console = { 60 "efi", 61 "EFI console", 62 0, 63 efi_cons_probe, 64 efi_cons_init, 65 efi_cons_putchar, 66 efi_cons_getchar, 67 efi_cons_poll 68}; 69 70#ifdef TERM_EMU 71 72/* Get cursor position. */ 73void 74get_pos(int *x, int *y) 75{ 76 *x = conout->Mode->CursorColumn; 77 *y = conout->Mode->CursorRow; 78} 79 80/* Move cursor to x rows and y cols (0-based). */ 81void 82curs_move(int *_x, int *_y, int x, int y) 83{ 84 conout->SetCursorPosition(conout, x, y); 85 if (_x != NULL) 86 *_x = conout->Mode->CursorColumn; 87 if (_y != NULL) 88 *_y = conout->Mode->CursorRow; 89} 90 91/* Clear internal state of the terminal emulation code. */ 92void 93end_term(void) 94{ 95 esc = 0; 96 argc = -1; 97} 98 99#endif 100 101static void 102efi_cons_probe(struct console *cp) 103{ 104 conout = ST->ConOut; 105 conin = ST->ConIn; 106 cp->c_flags |= C_PRESENTIN | C_PRESENTOUT; 107} 108 109static int 110efi_cons_init(int arg) 111{ 112 conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, 113 DEFAULT_BGCOLOR)); 114#ifdef TERM_EMU 115 end_term(); 116 get_pos(&curx, &cury); 117 curs_move(&curx, &cury, curx, cury); 118 fg_c = DEFAULT_FGCOLOR; 119 bg_c = DEFAULT_BGCOLOR; 120#endif 121 conout->EnableCursor(conout, TRUE); 122 return 0; 123} 124 125static void 126efi_cons_rawputchar(int c) 127{ 128 int i; 129 UINTN x, y; 130 conout->QueryMode(conout, conout->Mode->Mode, &x, &y); 131 132 if (c == '\t') 133 /* XXX lame tab expansion */ 134 for (i = 0; i < 8; i++) 135 efi_cons_rawputchar(' '); 136 else { 137#ifndef TERM_EMU 138 if (c == '\n') 139 efi_cons_efiputchar('\r'); 140 else 141 efi_cons_efiputchar(c); 142#else 143 switch (c) { 144 case '\r': 145 curx = 0; 146 curs_move(&curx, &cury, curx, cury); 147 return; 148 case '\n': 149 cury++; 150 if (cury >= y) { 151 efi_cons_efiputchar('\n'); 152 cury--; 153 } else 154 curs_move(&curx, &cury, curx, cury); 155 return; 156 case '\b': 157 if (curx > 0) { 158 curx--; 159 curs_move(&curx, &cury, curx, cury); 160 } 161 return; 162 default: 163 efi_cons_efiputchar(c); 164 curx++; 165 if (curx > x-1) { 166 curx = 0; 167 cury++; 168 } 169 if (cury > y-1) { 170 curx = 0; 171 cury--; 172 } 173 } 174 curs_move(&curx, &cury, curx, cury); 175#endif 176 } 177} 178 179/* Gracefully exit ESC-sequence processing in case of misunderstanding. */ 180static void 181bail_out(int c) 182{ 183 char buf[16], *ch; 184 int i; 185 186 if (esc) { 187 efi_cons_rawputchar('\033'); 188 if (esc != '\033') 189 efi_cons_rawputchar(esc); 190 for (i = 0; i <= argc; ++i) { 191 sprintf(buf, "%d", args[i]); 192 ch = buf; 193 while (*ch) 194 efi_cons_rawputchar(*ch++); 195 } 196 } 197 efi_cons_rawputchar(c); 198 end_term(); 199} 200 201/* Clear display from current position to end of screen. */ 202static void 203CD(void) { 204 int i; 205 UINTN x, y; 206 207 get_pos(&curx, &cury); 208 if (curx == 0 && cury == 0) { 209 conout->ClearScreen(conout); 210 end_term(); 211 return; 212 } 213 214 conout->QueryMode(conout, conout->Mode->Mode, &x, &y); 215 CL(0); /* clear current line from cursor to end */ 216 for (i = cury + 1; i < y-1; i++) { 217 curs_move(NULL, NULL, 0, i); 218 CL(0); 219 } 220 curs_move(NULL, NULL, curx, cury); 221 end_term(); 222} 223 224/* 225 * Absolute cursor move to args[0] rows and args[1] columns 226 * (the coordinates are 1-based). 227 */ 228static void 229CM(void) 230{ 231 if (args[0] > 0) 232 args[0]--; 233 if (args[1] > 0) 234 args[1]--; 235 curs_move(&curx, &cury, args[1], args[0]); 236 end_term(); 237} 238 239/* Home cursor (left top corner), also called from mode command. */ 240void 241HO(void) 242{ 243 argc = 1; 244 args[0] = args[1] = 1; 245 CM(); 246} 247 248/* Clear line from current position to end of line */ 249static void 250CL(int direction) 251{ 252 int i, len; 253 UINTN x, y; 254 CHAR16 *line; 255 256 conout->QueryMode(conout, conout->Mode->Mode, &x, &y); 257 switch (direction) { 258 case 0: /* from cursor to end */ 259 len = x - curx + 1; 260 break; 261 case 1: /* from beginning to cursor */ 262 len = curx; 263 break; 264 case 2: /* entire line */ 265 len = x; 266 break; 267 } 268 269 if (cury == y - 1) 270 len--; 271 272 line = malloc(len * sizeof (CHAR16)); 273 if (line == NULL) { 274 printf("out of memory\n"); 275 return; 276 } 277 for (i = 0; i < len; i++) 278 line[i] = ' '; 279 line[len-1] = 0; 280 281 if (direction != 0) 282 curs_move(NULL, NULL, 0, cury); 283 284 conout->OutputString(conout, line); 285 /* restore cursor position */ 286 curs_move(NULL, NULL, curx, cury); 287 free(line); 288 end_term(); 289} 290 291static void 292get_arg(int c) 293{ 294 if (argc < 0) 295 argc = 0; 296 args[argc] *= 10; 297 args[argc] += c - '0'; 298} 299 300/* Emulate basic capabilities of cons25 terminal */ 301static void 302efi_term_emu(int c) 303{ 304 static int ansi_col[] = { 305 0, 4, 2, 6, 1, 5, 3, 7 306 }; 307 int t, i; 308 309 switch (esc) { 310 case 0: 311 switch (c) { 312 case '\033': 313 esc = c; 314 break; 315 default: 316 efi_cons_rawputchar(c); 317 break; 318 } 319 break; 320 case '\033': 321 switch (c) { 322 case '[': 323 esc = c; 324 args[0] = 0; 325 argc = -1; 326 break; 327 default: 328 bail_out(c); 329 break; 330 } 331 break; 332 case '[': 333 switch (c) { 334 case ';': 335 if (argc < 0) 336 argc = 0; 337 else if (argc + 1 >= MAXARGS) 338 bail_out(c); 339 else 340 args[++argc] = 0; 341 break; 342 case 'H': /* ho = \E[H */ 343 if (argc < 0) 344 HO(); 345 else if (argc == 1) 346 CM(); 347 else 348 bail_out(c); 349 break; 350 case 'J': /* cd = \E[J */ 351 if (argc < 0) 352 CD(); 353 else 354 bail_out(c); 355 break; 356 case 'm': 357 if (argc < 0) { 358 fg_c = DEFAULT_FGCOLOR; 359 bg_c = DEFAULT_BGCOLOR; 360 } 361 for (i = 0; i <= argc; ++i) { 362 switch (args[i]) { 363 case 0: /* back to normal */ 364 fg_c = DEFAULT_FGCOLOR; 365 bg_c = DEFAULT_BGCOLOR; 366 break; 367 case 1: /* bold */ 368 fg_c |= 0x8; 369 break; 370 case 4: /* underline */ 371 case 5: /* blink */ 372 bg_c |= 0x8; 373 break; 374 case 7: /* reverse */ 375 t = fg_c; 376 fg_c = bg_c; 377 bg_c = t; 378 break; 379 case 30: case 31: case 32: case 33: 380 case 34: case 35: case 36: case 37: 381 fg_c = ansi_col[args[i] - 30]; 382 break; 383 case 39: /* normal */ 384 fg_c = DEFAULT_FGCOLOR; 385 break; 386 case 40: case 41: case 42: case 43: 387 case 44: case 45: case 46: case 47: 388 bg_c = ansi_col[args[i] - 40]; 389 break; 390 case 49: /* normal */ 391 bg_c = DEFAULT_BGCOLOR; 392 break; 393 } 394 } 395 conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c)); 396 end_term(); 397 break; 398 default: 399 if (isdigit(c)) 400 get_arg(c); 401 else 402 bail_out(c); 403 break; 404 } 405 break; 406 default: 407 bail_out(c); 408 break; 409 } 410} 411 412void 413efi_cons_putchar(int c) 414{ 415#ifdef TERM_EMU 416 efi_term_emu(c); 417#else 418 efi_cons_rawputchar(c); 419#endif 420} 421 422int 423efi_cons_getchar() 424{ 425 EFI_INPUT_KEY key; 426 EFI_STATUS status; 427 UINTN junk; 428 429 /* Try to read a key stroke. We wait for one if none is pending. */ 430 status = conin->ReadKeyStroke(conin, &key); 431 if (status == EFI_NOT_READY) { 432 BS->WaitForEvent(1, &conin->WaitForKey, &junk); 433 status = conin->ReadKeyStroke(conin, &key); 434 } 435 switch (key.ScanCode) { 436 case 0x17: /* ESC */ 437 return (0x1b); /* esc */ 438 } 439 440 /* this can return */ 441 return (key.UnicodeChar); 442} 443 444int 445efi_cons_poll() 446{ 447 /* This can clear the signaled state. */ 448 return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS); 449} 450 451/* Plain direct access to EFI OutputString(). */ 452void 453efi_cons_efiputchar(int c) 454{ 455 CHAR16 buf[2]; 456 457 /* 458 * translate box chars to unicode 459 */ 460 switch (c) { 461 /* single frame */ 462 case 0xb3: buf[0] = BOXDRAW_VERTICAL; break; 463 case 0xbf: buf[0] = BOXDRAW_DOWN_LEFT; break; 464 case 0xc0: buf[0] = BOXDRAW_UP_RIGHT; break; 465 case 0xc4: buf[0] = BOXDRAW_HORIZONTAL; break; 466 case 0xda: buf[0] = BOXDRAW_DOWN_RIGHT; break; 467 case 0xd9: buf[0] = BOXDRAW_UP_LEFT; break; 468 469 /* double frame */ 470 case 0xba: buf[0] = BOXDRAW_DOUBLE_VERTICAL; break; 471 case 0xbb: buf[0] = BOXDRAW_DOUBLE_DOWN_LEFT; break; 472 case 0xbc: buf[0] = BOXDRAW_DOUBLE_UP_LEFT; break; 473 case 0xc8: buf[0] = BOXDRAW_DOUBLE_UP_RIGHT; break; 474 case 0xc9: buf[0] = BOXDRAW_DOUBLE_DOWN_RIGHT; break; 475 case 0xcd: buf[0] = BOXDRAW_DOUBLE_HORIZONTAL; break; 476 477 default: 478 buf[0] = c; 479 } 480 buf[1] = 0; /* terminate string */ 481 482 conout->OutputString(conout, buf); 483} 484