Rename lxbios to nvramtool, step 3 (rename directory).
[coreboot.git] / util / nvramtool / cmos_ops.c
1 /*****************************************************************************\
2  * cmos_ops.c
3  * $Id$
4  *****************************************************************************
5  *  Copyright (C) 2002-2005 The Regents of the University of California.
6  *  Produced at the Lawrence Livermore National Laboratory.
7  *  Written by David S. Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>.
8  *  UCRL-CODE-2003-012
9  *  All rights reserved.
10  *
11  *  This file is part of nvramtool, a utility for reading/writing coreboot
12  *  parameters and displaying information from the coreboot table.
13  *  For details, see http://coreboot.org/nvramtool.
14  *
15  *  Please also read the file DISCLAIMER which is included in this software
16  *  distribution.
17  *
18  *  This program is free software; you can redistribute it and/or modify it
19  *  under the terms of the GNU General Public License (as published by the
20  *  Free Software Foundation) version 2, dated June 1991.
21  *
22  *  This program is distributed in the hope that it will be useful, but
23  *  WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
24  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the terms and
25  *  conditions of the GNU General Public License for more details.
26  *
27  *  You should have received a copy of the GNU General Public License along
28  *  with this program; if not, write to the Free Software Foundation, Inc.,
29  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
30 \*****************************************************************************/
31
32 #include "common.h"
33 #include "cmos_ops.h"
34 #include "cmos_lowlevel.h"
35
36 static int prepare_cmos_op_common (const cmos_entry_t *e);
37
38 /****************************************************************************
39  * prepare_cmos_op_common
40  *
41  * Perform a few checks common to both reads and writes.
42  ****************************************************************************/
43 static int prepare_cmos_op_common (const cmos_entry_t *e)
44  { int result;
45
46    if (e->config == CMOS_ENTRY_RESERVED)
47       /* Access to reserved parameters is not permitted. */
48       return CMOS_OP_RESERVED;
49
50    if ((result = verify_cmos_op(e->bit, e->length)) != OK)
51       return result;
52
53    assert(e->length > 0);
54    return OK;
55  }
56
57 /****************************************************************************
58  * prepare_cmos_read
59  *
60  * The caller wishes to read a CMOS parameter represented by 'e'.  Perform
61  * sanity checking on 'e'.  If a problem was found with e, return an error
62  * code.  Else return OK.
63  ****************************************************************************/
64 int prepare_cmos_read (const cmos_entry_t *e)
65  { int result;
66
67    if ((result = prepare_cmos_op_common(e)) != OK)
68       return result;
69
70    switch (e->config)
71     { case CMOS_ENTRY_ENUM:
72       case CMOS_ENTRY_HEX:
73          break;
74
75       default:
76          BUG();
77     }
78
79    return OK;
80  }
81
82 /****************************************************************************
83  * prepare_cmos_write
84  *
85  * The caller wishes to set a CMOS parameter represented by 'e' to a value
86  * whose string representation is stored in 'value_str'.  Perform sanity
87  * checking on 'value_str'.  On error, return an error code.  Else store the
88  * numeric equivalent of 'value_str' in '*value' and return OK.
89  ****************************************************************************/
90 int prepare_cmos_write (const cmos_entry_t *e, const char value_str[],
91                         unsigned long long *value)
92  { const cmos_enum_t *q;
93    unsigned long long out;
94    const char *p;
95    int negative, result, found_one;
96
97    if ((result = prepare_cmos_op_common(e)) != OK)
98       return result;
99
100    switch (e->config)
101     { case CMOS_ENTRY_ENUM:
102          /* Make sure the user's input corresponds to a valid option. */
103          for (q = first_cmos_enum_id(e->config_id), found_one = 0;
104               q != NULL;
105               q = next_cmos_enum_id(q))
106           { found_one = 1;
107
108             if (!strncmp(q->text, value_str, CMOS_MAX_TEXT_LENGTH))
109                break;
110           }
111
112          if (!found_one)
113             return CMOS_OP_NO_MATCHING_ENUM;
114
115          if (q == NULL)
116             return CMOS_OP_BAD_ENUM_VALUE;
117
118          out = q->value;
119          break;
120
121       case CMOS_ENTRY_HEX:
122          /* See if the first character of 'value_str' (excluding any initial
123           * whitespace) is a minus sign.
124           */
125          for (p = value_str; isspace(*p); p++);
126          negative = (*p == '-');
127
128          out = strtoull(value_str, (char **) &p, 0);
129
130          if (*p)
131             return CMOS_OP_INVALID_INT;
132
133          /* If we get this far, the user specified a valid integer.  However
134           * we do not currently support the use of negative numbers as CMOS
135           * parameter values.
136           */
137          if (negative)
138             return CMOS_OP_NEGATIVE_INT;
139
140          break;
141
142       default:
143          BUG();
144     }
145
146    if ((e->length < (8 * sizeof(*value))) &&
147        (out >= (1ull << e->length)))
148       return CMOS_OP_VALUE_TOO_WIDE;
149
150    *value = out;
151    return OK;
152  }
153
154 /****************************************************************************
155  * cmos_checksum_read
156  *
157  * Read the checksum for the coreboot parameters stored in CMOS and return
158  * this value.
159  ****************************************************************************/
160 uint16_t cmos_checksum_read (void)
161  { uint16_t lo, hi;
162
163    /* The checksum is stored in a big-endian format. */
164    hi = cmos_read_byte(cmos_checksum_index);
165    lo = cmos_read_byte(cmos_checksum_index + 1);
166    return (hi << 8) + lo;
167  }
168
169 /****************************************************************************
170  * cmos_checksum_write
171  *
172  * Set the checksum for the coreboot parameters stored in CMOS to
173  * 'checksum'.
174  ****************************************************************************/
175 void cmos_checksum_write (uint16_t checksum)
176  { unsigned char lo, hi;
177
178    /* The checksum is stored in a big-endian format. */
179    hi = (unsigned char) (checksum >> 8);
180    lo = (unsigned char) (checksum & 0x00ff);
181    cmos_write_byte(cmos_checksum_index, hi);
182    cmos_write_byte(cmos_checksum_index + 1, lo);
183  }
184
185 /****************************************************************************
186  * cmos_checksum_compute
187  *
188  * Compute a checksum for the coreboot parameter values currently stored in
189  * CMOS and return this checksum.
190  ****************************************************************************/
191 uint16_t cmos_checksum_compute (void)
192  { unsigned i, sum;
193
194    sum = 0;
195
196    for (i = cmos_checksum_start; i <= cmos_checksum_end; i++)
197       sum += cmos_read_byte(i);
198
199    return ~((uint16_t) (sum & 0xffff));
200  }
201
202 /****************************************************************************
203  * cmos_checksum_verify
204  *
205  * Verify that the coreboot CMOS checksum is valid.  If checksum is not
206  * valid then print warning message and exit.
207  ****************************************************************************/
208 void cmos_checksum_verify (void)
209  { uint16_t computed, actual;
210
211    set_iopl(3);
212    computed = cmos_checksum_compute();
213    actual = cmos_checksum_read();
214    set_iopl(0);
215
216    if (computed != actual)
217     { fprintf(stderr, "%s: Warning: Coreboot CMOS checksum is bad.\n",
218               prog_name);
219       exit(1);
220     }
221  }