blob: 5a8ca5047ab0fd1bc1cd2bb65d147ae79e88a73f [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.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
Paul Menzela46a7122013-02-23 18:37:27 +010017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010018 */
19
20#include <stdlib.h>
21#include <string.h>
22
23#include <libpayload.h>
24#include <coreboot_tables.h>
25
26#include <curses.h>
27#include <menu.h>
28#include <form.h>
29
30#ifndef HOSTED
31#define HOSTED 0
32#endif
33
34static int min(int x, int y)
35{
36 if (x < y)
37 return x;
38 return y;
39}
40
41static int max(int x, int y)
42{
43 if (x > y)
44 return x;
45 return y;
46}
47
48void render_form(FORM *form)
49{
50 int y, x, line;
51 WINDOW *w = form_win(form);
52 WINDOW *inner_w = form_sub(form);
53 int numlines = getmaxy(w)-2;
54 getyx(inner_w, y, x);
55 line = y - (y % numlines);
56 WINDOW *der = derwin(w, getmaxy(w)-2, getmaxx(w)-2, 1, 1);
57 wclear(der);
58 wrefresh(der);
59 delwin(der);
60 copywin(inner_w, w, line, 0, 1, 1, min(numlines, getmaxy(inner_w)-line), 68, 0);
61 wmove(w, y + 1 - line, x + 1);
62 wrefresh(w);
63}
64
65int main()
66{
67 int ch, done;
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010068
69 /* coreboot data structures */
70 lib_get_sysinfo();
71
72 struct cb_cmos_option_table *opttbl = get_system_option_table();
73
74 if (opttbl == NULL) {
75 printf("Could not find coreboot option table\n");
76 halt();
77 }
78
Patrick Georgi4b62ebe2012-11-16 15:05:11 +010079 /* prep CMOS layout into libcurses data structures */
80
81 /* determine number of options, and maximum option name length */
82 int numopts=0;
83 int maxlength=0;
84 struct cb_cmos_entries *option = first_cmos_entry(opttbl);
85 while (option) {
86 if ((option->config != 'r') && (strcmp("check_sum", option->name) != 0)) {
87 maxlength = max(maxlength, strlen(option->name));
88 numopts++;
89 }
90 option = next_cmos_entry(option);
91 }
92 if (numopts == 0) {
93 printf("NO CMOS OPTIONS FOUND. EXITING!!!");
94 return 1;
95 }
96 FIELD **fields = malloc(sizeof(FIELD*)*(2*numopts+1));
97 int i;
98
99 /* walk over options, fetch details */
100 option = first_cmos_entry(opttbl);
101 for (i=0;i<numopts;i++) {
102 while ((option->config == 'r') || (strcmp("check_sum", option->name) == 0)) {
103 option = next_cmos_entry(option);
104 }
105 fields[2*i] = new_field(1, strlen(option->name), i*2, 1, 0, 0);
106 set_field_buffer(fields[2*i], 0, option->name);
107 field_opts_off(fields[2*i], O_ACTIVE);
108
109 fields[2*i+1] = new_field(1, 40, i*2, maxlength+2, 0, 0);
110 char *buf = NULL;
111 int fail = get_option_as_string(use_nvram, opttbl, &buf, option->name);
112 switch (option->config) {
113 case 'h': {
114 set_field_type(fields[2*i+1], TYPE_INTEGER, 0, 0, (1<<option->length)-1);
115 field_opts_on(fields[2*i+1], O_BLANK);
116 break;
117 }
118 case 's': {
119 set_max_field(fields[2*i+1], option->length/8);
120 field_opts_off(fields[2*i+1], O_STATIC);
121 break;
122 }
123 case 'e': {
124 int numvals = 0;
125 struct cb_cmos_enums *cmos_enum = first_cmos_enum_of_id(opttbl, option->config_id);
126
127 /* if invalid data in CMOS, set buf to first enum */
128 if (fail && cmos_enum) {
129 buf = cmos_enum->text;
130 }
131
132 while (cmos_enum) {
133 numvals++;
134 cmos_enum = next_cmos_enum_of_id(cmos_enum, option->config_id);
135 }
136
Lubomir Rintel18860d72015-02-01 16:56:58 +0100137 char **values = malloc(sizeof(char*)*(numvals + 1));
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100138 int cnt = 0;
139
140 cmos_enum = first_cmos_enum_of_id(opttbl, option->config_id);
141 while (cmos_enum) {
142 values[cnt] = cmos_enum->text;
143 cnt++;
144 cmos_enum = next_cmos_enum_of_id(cmos_enum, option->config_id);
145 }
146 values[cnt] = NULL;
147 field_opts_off(fields[2*i+1], O_EDIT);
148 set_field_type(fields[2*i+1], TYPE_ENUM, values, 1, 1);
149 free(values); // copied by set_field_type
150 break;
151 }
152 default:
153 break;
154 }
155 if (buf) set_field_buffer(fields[2*i+1], 0, buf);
156#if HOSTED
157// underline is non-trivial on VGA text
158 set_field_back(fields[2*i+1], A_UNDERLINE);
159#endif
160 field_opts_off(fields[2*i+1], O_BLANK | O_AUTOSKIP | O_NULLOK);
161
162 option = next_cmos_entry(option);
163 }
164 fields[2*numopts]=NULL;
165
Lubomir Rintel1ecc8af2015-02-24 20:33:35 +0100166 /* display initialization */
167 initscr();
168 keypad(stdscr, TRUE);
169 cbreak();
170 noecho();
171
172 if (start_color()) {
173 assume_default_colors (COLOR_BLUE, COLOR_CYAN);
174 }
175 leaveok(stdscr, TRUE);
176 curs_set(1);
177
178 erase();
179 box(stdscr, 0, 0);
180 mvaddstr(0, 2, "coreboot configuration utility");
181 refresh();
182
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100183 FORM *form = new_form(fields);
184 int numlines = min(numopts*2, 16);
185 WINDOW *w = newwin(numlines+2, 70, 2, 1);
186 WINDOW *inner_w = newpad(numopts*2, 68);
187 box(w, 0, 0);
188 mvwaddstr(w, 0, 2, "Press F1 when done");
189 set_form_win(form, w);
190 set_form_sub(form, inner_w);
191 post_form(form);
192
193 done = 0;
194 while(!done) {
Lubomir Rintel68009e92015-02-01 15:24:43 +0100195 render_form(form);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100196 ch=getch();
197 if (ch == ERR) continue;
198 switch (ch) {
199 case KEY_DOWN:
200 form_driver(form, REQ_NEXT_FIELD);
201 break;
202 case KEY_UP:
203 form_driver(form, REQ_PREV_FIELD);
204 break;
205 case KEY_LEFT:
206 if (field_type(current_field(form)) == TYPE_ENUM) {
207 form_driver(form, REQ_PREV_CHOICE);
208 } else {
209 form_driver(form, REQ_LEFT_CHAR);
210 }
211 break;
212 case KEY_RIGHT:
213 if (field_type(current_field(form)) == TYPE_ENUM) {
214 form_driver(form, REQ_NEXT_CHOICE);
215 } else {
216 form_driver(form, REQ_RIGHT_CHAR);
217 }
218 break;
219 case KEY_BACKSPACE:
220 case '\b':
221 form_driver(form, REQ_DEL_PREV);
222 break;
223 case KEY_DC:
224 form_driver(form, REQ_DEL_CHAR);
225 break;
226 case KEY_F(1):
227 done=1;
228 break;
229 default:
230 form_driver(form, ch);
231 break;
232 }
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100233 }
234
Lubomir Rintel1ecc8af2015-02-24 20:33:35 +0100235 endwin();
236
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100237 for (i = 0; i < numopts; i++) {
238 char *name = field_buffer(fields[2*i], 0);
239 char *value = field_buffer(fields[2*i+1], 0);
Vladimir Serbinenkoc9babb22014-01-15 22:07:52 +0100240 char *ptr;
241 for (ptr = value + strlen (value) - 1;
242 ptr >= value && *ptr == ' '; ptr--);
243 ptr[1] = '\0';
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100244 set_option_from_string(use_nvram, opttbl, value, name);
245 }
246
247 unpost_form(form);
248 free_form(form);
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100249
Patrick Georgi4b62ebe2012-11-16 15:05:11 +0100250 /* TODO: reboot */
251 halt();
252}
253