blob: b3a8306b263b732f7ea8eb9595bfe6b646f1e2b1 [file] [log] [blame]
Patrick Georgi4b62ebe2012-11-16 15:05:11 +01001/*
Patrick Georgi4b62ebe2012-11-16 15:05:11 +01002 *
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.
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010013 */
14
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010015#include <coreboot_tables.h>
Martin Rothf62065f2016-04-23 17:24:57 -060016#include <libpayload.h>
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010017
18#include <curses.h>
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010019#include <form.h>
Martin Rothf62065f2016-04-23 17:24:57 -060020#include <menu.h>
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010021
22#ifndef HOSTED
23#define HOSTED 0
24#endif
25
26static int min(int x, int y)
27{
28 if (x < y)
29 return x;
30 return y;
31}
32
33static int max(int x, int y)
34{
35 if (x > y)
36 return x;
37 return y;
38}
39
Nico Huber92675d62020-11-15 19:29:22 +010040static void render_form(FORM *form)
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010041{
42 int y, x, line;
43 WINDOW *w = form_win(form);
44 WINDOW *inner_w = form_sub(form);
Martin Rothf62065f2016-04-23 17:24:57 -060045 int numlines = getmaxy(w) - 2;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010046 getyx(inner_w, y, x);
47 line = y - (y % numlines);
Martin Rothf62065f2016-04-23 17:24:57 -060048 WINDOW *der = derwin(w, getmaxy(w) - 2, getmaxx(w) - 2, 1, 1);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010049 wclear(der);
50 wrefresh(der);
51 delwin(der);
Elyes Haouasae2c0452022-02-15 09:59:58 +010052 copywin(inner_w, w, line, 0, 1, 1, min(numlines, getmaxy(inner_w) - line), 68, 0);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010053 wmove(w, y + 1 - line, x + 1);
54 wrefresh(w);
55}
56
Antonello Dettori904dd302016-08-18 10:32:27 +020057/* determine number of options, and maximum option name length */
Elyes Haouasae2c0452022-02-15 09:59:58 +010058static int count_cmos_options(struct cb_cmos_entries *option, int *numopts, int *maxlength)
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010059{
Antonello Dettori904dd302016-08-18 10:32:27 +020060 int n_opts = 0;
61 int max_l = 0;
Martin Rothf62065f2016-04-23 17:24:57 -060062
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010063 while (option) {
Elyes Haouasae2c0452022-02-15 09:59:58 +010064 if ((option->config != 'r') && (strcmp("check_sum", (char *)option->name) != 0)) {
Antonello Dettori904dd302016-08-18 10:32:27 +020065 max_l = max(max_l, strlen((char *)option->name));
66 n_opts++;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010067 }
Antonello Dettori904dd302016-08-18 10:32:27 +020068
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010069 option = next_cmos_entry(option);
70 }
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010071
Antonello Dettori904dd302016-08-18 10:32:27 +020072 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;
Antonello Dettori904dd302016-08-18 10:32:27 +020081}
82
83/* walk over options, fetch details */
Elyes Haouasae2c0452022-02-15 09:59:58 +010084static void cmos_walk_options(struct cb_cmos_option_table *opttbl, FIELD **fields, int numopts,
85 int maxlength)
Antonello Dettori904dd302016-08-18 10:32:27 +020086{
87 struct cb_cmos_entries *option = first_cmos_entry(opttbl);
Paul Menzele7385d12017-01-20 23:29:21 +010088 int i;
Antonello Dettori904dd302016-08-18 10:32:27 +020089
Paul Menzele7385d12017-01-20 23:29:21 +010090 for (i = 0; i < numopts; i++) {
Martin Rothf62065f2016-04-23 17:24:57 -060091 while ((option->config == 'r') ||
Martin Roth0cf7acc2016-04-26 12:33:44 -060092 (strcmp("check_sum", (char *)option->name) == 0)) {
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010093 option = next_cmos_entry(option);
94 }
Elyes Haouasae2c0452022-02-15 09:59:58 +010095 fields[2 * i] = new_field(1, strlen((char *)option->name), i * 2, 1, 0, 0);
Martin Roth0cf7acc2016-04-26 12:33:44 -060096 set_field_buffer(fields[2 * i], 0, (char *)option->name);
Martin Rothf62065f2016-04-23 17:24:57 -060097 field_opts_off(fields[2 * i], O_ACTIVE);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010098
Elyes Haouasae2c0452022-02-15 09:59:58 +010099 fields[2 * i + 1] = new_field(1, 40, i * 2, maxlength + 2, 0, 0);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100100 char *buf = NULL;
Elyes Haouasae2c0452022-02-15 09:59:58 +0100101 int fail = get_option_as_string(use_nvram, opttbl, &buf, (char *)option->name);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100102 switch (option->config) {
103 case 'h': {
Martin Rothf62065f2016-04-23 17:24:57 -0600104 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);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100107 break;
Martin Rothf62065f2016-04-23 17:24:57 -0600108 }
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100109 case 's': {
Martin Rothf62065f2016-04-23 17:24:57 -0600110 set_max_field(fields[2 * i + 1], option->length / 8);
111 field_opts_off(fields[2 * i + 1], O_STATIC);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100112 break;
Martin Rothf62065f2016-04-23 17:24:57 -0600113 }
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100114 case 'e': {
115 int numvals = 0;
Martin Rothf62065f2016-04-23 17:24:57 -0600116 struct cb_cmos_enums *cmos_enum =
117 first_cmos_enum_of_id(opttbl, option->config_id);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100118
119 /* if invalid data in CMOS, set buf to first enum */
120 if (fail && cmos_enum) {
Martin Roth0cf7acc2016-04-26 12:33:44 -0600121 buf = (char *)cmos_enum->text;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100122 }
123
124 while (cmos_enum) {
125 numvals++;
Elyes Haouasae2c0452022-02-15 09:59:58 +0100126 cmos_enum = next_cmos_enum_of_id(cmos_enum, option->config_id);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100127 }
128
Martin Rothf62065f2016-04-23 17:24:57 -0600129 char **values = malloc(sizeof(char *) * (numvals + 1));
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100130 int cnt = 0;
131
Martin Rothf62065f2016-04-23 17:24:57 -0600132 cmos_enum =
133 first_cmos_enum_of_id(opttbl, option->config_id);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100134 while (cmos_enum) {
Martin Roth0cf7acc2016-04-26 12:33:44 -0600135 values[cnt] = (char *)cmos_enum->text;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100136 cnt++;
Elyes Haouasae2c0452022-02-15 09:59:58 +0100137 cmos_enum = next_cmos_enum_of_id(cmos_enum, option->config_id);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100138 }
139 values[cnt] = NULL;
Martin Rothf62065f2016-04-23 17:24:57 -0600140 field_opts_off(fields[2 * i + 1], O_EDIT);
Elyes Haouasae2c0452022-02-15 09:59:58 +0100141 set_field_type(fields[2 * i + 1], TYPE_ENUM, values, 1, 1);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100142 free(values); // copied by set_field_type
143 break;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100144 }
Martin Rothf62065f2016-04-23 17:24:57 -0600145 default:
146 break;
147 }
148 if (buf)
149 set_field_buffer(fields[2 * i + 1], 0, buf);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100150#if HOSTED
Martin Rothf62065f2016-04-23 17:24:57 -0600151 // underline is non-trivial on VGA text
152 set_field_back(fields[2 * i + 1], A_UNDERLINE);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100153#endif
Elyes Haouasae2c0452022-02-15 09:59:58 +0100154 field_opts_off(fields[2 * i + 1], O_BLANK | O_AUTOSKIP | O_NULLOK);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100155
156 option = next_cmos_entry(option);
157 }
Antonello Dettori904dd302016-08-18 10:32:27 +0200158
Martin Rothf62065f2016-04-23 17:24:57 -0600159 fields[2 * numopts] = NULL;
Antonello Dettori904dd302016-08-18 10:32:27 +0200160}
161
162int main(void)
163{
164 int ch, done;
Paul Menzele7385d12017-01-20 23:29:21 +0100165 int i;
Antonello Dettori904dd302016-08-18 10:32:27 +0200166
Julius Wernereab2a292019-03-05 16:55:15 -0800167 if (CONFIG(LP_USB))
Paul Menzelafbc2c92017-03-13 17:56:17 +0100168 usb_initialize();
Nicola Cornafece39b2017-03-10 17:34:03 +0100169
Antonello Dettori904dd302016-08-18 10:32:27 +0200170 /* coreboot data structures */
171 lib_get_sysinfo();
172
173 struct cb_cmos_option_table *opttbl = get_system_option_table();
174
Antonello Dettori079feec2016-08-18 10:32:27 +0200175 if (opttbl == NULL) {
176 printf("Could not find coreboot option table.\n");
Antonello Dettori904dd302016-08-18 10:32:27 +0200177 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);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100191
Lubomir Rintel1ecc8af2015-02-24 20:33:35 +0100192 /* display initialization */
193 initscr();
194 keypad(stdscr, TRUE);
195 cbreak();
196 noecho();
197
198 if (start_color()) {
Martin Rothf62065f2016-04-23 17:24:57 -0600199 assume_default_colors(COLOR_BLUE, COLOR_CYAN);
Lubomir Rintel1ecc8af2015-02-24 20:33:35 +0100200 }
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
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100209 FORM *form = new_form(fields);
Martin Rothf62065f2016-04-23 17:24:57 -0600210 int numlines = min(numopts * 2, 16);
211 WINDOW *w = newwin(numlines + 2, 70, 2, 1);
212 WINDOW *inner_w = newpad(numopts * 2, 68);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100213 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;
Martin Rothf62065f2016-04-23 17:24:57 -0600220 while (!done) {
Lubomir Rintel68009e92015-02-01 15:24:43 +0100221 render_form(form);
Martin Rothf62065f2016-04-23 17:24:57 -0600222 ch = getch();
223 if (ch == ERR)
224 continue;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100225 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):
Martin Rothf62065f2016-04-23 17:24:57 -0600254 done = 1;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100255 break;
256 default:
257 form_driver(form, ch);
258 break;
259 }
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100260 }
261
Lubomir Rintel1ecc8af2015-02-24 20:33:35 +0100262 endwin();
263
Paul Menzele7385d12017-01-20 23:29:21 +0100264 for (i = 0; i < numopts; i++) {
Martin Rothf62065f2016-04-23 17:24:57 -0600265 char *name = field_buffer(fields[2 * i], 0);
266 char *value = field_buffer(fields[2 * i + 1], 0);
Vladimir Serbinenkoc9babb22014-01-15 22:07:52 +0100267 char *ptr;
Martin Rothf62065f2016-04-23 17:24:57 -0600268 for (ptr = value + strlen(value) - 1;
269 ptr >= value && *ptr == ' '; ptr--)
270 ;
Vladimir Serbinenkoc9babb22014-01-15 22:07:52 +0100271 ptr[1] = '\0';
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100272 set_option_from_string(use_nvram, opttbl, value, name);
273 }
274
275 unpost_form(form);
276 free_form(form);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100277
Vladimir Serbinenkoc7282882014-01-15 22:09:25 +0100278 /* reboot */
Martin Rothf62065f2016-04-23 17:24:57 -0600279 outb(0x6, 0xcf9);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100280 halt();
281}