summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Georgi <patrick.georgi@secunet.com>2012-11-16 15:05:11 +0100
committerStefan Reinauer <stefan.reinauer@coreboot.org>2012-11-19 19:10:24 +0100
commit4b62ebe961846b5b07aa57dacc24878a30ea9cc9 (patch)
tree2d802815834d67a9ee499534b8c58e886b826dfe
parent1fc2bda92b9994e1b39e505c94987109762bd587 (diff)
downloadcoreboot-4b62ebe961846b5b07aa57dacc24878a30ea9cc9.tar.xz
Add nvramcui
nvramcui is a small libpayload based utility that provides an interactive CMOS editor for pre-boot environments. Change-Id: I514b8a7682f89d242d1b31b6907cc6bff34da4bf Signed-off-by: Patrick Georgi <patrick.georgi@secunet.com> Reviewed-on: http://review.coreboot.org/1871 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
-rw-r--r--payloads/nvramcui/nvramcui.c247
-rwxr-xr-xpayloads/nvramcui/payload.sh7
2 files changed, 254 insertions, 0 deletions
diff --git a/payloads/nvramcui/nvramcui.c b/payloads/nvramcui/nvramcui.c
new file mode 100644
index 0000000000..e9801305bb
--- /dev/null
+++ b/payloads/nvramcui/nvramcui.c
@@ -0,0 +1,247 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libpayload.h>
+#include <coreboot_tables.h>
+
+#include <curses.h>
+#include <menu.h>
+#include <form.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;
+}
+
+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);
+}
+
+int main()
+{
+ int ch, done;
+ ITEM *cur;
+
+ /* 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();
+ }
+
+ /* display initialization */
+ initscr();
+ keypad(stdscr, TRUE);
+ cbreak();
+ noecho();
+ start_color();
+ leaveok(stdscr, TRUE);
+ curs_set(1);
+
+ erase();
+ box(stdscr, 0, 0);
+ mvaddstr(0, 2, "coreboot configuration utility");
+
+ /* prep CMOS layout into libcurses data structures */
+
+ /* determine number of options, and maximum option name length */
+ int numopts=0;
+ int maxlength=0;
+ struct cb_cmos_entries *option = first_cmos_entry(opttbl);
+ while (option) {
+ if ((option->config != 'r') && (strcmp("check_sum", option->name) != 0)) {
+ maxlength = max(maxlength, strlen(option->name));
+ numopts++;
+ }
+ option = next_cmos_entry(option);
+ }
+ if (numopts == 0) {
+ printf("NO CMOS OPTIONS FOUND. EXITING!!!");
+ return 1;
+ }
+ FIELD **fields = malloc(sizeof(FIELD*)*(2*numopts+1));
+ int i;
+
+ /* walk over options, fetch details */
+ option = first_cmos_entry(opttbl);
+ for (i=0;i<numopts;i++) {
+ while ((option->config == 'r') || (strcmp("check_sum", option->name) == 0)) {
+ option = next_cmos_entry(option);
+ }
+ fields[2*i] = new_field(1, strlen(option->name), i*2, 1, 0, 0);
+ set_field_buffer(fields[2*i], 0, 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, 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 = 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] = 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;
+
+ 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) {
+ 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;
+ }
+ render_form(form);
+ }
+
+ for (i = 0; i < numopts; i++) {
+ char *name = field_buffer(fields[2*i], 0);
+ char *value = field_buffer(fields[2*i+1], 0);
+ set_option_from_string(use_nvram, opttbl, value, name);
+ }
+
+ unpost_form(form);
+ free_form(form);
+ touchwin(stdscr);
+ refresh();
+
+ endwin();
+ /* TODO: reboot */
+ halt();
+}
+
diff --git a/payloads/nvramcui/payload.sh b/payloads/nvramcui/payload.sh
new file mode 100755
index 0000000000..57ed38b3a6
--- /dev/null
+++ b/payloads/nvramcui/payload.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+#
+# This is a trivial payload compile & find script for abuild
+#
+DIR=`dirname $0`
+lpgcc -o $DIR/nvramcui.elf $DIR/nvramcui.c 2>&1 >/dev/null || exit 1
+echo "$DIR/nvramcui.elf"