Change-Id: If5b4ae7d9f9046e56ca098c0469b503130bc8707 Signed-off-by: Elyes Haouas <ehaouas@noos.fr> Reviewed-on: https://review.coreboot.org/c/coreboot/+/61955 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Martin L Roth <gaumless@tutanota.com>
		
			
				
	
	
		
			282 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *
 | |
|  * Copyright (C) 2012 secunet Security Networks AG
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or modify
 | |
|  * it under the terms of the GNU General Public License as published by
 | |
|  * the Free Software Foundation; version 2 of the License.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  */
 | |
| 
 | |
| #include <coreboot_tables.h>
 | |
| #include <libpayload.h>
 | |
| 
 | |
| #include <curses.h>
 | |
| #include <form.h>
 | |
| #include <menu.h>
 | |
| 
 | |
| #ifndef HOSTED
 | |
| #define HOSTED 0
 | |
| #endif
 | |
| 
 | |
| static int min(int x, int y)
 | |
| {
 | |
| 	if (x < y)
 | |
| 		return x;
 | |
| 	return y;
 | |
| }
 | |
| 
 | |
| static int max(int x, int y)
 | |
| {
 | |
| 	if (x > y)
 | |
| 		return x;
 | |
| 	return y;
 | |
| }
 | |
| 
 | |
| static void render_form(FORM *form)
 | |
| {
 | |
| 	int y, x, line;
 | |
| 	WINDOW *w = form_win(form);
 | |
| 	WINDOW *inner_w = form_sub(form);
 | |
| 	int numlines = getmaxy(w) - 2;
 | |
| 	getyx(inner_w, y, x);
 | |
| 	line = y - (y % numlines);
 | |
| 	WINDOW *der = derwin(w, getmaxy(w) - 2, getmaxx(w) - 2, 1, 1);
 | |
| 	wclear(der);
 | |
| 	wrefresh(der);
 | |
| 	delwin(der);
 | |
| 	copywin(inner_w, w, line, 0, 1, 1, min(numlines, getmaxy(inner_w) - line), 68, 0);
 | |
| 	wmove(w, y + 1 - line, x + 1);
 | |
| 	wrefresh(w);
 | |
| }
 | |
| 
 | |
| /* determine number of options, and maximum option name length */
 | |
| static int count_cmos_options(struct cb_cmos_entries *option, int *numopts, int *maxlength)
 | |
