blob: 738c8ed387930ba36e101f3afe71610f384005e2 [file] [log] [blame]
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001/*****************************************************************************\
2 * cmos_ops.c
Stefan Reinauer6540ae52007-07-12 16:35:42 +00003 *****************************************************************************
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 *
Uwe Hermann6e565942008-03-01 19:06:32 +000010 * This file is part of nvramtool, a utility for reading/writing coreboot
Stefan Reinauerf527e702008-01-18 15:33:49 +000011 * parameters and displaying information from the coreboot table.
Uwe Hermann6e565942008-03-01 19:06:32 +000012 * For details, see http://coreboot.org/nvramtool.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000013 *
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.,
Stefan Reinauerac7a2d22009-09-23 21:53:25 +000028 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000029\*****************************************************************************/
30
31#include "common.h"
32#include "cmos_ops.h"
33#include "cmos_lowlevel.h"
34
35static int prepare_cmos_op_common (const cmos_entry_t *e);
36
37/****************************************************************************
38 * prepare_cmos_op_common
39 *
40 * Perform a few checks common to both reads and writes.
41 ****************************************************************************/
42static int prepare_cmos_op_common (const cmos_entry_t *e)
43 { int result;
44
45 if (e->config == CMOS_ENTRY_RESERVED)
46 /* Access to reserved parameters is not permitted. */
47 return CMOS_OP_RESERVED;
48
Stefan Reinauera67aab72008-09-27 10:08:28 +000049 if ((result = verify_cmos_op(e->bit, e->length, e->config)) != OK)
Stefan Reinauer6540ae52007-07-12 16:35:42 +000050 return result;
51
52 assert(e->length > 0);
53 return OK;
54 }
55
56/****************************************************************************
57 * prepare_cmos_read
58 *
59 * The caller wishes to read a CMOS parameter represented by 'e'. Perform
60 * sanity checking on 'e'. If a problem was found with e, return an error
61 * code. Else return OK.
62 ****************************************************************************/
63int prepare_cmos_read (const cmos_entry_t *e)
64 { int result;
65
66 if ((result = prepare_cmos_op_common(e)) != OK)
67 return result;
68
69 switch (e->config)
70 { case CMOS_ENTRY_ENUM:
71 case CMOS_ENTRY_HEX:
Stefan Reinauera67aab72008-09-27 10:08:28 +000072 case CMOS_ENTRY_STRING:
Stefan Reinauer6540ae52007-07-12 16:35:42 +000073 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;
Stefan Reinauera67aab72008-09-27 10:08:28 +000095 char *memory;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000096 int negative, result, found_one;
97
98 if ((result = prepare_cmos_op_common(e)) != OK)
99 return result;
100
101 switch (e->config)
102 { case CMOS_ENTRY_ENUM:
103 /* Make sure the user's input corresponds to a valid option. */
104 for (q = first_cmos_enum_id(e->config_id), found_one = 0;
105 q != NULL;
106 q = next_cmos_enum_id(q))
107 { found_one = 1;
108
109 if (!strncmp(q->text, value_str, CMOS_MAX_TEXT_LENGTH))
110 break;
111 }
112
113 if (!found_one)
114 return CMOS_OP_NO_MATCHING_ENUM;
115
116 if (q == NULL)
117 return CMOS_OP_BAD_ENUM_VALUE;
118
119 out = q->value;
120 break;
121
122 case CMOS_ENTRY_HEX:
123 /* See if the first character of 'value_str' (excluding any initial
124 * whitespace) is a minus sign.
125 */
126 for (p = value_str; isspace(*p); p++);
127 negative = (*p == '-');
128
129 out = strtoull(value_str, (char **) &p, 0);
130
131 if (*p)
132 return CMOS_OP_INVALID_INT;
133
134 /* If we get this far, the user specified a valid integer. However
135 * we do not currently support the use of negative numbers as CMOS
136 * parameter values.
137 */
138 if (negative)
139 return CMOS_OP_NEGATIVE_INT;
140
141 break;
142
Stefan Reinauera67aab72008-09-27 10:08:28 +0000143 case CMOS_ENTRY_STRING:
144 if (e->length < (8 * strlen(value_str)))
145 return CMOS_OP_VALUE_TOO_WIDE;
146 memory = malloc(e->length / 8);
147 memset(memory, 0, e->length / 8);
148 strcpy(memory, value_str);
149 out = (unsigned long)memory;
150 break;
151
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000152 default:
153 BUG();
154 }
155
156 if ((e->length < (8 * sizeof(*value))) &&
157 (out >= (1ull << e->length)))
158 return CMOS_OP_VALUE_TOO_WIDE;
159
160 *value = out;
161 return OK;
162 }
163
164/****************************************************************************
165 * cmos_checksum_read
166 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000167 * Read the checksum for the coreboot parameters stored in CMOS and return
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000168 * this value.
169 ****************************************************************************/
170uint16_t cmos_checksum_read (void)
171 { uint16_t lo, hi;
172
173 /* The checksum is stored in a big-endian format. */
174 hi = cmos_read_byte(cmos_checksum_index);
175 lo = cmos_read_byte(cmos_checksum_index + 1);
176 return (hi << 8) + lo;
177 }
178
179/****************************************************************************
180 * cmos_checksum_write
181 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000182 * Set the checksum for the coreboot parameters stored in CMOS to
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000183 * 'checksum'.
184 ****************************************************************************/
185void cmos_checksum_write (uint16_t checksum)
186 { unsigned char lo, hi;
187
188 /* The checksum is stored in a big-endian format. */
189 hi = (unsigned char) (checksum >> 8);
190 lo = (unsigned char) (checksum & 0x00ff);
191 cmos_write_byte(cmos_checksum_index, hi);
192 cmos_write_byte(cmos_checksum_index + 1, lo);
193 }
194
195/****************************************************************************
196 * cmos_checksum_compute
197 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000198 * Compute a checksum for the coreboot parameter values currently stored in
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000199 * CMOS and return this checksum.
200 ****************************************************************************/
201uint16_t cmos_checksum_compute (void)
202 { unsigned i, sum;
203
204 sum = 0;
205
206 for (i = cmos_checksum_start; i <= cmos_checksum_end; i++)
207 sum += cmos_read_byte(i);
208
209 return ~((uint16_t) (sum & 0xffff));
210 }
211
212/****************************************************************************
213 * cmos_checksum_verify
214 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000215 * Verify that the coreboot CMOS checksum is valid. If checksum is not
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000216 * valid then print warning message and exit.
217 ****************************************************************************/
218void cmos_checksum_verify (void)
219 { uint16_t computed, actual;
220
221 set_iopl(3);
222 computed = cmos_checksum_compute();
223 actual = cmos_checksum_read();
224 set_iopl(0);
225
226 if (computed != actual)
Stefan Reinauerf527e702008-01-18 15:33:49 +0000227 { fprintf(stderr, "%s: Warning: Coreboot CMOS checksum is bad.\n",
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000228 prog_name);
229 exit(1);
230 }
231 }