1 /*****************************************************************************\
3 *****************************************************************************
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>.
10 * This file is part of nvramtool, a utility for reading/writing coreboot
11 * parameters and displaying information from the coreboot table.
12 * For details, see https://coreboot.org/nvramtool.
14 * Please also read the file DISCLAIMER which is included in this software
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.
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 \*****************************************************************************/
29 #include "cmos_lowlevel.h"
31 static int prepare_cmos_op_common(const cmos_entry_t
* e
);
33 /****************************************************************************
34 * prepare_cmos_op_common
36 * Perform a few checks common to both reads and writes.
37 ****************************************************************************/
38 static int prepare_cmos_op_common(const cmos_entry_t
* e
)
42 if (e
->config
== CMOS_ENTRY_RESERVED
)
43 /* Access to reserved parameters is not permitted. */
44 return CMOS_OP_RESERVED
;
46 if ((result
= verify_cmos_op(e
->bit
, e
->length
, e
->config
)) != OK
)
49 assert(e
->length
> 0);
53 /****************************************************************************
56 * The caller wishes to read a CMOS parameter represented by 'e'. Perform
57 * sanity checking on 'e'. If a problem was found with e, return an error
58 * code. Else return OK.
59 ****************************************************************************/
60 int prepare_cmos_read(const cmos_entry_t
* e
)
64 if ((result
= prepare_cmos_op_common(e
)) != OK
)
70 case CMOS_ENTRY_STRING
:
80 /****************************************************************************
83 * The caller wishes to set a CMOS parameter represented by 'e' to a value
84 * whose string representation is stored in 'value_str'. Perform sanity
85 * checking on 'value_str'. On error, return an error code. Else store the
86 * numeric equivalent of 'value_str' in '*value' and return OK.
87 ****************************************************************************/
88 int prepare_cmos_write(const cmos_entry_t
* e
, const char value_str
[],
89 unsigned long long *value
)
92 unsigned long long out
;
95 int negative
, result
, found_one
;
97 if ((result
= prepare_cmos_op_common(e
)) != OK
)
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
; q
= next_cmos_enum_id(q
)) {
107 if (!strncmp(q
->text
, value_str
, CMOS_MAX_TEXT_LENGTH
))
112 return CMOS_OP_NO_MATCHING_ENUM
;
115 return CMOS_OP_BAD_ENUM_VALUE
;
121 /* See if the first character of 'value_str' (excluding
122 * any initial whitespace) is a minus sign.
124 for (p
= value_str
; isspace((int)(unsigned char)*p
); p
++) ;
125 negative
= (*p
== '-');
127 out
= strtoull(value_str
, (char **)&p
, 0);
130 return CMOS_OP_INVALID_INT
;
132 /* If we get this far, the user specified a valid integer.
133 * However we do not currently support the use of negative
134 * numbers as CMOS parameter values.
137 return CMOS_OP_NEGATIVE_INT
;
141 case CMOS_ENTRY_STRING
:
142 if (e
->length
< (8 * strlen(value_str
)))
143 return CMOS_OP_VALUE_TOO_WIDE
;
144 memory
= malloc(e
->length
/ 8);
145 memset(memory
, 0, e
->length
/ 8);
146 strcpy(memory
, value_str
);
147 out
= (unsigned long)memory
;
154 if ((e
->length
< (8 * sizeof(*value
))) && (out
>= (1ull << e
->length
))) {
155 if (memory
) free(memory
);
156 return CMOS_OP_VALUE_TOO_WIDE
;
163 /****************************************************************************
166 * Read the checksum for the coreboot parameters stored in CMOS and return
168 ****************************************************************************/
169 uint16_t cmos_checksum_read(void)
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
;
179 /****************************************************************************
180 * cmos_checksum_write
182 * Set the checksum for the coreboot parameters stored in CMOS to
184 ****************************************************************************/
185 void cmos_checksum_write(uint16_t checksum
)
187 unsigned char lo
, hi
;
189 /* The checksum is stored in a big-endian format. */
190 hi
= (unsigned char)(checksum
>> 8);
191 lo
= (unsigned char)(checksum
& 0x00ff);
192 cmos_write_byte(cmos_checksum_index
, hi
);
193 cmos_write_byte(cmos_checksum_index
+ 1, lo
);
196 /****************************************************************************
197 * cmos_checksum_compute
199 * Compute a checksum for the coreboot parameter values currently stored in
200 * CMOS and return this checksum.
201 ****************************************************************************/
202 uint16_t cmos_checksum_compute(void)
208 for (i
= cmos_checksum_start
; i
<= cmos_checksum_end
; i
++)
209 sum
+= cmos_read_byte(i
);
211 return (uint16_t)(sum
& 0xffff);
214 /****************************************************************************
215 * cmos_checksum_verify
217 * Verify that the coreboot CMOS checksum is valid. If checksum is not
218 * valid then print warning message and exit.
219 ****************************************************************************/
220 void cmos_checksum_verify(void)
222 uint16_t computed
, actual
;
225 computed
= cmos_checksum_compute();
226 actual
= cmos_checksum_read();
229 if (computed
!= actual
) {
230 fprintf(stderr
, "%s: Warning: coreboot CMOS checksum is bad.\n",
232 fprintf(stderr
, "Computed checksum: 0x%x. Stored checksum: 0x%x\n",