coreinfo: Rewrite bootlog_module
The old bootlog_module implementation was completely broken: - It assumed that the console buffer is located at address 0x90000, and of size 64K. It is not correct nowadays. - It displayed the buffer in a very hacky way, the code was riddled with TODOs and FIXMEs. Scrolling had sometimes unexpected behavior. The new implementation: - Uses the cbmem console as the source of data. It takes the console information from lib_sysinfo of libpayload, which is constructed from the coreboot tables (no more hardcoded adressess). - Properly sanitizes the console buffer for display, which makes scolling and display much easier to implement. Change-Id: I3f87ec920631da2acfd3f52273228703f22f469f Signed-off-by: Yasha Cherikovsky <yasha.che3@gmail.com> Reviewed-on: http://review.coreboot.org/12440 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth <martinroth@google.com>
This commit is contained in:
		
				
					committed by
					
						
						Stefan Reinauer
					
				
			
			
				
	
			
			
			
						parent
						
							75cdfd1d06
						
					
				
				
					commit
					37f4565b8b
				
			@@ -17,33 +17,134 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#if IS_ENABLED(CONFIG_MODULE_BOOTLOG)
 | 
					#if IS_ENABLED(CONFIG_MODULE_BOOTLOG)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CONFIG_COREBOOT_PRINTK_BUFFER_ADDR 0x90000
 | 
					#define LINES_SHOWN 19
 | 
				
			||||||
#define CONFIG_COREBOOT_PRINTK_BUFFER_SIZE 65536
 | 
					#define TAB_WIDTH 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *buf;
 | 
					
 | 
				
			||||||
static s32 cursor = 0;
 | 
					/* Globals that are used for tracking screen state */
 | 
				
			||||||
