amd/stoneyridge: Add warm reset detection
[coreboot.git] / payloads / coreinfo / bootlog_module.c
blob1d00744eac190a524dec47d58459acc77afe8137
1 /*
2 * This file is part of the coreinfo project.
4 * Copyright (C) 2008 Uwe Hermann <uwe@hermann-uwe.de>
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.
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.
16 #include "coreinfo.h"
18 #if IS_ENABLED(CONFIG_MODULE_BOOTLOG)
20 #define LINES_SHOWN 19
21 #define TAB_WIDTH 2
24 /* Globals that are used for tracking screen state */
25 static char *g_buf = NULL;
26 static s32 g_line = 0;
27 static s32 g_lines_count = 0;
28 static s32 g_max_cursor_line = 0;
31 /* Copied from libpayload/drivers/cbmem_console.c */
32 struct cbmem_console {
33 u32 size;
34 u32 cursor;
35 u8 body[0];
36 } __packed;
38 #define CURSOR_MASK ((1 << 28) - 1)
39 #define OVERFLOW (1 << 31)
42 static u32 char_width(char c, u32 cursor, u32 screen_width)
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;
52 return 0;
55 static u32 calculate_chars_count(char *str, u32 str_len, u32 screen_width, u32 screen_height)
57 u32 i, count = 0;
59 for (i = 0; i < str_len; i++) {
60 count += char_width(str[i], count, screen_width);
63 /* Ensure that 'count' can occupy at least the whole screen */
64 if (count < screen_width * screen_height) {
65 count = screen_width * screen_height;
68 /* Pad to line end */
69 if (count % screen_width != 0) {
70 count += screen_width - (count % screen_width);
73 return count;
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
82 static int sanitize_buffer_for_display(char *str, u32 str_len, char *out, u32 out_len, u32 screen_width)
84 u32 cursor = 0;
85 u32 i;
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++] = ' ';
98 /* Fill the rest of the out buffer with spaces */
99 while (cursor < out_len) {
100 out[cursor++] = ' ';
103 return 0;
106 static int bootlog_module_init(void)
108 /* Make sure that lib_sysinfo is initialized */
109 int ret = lib_get_sysinfo();
110 if (ret) {
111 return -1;
114 struct cbmem_console *console = lib_sysinfo.cbmem_cons;
115 if (console == NULL) {
116 return -1;
118 /* Extract console information */
119 char *buffer = (char *)(&(console->body));
120 u32 size = console->size;
121 u32 cursor = console->cursor & CURSOR_MASK;
123 /* The cursor may be bigger than buffer size with older console code */
124 if (cursor >= size) {
125 cursor = size - 1;
128 /* Calculate how much characters will be displayed on screen */
129 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);
136 /* Sanity check, chars_count must be padded to full line */
137 if (chars_count % SCREEN_X || overflow_chars_count % SCREEN_X) {
138 return -2;
141 g_lines_count = (chars_count + overflow_chars_count) / SCREEN_X;
142 g_max_cursor_line = MAX(g_lines_count - 1 - LINES_SHOWN, 0);
144 g_buf = malloc(chars_count);
145 if (!g_buf) {
146 return -3;
149 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;
155 if (sanitize_buffer_for_display(buffer, cursor,
156 g_buf + overflow_chars_count,
157 chars_count, SCREEN_X) < 0) {
158 goto err_free;
161 /* TODO: Maybe a _cleanup hook where we call free()? */
163 return 0;
165 err_free:
166 free(g_buf);
167 g_buf = NULL;
168 return -4;
171 static int bootlog_module_redraw(WINDOW *win)
173 print_module_title(win, "coreboot Bootlog");
175 if (!g_buf) {
176 return -1;
179 int x = 0, y = 0;
180 char *tmp = g_buf + g_line * SCREEN_X;
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++;
190 return 0;
193 static int bootlog_module_handle(int key)
195 if (!g_buf) {
196 return 0;
199 switch (key) {
200 case KEY_DOWN:
201 g_line++;
202 break;
203 case KEY_UP:
204 g_line--;
205 break;
206 case KEY_NPAGE: /* Page up */
207 g_line -= LINES_SHOWN;
208 break;
209 case KEY_PPAGE: /* Page down */
210 g_line += LINES_SHOWN;
211 break;
214 if (g_line < 0)
215 g_line = 0;
217 if (g_line > g_max_cursor_line)
218 g_line = g_max_cursor_line;
220 return 1;
223 struct coreinfo_module bootlog_module = {
224 .name = "Bootlog",
225 .init = bootlog_module_init,
226 .redraw = bootlog_module_redraw,
227 .handle = bootlog_module_handle,
230 #else
232 struct coreinfo_module bootlog_module = {
235 #endif