freebsd-dev/sys/boot/efi/libefi/efi_console.c
Steven Hartland 022e692a47 Enable warnings in EFI boot code
Set WARNS if not set for EFI boot code and fix the issues highlighted by
setting it.

Most components are set to WARNS level 6 with few being left at lower
levels due to the amount of changes needed to fix at higher levels.

Error types fixed:
* Missing / invalid casts
* Missing inner structs
* Unused vars
* Missing static for internal only funcs
* Missing prototypes
* Alignment changes
* Use of uninitialised vars
* Unknown pragma (intrinsic)
* Missing types etc due to missing includes
* printf formatting types

Reviewed by:	emaste (in part)
MFC after:	2 weeks
X-MFC-With:	r293268
Sponsored by:	Multiplay
Differential Revision:	https://reviews.freebsd.org/D4839
2016-01-12 02:17:39 +00:00

486 lines
9.6 KiB
C

/*-
* Copyright (c) 2000 Doug Rabson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <efi.h>
#include <efilib.h>
#include "bootstrap.h"
static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
static SIMPLE_INPUT_INTERFACE *conin;
#ifdef TERM_EMU
#define DEFAULT_FGCOLOR EFI_LIGHTGRAY
#define DEFAULT_BGCOLOR EFI_BLACK
#define MAXARGS 8
static int args[MAXARGS], argc;
static int fg_c, bg_c, curx, cury;
static int esc;
void get_pos(int *x, int *y);
void curs_move(int *_x, int *_y, int x, int y);
static void CL(int);
void HO(void);
void end_term(void);
#endif
static void efi_cons_probe(struct console *);
static int efi_cons_init(int);
void efi_cons_putchar(int);
int efi_cons_getchar(void);
void efi_cons_efiputchar(int);
int efi_cons_poll(void);
struct console efi_console = {
"efi",
"EFI console",
0,
efi_cons_probe,
efi_cons_init,
efi_cons_putchar,
efi_cons_getchar,
efi_cons_poll
};
#ifdef TERM_EMU
/* Get cursor position. */
void
get_pos(int *x, int *y)
{
*x = conout->Mode->CursorColumn;
*y = conout->Mode->CursorRow;
}
/* Move cursor to x rows and y cols (0-based). */
void
curs_move(int *_x, int *_y, int x, int y)
{
conout->SetCursorPosition(conout, x, y);
if (_x != NULL)
*_x = conout->Mode->CursorColumn;
if (_y != NULL)
*_y = conout->Mode->CursorRow;
}
/* Clear internal state of the terminal emulation code. */
void
end_term(void)
{
esc = 0;
argc = -1;
}
#endif
static void
efi_cons_probe(struct console *cp)
{
conout = ST->ConOut;
conin = ST->ConIn;
cp->c_flags |= C_PRESENTIN | C_PRESENTOUT;
}
static int
efi_cons_init(int arg)
{
conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR,
DEFAULT_BGCOLOR));
#ifdef TERM_EMU
end_term();
get_pos(&curx, &cury);
curs_move(&curx, &cury, curx, cury);
fg_c = DEFAULT_FGCOLOR;
bg_c = DEFAULT_BGCOLOR;
#endif
conout->EnableCursor(conout, TRUE);
return 0;
}
static void
efi_cons_rawputchar(int c)
{
int i;
UINTN x, y;
conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
if (c == '\t')
/* XXX lame tab expansion */
for (i = 0; i < 8; i++)
efi_cons_rawputchar(' ');
else {
#ifndef TERM_EMU
if (c == '\n')
efi_cons_efiputchar('\r');
else
efi_cons_efiputchar(c);
#else
switch (c) {
case '\r':
curx = 0;
curs_move(&curx, &cury, curx, cury);
return;
case '\n':
cury++;
if (cury >= y) {
efi_cons_efiputchar('\n');
cury--;
} else
curs_move(&curx, &cury, curx, cury);
return;
case '\b':
if (curx > 0) {
curx--;
curs_move(&curx, &cury, curx, cury);
}
return;
default:
efi_cons_efiputchar(c);
curx++;
if (curx > x-1) {
curx = 0;
cury++;
}
if (cury > y-1) {
curx = 0;
cury--;
}
}
curs_move(&curx, &cury, curx, cury);
#endif
}
}
/* Gracefully exit ESC-sequence processing in case of misunderstanding. */
static void
bail_out(int c)
{
char buf[16], *ch;
int i;
if (esc) {
efi_cons_rawputchar('\033');
if (esc != '\033')
efi_cons_rawputchar(esc);
for (i = 0; i <= argc; ++i) {
sprintf(buf, "%d", args[i]);
ch = buf;
while (*ch)
efi_cons_rawputchar(*ch++);
}
}
efi_cons_rawputchar(c);
end_term();
}
/* Clear display from current position to end of screen. */
static void
CD(void) {
int i;
UINTN x, y;
get_pos(&curx, &cury);
if (curx == 0 && cury == 0) {
conout->ClearScreen(conout);
end_term();
return;
}
conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
CL(0); /* clear current line from cursor to end */
for (i = cury + 1; i < y-1; i++) {
curs_move(NULL, NULL, 0, i);
CL(0);
}
curs_move(NULL, NULL, curx, cury);
end_term();
}
/*
* Absolute cursor move to args[0] rows and args[1] columns
* (the coordinates are 1-based).
*/
static void
CM(void)
{
if (args[0] > 0)
args[0]--;
if (args[1] > 0)
args[1]--;
curs_move(&curx, &cury, args[1], args[0]);
end_term();
}
/* Home cursor (left top corner), also called from mode command. */
void
HO(void)
{
argc = 1;
args[0] = args[1] = 1;
CM();
}
/* Clear line from current position to end of line */
static void
CL(int direction)
{
int i, len;
UINTN x, y;
CHAR16 *line;
conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
switch (direction) {
case 0: /* from cursor to end */
len = x - curx + 1;
break;
case 1: /* from beginning to cursor */
len = curx;
break;
case 2: /* entire line */
len = x;
break;
}
if (cury == y - 1)
len--;
line = malloc(len * sizeof (CHAR16));
if (line == NULL) {
printf("out of memory\n");
return;
}
for (i = 0; i < len; i++)
line[i] = ' ';
line[len-1] = 0;
if (direction != 0)
curs_move(NULL, NULL, 0, cury);
conout->OutputString(conout, line);
/* restore cursor position */
curs_move(NULL, NULL, curx, cury);
free(line);
end_term();
}
static void
get_arg(int c)
{
if (argc < 0)
argc = 0;
args[argc] *= 10;
args[argc] += c - '0';
}
/* Emulate basic capabilities of cons25 terminal */
static void
efi_term_emu(int c)
{
static int ansi_col[] = {
0, 4, 2, 6, 1, 5, 3, 7
};
int t, i;
switch (esc) {
case 0:
switch (c) {
case '\033':
esc = c;
break;
default:
efi_cons_rawputchar(c);
break;
}
break;
case '\033':
switch (c) {
case '[':
esc = c;
args[0] = 0;
argc = -1;
break;
default:
bail_out(c);
break;
}
break;
case '[':
switch (c) {
case ';':
if (argc < 0)
argc = 0;
else if (argc + 1 >= MAXARGS)
bail_out(c);
else
args[++argc] = 0;
break;
case 'H': /* ho = \E[H */
if (argc < 0)
HO();
else if (argc == 1)
CM();
else
bail_out(c);
break;
case 'J': /* cd = \E[J */
if (argc < 0)
CD();
else
bail_out(c);
break;
case 'm':
if (argc < 0) {
fg_c = DEFAULT_FGCOLOR;
bg_c = DEFAULT_BGCOLOR;
}
for (i = 0; i <= argc; ++i) {
switch (args[i]) {
case 0: /* back to normal */
fg_c = DEFAULT_FGCOLOR;
bg_c = DEFAULT_BGCOLOR;
break;
case 1: /* bold */
fg_c |= 0x8;
break;
case 4: /* underline */
case 5: /* blink */
bg_c |= 0x8;
break;
case 7: /* reverse */
t = fg_c;
fg_c = bg_c;
bg_c = t;
break;
case 30: case 31: case 32: case 33:
case 34: case 35: case 36: case 37:
fg_c = ansi_col[args[i] - 30];
break;
case 39: /* normal */
fg_c = DEFAULT_FGCOLOR;
break;
case 40: case 41: case 42: case 43:
case 44: case 45: case 46: case 47:
bg_c = ansi_col[args[i] - 40];
break;
case 49: /* normal */
bg_c = DEFAULT_BGCOLOR;
break;
}
}
conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c));
end_term();
break;
default:
if (isdigit(c))
get_arg(c);
else
bail_out(c);
break;
}
break;
default:
bail_out(c);
break;
}
}
void
efi_cons_putchar(int c)
{
#ifdef TERM_EMU
efi_term_emu(c);
#else
efi_cons_rawputchar(c);
#endif
}
int
efi_cons_getchar()
{
EFI_INPUT_KEY key;
EFI_STATUS status;
UINTN junk;
/* Try to read a key stroke. We wait for one if none is pending. */
status = conin->ReadKeyStroke(conin, &key);
if (status == EFI_NOT_READY) {
BS->WaitForEvent(1, &conin->WaitForKey, &junk);
status = conin->ReadKeyStroke(conin, &key);
}
switch (key.ScanCode) {
case 0x17: /* ESC */
return (0x1b); /* esc */
}
/* this can return */
return (key.UnicodeChar);
}
int
efi_cons_poll()
{
/* This can clear the signaled state. */
return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS);
}
/* Plain direct access to EFI OutputString(). */
void
efi_cons_efiputchar(int c)
{
CHAR16 buf[2];
/*
* translate box chars to unicode
*/
switch (c) {
/* single frame */
case 0xb3: buf[0] = BOXDRAW_VERTICAL; break;
case 0xbf: buf[0] = BOXDRAW_DOWN_LEFT; break;
case 0xc0: buf[0] = BOXDRAW_UP_RIGHT; break;
case 0xc4: buf[0] = BOXDRAW_HORIZONTAL; break;
case 0xda: buf[0] = BOXDRAW_DOWN_RIGHT; break;
case 0xd9: buf[0] = BOXDRAW_UP_LEFT; break;
/* double frame */
case 0xba: buf[0] = BOXDRAW_DOUBLE_VERTICAL; break;
case 0xbb: buf[0] = BOXDRAW_DOUBLE_DOWN_LEFT; break;
case 0xbc: buf[0] = BOXDRAW_DOUBLE_UP_LEFT; break;
case 0xc8: buf[0] = BOXDRAW_DOUBLE_UP_RIGHT; break;
case 0xc9: buf[0] = BOXDRAW_DOUBLE_DOWN_RIGHT; break;
case 0xcd: buf[0] = BOXDRAW_DOUBLE_HORIZONTAL; break;
default:
buf[0] = c;
}
buf[1] = 0; /* terminate string */
conout->OutputString(conout, buf);
}