]> git.proxmox.com Git - efi-boot-shim.git/blob - lib/console.c
Fix console_print_box*() parameters.
[efi-boot-shim.git] / lib / console.c
1 /*
2 * Copyright 2012 <James.Bottomley@HansenPartnership.com>
3 * Copyright 2013 Red Hat Inc. <pjones@redhat.com>
4 *
5 * see COPYING file
6 */
7 #include <efi.h>
8 #include <efilib.h>
9
10 #include <console.h>
11 #include <variables.h>
12 #include <errors.h>
13
14 static EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
15
16 static int min(int a, int b)
17 {
18 if (a < b)
19 return a;
20 return b;
21 }
22
23 static int
24 count_lines(CHAR16 *str_arr[])
25 {
26 int i = 0;
27
28 while (str_arr[i])
29 i++;
30 return i;
31 }
32
33 static void
34 SetMem16(CHAR16 *dst, UINT32 n, CHAR16 c)
35 {
36 unsigned int i;
37
38 for (i = 0; i < n/2; i++) {
39 dst[i] = c;
40 }
41 }
42
43 EFI_STATUS
44 console_get_keystroke(EFI_INPUT_KEY *key)
45 {
46 UINTN EventIndex;
47 EFI_STATUS status;
48
49 do {
50 uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &EventIndex);
51 status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, key);
52 } while (status == EFI_NOT_READY);
53
54 return status;
55 }
56
57 void
58 console_print_box_at(CHAR16 *str_arr[], int highlight,
59 int start_col, int start_row,
60 int size_cols, int size_rows,
61 int offset, int lines)
62 {
63 int i;
64 SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
65 UINTN rows, cols;
66 CHAR16 *Line;
67
68 if (lines == 0)
69 return;
70
71 uefi_call_wrapper(co->QueryMode, 4, co, co->Mode->Mode, &cols, &rows);
72
73 /* last row on screen is unusable without scrolling, so ignore it */
74 rows--;
75
76 if (size_rows < 0)
77 size_rows = rows + size_rows + 1;
78 if (size_cols < 0)
79 size_cols = cols + size_cols + 1;
80
81 if (start_col < 0)
82 start_col = (cols + start_col + 2)/2;
83 if (start_row < 0)
84 start_row = (rows + start_row + 2)/2;
85 if (start_col < 0)
86 start_col = 0;
87 if (start_row < 0)
88 start_row = 0;
89
90 if (start_col > (int)cols || start_row > (int)rows) {
91 Print(L"Starting Position (%d,%d) is off screen\n",
92 start_col, start_row);
93 return;
94 }
95 if (size_cols + start_col > (int)cols)
96 size_cols = cols - start_col;
97 if (size_rows + start_row > (int)rows)
98 size_rows = rows - start_row;
99
100 if (lines > size_rows - 2)
101 lines = size_rows - 2;
102
103 Line = AllocatePool((size_cols+1)*sizeof(CHAR16));
104 if (!Line) {
105 Print(L"Failed Allocation\n");
106 return;
107 }
108
109 SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL);
110
111 Line[0] = BOXDRAW_DOWN_RIGHT;
112 Line[size_cols - 1] = BOXDRAW_DOWN_LEFT;
113 Line[size_cols] = L'\0';
114 uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, start_row);
115 uefi_call_wrapper(co->OutputString, 2, co, Line);
116
117 int start;
118 if (offset == 0)
119 /* middle */
120 start = (size_rows - lines)/2 + start_row + offset;
121 else if (offset < 0)
122 /* from bottom */
123 start = start_row + size_rows - lines + offset - 1;
124 else
125 /* from top */
126 start = start_row + offset;
127
128 for (i = start_row + 1; i < size_rows + start_row - 1; i++) {
129 int line = i - start;
130
131 SetMem16 (Line, size_cols*2, L' ');
132 Line[0] = BOXDRAW_VERTICAL;
133 Line[size_cols - 1] = BOXDRAW_VERTICAL;
134 Line[size_cols] = L'\0';
135 if (line >= 0 && line < lines) {
136 CHAR16 *s = str_arr[line];
137 int len = StrLen(s);
138 int col = (size_cols - 2 - len)/2;
139
140 if (col < 0)
141 col = 0;
142
143 CopyMem(Line + col + 1, s, min(len, size_cols - 2)*2);
144 }
145 if (line >= 0 && line == highlight)
146 uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
147 uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, i);
148 uefi_call_wrapper(co->OutputString, 2, co, Line);
149 if (line >= 0 && line == highlight)
150 uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
151
152 }
153 SetMem16 (Line, size_cols * 2, BOXDRAW_HORIZONTAL);
154 Line[0] = BOXDRAW_UP_RIGHT;
155 Line[size_cols - 1] = BOXDRAW_UP_LEFT;
156 Line[size_cols] = L'\0';
157 uefi_call_wrapper(co->SetCursorPosition, 3, co, start_col, i);
158 uefi_call_wrapper(co->OutputString, 2, co, Line);
159
160 FreePool (Line);
161
162 }
163
164 void
165 console_print_box(CHAR16 *str_arr[], int highlight)
166 {
167 SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;
168 SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
169 EFI_INPUT_KEY key;
170
171 CopyMem(&SavedConsoleMode, co->Mode, sizeof(SavedConsoleMode));
172 uefi_call_wrapper(co->EnableCursor, 2, co, FALSE);
173 uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
174
175 console_print_box_at(str_arr, highlight, 0, 0, -1, -1, 0,
176 count_lines(str_arr));
177
178 console_get_keystroke(&key);
179
180 uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible);
181 uefi_call_wrapper(co->SetCursorPosition, 3, co, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);
182 uefi_call_wrapper(co->SetAttribute, 2, co, SavedConsoleMode.Attribute);
183 }
184
185 int
186 console_select(CHAR16 *title[], CHAR16* selectors[], unsigned int start)
187 {
188 SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;
189 SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
190 EFI_INPUT_KEY k;
191 EFI_STATUS status;
192 unsigned int selector;
193 unsigned int selector_lines = count_lines(selectors);
194 int selector_max_cols = 0;
195 unsigned int i, offs_col, offs_row, size_cols, size_rows, lines;
196 unsigned int selector_offset;
197 UINTN cols, rows;
198
199 uefi_call_wrapper(co->QueryMode, 4, co, co->Mode->Mode, &cols, &rows);
200
201 for (i = 0; i < selector_lines; i++) {
202 int len = StrLen(selectors[i]);
203
204 if (len > selector_max_cols)
205 selector_max_cols = len;
206 }
207
208 if (start < 0)
209 start = 0;
210 if (start >= selector_lines)
211 start = selector_lines - 1;
212
213 offs_col = - selector_max_cols - 4;
214 size_cols = selector_max_cols + 4;
215
216 if (selector_lines > rows - 10) {
217 int title_lines = count_lines(title);
218 offs_row = title_lines + 1;
219 size_rows = rows - 3 - title_lines;
220 lines = size_rows - 2;
221 } else {
222 offs_row = - selector_lines - 4;
223 size_rows = selector_lines + 2;
224 lines = selector_lines;
225 }
226
227 if (start > lines) {
228 selector = lines;
229 selector_offset = start - lines;
230 } else {
231 selector = start;
232 selector_offset = 0;
233 }
234
235 CopyMem(&SavedConsoleMode, co->Mode, sizeof(SavedConsoleMode));
236 uefi_call_wrapper(co->EnableCursor, 2, co, FALSE);
237 uefi_call_wrapper(co->SetAttribute, 2, co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
238
239 console_print_box_at(title, -1, 0, 0, -1, -1, 1, count_lines(title));
240
241 console_print_box_at(selectors, selector, offs_col, offs_row,
242 size_cols, size_rows, 0, lines);
243
244 do {
245 status = console_get_keystroke(&k);
246 if (EFI_ERROR (status)) {
247 Print(L"Failed to read the keystroke: %r", status);
248 selector = -1;
249 break;
250 }
251
252 if (k.ScanCode == SCAN_ESC) {
253 selector = -1;
254 break;
255 }
256
257 if (k.ScanCode == SCAN_UP) {
258 if (selector > 0)
259 selector--;
260 else if (selector_offset > 0)
261 selector_offset--;
262 } else if (k.ScanCode == SCAN_DOWN) {
263 if (selector < lines - 1)
264 selector++;
265 else if (selector_offset < (selector_lines - lines))
266 selector_offset++;
267 }
268
269 console_print_box_at(&selectors[selector_offset], selector,
270 offs_col, offs_row,
271 size_cols, size_rows, 0, lines);
272 } while (!(k.ScanCode == SCAN_NULL
273 && k.UnicodeChar == CHAR_CARRIAGE_RETURN));
274
275 uefi_call_wrapper(co->EnableCursor, 2, co, SavedConsoleMode.CursorVisible);
276 uefi_call_wrapper(co->SetCursorPosition, 3, co, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);
277 uefi_call_wrapper(co->SetAttribute, 2, co, SavedConsoleMode.Attribute);
278
279 if (selector < 0)
280 /* ESC pressed */
281 return selector;
282 return selector + selector_offset;
283 }
284
285
286 int
287 console_yes_no(CHAR16 *str_arr[])
288 {
289 return console_select(str_arr, (CHAR16 *[]){ L"No", L"Yes", NULL }, 0);
290 }
291
292 void
293 console_alertbox(CHAR16 **title)
294 {
295 console_select(title, (CHAR16 *[]){ L"OK", 0 }, 0);
296 }
297
298 void
299 console_errorbox(CHAR16 *err)
300 {
301 CHAR16 **err_arr = (CHAR16 *[]){
302 L"ERROR",
303 L"",
304 0,
305 0,
306 };
307
308 err_arr[2] = err;
309
310 console_alertbox(err_arr);
311 }
312
313 void
314 console_notify(CHAR16 *string)
315 {
316 CHAR16 **str_arr = (CHAR16 *[]){
317 0,
318 0,
319 };
320
321 str_arr[0] = string;
322
323 console_alertbox(str_arr);
324 }
325
326 #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
327
328 /* Copy of gnu-efi-3.0 with the added secure boot strings */
329 static struct {
330 EFI_STATUS Code;
331 WCHAR *Desc;
332 } error_table[] = {
333 { EFI_SUCCESS, L"Success"},
334 { EFI_LOAD_ERROR, L"Load Error"},
335 { EFI_INVALID_PARAMETER, L"Invalid Parameter"},
336 { EFI_UNSUPPORTED, L"Unsupported"},
337 { EFI_BAD_BUFFER_SIZE, L"Bad Buffer Size"},
338 { EFI_BUFFER_TOO_SMALL, L"Buffer Too Small"},
339 { EFI_NOT_READY, L"Not Ready"},
340 { EFI_DEVICE_ERROR, L"Device Error"},
341 { EFI_WRITE_PROTECTED, L"Write Protected"},
342 { EFI_OUT_OF_RESOURCES, L"Out of Resources"},
343 { EFI_VOLUME_CORRUPTED, L"Volume Corrupt"},
344 { EFI_VOLUME_FULL, L"Volume Full"},
345 { EFI_NO_MEDIA, L"No Media"},
346 { EFI_MEDIA_CHANGED, L"Media changed"},
347 { EFI_NOT_FOUND, L"Not Found"},
348 { EFI_ACCESS_DENIED, L"Access Denied"},
349 { EFI_NO_RESPONSE, L"No Response"},
350 { EFI_NO_MAPPING, L"No mapping"},
351 { EFI_TIMEOUT, L"Time out"},
352 { EFI_NOT_STARTED, L"Not started"},
353 { EFI_ALREADY_STARTED, L"Already started"},
354 { EFI_ABORTED, L"Aborted"},
355 { EFI_ICMP_ERROR, L"ICMP Error"},
356 { EFI_TFTP_ERROR, L"TFTP Error"},
357 { EFI_PROTOCOL_ERROR, L"Protocol Error"},
358 { EFI_INCOMPATIBLE_VERSION, L"Incompatible Version"},
359 { EFI_SECURITY_VIOLATION, L"Security Violation"},
360
361 // warnings
362 { EFI_WARN_UNKOWN_GLYPH, L"Warning Unknown Glyph"},
363 { EFI_WARN_DELETE_FAILURE, L"Warning Delete Failure"},
364 { EFI_WARN_WRITE_FAILURE, L"Warning Write Failure"},
365 { EFI_WARN_BUFFER_TOO_SMALL, L"Warning Buffer Too Small"},
366 { 0, NULL}
367 } ;
368
369
370 static CHAR16 *
371 err_string (
372 IN EFI_STATUS Status
373 )
374 {
375 UINTN Index;
376
377 for (Index = 0; error_table[Index].Desc; Index +=1) {
378 if (error_table[Index].Code == Status) {
379 return error_table[Index].Desc;
380 }
381 }
382
383 return L"";
384 }
385
386
387 void
388 console_error(CHAR16 *err, EFI_STATUS status)
389 {
390 CHAR16 **err_arr = (CHAR16 *[]){
391 L"ERROR",
392 L"",
393 0,
394 0,
395 };
396 CHAR16 str[512];
397
398 SPrint(str, sizeof(str), L"%s: (%d) %s", err, status, err_string(status));
399
400 err_arr[2] = str;
401
402 console_alertbox(err_arr);
403 }
404
405 void
406 console_reset(void)
407 {
408 SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
409
410 uefi_call_wrapper(co->Reset, 2, co, TRUE);
411 /* set mode 0 - required to be 80x25 */
412 uefi_call_wrapper(co->SetMode, 2, co, 0);
413 uefi_call_wrapper(co->ClearScreen, 1, co);
414 }
415
416 UINT8 verbose;
417
418 VOID
419 setup_verbosity(VOID)
420 {
421 EFI_STATUS status;
422 EFI_GUID guid = SHIM_LOCK_GUID;
423 UINT8 verbose_check;
424 UINTN verbose_check_size;
425
426 verbose_check_size = 1;
427 status = get_variable(L"SHIM_VERBOSE", (void *)&verbose_check,
428 &verbose_check_size, guid);
429 verbose = 0;
430 if (!EFI_ERROR(status))
431 verbose = verbose_check;
432 }
433
434 VOID setup_console (int text)
435 {
436 EFI_STATUS status;
437 EFI_GUID console_control_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
438 EFI_CONSOLE_CONTROL_PROTOCOL *concon;
439 static EFI_CONSOLE_CONTROL_SCREEN_MODE mode =
440 EfiConsoleControlScreenGraphics;
441 EFI_CONSOLE_CONTROL_SCREEN_MODE new_mode;
442
443 status = LibLocateProtocol(&console_control_guid, (VOID **)&concon);
444 if (status != EFI_SUCCESS)
445 return;
446
447 if (text) {
448 new_mode = EfiConsoleControlScreenText;
449
450 status = uefi_call_wrapper(concon->GetMode, 4, concon, &mode,
451 0, 0);
452 /* If that didn't work, assume it's graphics */
453 if (status != EFI_SUCCESS)
454 mode = EfiConsoleControlScreenGraphics;
455 } else {
456 new_mode = mode;
457 }
458
459 uefi_call_wrapper(concon->SetMode, 2, concon, new_mode);
460 }