blob: 8a9e7a3e04326c418ba1ab4c04417bfd88a9899c [file] [log] [blame]
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +00001/*
2 * This file is part of the coreinfo project.
3 *
4 * Copyright (C) 2008 Uwe Hermann <uwe@hermann-uwe.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +000014 */
15
16#include "coreinfo.h"
17
Stefan Reinauer04fb7a82015-06-29 16:08:39 -070018#if IS_ENABLED(CONFIG_MODULE_BOOTLOG)
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +000019
Yasha Cherikovsky37f45652015-11-14 19:21:14 +020020#define LINES_SHOWN 19
21#define TAB_WIDTH 2
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +000022
Yasha Cherikovsky37f45652015-11-14 19:21:14 +020023
24/* Globals that are used for tracking screen state */
25static char *g_buf = NULL;
26static s32 g_line = 0;
27static s32 g_lines_count = 0;
28static s32 g_max_cursor_line = 0;
29
30
31/* Copied from libpayload/drivers/cbmem_console.c */
32struct cbmem_console {
33 u32 size;
34 u32 cursor;
35 u8 body[0];
36} __attribute__ ((__packed__));
37
Julius Wernerd67c6872017-02-02 17:32:00 -080038#define CURSOR_MASK ((1 << 28) - 1)
39#define OVERFLOW (1 << 31)
40
Yasha Cherikovsky37f45652015-11-14 19:21:14 +020041
42static u32 char_width(char c, u32 cursor, u32 screen_width)
43{
44 if (c == '\n') {
45 return screen_width - (cursor % screen_width);
46 } else if (c == '\t') {
47 return TAB_WIDTH;
48 } else if (isprint(c)) {
49 return 1;
50 }
51
52 return 0;
53}
54
55static u32 calculate_chars_count(char *str, u32 str_len, u32 screen_width, u32 screen_height)
56{
57 u32 i, count = 0;
58
59 for (i = 0; i < str_len; i++) {
60 count += char_width(str[i], count, screen_width);
61 }
62
63 /* Ensure that 'count' can occupy at least the whole screen */
64 if (count < screen_width * screen_height) {
65 count = screen_width * screen_height;
66 }
67
68 /* Pad to line end */
69 if (count % screen_width != 0) {
70 count += screen_width - (count % screen_width);
71 }
72
73 return count;
74}
75
76/*
77 * This method takes an input buffer and sanitizes it for display, which means:
78 * - '\n' is converted to spaces until end of line
79 * - Tabs are converted to spaces of size TAB_WIDTH
80 * - Only printable characters are preserved
81 */
82static int sanitize_buffer_for_display(char *str, u32 str_len, char *out, u32 out_len, u32 screen_width)
83{
84 u32 cursor = 0;
85 u32 i;
86
87 for (i = 0; i < str_len && cursor < out_len; i++) {
88 u32 width = char_width(str[i], cursor, screen_width);
89 if (width == 1) {
90 out[cursor++] = str[i];
91 } else if (width > 1) {
92 while (width-- && cursor < out_len) {
93 out[cursor++] = ' ';
94 }
95 }
96 }
97
98 /* Fill the rest of the out buffer with spaces */
99 while (cursor < out_len) {
100 out[cursor++] = ' ';
101 }
102
103 return 0;
104}
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000105
106static int bootlog_module_init(void)
107{
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200108 /* Make sure that lib_sysinfo is initialized */
109 int ret = lib_get_sysinfo();
110 if (ret) {
111 return -1;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000112 }
113
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200114 struct cbmem_console *console = lib_sysinfo.cbmem_cons;
115 if (console == NULL) {
116 return -1;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000117 }
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200118 /* Extract console information */
119 char *buffer = (char *)(&(console->body));
Julius Wernerd67c6872017-02-02 17:32:00 -0800120 u32 size = console->size;
121 u32 cursor = console->cursor & CURSOR_MASK;
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200122
Julius Wernerd67c6872017-02-02 17:32:00 -0800123 /* The cursor may be bigger than buffer size with older console code */
124 if (cursor >= size) {
125 cursor = size - 1;
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200126 }
127
128 /* Calculate how much characters will be displayed on screen */
Julius Wernerd67c6872017-02-02 17:32:00 -0800129 u32 chars_count = calculate_chars_count(buffer, cursor, SCREEN_X, LINES_SHOWN);
130 u32 overflow_chars_count = 0;
131 if (console->cursor & OVERFLOW) {
132 overflow_chars_count = calculate_chars_count(buffer + cursor,
133 size - cursor, SCREEN_X, LINES_SHOWN);
134 }
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200135
136 /* Sanity check, chars_count must be padded to full line */
Julius Wernerd67c6872017-02-02 17:32:00 -0800137 if (chars_count % SCREEN_X || overflow_chars_count % SCREEN_X) {
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200138 return -2;
139 }
140
Julius Wernerd67c6872017-02-02 17:32:00 -0800141 g_lines_count = (chars_count + overflow_chars_count) / SCREEN_X;
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200142 g_max_cursor_line = MAX(g_lines_count - 1 - LINES_SHOWN, 0);
143
144 g_buf = malloc(chars_count);
145 if (!g_buf) {
146 return -3;
147 }
148
Julius Wernerd67c6872017-02-02 17:32:00 -0800149 if (console->cursor & OVERFLOW) {
150 if (sanitize_buffer_for_display(buffer + cursor, size - cursor,
151 g_buf, overflow_chars_count, SCREEN_X) < 0) {
152 goto err_free;
153 }
154 }
155 if (sanitize_buffer_for_display(buffer, cursor,
156 g_buf + overflow_chars_count,
157 chars_count, SCREEN_X) < 0) {
158 goto err_free;
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200159 }
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000160
161 /* TODO: Maybe a _cleanup hook where we call free()? */
162
163 return 0;
Julius Wernerd67c6872017-02-02 17:32:00 -0800164
165err_free:
166 free(g_buf);
167 g_buf = NULL;
168 return -4;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000169}
170
171static int bootlog_module_redraw(WINDOW *win)
172{
Martin Rothe81ce042017-06-03 20:00:36 -0600173 print_module_title(win, "coreboot Bootlog");
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000174
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200175 if (!g_buf) {
176 return -1;
177 }
178
179 int x = 0, y = 0;
180 char *tmp = g_buf + g_line * SCREEN_X;
181
182 for (y = 0; y < LINES_SHOWN; y++) {
183 for (x = 0; x < SCREEN_X; x++) {
184 mvwaddch(win, y + 2, x, *tmp);
185 tmp++;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000186 }
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200187
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000188 }
189
190 return 0;
191}
192
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000193static int bootlog_module_handle(int key)
194{
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200195 if (!g_buf) {
196 return 0;
197 }
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000198
199 switch (key) {
200 case KEY_DOWN:
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200201 g_line++;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000202 break;
203 case KEY_UP:
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200204 g_line--;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000205 break;
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200206 case KEY_NPAGE: /* Page up */
207 g_line -= LINES_SHOWN;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000208 break;
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200209 case KEY_PPAGE: /* Page down */
210 g_line += LINES_SHOWN;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000211 break;
212 }
213
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200214 if (g_line < 0)
215 g_line = 0;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000216
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200217 if (g_line > g_max_cursor_line)
218 g_line = g_max_cursor_line;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000219
220 return 1;
221}
222
223struct coreinfo_module bootlog_module = {
224 .name = "Bootlog",
225 .init = bootlog_module_init,
226 .redraw = bootlog_module_redraw,
227 .handle = bootlog_module_handle,
228};
229
230#else
231
232struct coreinfo_module bootlog_module = {
233};
234
235#endif