1 /* SPDX-License-Identifier: GPL-2.0-only */
5 #if CONFIG(MODULE_BOOTLOG)
10 /* Globals that are used for tracking screen state */
11 static char *g_buf
= NULL
;
12 static s32 g_line
= 0;
13 static s32 g_lines_count
= 0;
14 static s32 g_max_cursor_line
= 0;
16 /* Copied from libpayload/drivers/cbmem_console.c */
17 struct cbmem_console
{
23 #define CURSOR_MASK ((1 << 28) - 1)
24 #define OVERFLOW (1 << 31)
26 static u32
char_width(char c
, u32 cursor
, u32 screen_width
)
29 return screen_width
- (cursor
% screen_width
);
30 } else if (c
== '\t') {
32 } else if (isprint(c
)) {
39 static u32
calculate_chars_count(char *str
, u32 str_len
, u32 screen_width
, u32 screen_height
)
43 for (i
= 0; i
< str_len
; i
++) {
44 count
+= char_width(str
[i
], count
, screen_width
);
47 /* Ensure that 'count' can occupy at least the whole screen */
48 if (count
< screen_width
* screen_height
) {
49 count
= screen_width
* screen_height
;
53 if (count
% screen_width
!= 0) {
54 count
+= screen_width
- (count
% screen_width
);
61 * This method takes an input buffer and sanitizes it for display, which means:
62 * - '\n' is converted to spaces until end of line
63 * - Tabs are converted to spaces of size TAB_WIDTH
64 * - Only printable characters are preserved
66 static int sanitize_buffer_for_display(char *str
, u32 str_len
, char *out
, u32 out_len
, u32 screen_width
)
71 for (i
= 0; i
< str_len
&& cursor
< out_len
; i
++) {
72 u32 width
= char_width(str
[i
], cursor
, screen_width
);
74 out
[cursor
++] = str
[i
];
75 } else if (width
> 1) {
76 while (width
-- && cursor
< out_len
) {
82 /* Fill the rest of the out buffer with spaces */
83 while (cursor
< out_len
) {
90 static int bootlog_module_init(void)
92 /* Make sure that lib_sysinfo is initialized */
93 int ret
= lib_get_sysinfo();
98 struct cbmem_console
*console
= phys_to_virt(lib_sysinfo
.cbmem_cons
);
99 if (console
== NULL
) {
102 /* Extract console information */
103 char *buffer
= (char *)(&(console
->body
));
104 u32 size
= console
->size
;
105 u32 cursor
= console
->cursor
& CURSOR_MASK
;
107 /* The cursor may be bigger than buffer size with older console code */
108 if (cursor
>= size
) {
112 /* Calculate how much characters will be displayed on screen */
113 u32 chars_count
= calculate_chars_count(buffer
, cursor
, SCREEN_X
, LINES_SHOWN
);
114 u32 overflow_chars_count
= 0;
115 if (console
->cursor
& OVERFLOW
) {
116 overflow_chars_count
= calculate_chars_count(buffer
+ cursor
,
117 size
- cursor
, SCREEN_X
, LINES_SHOWN
);
120 /* Sanity check, chars_count must be padded to full line */
121 if (chars_count
% SCREEN_X
|| overflow_chars_count
% SCREEN_X
) {
125 g_lines_count
= (chars_count
+ overflow_chars_count
) / SCREEN_X
;
126 g_max_cursor_line
= MAX(g_lines_count
- 1 - LINES_SHOWN
, 0);
128 g_buf
= malloc(chars_count
);
133 if (console
->cursor
& OVERFLOW
) {
134 if (sanitize_buffer_for_display(buffer
+ cursor
, size
- cursor
,
135 g_buf
, overflow_chars_count
, SCREEN_X
) < 0) {
139 if (sanitize_buffer_for_display(buffer
, cursor
,
140 g_buf
+ overflow_chars_count
,
141 chars_count
, SCREEN_X
) < 0) {
145 /* TODO: Maybe a _cleanup hook where we call free()? */
155 static int bootlog_module_redraw(WINDOW
*win
)
157 print_module_title(win
, "coreboot Bootlog");
164 char *tmp
= g_buf
+ g_line
* SCREEN_X
;
166 for (y
= 0; y
< LINES_SHOWN
; y
++) {
167 for (x
= 0; x
< SCREEN_X
; x
++) {
168 mvwaddch(win
, y
+ 2, x
, *tmp
);
177 static int bootlog_module_handle(int key
)
190 case KEY_NPAGE
: /* Page up */
191 g_line
-= LINES_SHOWN
;
193 case KEY_PPAGE
: /* Page down */
194 g_line
+= LINES_SHOWN
;
201 if (g_line
> g_max_cursor_line
)
202 g_line
= g_max_cursor_line
;
207 struct coreinfo_module bootlog_module
= {
209 .init
= bootlog_module_init
,
210 .redraw
= bootlog_module_redraw
,
211 .handle
= bootlog_module_handle
,
216 struct coreinfo_module bootlog_module
= {