blob: 4bb416272d149264b92517e938bcd84e9952049f [file] [log] [blame]
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001/*****************************************************************************\
2 * cmos_ops.c
3 * $Id: cmos_ops.c,v 1.3 2006/01/24 00:25:40 dsp_llnl Exp $
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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +000011 * This file is part of lxbios, a utility for reading/writing coreboot
12 * parameters and displaying information from the coreboot table.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000013 * For details, see <http://www.llnl.gov/linux/lxbios/>.
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
36static 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 ****************************************************************************/
43static 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 ****************************************************************************/
64int 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 ****************************************************************************/
90int 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000157 * Read the checksum for the coreboot parameters stored in CMOS and return
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000158 * this value.
159 ****************************************************************************/
160uint16_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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000172 * Set the checksum for the coreboot parameters stored in CMOS to
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000173 * 'checksum'.
174 ****************************************************************************/
175void 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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000188 * Compute a checksum for the coreboot parameter values currently stored in
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000189 * CMOS and return this checksum.
190 ****************************************************************************/
191uint16_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 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000205 * Verify that the coreboot CMOS checksum is valid. If checksum is not
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000206 * valid then print warning message and exit.
207 ****************************************************************************/
208void 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)
Stefan Reinauerf527e702008-01-18 15:33:49 +0000217 { fprintf(stderr, "%s: Warning: Coreboot CMOS checksum is bad.\n",
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000218 prog_name);
219 exit(1);
220 }
221 }