xref: /aosp_15_r20/external/coreboot/payloads/nvramcui/nvramcui.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2  *
3  * Copyright (C) 2012 secunet Security Networks AG
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; version 2 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14 
15 #include <coreboot_tables.h>
16 #include <libpayload.h>
17 
18 #include <curses.h>
19 #include <form.h>
20 #include <menu.h>
21 
22 #ifndef HOSTED
23 #define HOSTED 0
24 #endif
25 
min(int x,int y)26 static int min(int x, int y)
27 {
28 	if (x < y)
29 		return x;
30 	return y;
31 }
32 
max(int x,int y)33 static int max(int x, int y)
34 {
35 	if (x > y)
36 		return x;
37 	return y;
38 }
39 
render_form(FORM * form)40 static void render_form(FORM *form)
41 {
42 	int y, x, line;
43 	WINDOW *w = form_win(form);
44 	WINDOW *inner_w = form_sub(form);
45 	int numlines = getmaxy(w) - 2;
46 	getyx(inner_w, y, x);
47 	line = y - (y % numlines);
48 	WINDOW *der = derwin(w, getmaxy(w) - 2, getmaxx(w) - 2, 1, 1);
49 	wclear(der);
50 	wrefresh(der);
51 	delwin(der);
52 	copywin(inner_w, w, line, 0, 1, 1, min(numlines, getmaxy(inner_w) - line), 68, 0);
53 	wmove(w, y + 1 - line, x + 1);
54 	wrefresh(w);
55 }
56 
57 /* determine number of options, and maximum option name length */
count_cmos_options(struct cb_cmos_entries * option,int * numopts,int * maxlength)58 static int count_cmos_options(struct cb_cmos_entries *option, int *numopts, int *maxlength)
59 {
60 	int n_opts = 0;
61 	int max_l = 0;
62 
63 	while (option) {
64 		if ((option->config != 'r') && (strcmp("check_sum", (char *)option->name) != 0)) {
65 			max_l = max(max_l, strlen((char *)option->name));
66 			n_opts++;
67 		}
68 
69 		option = next_cmos_entry(option);
70 	}
71 
72 	if (n_opts == 0) {
73 		printf("NO CMOS OPTIONS FOUND. EXITING!!!");
74 		return -1;
75 	}
76 
77 	*numopts = n_opts;
78 	*maxlength = max_l;
79 
80 	return 0;
81 }
82 
83 /* walk over options, fetch details */
cmos_walk_options(struct cb_cmos_option_table * opttbl,FIELD ** fields,int numopts,int maxlength)84 static void cmos_walk_options(struct cb_cmos_option_table *opttbl, FIELD **fields, int numopts,
85 			      int maxlength)
86 {
87 	struct cb_cmos_entries *option = first_cmos_entry(opttbl);
88 	int i;
89 
90 	for (i = 0; i < numopts; i++) {
91 		while ((option->config == 'r') ||
92 		       (strcmp("check_sum", (char *)option->name) == 0)) {
93 			option = next_cmos_entry(option);
94 		}
95 		fields[2 * i] = new_field(1, strlen((char *)option->name), i * 2, 1, 0, 0);
96 		set_field_buffer(fields[2 * i], 0, (char *)option->name);
97 		field_opts_off(fields[2 * i], O_ACTIVE);
98 
99 		fields[2 * i + 1] = new_field(1, 40, i * 2, maxlength + 2, 0, 0);
100 		char *buf = NULL;
101 		int fail = get_option_as_string(use_nvram, opttbl, &buf, (char *)option->name);
102 		switch (option->config) {
103 		case 'h': {
104 			set_field_type(fields[2 * i + 1], TYPE_INTEGER, 0, 0,
105 				       (1 << option->length) - 1);
106 			field_opts_on(fields[2 * i + 1], O_BLANK);
107 			break;
108 		}
109 		case 's': {
110 			set_max_field(fields[2 * i + 1], option->length / 8);
111 			field_opts_off(fields[2 * i + 1], O_STATIC);
112 			break;
113 		}
114 		case 'e': {
115 			int numvals = 0;
116 			struct cb_cmos_enums *cmos_enum =
117 			    first_cmos_enum_of_id(opttbl, option->config_id);
118 
119 			/* if invalid data in CMOS, set buf to first enum */
120 			if (fail && cmos_enum) {
121 				buf = (char *)cmos_enum->text;
122 			}
123 
124 			while (cmos_enum) {
125 				numvals++;
126 				cmos_enum = next_cmos_enum_of_id(cmos_enum, option->config_id);
127 			}
128 
129 			char **values = malloc(sizeof(char *) * (numvals + 1));
130 			int cnt = 0;
131 
132 			cmos_enum =
133 			    first_cmos_enum_of_id(opttbl, option->config_id);
134 			while (cmos_enum) {
135 				values[cnt] = (char *)cmos_enum->text;
136 				cnt++;
137 				cmos_enum = next_cmos_enum_of_id(cmos_enum, option->config_id);
138 			}
139 			values[cnt] = NULL;
140 			field_opts_off(fields[2 * i + 1], O_EDIT);
141 			set_field_type(fields[2 * i + 1], TYPE_ENUM, values, 1, 1);
142 			free(values); // copied by set_field_type
143 			break;
144 		}
145 		default:
146 			break;
147 		}
148 		if (buf)
149 			set_field_buffer(fields[2 * i + 1], 0, buf);
150 #if HOSTED
151 		// underline is non-trivial on VGA text
152 		set_field_back(fields[2 * i + 1], A_UNDERLINE);
153 #endif
154 		field_opts_off(fields[2 * i + 1], O_BLANK | O_AUTOSKIP | O_NULLOK);
155 
156 		option = next_cmos_entry(option);
157 	}
158 
159 	fields[2 * numopts] = NULL;
160 }
161 
main(void)162 int main(void)
163 {
164 	int ch, done;
165 	int i;
166 
167 	if (CONFIG(LP_USB))
168 		usb_initialize();
169 
170 	/* coreboot data structures */
171 	lib_get_sysinfo();
172 
173 	struct cb_cmos_option_table *opttbl = get_system_option_table();
174 
175 	if (opttbl == NULL) {
176 		printf("Could not find coreboot option table.\n");
177 		halt();
178 	}
179 
180 	/* prep CMOS layout into libcurses data structures */
181 
182 	struct cb_cmos_entries *option = first_cmos_entry(opttbl);
183 	int numopts = 0;
184 	int maxlength = 0;
185 
186 	count_cmos_options(option, &numopts, &maxlength);
187 
188 	FIELD **fields = malloc(sizeof(FIELD *) * (2 * numopts + 1));
189 
190 	cmos_walk_options(opttbl, fields, numopts, maxlength);
191 
192 	/* display initialization */
193 	initscr();
194 	keypad(stdscr, TRUE);
195 	cbreak();
196 	noecho();
197 
198 	if (start_color()) {
199 		assume_default_colors(COLOR_BLUE, COLOR_CYAN);
200 	}
201 	leaveok(stdscr, TRUE);
202 	curs_set(1);
203 
204 	erase();
205 	box(stdscr, 0, 0);
206 	mvaddstr(0, 2, "coreboot configuration utility");
207 	refresh();
208 
209 	FORM *form = new_form(fields);
210 	int numlines = min(numopts * 2, 16);
211 	WINDOW *w = newwin(numlines + 2, 70, 2, 1);
212 	WINDOW *inner_w = newpad(numopts * 2, 68);
213 	box(w, 0, 0);
214 	mvwaddstr(w, 0, 2, "Press F1 when done");
215 	set_form_win(form, w);
216 	set_form_sub(form, inner_w);
217 	post_form(form);
218 
219 	done = 0;
220 	while (!done) {
221 		render_form(form);
222 		ch = getch();
223 		if (ch == ERR)
224 			continue;
225 		switch (ch) {
226 		case KEY_DOWN:
227 			form_driver(form, REQ_NEXT_FIELD);
228 			break;
229 		case KEY_UP:
230 			form_driver(form, REQ_PREV_FIELD);
231 			break;
232 		case KEY_LEFT:
233 			if (field_type(current_field(form)) == TYPE_ENUM) {
234 				form_driver(form, REQ_PREV_CHOICE);
235 			} else {
236 				form_driver(form, REQ_LEFT_CHAR);
237 			}
238 			break;
239 		case KEY_RIGHT:
240 			if (field_type(current_field(form)) == TYPE_ENUM) {
241 				form_driver(form, REQ_NEXT_CHOICE);
242 			} else {
243 				form_driver(form, REQ_RIGHT_CHAR);
244 			}
245 			break;
246 		case KEY_BACKSPACE:
247 		case '\b':
248 			form_driver(form, REQ_DEL_PREV);
249 			break;
250 		case KEY_DC:
251 			form_driver(form, REQ_DEL_CHAR);
252 			break;
253 		case KEY_F(1):
254 			done = 1;
255 			break;
256 		default:
257 			form_driver(form, ch);
258 			break;
259 		}
260 	}
261 
262 	endwin();
263 
264 	for (i = 0; i < numopts; i++) {
265 		char *name = field_buffer(fields[2 * i], 0);
266 		char *value = field_buffer(fields[2 * i + 1], 0);
267 		char *ptr;
268 		for (ptr = value + strlen(value) - 1;
269 		     ptr >= value && *ptr == ' '; ptr--)
270 			;
271 		ptr[1] = '\0';
272 		set_option_from_string(use_nvram, opttbl, value, name);
273 	}
274 
275 	unpost_form(form);
276 	free_form(form);
277 
278 	/* reboot */
279 	outb(0x6, 0xcf9);
280 	halt();
281 }
282