blob: 08fef010c81fcb4281dfdd6a24140392f0f998bb [file] [log] [blame]
Patrick Georgi4b62ebe2012-11-16 15:05:11 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012 secunet Security Networks AG
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010014 */
15
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010016#include <coreboot_tables.h>
Martin Rothf62065f2016-04-23 17:24:57 -060017#include <libpayload.h>
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010018
19#include <curses.h>
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010020#include <form.h>
Martin Rothf62065f2016-04-23 17:24:57 -060021#include <menu.h>
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010022
23#ifndef HOSTED
24#define HOSTED 0
25#endif
26
27static int min(int x, int y)
28{
29 if (x < y)
30 return x;
31 return y;
32}
33
34static int max(int x, int y)
35{
36 if (x > y)
37 return x;
38 return y;
39}
40
41void render_form(FORM *form)
42{
43 int y, x, line;
44 WINDOW *w = form_win(form);
45 WINDOW *inner_w = form_sub(form);
Martin Rothf62065f2016-04-23 17:24:57 -060046 int numlines = getmaxy(w) - 2;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010047 getyx(inner_w, y, x);
48 line = y - (y % numlines);
Martin Rothf62065f2016-04-23 17:24:57 -060049 WINDOW *der = derwin(w, getmaxy(w) - 2, getmaxx(w) - 2, 1, 1);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010050 wclear(der);
51 wrefresh(der);
52 delwin(der);
Martin Rothf62065f2016-04-23 17:24:57 -060053 copywin(inner_w, w, line, 0, 1, 1,
54 min(numlines, getmaxy(inner_w) - line), 68, 0);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010055 wmove(w, y + 1 - line, x + 1);
56 wrefresh(w);
57}
58
59int main()
60{
61 int ch, done;
Martin Rothf62065f2016-04-23 17:24:57 -060062
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010063 /* coreboot data structures */
64 lib_get_sysinfo();
65
66 struct cb_cmos_option_table *opttbl = get_system_option_table();
67
68 if (opttbl == NULL) {
69 printf("Could not find coreboot option table\n");
70 halt();
71 }
72
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010073 /* prep CMOS layout into libcurses data structures */
Martin Rothf62065f2016-04-23 17:24:57 -060074
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010075 /* determine number of options, and maximum option name length */
Martin Rothf62065f2016-04-23 17:24:57 -060076 int numopts = 0;
77 int maxlength = 0;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010078 struct cb_cmos_entries *option = first_cmos_entry(opttbl);
79 while (option) {
Martin Rothf62065f2016-04-23 17:24:57 -060080 if ((option->config != 'r') &&
Martin Roth0cf7acc2016-04-26 12:33:44 -060081 (strcmp("check_sum", (char *)option->name) != 0)) {
82 maxlength = max(maxlength, strlen((char *)option->name));
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010083 numopts++;
84 }
85 option = next_cmos_entry(option);
86 }
87 if (numopts == 0) {
88 printf("NO CMOS OPTIONS FOUND. EXITING!!!");
89 return 1;
90 }
Martin Rothf62065f2016-04-23 17:24:57 -060091 FIELD **fields = malloc(sizeof(FIELD *) * (2 * numopts + 1));
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010092 int i;
93
94 /* walk over options, fetch details */
95 option = first_cmos_entry(opttbl);
Martin Rothf62065f2016-04-23 17:24:57 -060096 for (i = 0; i < numopts; i++) {
97 while ((option->config == 'r') ||
Martin Roth0cf7acc2016-04-26 12:33:44 -060098 (strcmp("check_sum", (char *)option->name) == 0)) {
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010099 option = next_cmos_entry(option);
100 }
Martin Rothf62065f2016-04-23 17:24:57 -0600101 fields[2 * i] =
Martin Roth0cf7acc2016-04-26 12:33:44 -0600102 new_field(1, strlen((char *)option->name), i * 2, 1, 0, 0);
103 set_field_buffer(fields[2 * i], 0, (char *)option->name);
Martin Rothf62065f2016-04-23 17:24:57 -0600104 field_opts_off(fields[2 * i], O_ACTIVE);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100105
Martin Rothf62065f2016-04-23 17:24:57 -0600106 fields[2 * i + 1] =
107 new_field(1, 40, i * 2, maxlength + 2, 0, 0);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100108 char *buf = NULL;
Martin Rothf62065f2016-04-23 17:24:57 -0600109 int fail =
Martin Roth0cf7acc2016-04-26 12:33:44 -0600110 get_option_as_string(use_nvram, opttbl, &buf, (char *)option->name);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100111 switch (option->config) {
112 case 'h': {
Martin Rothf62065f2016-04-23 17:24:57 -0600113 set_field_type(fields[2 * i + 1], TYPE_INTEGER, 0, 0,
114 (1 << option->length) - 1);
115 field_opts_on(fields[2 * i + 1], O_BLANK);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100116 break;
Martin Rothf62065f2016-04-23 17:24:57 -0600117 }
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100118 case 's': {
Martin Rothf62065f2016-04-23 17:24:57 -0600119 set_max_field(fields[2 * i + 1], option->length / 8);
120 field_opts_off(fields[2 * i + 1], O_STATIC);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100121 break;
Martin Rothf62065f2016-04-23 17:24:57 -0600122 }
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100123 case 'e': {
124 int numvals = 0;
Martin Rothf62065f2016-04-23 17:24:57 -0600125 struct cb_cmos_enums *cmos_enum =
126 first_cmos_enum_of_id(opttbl, option->config_id);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100127
128 /* if invalid data in CMOS, set buf to first enum */
129 if (fail && cmos_enum) {
Martin Roth0cf7acc2016-04-26 12:33:44 -0600130 buf = (char *)cmos_enum->text;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100131 }
132
133 while (cmos_enum) {
134 numvals++;
Martin Rothf62065f2016-04-23 17:24:57 -0600135 cmos_enum = next_cmos_enum_of_id(
136 cmos_enum, option->config_id);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100137 }
138
Martin Rothf62065f2016-04-23 17:24:57 -0600139 char **values = malloc(sizeof(char *) * (numvals + 1));
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100140 int cnt = 0;
141
Martin Rothf62065f2016-04-23 17:24:57 -0600142 cmos_enum =
143 first_cmos_enum_of_id(opttbl, option->config_id);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100144 while (cmos_enum) {
Martin Roth0cf7acc2016-04-26 12:33:44 -0600145 values[cnt] = (char *)cmos_enum->text;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100146 cnt++;
Martin Rothf62065f2016-04-23 17:24:57 -0600147 cmos_enum = next_cmos_enum_of_id(
148 cmos_enum, option->config_id);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100149 }
150 values[cnt] = NULL;
Martin Rothf62065f2016-04-23 17:24:57 -0600151 field_opts_off(fields[2 * i + 1], O_EDIT);
152 set_field_type(fields[2 * i + 1], TYPE_ENUM, values, 1,
153 1);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100154 free(values); // copied by set_field_type
155 break;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100156 }
Martin Rothf62065f2016-04-23 17:24:57 -0600157 default:
158 break;
159 }
160 if (buf)
161 set_field_buffer(fields[2 * i + 1], 0, buf);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100162#if HOSTED
Martin Rothf62065f2016-04-23 17:24:57 -0600163 // underline is non-trivial on VGA text
164 set_field_back(fields[2 * i + 1], A_UNDERLINE);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100165#endif
Martin Rothf62065f2016-04-23 17:24:57 -0600166 field_opts_off(fields[2 * i + 1],
167 O_BLANK | O_AUTOSKIP | O_NULLOK);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100168
169 option = next_cmos_entry(option);
170 }
Martin Rothf62065f2016-04-23 17:24:57 -0600171 fields[2 * numopts] = NULL;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100172
Lubomir Rintel1ecc8af2015-02-24 20:33:35 +0100173 /* display initialization */
174 initscr();
175 keypad(stdscr, TRUE);
176 cbreak();
177 noecho();
178
179 if (start_color()) {
Martin Rothf62065f2016-04-23 17:24:57 -0600180 assume_default_colors(COLOR_BLUE, COLOR_CYAN);
Lubomir Rintel1ecc8af2015-02-24 20:33:35 +0100181 }
182 leaveok(stdscr, TRUE);
183 curs_set(1);
184
185 erase();
186 box(stdscr, 0, 0);
187 mvaddstr(0, 2, "coreboot configuration utility");
188 refresh();
189
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100190 FORM *form = new_form(fields);
Martin Rothf62065f2016-04-23 17:24:57 -0600191 int numlines = min(numopts * 2, 16);
192 WINDOW *w = newwin(numlines + 2, 70, 2, 1);
193 WINDOW *inner_w = newpad(numopts * 2, 68);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100194 box(w, 0, 0);
195 mvwaddstr(w, 0, 2, "Press F1 when done");
196 set_form_win(form, w);
197 set_form_sub(form, inner_w);
198 post_form(form);
199
200 done = 0;
Martin Rothf62065f2016-04-23 17:24:57 -0600201 while (!done) {
Lubomir Rintel68009e92015-02-01 15:24:43 +0100202 render_form(form);
Martin Rothf62065f2016-04-23 17:24:57 -0600203 ch = getch();
204 if (ch == ERR)
205 continue;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100206 switch (ch) {
207 case KEY_DOWN:
208 form_driver(form, REQ_NEXT_FIELD);
209 break;
210 case KEY_UP:
211 form_driver(form, REQ_PREV_FIELD);
212 break;
213 case KEY_LEFT:
214 if (field_type(current_field(form)) == TYPE_ENUM) {
215 form_driver(form, REQ_PREV_CHOICE);
216 } else {
217 form_driver(form, REQ_LEFT_CHAR);
218 }
219 break;
220 case KEY_RIGHT:
221 if (field_type(current_field(form)) == TYPE_ENUM) {
222 form_driver(form, REQ_NEXT_CHOICE);
223 } else {
224 form_driver(form, REQ_RIGHT_CHAR);
225 }
226 break;
227 case KEY_BACKSPACE:
228 case '\b':
229 form_driver(form, REQ_DEL_PREV);
230 break;
231 case KEY_DC:
232 form_driver(form, REQ_DEL_CHAR);
233 break;
234 case KEY_F(1):
Martin Rothf62065f2016-04-23 17:24:57 -0600235 done = 1;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100236 break;
237 default:
238 form_driver(form, ch);
239 break;
240 }
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100241 }
242
Lubomir Rintel1ecc8af2015-02-24 20:33:35 +0100243 endwin();
244
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100245 for (i = 0; i < numopts; i++) {
Martin Rothf62065f2016-04-23 17:24:57 -0600246 char *name = field_buffer(fields[2 * i], 0);
247 char *value = field_buffer(fields[2 * i + 1], 0);
Vladimir Serbinenkoc9babb22014-01-15 22:07:52 +0100248 char *ptr;
Martin Rothf62065f2016-04-23 17:24:57 -0600249 for (ptr = value + strlen(value) - 1;
250 ptr >= value && *ptr == ' '; ptr--)
251 ;
Vladimir Serbinenkoc9babb22014-01-15 22:07:52 +0100252 ptr[1] = '\0';
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100253 set_option_from_string(use_nvram, opttbl, value, name);
254 }
255
256 unpost_form(form);
257 free_form(form);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100258
Vladimir Serbinenkoc7282882014-01-15 22:09:25 +0100259 /* reboot */
Martin Rothf62065f2016-04-23 17:24:57 -0600260 outb(0x6, 0xcf9);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100261 halt();
262}