diff options
Diffstat (limited to 'util/lxbios/cmos_ops.c')
-rw-r--r-- | util/lxbios/cmos_ops.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/util/lxbios/cmos_ops.c b/util/lxbios/cmos_ops.c new file mode 100644 index 0000000000..02b7049b3c --- /dev/null +++ b/util/lxbios/cmos_ops.c @@ -0,0 +1,221 @@ +/*****************************************************************************\ + * cmos_ops.c + * $Id: cmos_ops.c,v 1.3 2006/01/24 00:25:40 dsp_llnl Exp $ + ***************************************************************************** + * Copyright (C) 2002-2005 The Regents of the University of California. + * Produced at the Lawrence Livermore National Laboratory. + * Written by David S. Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>. + * UCRL-CODE-2003-012 + * All rights reserved. + * + * This file is part of lxbios, a utility for reading/writing LinuxBIOS + * parameters and displaying information from the LinuxBIOS table. + * For details, see <http://www.llnl.gov/linux/lxbios/>. + * + * Please also read the file DISCLAIMER which is included in this software + * distribution. + * + * 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, dated June 1991. + * + * 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 terms and + * conditions of 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +\*****************************************************************************/ + +#include "common.h" +#include "cmos_ops.h" +#include "cmos_lowlevel.h" + +static int prepare_cmos_op_common (const cmos_entry_t *e); + +/**************************************************************************** + * prepare_cmos_op_common + * + * Perform a few checks common to both reads and writes. + ****************************************************************************/ +static int prepare_cmos_op_common (const cmos_entry_t *e) + { int result; + + if (e->config == CMOS_ENTRY_RESERVED) + /* Access to reserved parameters is not permitted. */ + return CMOS_OP_RESERVED; + + if ((result = verify_cmos_op(e->bit, e->length)) != OK) + return result; + + assert(e->length > 0); + return OK; + } + +/**************************************************************************** + * prepare_cmos_read + * + * The caller wishes to read a CMOS parameter represented by 'e'. Perform + * sanity checking on 'e'. If a problem was found with e, return an error + * code. Else return OK. + ****************************************************************************/ +int prepare_cmos_read (const cmos_entry_t *e) + { int result; + + if ((result = prepare_cmos_op_common(e)) != OK) + return result; + + switch (e->config) + { case CMOS_ENTRY_ENUM: + case CMOS_ENTRY_HEX: + break; + + default: + BUG(); + } + + return OK; + } + +/**************************************************************************** + * prepare_cmos_write + * + * The caller wishes to set a CMOS parameter represented by 'e' to a value + * whose string representation is stored in 'value_str'. Perform sanity + * checking on 'value_str'. On error, return an error code. Else store the + * numeric equivalent of 'value_str' in '*value' and return OK. + ****************************************************************************/ +int prepare_cmos_write (const cmos_entry_t *e, const char value_str[], + unsigned long long *value) + { const cmos_enum_t *q; + unsigned long long out; + const char *p; + int negative, result, found_one; + + if ((result = prepare_cmos_op_common(e)) != OK) + return result; + + switch (e->config) + { case CMOS_ENTRY_ENUM: + /* Make sure the user's input corresponds to a valid option. */ + for (q = first_cmos_enum_id(e->config_id), found_one = 0; + q != NULL; + q = next_cmos_enum_id(q)) + { found_one = 1; + + if (!strncmp(q->text, value_str, CMOS_MAX_TEXT_LENGTH)) + break; + } + + if (!found_one) + return CMOS_OP_NO_MATCHING_ENUM; + + if (q == NULL) + return CMOS_OP_BAD_ENUM_VALUE; + + out = q->value; + break; + + case CMOS_ENTRY_HEX: + /* See if the first character of 'value_str' (excluding any initial + * whitespace) is a minus sign. + */ + for (p = value_str; isspace(*p); p++); + negative = (*p == '-'); + + out = strtoull(value_str, (char **) &p, 0); + + if (*p) + return CMOS_OP_INVALID_INT; + + /* If we get this far, the user specified a valid integer. However + * we do not currently support the use of negative numbers as CMOS + * parameter values. + */ + if (negative) + return CMOS_OP_NEGATIVE_INT; + + break; + + default: + BUG(); + } + + if ((e->length < (8 * sizeof(*value))) && + (out >= (1ull << e->length))) + return CMOS_OP_VALUE_TOO_WIDE; + + *value = out; + return OK; + } + +/**************************************************************************** + * cmos_checksum_read + * + * Read the checksum for the LinuxBIOS parameters stored in CMOS and return + * this value. + ****************************************************************************/ +uint16_t cmos_checksum_read (void) + { uint16_t lo, hi; + + /* The checksum is stored in a big-endian format. */ + hi = cmos_read_byte(cmos_checksum_index); + lo = cmos_read_byte(cmos_checksum_index + 1); + return (hi << 8) + lo; + } + +/**************************************************************************** + * cmos_checksum_write + * + * Set the checksum for the LinuxBIOS parameters stored in CMOS to + * 'checksum'. + ****************************************************************************/ +void cmos_checksum_write (uint16_t checksum) + { unsigned char lo, hi; + + /* The checksum is stored in a big-endian format. */ + hi = (unsigned char) (checksum >> 8); + lo = (unsigned char) (checksum & 0x00ff); + cmos_write_byte(cmos_checksum_index, hi); + cmos_write_byte(cmos_checksum_index + 1, lo); + } + +/**************************************************************************** + * cmos_checksum_compute + * + * Compute a checksum for the LinuxBIOS parameter values currently stored in + * CMOS and return this checksum. + ****************************************************************************/ +uint16_t cmos_checksum_compute (void) + { unsigned i, sum; + + sum = 0; + + for (i = cmos_checksum_start; i <= cmos_checksum_end; i++) + sum += cmos_read_byte(i); + + return ~((uint16_t) (sum & 0xffff)); + } + +/**************************************************************************** + * cmos_checksum_verify + * + * Verify that the LinuxBIOS CMOS checksum is valid. If checksum is not + * valid then print warning message and exit. + ****************************************************************************/ +void cmos_checksum_verify (void) + { uint16_t computed, actual; + + set_iopl(3); + computed = cmos_checksum_compute(); + actual = cmos_checksum_read(); + set_iopl(0); + + if (computed != actual) + { fprintf(stderr, "%s: Warning: LinuxBIOS CMOS checksum is bad.\n", + prog_name); + exit(1); + } + } |