| {
 | |
| 	int n_opts = 0;
 | |
| 	int max_l = 0;
 | |
| 
 | |
| 	while (option) {
 | |
| 		if ((option->config != 'r') && (strcmp("check_sum", (char *)option->name) != 0)) {
 | |
| 			max_l = max(max_l, strlen((char *)option->name));
 | |
| 			n_opts++;
 | |
| 		}
 | |
| 
 | |
| 		option = next_cmos_entry(option);
 | |
| 	}
 | |
| 
 | |
| 	if (n_opts == 0) {
 | |
| 		printf("NO CMOS OPTIONS FOUND. EXITING!!!");
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	*numopts = n_opts;
 | |
| 	*maxlength = max_l;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* walk over options, fetch details */
 | |
| static void cmos_walk_options(struct cb_cmos_option_table *opttbl, FIELD **fields, int numopts,
 | |
| 			      int maxlength)
 | |
| {
 | |
| 	struct cb_cmos_entries *option = first_cmos_entry(opttbl);
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = 0; i < numopts; i++) {
 | |
| 		while ((option->config == 'r') ||
 | |
| 		       (strcmp("check_sum", (char *)option->name) == 0)) {
 | |
| 			option = next_cmos_entry(option);
 | |
| 		}
 | |
| 		fields[2 * i] = new_field(1, strlen((char *)option->name), i * 2, 1, 0, 0);
 | |
| 		set_field_buffer(fields[2 * i], 0, (char *)option->name);
 | |
| 		field_opts_off(fields[2 * i], O_ACTIVE);
 | |
| 
 | |
| 		fields[2 * i + 1] = new_field(1, 40, i * 2, maxlength + 2, 0, 0);
 | |
| 		char *buf = NULL;
 | |
| 		int fail = get_option_as_string(use_nvram, opttbl, &buf, (char *)option->name);
 | |
| 		switch (option->config) {
 | |
| 		case 'h': {
 | |
| 			set_field_type(fields[2 * i + 1], TYPE_INTEGER, 0, 0,
 | |
| 				       (1 << option->length) - 1);
 | |
| 			field_opts_on(fields[2 * i + 1], O_BLANK);
 | |
| 			break;
 | |
| 		}
 | |
| 		case 's': {
 | |
| 			set_max_field(fields[2 * i + 1], option->length / 8);
 | |
| 			field_opts_off(fields[2 * i + 1], O_STATIC);
 | |
| 			break;
 | |
| 		}
 | |
| 		case 'e': {
 | |
| 			int numvals = 0;
 | |
| 			struct cb_cmos_enums *cmos_enum =
 | |
| 			    first_cmos_enum_of_id(opttbl, option->config_id);
 | |
| 
 | |
| 			/* if invalid data in CMOS, set buf to first enum */
 | |
| 			if (fail && cmos_enum) {
 | |
| 				buf = (char *)cmos_enum->text;
 | |
| 			}
 | |
| 
 | |
| 			while (cmos_enum) {
 | |
| 				numvals++;
 | |
| 				cmos_enum = next_cmos_enum_of_id(cmos_enum, option->config_id);
 | |
| 			}
 | |
| 
 | |
| 			char **values = malloc(sizeof(char *) * (numvals + 1));
 | |
| 			int cnt = 0;
 | |
| 
 | |
| 			cmos_enum =
 | |
| 			    first_cmos_enum_of_id(opttbl, option->config_id);
 | |
| 			while (cmos_enum) {
 | |
| 				values[cnt] = (char *)cmos_enum->text;
 | |
| 				cnt++;
 | |
| 				cmos_enum = next_cmos_enum_of_id(cmos_enum, option->config_id);
 | |
| 			}
 | |
| 			values[cnt] = NULL;
 | |
| 			field_opts_off(fields[2 * i + 1], O_EDIT);
 | |
| 			set_field_type(fields[2 * i + 1], TYPE_ENUM, values, 1, 1);
 | |
| 			free(values); // copied by set_field_type
 | |
| 			break;
 | |
| 		}
 | |
| 		default:
 | |
| 			break;
 | |
| 		}
 | |
| 		if (buf)
 | |
| 			set_field_buffer(fields[2 * i + 1], 0, buf);
 | |
| #if HOSTED
 | |
| 		// underline is non-trivial on VGA text
 | |
| 		set_field_back(fields[2 * i + 1], A_UNDERLINE);
 | |
| #endif
 | |
| 		field_opts_off(fields[2 * i + 1], O_BLANK | O_AUTOSKIP | O_NULLOK);
 | |
| 
 | |
| 		option = next_cmos_entry(option);
 | |
| 	}
 | |
| 
 | |
| 	fields[2 * numopts] = NULL;
 | |
| }
 | |
| 
 | |
| int main(void)
 | |
| {
 | |
| 	int ch, done;
 | |
| 	int i;
 | |
| 
 | |
| 	if (CONFIG(LP_USB))
 | |
| 		usb_initialize();
 | |
| 
 | |
| 	/* coreboot data structures */
 | |
| 	lib_get_sysinfo();
 | |
| 
 | |
| 	struct cb_cmos_option_table *opttbl = get_system_option_table();
 | |
| 
 | |
| 	if (opttbl == NULL) {
 | |
| 		printf("Could not find coreboot option table.\n");
 | |
| 		halt();
 | |
| 	}
 | |
| 
 | |
| 	/* prep CMOS layout into libcurses data structures */
 | |
| 
 | |
| 	struct cb_cmos_entries *option = first_cmos_entry(opttbl);
 | |
| 	int numopts = 0;
 | |
| 	int maxlength = 0;
 | |
| 
 | |
| 	count_cmos_options(option, &numopts, &maxlength);
 | |
| 
 | |
| 	FIELD **fields = malloc(sizeof(FIELD *) * (2 * numopts + 1));
 | |
| 
 | |
| 	cmos_walk_options(opttbl, fields, numopts, maxlength);
 | |
| 
 | |
| 	/* display initialization */
 | |
| 	initscr();
 | |
| 	keypad(stdscr, TRUE);
 | |
| 	cbreak();
 | |
| 	noecho();
 | |
| 
 | |
| 	if (start_color()) {
 | |
| 		assume_default_colors(COLOR_BLUE, COLOR_CYAN);
 | |
| 	}
 | |
| 	leaveok(stdscr, TRUE);
 | |
| 	curs_set(1);
 | |
| 
 | |
| 	erase();
 | |
| 	box(stdscr, 0, 0);
 | |
| 	mvaddstr(0, 2, "coreboot configuration utility");
 | |
| 	refresh();
 | |
| 
 | |
| 	FORM *form = new_form(fields);
 | |
| 	int numlines = min(numopts * 2, 16);
 | |
| 	WINDOW *w = newwin(numlines + 2, 70, 2, 1);
 | |
| 	WINDOW *inner_w = newpad(numopts * 2, 68);
 | |
| 	box(w, 0, 0);
 | |
| 	mvwaddstr(w, 0, 2, "Press F1 when done");
 | |
| 	set_form_win(form, w);
 | |
| 	set_form_sub(form, inner_w);
 | |
| 	post_form(form);
 | |
| 
 | |
| 	done = 0;
 | |
| 	while (!done) {
 | |
| 		render_form(form);
 | |
| 		ch = getch();
 | |
| 		if (ch == ERR)
 | |
| 			continue;
 | |
| 		switch (ch) {
 | |
| 		case KEY_DOWN:
 | |
| 			form_driver(form, REQ_NEXT_FIELD);
 | |
| 			break;
 | |
| 		case KEY_UP:
 | |
| 			form_driver(form, REQ_PREV_FIELD);
 | |
| 			break;
 | |
| 		case KEY_LEFT:
 | |
| 			if (field_type(current_field(form)) == TYPE_ENUM) {
 | |
| 				form_driver(form, REQ_PREV_CHOICE);
 | |
| 			} else {
 | |
| 				form_driver(form, REQ_LEFT_CHAR);
 | |
| 			}
 | |
| 			break;
 | |
| 		case KEY_RIGHT:
 | |
| 			if (field_type(current_field(form)) == TYPE_ENUM) {
 | |
| 				form_driver(form, REQ_NEXT_CHOICE);
 | |
| 			} else {
 | |
| 				form_driver(form, REQ_RIGHT_CHAR);
 | |
| 			}
 | |
| 			break;
 | |
| 		case KEY_BACKSPACE:
 | |
| 		case '\b':
 | |
| 			form_driver(form, REQ_DEL_PREV);
 | |
| 			break;
 | |
| 		case KEY_DC:
 | |
| 			form_driver(form, REQ_DEL_CHAR);
 | |
| 			break;
 | |
| 		case KEY_F(1):
 | |
| 			done = 1;
 | |
| 			break;
 | |
| 		default:
 | |
| 			form_driver(form, ch);
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	endwin();
 | |
| 
 | |
| 	for (i = 0; i < numopts; i++) {
 | |
| 		char *name = field_buffer(fields[2 * i], 0);
 | |
| 		char *value = field_buffer(fields[2 * i + 1], 0);
 | |
| 		char *ptr;
 | |
| 		for (ptr = value + strlen(value) - 1;
 | |
| 		     ptr >= value && *ptr == ' '; ptr--)
 | |
| 			;
 | |
| 		ptr[1] = '\0';
 | |
| 		set_option_from_string(use_nvram, opttbl, value, name);
 | |
| 	}
 | |
| 
 | |
| 	unpost_form(form);
 | |
| 	free_form(form);
 | |
| 
 | |
| 	/* reboot */
 | |
| 	outb(0x6, 0xcf9);
 | |
| 	halt();
 | |
| }
 |