efi_console.c revision 301703
177943Sdfr/*- 277943Sdfr * Copyright (c) 2000 Doug Rabson 377943Sdfr * All rights reserved. 477943Sdfr * 577943Sdfr * Redistribution and use in source and binary forms, with or without 677943Sdfr * modification, are permitted provided that the following conditions 777943Sdfr * are met: 877943Sdfr * 1. Redistributions of source code must retain the above copyright 977943Sdfr * notice, this list of conditions and the following disclaimer. 1077943Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1177943Sdfr * notice, this list of conditions and the following disclaimer in the 1277943Sdfr * documentation and/or other materials provided with the distribution. 1377943Sdfr * 1477943Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1577943Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1677943Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1777943Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1877943Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1977943Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2077943Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2177943Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2277943Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2377943Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2477943Sdfr * SUCH DAMAGE. 2577943Sdfr */ 2677943Sdfr 27113038Sobrien#include <sys/cdefs.h> 28113038Sobrien__FBSDID("$FreeBSD: head/sys/boot/efi/libefi/efi_console.c 301703 2016-06-08 23:13:20Z andrew $"); 2978327Sobrien 3077943Sdfr#include <efi.h> 3177943Sdfr#include <efilib.h> 3277943Sdfr 3377943Sdfr#include "bootstrap.h" 3477943Sdfr 3577943Sdfrstatic SIMPLE_TEXT_OUTPUT_INTERFACE *conout; 3677943Sdfrstatic SIMPLE_INPUT_INTERFACE *conin; 3777943Sdfr 38293233Semaste#ifdef TERM_EMU 39293233Semaste#define DEFAULT_FGCOLOR EFI_LIGHTGRAY 40293233Semaste#define DEFAULT_BGCOLOR EFI_BLACK 41293233Semaste 42293233Semaste#define MAXARGS 8 43293233Semastestatic int args[MAXARGS], argc; 44293233Semastestatic int fg_c, bg_c, curx, cury; 45293233Semastestatic int esc; 46293233Semaste 47293233Semastevoid get_pos(int *x, int *y); 48293233Semastevoid curs_move(int *_x, int *_y, int x, int y); 49293233Semastestatic void CL(int); 50293724Ssmhvoid HO(void); 51293724Ssmhvoid end_term(void); 52293233Semaste#endif 53293233Semaste 54293233Semastestatic void efi_cons_probe(struct console *); 55293233Semastestatic int efi_cons_init(int); 56293233Semastevoid efi_cons_putchar(int); 57293233Semasteint efi_cons_getchar(void); 58293233Semastevoid efi_cons_efiputchar(int); 59293233Semasteint efi_cons_poll(void); 60293233Semaste 61293233Semastestruct console efi_console = { 62293233Semaste "efi", 63293233Semaste "EFI console", 64300056Simp C_WIDEOUT, 65293233Semaste efi_cons_probe, 66293233Semaste efi_cons_init, 67293233Semaste efi_cons_putchar, 68293233Semaste efi_cons_getchar, 69293233Semaste efi_cons_poll 70293233Semaste}; 71293233Semaste 72293233Semaste#ifdef TERM_EMU 73293233Semaste 74293233Semaste/* Get cursor position. */ 75293233Semastevoid 76293233Semasteget_pos(int *x, int *y) 77293233Semaste{ 78293233Semaste *x = conout->Mode->CursorColumn; 79293233Semaste *y = conout->Mode->CursorRow; 80293233Semaste} 81293233Semaste 82293233Semaste/* Move cursor to x rows and y cols (0-based). */ 83293233Semastevoid 84293233Semastecurs_move(int *_x, int *_y, int x, int y) 85293233Semaste{ 86293233Semaste conout->SetCursorPosition(conout, x, y); 87293233Semaste if (_x != NULL) 88293233Semaste *_x = conout->Mode->CursorColumn; 89293233Semaste if (_y != NULL) 90293233Semaste *_y = conout->Mode->CursorRow; 91293233Semaste} 92293233Semaste 93293233Semaste/* Clear internal state of the terminal emulation code. */ 94293233Semastevoid 95293233Semasteend_term(void) 96293233Semaste{ 97293233Semaste esc = 0; 98293233Semaste argc = -1; 99293233Semaste} 100293233Semaste 101293233Semaste#endif 102293233Semaste 10377943Sdfrstatic void 10477943Sdfrefi_cons_probe(struct console *cp) 10577943Sdfr{ 10677943Sdfr conout = ST->ConOut; 10777943Sdfr conin = ST->ConIn; 10877943Sdfr cp->c_flags |= C_PRESENTIN | C_PRESENTOUT; 10977943Sdfr} 11077943Sdfr 11177943Sdfrstatic int 11277943Sdfrefi_cons_init(int arg) 11377943Sdfr{ 114301702Sandrew#ifdef TERM_EMU 115293233Semaste conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, 116293233Semaste DEFAULT_BGCOLOR)); 117293233Semaste end_term(); 118293233Semaste get_pos(&curx, &cury); 119293233Semaste curs_move(&curx, &cury, curx, cury); 120293233Semaste fg_c = DEFAULT_FGCOLOR; 121293233Semaste bg_c = DEFAULT_BGCOLOR; 122293233Semaste#endif 123293233Semaste conout->EnableCursor(conout, TRUE); 12477943Sdfr return 0; 12577943Sdfr} 12677943Sdfr 127293233Semastestatic void 128293233Semasteefi_cons_rawputchar(int c) 129293233Semaste{ 130293233Semaste int i; 131293233Semaste UINTN x, y; 132293233Semaste conout->QueryMode(conout, conout->Mode->Mode, &x, &y); 133293233Semaste 134293233Semaste if (c == '\t') 135293233Semaste /* XXX lame tab expansion */ 136293233Semaste for (i = 0; i < 8; i++) 137293233Semaste efi_cons_rawputchar(' '); 138293233Semaste else { 139293233Semaste#ifndef TERM_EMU 140293233Semaste if (c == '\n') 141293233Semaste efi_cons_efiputchar('\r'); 142301703Sandrew efi_cons_efiputchar(c); 143293233Semaste#else 144293233Semaste switch (c) { 145293233Semaste case '\r': 146293233Semaste curx = 0; 147293233Semaste curs_move(&curx, &cury, curx, cury); 148293233Semaste return; 149293233Semaste case '\n': 150293233Semaste cury++; 151293233Semaste if (cury >= y) { 152293233Semaste efi_cons_efiputchar('\n'); 153293233Semaste cury--; 154293233Semaste } else 155293233Semaste curs_move(&curx, &cury, curx, cury); 156293233Semaste return; 157293233Semaste case '\b': 158293233Semaste if (curx > 0) { 159293233Semaste curx--; 160293233Semaste curs_move(&curx, &cury, curx, cury); 161293233Semaste } 162293233Semaste return; 163293233Semaste default: 164293233Semaste efi_cons_efiputchar(c); 165293233Semaste curx++; 166293233Semaste if (curx > x-1) { 167293233Semaste curx = 0; 168293233Semaste cury++; 169293233Semaste } 170293233Semaste if (cury > y-1) { 171293233Semaste curx = 0; 172293233Semaste cury--; 173293233Semaste } 174293233Semaste } 175293233Semaste curs_move(&curx, &cury, curx, cury); 176293233Semaste#endif 177293233Semaste } 178293233Semaste} 179293233Semaste 180301702Sandrew#ifdef TERM_EMU 181293233Semaste/* Gracefully exit ESC-sequence processing in case of misunderstanding. */ 182293233Semastestatic void 183293233Semastebail_out(int c) 184293233Semaste{ 185293233Semaste char buf[16], *ch; 186293233Semaste int i; 187293233Semaste 188293233Semaste if (esc) { 189293233Semaste efi_cons_rawputchar('\033'); 190293233Semaste if (esc != '\033') 191293233Semaste efi_cons_rawputchar(esc); 192293233Semaste for (i = 0; i <= argc; ++i) { 193293233Semaste sprintf(buf, "%d", args[i]); 194293233Semaste ch = buf; 195293233Semaste while (*ch) 196293233Semaste efi_cons_rawputchar(*ch++); 197293233Semaste } 198293233Semaste } 199293233Semaste efi_cons_rawputchar(c); 200293233Semaste end_term(); 201293233Semaste} 202293233Semaste 203293233Semaste/* Clear display from current position to end of screen. */ 204293233Semastestatic void 205293233SemasteCD(void) { 206293233Semaste int i; 207293233Semaste UINTN x, y; 208293233Semaste 209293233Semaste get_pos(&curx, &cury); 210293233Semaste if (curx == 0 && cury == 0) { 211293233Semaste conout->ClearScreen(conout); 212293233Semaste end_term(); 213293233Semaste return; 214293233Semaste } 215293233Semaste 216293233Semaste conout->QueryMode(conout, conout->Mode->Mode, &x, &y); 217293233Semaste CL(0); /* clear current line from cursor to end */ 218293233Semaste for (i = cury + 1; i < y-1; i++) { 219293233Semaste curs_move(NULL, NULL, 0, i); 220293233Semaste CL(0); 221293233Semaste } 222293233Semaste curs_move(NULL, NULL, curx, cury); 223293233Semaste end_term(); 224293233Semaste} 225293233Semaste 226293233Semaste/* 227293233Semaste * Absolute cursor move to args[0] rows and args[1] columns 228293233Semaste * (the coordinates are 1-based). 229293233Semaste */ 230293233Semastestatic void 231293233SemasteCM(void) 232293233Semaste{ 233293233Semaste if (args[0] > 0) 234293233Semaste args[0]--; 235293233Semaste if (args[1] > 0) 236293233Semaste args[1]--; 237293233Semaste curs_move(&curx, &cury, args[1], args[0]); 238293233Semaste end_term(); 239293233Semaste} 240293233Semaste 241293233Semaste/* Home cursor (left top corner), also called from mode command. */ 24277943Sdfrvoid 243293233SemasteHO(void) 24477943Sdfr{ 245293233Semaste argc = 1; 246293233Semaste args[0] = args[1] = 1; 247293233Semaste CM(); 248293233Semaste} 24977943Sdfr 250293233Semaste/* Clear line from current position to end of line */ 251293233Semastestatic void 252293233SemasteCL(int direction) 253293233Semaste{ 254293233Semaste int i, len; 255293233Semaste UINTN x, y; 256293233Semaste CHAR16 *line; 25777943Sdfr 258293233Semaste conout->QueryMode(conout, conout->Mode->Mode, &x, &y); 259293233Semaste switch (direction) { 260293233Semaste case 0: /* from cursor to end */ 261293233Semaste len = x - curx + 1; 262293233Semaste break; 263293233Semaste case 1: /* from beginning to cursor */ 264293233Semaste len = curx; 265293233Semaste break; 266293233Semaste case 2: /* entire line */ 267293233Semaste len = x; 268293233Semaste break; 269299972Spfg default: /* NOTREACHED */ 270299972Spfg __unreachable(); 271293233Semaste } 27277943Sdfr 273293233Semaste if (cury == y - 1) 274293233Semaste len--; 275293233Semaste 276293233Semaste line = malloc(len * sizeof (CHAR16)); 277293233Semaste if (line == NULL) { 278293233Semaste printf("out of memory\n"); 279293233Semaste return; 280293233Semaste } 281293233Semaste for (i = 0; i < len; i++) 282293233Semaste line[i] = ' '; 283293233Semaste line[len-1] = 0; 284293233Semaste 285293233Semaste if (direction != 0) 286293233Semaste curs_move(NULL, NULL, 0, cury); 287293233Semaste 288293233Semaste conout->OutputString(conout, line); 289293233Semaste /* restore cursor position */ 290293233Semaste curs_move(NULL, NULL, curx, cury); 291293233Semaste free(line); 292293233Semaste end_term(); 29377943Sdfr} 29477943Sdfr 295293233Semastestatic void 296293233Semasteget_arg(int c) 297293233Semaste{ 298293233Semaste if (argc < 0) 299293233Semaste argc = 0; 300293233Semaste args[argc] *= 10; 301293233Semaste args[argc] += c - '0'; 302293233Semaste} 303293233Semaste 304293233Semaste/* Emulate basic capabilities of cons25 terminal */ 305293233Semastestatic void 306293233Semasteefi_term_emu(int c) 307293233Semaste{ 308293233Semaste static int ansi_col[] = { 309293233Semaste 0, 4, 2, 6, 1, 5, 3, 7 310293233Semaste }; 311293233Semaste int t, i; 312293233Semaste 313293233Semaste switch (esc) { 314293233Semaste case 0: 315293233Semaste switch (c) { 316293233Semaste case '\033': 317293233Semaste esc = c; 318293233Semaste break; 319293233Semaste default: 320293233Semaste efi_cons_rawputchar(c); 321293233Semaste break; 322293233Semaste } 323293233Semaste break; 324293233Semaste case '\033': 325293233Semaste switch (c) { 326293233Semaste case '[': 327293233Semaste esc = c; 328293233Semaste args[0] = 0; 329293233Semaste argc = -1; 330293233Semaste break; 331293233Semaste default: 332293233Semaste bail_out(c); 333293233Semaste break; 334293233Semaste } 335293233Semaste break; 336293233Semaste case '[': 337293233Semaste switch (c) { 338293233Semaste case ';': 339293233Semaste if (argc < 0) 340293233Semaste argc = 0; 341293233Semaste else if (argc + 1 >= MAXARGS) 342293233Semaste bail_out(c); 343293233Semaste else 344293233Semaste args[++argc] = 0; 345293233Semaste break; 346293233Semaste case 'H': /* ho = \E[H */ 347293233Semaste if (argc < 0) 348293233Semaste HO(); 349293233Semaste else if (argc == 1) 350293233Semaste CM(); 351293233Semaste else 352293233Semaste bail_out(c); 353293233Semaste break; 354293233Semaste case 'J': /* cd = \E[J */ 355293233Semaste if (argc < 0) 356293233Semaste CD(); 357293233Semaste else 358293233Semaste bail_out(c); 359293233Semaste break; 360293233Semaste case 'm': 361293233Semaste if (argc < 0) { 362293233Semaste fg_c = DEFAULT_FGCOLOR; 363293233Semaste bg_c = DEFAULT_BGCOLOR; 364293233Semaste } 365293233Semaste for (i = 0; i <= argc; ++i) { 366293233Semaste switch (args[i]) { 367293233Semaste case 0: /* back to normal */ 368293233Semaste fg_c = DEFAULT_FGCOLOR; 369293233Semaste bg_c = DEFAULT_BGCOLOR; 370293233Semaste break; 371293233Semaste case 1: /* bold */ 372293233Semaste fg_c |= 0x8; 373293233Semaste break; 374293233Semaste case 4: /* underline */ 375293233Semaste case 5: /* blink */ 376293233Semaste bg_c |= 0x8; 377293233Semaste break; 378293233Semaste case 7: /* reverse */ 379293233Semaste t = fg_c; 380293233Semaste fg_c = bg_c; 381293233Semaste bg_c = t; 382293233Semaste break; 383293233Semaste case 30: case 31: case 32: case 33: 384293233Semaste case 34: case 35: case 36: case 37: 385293233Semaste fg_c = ansi_col[args[i] - 30]; 386293233Semaste break; 387293233Semaste case 39: /* normal */ 388293233Semaste fg_c = DEFAULT_FGCOLOR; 389293233Semaste break; 390293233Semaste case 40: case 41: case 42: case 43: 391293233Semaste case 44: case 45: case 46: case 47: 392293233Semaste bg_c = ansi_col[args[i] - 40]; 393293233Semaste break; 394293233Semaste case 49: /* normal */ 395293233Semaste bg_c = DEFAULT_BGCOLOR; 396293233Semaste break; 397293233Semaste } 398293233Semaste } 399293233Semaste conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c)); 400293233Semaste end_term(); 401293233Semaste break; 402293233Semaste default: 403293233Semaste if (isdigit(c)) 404293233Semaste get_arg(c); 405293233Semaste else 406293233Semaste bail_out(c); 407293233Semaste break; 408293233Semaste } 409293233Semaste break; 410293233Semaste default: 411293233Semaste bail_out(c); 412293233Semaste break; 413293233Semaste } 414293233Semaste} 415301702Sandrew#else 416301702Sandrewvoid 417301702SandrewHO(void) 418301702Sandrew{ 419301702Sandrew} 420301702Sandrew#endif 421293233Semaste 422293233Semastevoid 423293233Semasteefi_cons_putchar(int c) 424293233Semaste{ 425293233Semaste#ifdef TERM_EMU 426293233Semaste efi_term_emu(c); 427293233Semaste#else 428293233Semaste efi_cons_rawputchar(c); 429293233Semaste#endif 430293233Semaste} 431293233Semaste 43277943Sdfrint 43377943Sdfrefi_cons_getchar() 43477943Sdfr{ 43577943Sdfr EFI_INPUT_KEY key; 436107682Smarcel EFI_STATUS status; 43777943Sdfr UINTN junk; 43877943Sdfr 439107682Smarcel /* Try to read a key stroke. We wait for one if none is pending. */ 440107682Smarcel status = conin->ReadKeyStroke(conin, &key); 441107682Smarcel if (status == EFI_NOT_READY) { 442107682Smarcel BS->WaitForEvent(1, &conin->WaitForKey, &junk); 443107682Smarcel status = conin->ReadKeyStroke(conin, &key); 444107682Smarcel } 445293233Semaste switch (key.ScanCode) { 446293233Semaste case 0x17: /* ESC */ 447293233Semaste return (0x1b); /* esc */ 448293233Semaste } 449293233Semaste 450293233Semaste /* this can return */ 451107682Smarcel return (key.UnicodeChar); 45277943Sdfr} 45377943Sdfr 45477943Sdfrint 45577943Sdfrefi_cons_poll() 45677943Sdfr{ 457107682Smarcel /* This can clear the signaled state. */ 458107682Smarcel return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS); 45977943Sdfr} 46077943Sdfr 461293233Semaste/* Plain direct access to EFI OutputString(). */ 462293233Semastevoid 463293233Semasteefi_cons_efiputchar(int c) 464293233Semaste{ 465293233Semaste CHAR16 buf[2]; 466293233Semaste 467293233Semaste /* 468293233Semaste * translate box chars to unicode 469293233Semaste */ 470293233Semaste switch (c) { 471293233Semaste /* single frame */ 472293233Semaste case 0xb3: buf[0] = BOXDRAW_VERTICAL; break; 473293233Semaste case 0xbf: buf[0] = BOXDRAW_DOWN_LEFT; break; 474293233Semaste case 0xc0: buf[0] = BOXDRAW_UP_RIGHT; break; 475293233Semaste case 0xc4: buf[0] = BOXDRAW_HORIZONTAL; break; 476293233Semaste case 0xda: buf[0] = BOXDRAW_DOWN_RIGHT; break; 477293233Semaste case 0xd9: buf[0] = BOXDRAW_UP_LEFT; break; 478293233Semaste 479293233Semaste /* double frame */ 480293233Semaste case 0xba: buf[0] = BOXDRAW_DOUBLE_VERTICAL; break; 481293233Semaste case 0xbb: buf[0] = BOXDRAW_DOUBLE_DOWN_LEFT; break; 482293233Semaste case 0xbc: buf[0] = BOXDRAW_DOUBLE_UP_LEFT; break; 483293233Semaste case 0xc8: buf[0] = BOXDRAW_DOUBLE_UP_RIGHT; break; 484293233Semaste case 0xc9: buf[0] = BOXDRAW_DOUBLE_DOWN_RIGHT; break; 485293233Semaste case 0xcd: buf[0] = BOXDRAW_DOUBLE_HORIZONTAL; break; 486293233Semaste 487293233Semaste default: 488293233Semaste buf[0] = c; 489293233Semaste } 490293233Semaste buf[1] = 0; /* terminate string */ 491293233Semaste 492293233Semaste conout->OutputString(conout, buf); 493293233Semaste} 494