static s32 cursor_max;
 | 
					static char *g_buf = NULL;
 | 
				
			||||||
 | 
					static s32 g_line = 0;
 | 
				
			||||||
 | 
					static s32 g_lines_count = 0;
 | 
				
			||||||
 | 
					static s32 g_max_cursor_line = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Copied from libpayload/drivers/cbmem_console.c */
 | 
				
			||||||
 | 
					struct cbmem_console {
 | 
				
			||||||
 | 
						u32 size;
 | 
				
			||||||
 | 
						u32 cursor;
 | 
				
			||||||
 | 
						u8 body[0];
 | 
				
			||||||
 | 
					} __attribute__ ((__packed__));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static u32 char_width(char c, u32 cursor, u32 screen_width)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (c == '\n') {
 | 
				
			||||||
 | 
							return screen_width - (cursor % screen_width);
 | 
				
			||||||
 | 
						} else if (c == '\t') {
 | 
				
			||||||
 | 
							return TAB_WIDTH;
 | 
				
			||||||
 | 
						} else if (isprint(c)) {
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static u32 calculate_chars_count(char *str, u32 str_len, u32 screen_width, u32 screen_height)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 i, count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < str_len; i++) {
 | 
				
			||||||
 | 
							count += char_width(str[i], count, screen_width);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Ensure that 'count' can occupy at least the whole screen */
 | 
				
			||||||
 | 
						if (count < screen_width * screen_height) {
 | 
				
			||||||
 | 
							count = screen_width * screen_height;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Pad to line end */
 | 
				
			||||||
 | 
						if (count % screen_width != 0) {
 | 
				
			||||||
 | 
							count += screen_width - (count % screen_width);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This method takes an input buffer and sanitizes it for display, which means:
 | 
				
			||||||
 | 
					 *  - '\n' is converted to spaces until end of line
 | 
				
			||||||
 | 
					 *  - Tabs are converted to spaces of size TAB_WIDTH
 | 
				
			||||||
 | 
					 *  - Only printable characters are preserved
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int sanitize_buffer_for_display(char *str, u32 str_len, char *out, u32 out_len, u32 screen_width)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 cursor = 0;
 | 
				
			||||||
 | 
						u32 i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < str_len && cursor < out_len; i++) {
 | 
				
			||||||
 | 
							u32 width = char_width(str[i], cursor, screen_width);
 | 
				
			||||||
 | 
							if (width == 1) {
 | 
				
			||||||
 | 
								out[cursor++] = str[i];
 | 
				
			||||||
 | 
							} else if (width > 1) {
 | 
				
			||||||
 | 
								while (width-- && cursor < out_len) {
 | 
				
			||||||
 | 
									out[cursor++] = ' ';
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Fill the rest of the out buffer with spaces */
 | 
				
			||||||
 | 
						while (cursor < out_len) {
 | 
				
			||||||
 | 
							out[cursor++] = ' ';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int bootlog_module_init(void)
 | 
					static int bootlog_module_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						/* Make sure that lib_sysinfo is initialized */
 | 
				
			||||||
	volatile unsigned long *ptr =
 | 
						int ret = lib_get_sysinfo();
 | 
				
			||||||
		(void *)(CONFIG_COREBOOT_PRINTK_BUFFER_ADDR + 16); /* FIXME */
 | 
						if (ret) {
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
	buf = malloc(CONFIG_COREBOOT_PRINTK_BUFFER_SIZE);
 | 
					 | 
				
			||||||
	if (!buf) {
 | 
					 | 
				
			||||||
		/* TODO */
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memcpy(buf, (char *)ptr, CONFIG_COREBOOT_PRINTK_BUFFER_SIZE);
 | 
						struct cbmem_console *console = lib_sysinfo.cbmem_cons;
 | 
				
			||||||
 | 
						if (console == NULL) {
 | 
				
			||||||
	cursor_max = CONFIG_COREBOOT_PRINTK_BUFFER_SIZE;
 | 
							return -1;
 | 
				
			||||||
	for (i = 0; i < 20; i++) {
 | 
						}
 | 
				
			||||||
		do {
 | 
						/* Extract console information */
 | 
				
			||||||
			cursor_max--;
 | 
						char *buffer = (char *)(&(console->body));
 | 
				
			||||||
		} while (*(buf + cursor_max) != '\n');
 | 
						u32 buffer_size = console->size;
 | 
				
			||||||
 | 
						u32 cursor = console->cursor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The cursor may be bigger than buffer size when the buffer is full */
 | 
				
			||||||
 | 
						if (cursor >= buffer_size) {
 | 
				
			||||||
 | 
							cursor = buffer_size - 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Calculate how much characters will be displayed on screen */
 | 
				
			||||||
 | 
						u32 chars_count = calculate_chars_count(buffer, cursor + 1, SCREEN_X, LINES_SHOWN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Sanity check, chars_count must be padded to full line */
 | 
				
			||||||
 | 
						if (chars_count % SCREEN_X != 0) {
 | 
				
			||||||
 | 
							return -2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						g_lines_count = chars_count / SCREEN_X;
 | 
				
			||||||
 | 
						g_max_cursor_line = MAX(g_lines_count - 1 - LINES_SHOWN, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						g_buf = malloc(chars_count);
 | 
				
			||||||
 | 
						if (!g_buf) {
 | 
				
			||||||
 | 
							return -3;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sanitize_buffer_for_display(buffer, cursor + 1,
 | 
				
			||||||
 | 
														g_buf, chars_count,
 | 
				
			||||||
 | 
														SCREEN_X) < 0) {
 | 
				
			||||||
 | 
							free(g_buf);
 | 
				
			||||||
 | 
							g_buf = NULL;
 | 
				
			||||||
 | 
							return -4;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cursor_max++;	/* Stay _behind_ the newline. */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO: Maybe a _cleanup hook where we call free()? */
 | 
						/* TODO: Maybe a _cleanup hook where we call free()? */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -52,74 +153,52 @@ static int bootlog_module_init(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int bootlog_module_redraw(WINDOW *win)
 | 
					static int bootlog_module_redraw(WINDOW *win)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int x = 0, y = 0;
 | 
					 | 
				
			||||||
	char *tmp = buf + cursor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	print_module_title(win, "Coreboot Bootlog");
 | 
						print_module_title(win, "Coreboot Bootlog");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: Handle lines longer than 80 characters. */
 | 
						if (!g_buf) {
 | 
				
			||||||
	while (y <= 18) {
 | 
							return -1;
 | 
				
			||||||
		mvwaddch(win, y + 2, x, isprint(*tmp) ? *tmp : ' ');
 | 
					 | 
				
			||||||
		x++;
 | 
					 | 
				
			||||||
		tmp++;
 | 
					 | 
				
			||||||
		if (*tmp == '\n') {
 | 
					 | 
				
			||||||
			y++;
 | 
					 | 
				
			||||||
			x = 0;
 | 
					 | 
				
			||||||
			tmp++;		/* Skip the newline. */
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int x = 0, y = 0;
 | 
				
			||||||
 | 
						char *tmp = g_buf + g_line * SCREEN_X;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (y = 0; y < LINES_SHOWN; y++) {
 | 
				
			||||||
 | 
							for (x = 0; x < SCREEN_X; x++) {
 | 
				
			||||||
 | 
								mvwaddch(win, y + 2, x, *tmp);
 | 
				
			||||||
 | 
								tmp++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* TODO: Simplify code. */
 | 
					 | 
				
			||||||
static int bootlog_module_handle(int key)
 | 
					static int bootlog_module_handle(int key)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						if (!g_buf) {
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (key) {
 | 
						switch (key) {
 | 
				
			||||||
	case KEY_DOWN:
 | 
						case KEY_DOWN:
 | 
				
			||||||
		if (cursor == cursor_max)
 | 
							g_line++;
 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		while (*(buf + cursor) != '\n')
 | 
					 | 
				
			||||||
			cursor++;
 | 
					 | 
				
			||||||
		cursor++;	/* Skip the newline. */
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case KEY_UP:
 | 
						case KEY_UP:
 | 
				
			||||||
		if (cursor == 0)
 | 
							g_line--;
 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		cursor--;	/* Skip the newline. */
 | 
					 | 
				
			||||||
		do {
 | 
					 | 
				
			||||||
			cursor--;
 | 
					 | 
				
			||||||
		} while (*(buf + cursor) != '\n');
 | 
					 | 
				
			||||||
		cursor++;	/* Stay _behind_ the newline. */
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case KEY_NPAGE:
 | 
						case KEY_NPAGE: /* Page up */
 | 
				
			||||||
		if (cursor == cursor_max)
 | 
							g_line -= LINES_SHOWN;
 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		for (i = 0; i < 20; i++) {
 | 
					 | 
				
			||||||
			while (*(buf + cursor) != '\n')
 | 
					 | 
				
			||||||
				cursor++;
 | 
					 | 
				
			||||||
			cursor++;	/* Skip the newline. */
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case KEY_PPAGE:
 | 
						case KEY_PPAGE: /* Page down */
 | 
				
			||||||
		if (cursor == 0)
 | 
							g_line += LINES_SHOWN;
 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		for (i = 0; i < 20; i++) {
 | 
					 | 
				
			||||||
			do {
 | 
					 | 
				
			||||||
				cursor--;
 | 
					 | 
				
			||||||
			} while (*(buf + cursor) != '\n');
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		cursor++;	/* Stay _behind_ the newline. */
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cursor > cursor_max)
 | 
						if (g_line < 0)
 | 
				
			||||||
		cursor = cursor_max;
 | 
							g_line = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cursor < 0)
 | 
						if (g_line > g_max_cursor_line)
 | 
				
			||||||
		cursor = 0;
 | 
							g_line = g_max_cursor_line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user