coreboot/util/nvramtool/input_file.c
<<
>>
Prefs
   1/*****************************************************************************\
   2 * input_file.c
   3 *****************************************************************************
   4 *  Copyright (C) 2002-2005 The Regents of the University of California.
   5 *  Produced at the Lawrence Livermore National Laboratory.
   6 *  Written by David S. Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>.
   7 *  UCRL-CODE-2003-012
   8 *  All rights reserved.
   9 *
  10 *  This file is part of nvramtool, a utility for reading/writing coreboot
  11 *  parameters and displaying information from the coreboot table.
  12 *  For details, see http://coreboot.org/nvramtool.
  13 *
  14 *  Please also read the file DISCLAIMER which is included in this software
  15 *  distribution.
  16 *
  17 *  This program is free software; you can redistribute it and/or modify it
  18 *  under the terms of the GNU General Public License (as published by the
  19 *  Free Software Foundation) version 2, dated June 1991.
  20 *
  21 *  This program is distributed in the hope that it will be useful, but
  22 *  WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
  23 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the terms and
  24 *  conditions of the GNU General Public License for more details.
  25 *
  26 *  You should have received a copy of the GNU General Public License along
  27 *  with this program; if not, write to the Free Software Foundation, Inc.,
  28 *  51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  29\*****************************************************************************/
  30
  31#include "common.h"
  32#include "input_file.h"
  33#include "layout.h"
  34#include "cmos_ops.h"
  35#include "cmos_lowlevel.h"
  36#include "reg_expr.h"
  37
  38static int get_input_file_line(FILE * f, char line[], int line_buf_size);
  39static unsigned long long try_prepare_cmos_write(const cmos_entry_t * e,
  40                                                 const char value_str[]);
  41
  42/* matches either a blank line or a comment line */
  43static const char blank_or_comment_regex[] =
  44    /* a blank line */
  45    "(^[[:space:]]+$)" "|"      /* or ... */
  46    /* a line consisting of: optional whitespace followed by */
  47    "(^[[:space:]]*"
  48    /* a '#' character and optionally, additional characters */
  49    "#.*$)";
  50
  51/* matches an assignment line */
  52const char assignment_regex[] =
  53    /* optional whitespace */
  54    "^[[:space:]]*"
  55    /* followed by a coreboot parameter name */
  56    "([^[:space:]]+)"
  57    /* followed by optional whitespace */
  58    "[[:space:]]*"
  59    /* followed by an '=' character */
  60    "="
  61    /* followed by optional whitespace */
  62    "[[:space:]]*"
  63    /* followed by a value that may contain embedded whitespace */
  64    "([^[:space:]]+([[:space:]]+[^[:space:]]+)*)+"
  65    /* followed by optional whitespace */
  66    "[[:space:]]*$";
  67
  68static int line_num;
  69
  70/****************************************************************************
  71 * process_input_file
  72 *
  73 * Read the contents of file 'f' and return a pointer to a list of pending
  74 * write operations.  Perform sanity checking on all write operations and
  75 * exit with an error message if there is a problem.
  76 ****************************************************************************/
  77cmos_write_t *process_input_file(FILE * f)
  78{
  79        static const int LINE_BUF_SIZE = 256;
  80        static const size_t N_MATCHES = 4;
  81        char line[LINE_BUF_SIZE];
  82        const char *name, *value;
  83        cmos_write_t *list, *item, **p;
  84        regex_t blank_or_comment, assignment;
  85        regmatch_t match[N_MATCHES];
  86        const cmos_entry_t *e;
  87
  88        list = NULL;
  89        p = &list;
  90
  91        compile_reg_expr(REG_EXTENDED | REG_NEWLINE, blank_or_comment_regex, &blank_or_comment);
  92        compile_reg_expr(REG_EXTENDED | REG_NEWLINE, assignment_regex, &assignment);
  93
  94        /* each iteration processes one line from input file */
  95        for (line_num = 1; get_input_file_line(f, line, LINE_BUF_SIZE) == OK; line_num++) {     /* skip comments and blank lines */
  96                if (!regexec(&blank_or_comment, line, 0, NULL, 0))
  97                        continue;
  98
  99                /* Is this a valid assignment line?  If not, then it's a syntax
 100                 * error.
 101                 */
 102                if (regexec(&assignment, line, N_MATCHES, match, 0)) {
 103                        fprintf(stderr,
 104                                "%s: Syntax error on line %d of input file.\n",
 105                                prog_name, line_num);
 106                        exit(1);
 107                }
 108
 109                /* OK, we found an assignment.  Break the line into substrings
 110                 * representing the lefthand and righthand sides of the assignment.
 111                 */
 112                line[match[1].rm_eo] = '\0';
 113                line[match[2].rm_eo] = '\0';
 114                name = &line[match[1].rm_so];
 115                value = &line[match[2].rm_so];
 116
 117                /* now look up the coreboot parameter name */
 118                if (is_checksum_name(name)
 119                    || (e = find_cmos_entry(name)) == NULL) {
 120                        fprintf(stderr,
 121                                "%s: Error on line %d of input file: CMOS parameter "
 122                                "%s not found.\n", prog_name, line_num, name);
 123                        exit(1);
 124                }
 125
 126                /* At this point, we figure out what numeric value needs to be written
 127                 * to which location.  At the same time, we perform sanity checking on
 128                 * the write operation.
 129                 */
 130
 131                if ((item = (cmos_write_t *) malloc(sizeof(*item))) == NULL)
 132                        out_of_memory();
 133
 134                item->bit = e->bit;
 135                item->length = e->length;
 136                item->config = e->config;
 137                item->value = try_prepare_cmos_write(e, value);
 138
 139                /* Append write operation to pending write list. */
 140                item->next = NULL;
 141                *p = item;
 142                p = &item->next;
 143        }
 144
 145        regfree(&blank_or_comment);
 146        regfree(&assignment);
 147        return list;
 148}
 149
 150/****************************************************************************
 151 * do_cmos_writes
 152 *
 153 * 'list' is a linked list of pending CMOS write operations that have passed
 154 * all sanity checks.  Perform all write operations, destroying the list as
 155 * we go.
 156 ****************************************************************************/
 157void do_cmos_writes(cmos_write_t * list)
 158{
 159        cmos_write_t *item;
 160
 161        set_iopl(3);
 162
 163        while (list != NULL) {
 164                cmos_entry_t e;
 165                item = list;
 166                e.bit = item->bit;
 167                e.length = item->length;
 168                e.config = item->config;
 169                list = item->next;
 170                cmos_write(&e, item->value);
 171                free(item);
 172        }
 173
 174        cmos_checksum_write(cmos_checksum_compute());
 175        set_iopl(0);
 176}
 177
 178/****************************************************************************
 179 * get_input_file_line
 180 *
 181 * Get a line of input from file 'f'.  Store result in 'line' which is an
 182 * array of 'line_buf_size' bytes.  Return OK on success or an error code on
 183 * error.
 184 ****************************************************************************/
 185static int get_input_file_line(FILE * f, char line[], int line_buf_size)
 186{
 187        switch (get_line_from_file(f, line, line_buf_size)) {
 188        case OK:
 189                return OK;
 190
 191        case LINE_EOF:
 192                return LINE_EOF;
 193
 194        case LINE_TOO_LONG:
 195                fprintf(stderr,
 196                        "%s: Error on line %d of input file: Maximum line "
 197                        "length exceeded.  Max is %d characters.\n", prog_name,
 198                        line_num, line_buf_size - 2);
 199                break;
 200
 201        default:
 202                BUG();
 203        }
 204
 205        exit(1);
 206        return 1;               /* keep compiler happy */
 207}
 208
 209/****************************************************************************
 210 * try_prepare_cmos_write
 211 *
 212 * Attempt to convert 'value_str' to an integer representation for storage in
 213 * CMOS memory.  On success, return the converted value.  On error, exit with
 214 * an error message.
 215 ****************************************************************************/
 216static unsigned long long try_prepare_cmos_write(const cmos_entry_t * e,
 217                                                 const char value_str[])
 218{
 219        unsigned long long value;
 220
 221        switch (prepare_cmos_write(e, value_str, &value)) {
 222        case OK:
 223                return value;
 224
 225        case CMOS_OP_BAD_ENUM_VALUE:
 226                fprintf(stderr,
 227                        "%s: Error on line %d of input file: Bad value for "
 228                        "parameter %s.", prog_name, line_num, e->name);
 229                break;
 230
 231        case CMOS_OP_NEGATIVE_INT:
 232                fprintf(stderr,
 233                        "%s: Error on line %d of input file: This program "
 234                        "does not support assignment of negative numbers to "
 235                        "coreboot parameters.", prog_name, line_num);
 236                break;
 237
 238        case CMOS_OP_INVALID_INT:
 239                fprintf(stderr,
 240                        "%s: Error on line %d of input file: %s is not a "
 241                        "valid integer.", prog_name, line_num, value_str);
 242                break;
 243
 244        case CMOS_OP_RESERVED:
 245                fprintf(stderr,
 246                        "%s: Error on line %d of input file: Can not modify "
 247                        "reserved coreboot parameter %s.", prog_name, line_num,
 248                        e->name);
 249                break;
 250
 251        case CMOS_OP_VALUE_TOO_WIDE:
 252                fprintf(stderr,
 253                        "%s: Error on line %d of input file: Can not write "
 254                        "value %s to CMOS parameter %s that is only %d bits wide.",
 255                        prog_name, line_num, value_str, e->name, e->length);
 256                break;
 257
 258        case CMOS_OP_NO_MATCHING_ENUM:
 259                fprintf(stderr,
 260                        "%s: coreboot parameter %s has no matching enums.",
 261                        prog_name, e->name);
 262                break;
 263
 264        case CMOS_AREA_OUT_OF_RANGE:
 265                fprintf(stderr,
 266                        "%s: The CMOS area specified by the layout info for "
 267                        "coreboot parameter %s is out of range.", prog_name,
 268                        e->name);
 269                break;
 270
 271        case CMOS_AREA_OVERLAPS_RTC:
 272                fprintf(stderr,
 273                        "%s: The CMOS area specified by the layout info for "
 274                        "coreboot parameter %s overlaps the realtime clock area.",
 275                        prog_name, e->name);
 276                break;
 277
 278        case CMOS_AREA_TOO_WIDE:
 279                fprintf(stderr,
 280                        "%s: The CMOS area specified by the layout info for "
 281                        "coreboot parameter %s is too wide.", prog_name,
 282                        e->name);
 283                break;
 284
 285        default:
 286                fprintf(stderr,
 287                        "%s: Unknown error encountered while attempting to modify "
 288                        "coreboot parameter %s.", prog_name, e->name);
 289                break;
 290        }
 291
 292        fprintf(stderr, "  No CMOS writes performed.\n");
 293        exit(1);
 294        return 0;               /* keep compiler happy */
 295}
 296
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.