summaryrefslogtreecommitdiff
path: root/util/lxbios/cmos_ops.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/lxbios/cmos_ops.c')
-rw-r--r--util/lxbios/cmos_ops.c221
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);
+ }
+ }