blob: 1d990d1d0c6c7b2697d4da8f23cc88382d6ed7ba [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
38
39static u32 char_width(char c, u32 cursor, u32 screen_width)
40{
41 if (c == '\n') {
42 return screen_width - (cursor % screen_width);
43 } else if (c == '\t') {
44 return TAB_WIDTH;
45 } else if (isprint(c)) {
46 return 1;
47 }
48
49 return 0;
50}
51
52static u32 calculate_chars_count(char *str, u32 str_len, u32 screen_width, u32 screen_height)
53{
54 u32 i, count = 0;
55
56 for (i = 0; i < str_len; i++) {
57 count += char_width(str[i], count, screen_width);
58 }
59
60 /* Ensure that 'count' can occupy at least the whole screen */
61 if (count < screen_width * screen_height) {
62 count = screen_width * screen_height;
63 }
64
65 /* Pad to line end */
66 if (count % screen_width != 0) {
67 count += screen_width - (count % screen_width);
68 }
69
70 return count;
71}
72
73/*
74 * This method takes an input buffer and sanitizes it for display, which means:
75 * - '\n' is converted to spaces until end of line
76 * - Tabs are converted to spaces of size TAB_WIDTH
77 * - Only printable characters are preserved
78 */
79static int sanitize_buffer_for_display(char *str, u32 str_len, char *out, u32 out_len, u32 screen_width)
80{
81 u32 cursor = 0;
82 u32 i;
83
84 for (i = 0; i < str_len && cursor < out_len; i++) {
85 u32 width = char_width(str[i], cursor, screen_width);
86 if (width == 1) {
87 out[cursor++] = str[i];
88 } else if (width > 1) {
89 while (width-- && cursor < out_len) {
90 out[cursor++] = ' ';
91 }
92 }
93 }
94
95 /* Fill the rest of the out buffer with spaces */
96 while (cursor < out_len) {
97 out[cursor++] = ' ';
98 }
99
100 return 0;
101}
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000102
103static int bootlog_module_init(void)
104{
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200105 /* Make sure that lib_sysinfo is initialized */
106 int ret = lib_get_sysinfo();
107 if (ret) {
108 return -1;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000109 }
110
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200111 struct cbmem_console *console = lib_sysinfo.cbmem_cons;
112 if (console == NULL) {
113 return -1;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000114 }
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200115 /* Extract console information */
116 char *buffer = (char *)(&(console->body));
117 u32 buffer_size = console->size;
118 u32 cursor = console->cursor;
119
120 /* The cursor may be bigger than buffer size when the buffer is full */
121 if (cursor >= buffer_size) {
122 cursor = buffer_size - 1;
123 }
124
125 /* Calculate how much characters will be displayed on screen */
126 u32 chars_count = calculate_chars_count(buffer, cursor + 1, SCREEN_X, LINES_SHOWN);
127
128 /* Sanity check, chars_count must be padded to full line */
129 if (chars_count % SCREEN_X != 0) {
130 return -2;
131 }
132
133 g_lines_count = chars_count / SCREEN_X;
134 g_max_cursor_line = MAX(g_lines_count - 1 - LINES_SHOWN, 0);
135
136 g_buf = malloc(chars_count);
137 if (!g_buf) {
138 return -3;
139 }
140
141 if (sanitize_buffer_for_display(buffer, cursor + 1,
142 g_buf, chars_count,
143 SCREEN_X) < 0) {
144 free(g_buf);
145 g_buf = NULL;
146 return -4;
147 }
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000148
149 /* TODO: Maybe a _cleanup hook where we call free()? */
150
151 return 0;
152}
153
154static int bootlog_module_redraw(WINDOW *win)
155{
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000156 print_module_title(win, "Coreboot Bootlog");
157
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200158 if (!g_buf) {
159 return -1;
160 }
161
162 int x = 0, y = 0;
163 char *tmp = g_buf + g_line * SCREEN_X;
164
165 for (y = 0; y < LINES_SHOWN; y++) {
166 for (x = 0; x < SCREEN_X; x++) {
167 mvwaddch(win, y + 2, x, *tmp);
168 tmp++;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000169 }
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200170
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000171 }
172
173 return 0;
174}
175
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000176static int bootlog_module_handle(int key)
177{
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200178 if (!g_buf) {
179 return 0;
180 }
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000181
182 switch (key) {
183 case KEY_DOWN:
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200184 g_line++;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000185 break;
186 case KEY_UP:
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200187 g_line--;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000188 break;
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200189 case KEY_NPAGE: /* Page up */
190 g_line -= LINES_SHOWN;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000191 break;
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200192 case KEY_PPAGE: /* Page down */
193 g_line += LINES_SHOWN;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000194 break;
195 }
196
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200197 if (g_line < 0)
198 g_line = 0;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000199
Yasha Cherikovsky37f45652015-11-14 19:21:14 +0200200 if (g_line > g_max_cursor_line)
201 g_line = g_max_cursor_line;
Uwe Hermann0ab8cdd2008-04-22 20:19:53 +0000202
203 return 1;
204}
205
206struct coreinfo_module bootlog_module = {
207 .name = "Bootlog",
208 .init = bootlog_module_init,
209 .redraw = bootlog_module_redraw,
210 .handle = bootlog_module_handle,
211};
212
213#else
214
215struct coreinfo_module bootlog_module = {
216};
217
218#endif