1 /* SPDX-License-Identifier: GPL-2.0-only */
5 #include "cmos_lowlevel.h"
7 static int prepare_cmos_op_common(const cmos_entry_t
* e
);
9 /****************************************************************************
10 * prepare_cmos_op_common
12 * Perform a few checks common to both reads and writes.
13 ****************************************************************************/
14 static int prepare_cmos_op_common(const cmos_entry_t
* e
)
18 if (e
->config
== CMOS_ENTRY_RESERVED
)
19 /* Access to reserved parameters is not permitted. */
20 return CMOS_OP_RESERVED
;
22 if ((result
= verify_cmos_op(e
->bit
, e
->length
, e
->config
)) != OK
)
25 assert(e
->length
> 0);
29 /****************************************************************************
32 * The caller wishes to read a CMOS parameter represented by 'e'. Perform
33 * sanity checking on 'e'. If a problem was found with e, return an error
34 * code. Else return OK.
35 ****************************************************************************/
36 int prepare_cmos_read(const cmos_entry_t
* e
)
40 if ((result
= prepare_cmos_op_common(e
)) != OK
)
46 case CMOS_ENTRY_STRING
:
56 /****************************************************************************
59 * The caller wishes to set a CMOS parameter represented by 'e' to a value
60 * whose string representation is stored in 'value_str'. Perform sanity
61 * checking on 'value_str'. On error, return an error code. Else store the
62 * numeric equivalent of 'value_str' in '*value' and return OK.
63 ****************************************************************************/
64 int prepare_cmos_write(const cmos_entry_t
* e
, const char value_str
[],
65 unsigned long long *value
)
68 unsigned long long out
;
71 int negative
, result
, found_one
;
73 if ((result
= prepare_cmos_op_common(e
)) != OK
)
78 /* Make sure the user's input corresponds to a valid option. */
79 for (q
= first_cmos_enum_id(e
->config_id
), found_one
= 0;
80 q
!= NULL
; q
= next_cmos_enum_id(q
)) {
83 if (!strncmp(q
->text
, value_str
, CMOS_MAX_TEXT_LENGTH
))
88 return CMOS_OP_NO_MATCHING_ENUM
;
91 return CMOS_OP_BAD_ENUM_VALUE
;
97 /* See if the first character of 'value_str' (excluding
98 * any initial whitespace) is a minus sign.
100 for (p
= value_str
; isspace((int)(unsigned char)*p
); p
++) ;
101 negative
= (*p
== '-');
103 out
= strtoull(value_str
, (char **)&p
, 0);
106 return CMOS_OP_INVALID_INT
;
108 /* If we get this far, the user specified a valid integer.
109 * However we do not currently support the use of negative
110 * numbers as CMOS parameter values.
113 return CMOS_OP_NEGATIVE_INT
;
117 case CMOS_ENTRY_STRING
:
118 if (e
->length
< (8 * strlen(value_str
)))
119 return CMOS_OP_VALUE_TOO_WIDE
;
120 memory
= malloc(e
->length
/ 8);
121 memset(memory
, 0, e
->length
/ 8);
122 strcpy(memory
, value_str
);
123 out
= (unsigned long)memory
;
130 if ((e
->length
< (8 * sizeof(*value
))) && (out
>= (1ull << e
->length
))) {
131 if (memory
) free(memory
);
132 return CMOS_OP_VALUE_TOO_WIDE
;
139 /****************************************************************************
142 * Read the checksum for the coreboot parameters stored in CMOS and return
144 ****************************************************************************/
145 uint16_t cmos_checksum_read(void)
149 /* The checksum is stored in a big-endian format. */
150 hi
= cmos_read_byte(cmos_checksum_index
);
151 lo
= cmos_read_byte(cmos_checksum_index
+ 1);
152 return (hi
<< 8) + lo
;
155 /****************************************************************************
156 * cmos_checksum_write
158 * Set the checksum for the coreboot parameters stored in CMOS to
160 ****************************************************************************/
161 void cmos_checksum_write(uint16_t checksum
)
163 unsigned char lo
, hi
;
165 /* The checksum is stored in a big-endian format. */
166 hi
= (unsigned char)(checksum
>> 8);
167 lo
= (unsigned char)(checksum
& 0x00ff);
168 cmos_write_byte(cmos_checksum_index
, hi
);
169 cmos_write_byte(cmos_checksum_index
+ 1, lo
);
172 /****************************************************************************
173 * cmos_checksum_compute
175 * Compute a checksum for the coreboot parameter values currently stored in
176 * CMOS and return this checksum.
177 ****************************************************************************/
178 uint16_t cmos_checksum_compute(void)
184 for (i
= cmos_checksum_start
; i
<= cmos_checksum_end
; i
++)
185 sum
+= cmos_read_byte(i
);
187 return (uint16_t)(sum
& 0xffff);
190 /****************************************************************************
191 * cmos_checksum_verify
193 * Verify that the coreboot CMOS checksum is valid. If checksum is not
194 * valid then print warning message and exit.
195 ****************************************************************************/
196 void cmos_checksum_verify(void)
198 uint16_t computed
, actual
;
201 computed
= cmos_checksum_compute();
202 actual
= cmos_checksum_read();
205 if (computed
!= actual
) {
206 fprintf(stderr
, "%s: Warning: coreboot CMOS checksum is bad.\n",
208 fprintf(stderr
, "Computed checksum: 0x%x. Stored checksum: 0x%x\n",