Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | /* SPDX-License-Identifier: GPL-2.0-only */
#include "common.h"
#include "cmos_ops.h"
#include "cmos_lowlevel.h"
static int prepare_cmos_op_common(const cmos_entry_t * e);
/****************************************************************************
* prepare_cmos_op_common
*
* Perform a few checks common to both reads and writes.
****************************************************************************/
static int prepare_cmos_op_common(const cmos_entry_t * e)
{
int result;
if (e->config == CMOS_ENTRY_RESERVED)
/* Access to reserved parameters is not permitted. */
return CMOS_OP_RESERVED;
if ((result = verify_cmos_op(e->bit, e->length, e->config)) != OK)
return result;
assert(e->length > 0);
return OK;
}
/****************************************************************************
* prepare_cmos_read
*
* The caller wishes to read a CMOS parameter represented by 'e'. Perform
* sanity checking on 'e'. If a problem was found with e, return an error
* code. Else return OK.
****************************************************************************/
int prepare_cmos_read(const cmos_entry_t * e)
{
int result;
if ((result = prepare_cmos_op_common(e)) != OK)
return result;
switch (e->config) {
case CMOS_ENTRY_ENUM:
case CMOS_ENTRY_HEX:
case CMOS_ENTRY_STRING:
break;
default:
BUG();
}
return OK;
}
/****************************************************************************
* prepare_cmos_write
*
* The caller wishes to set a CMOS parameter represented by 'e' to a value
* whose string representation is stored in 'value_str'. Perform sanity
* checking on 'value_str'. On error, return an error code. Else store the
* numeric equivalent of 'value_str' in '*value' and return OK.
****************************************************************************/
int prepare_cmos_write(const cmos_entry_t * e, const char value_str[],
unsigned long long *value)
{
const cmos_enum_t *q;
unsigned long long out;
const char *p;
char *memory = NULL;
int negative, result, found_one;
if ((result = prepare_cmos_op_common(e)) != OK)
return result;
switch (e->config) {
case CMOS_ENTRY_ENUM:
/* Make sure the user's input corresponds to a valid option. */
for (q = first_cmos_enum_id(e->config_id), found_one = 0;
q != NULL; q = next_cmos_enum_id(q)) {
found_one = 1;
if (!strncmp(q->text, value_str, CMOS_MAX_TEXT_LENGTH))
break;
}
if (!found_one)
return CMOS_OP_NO_MATCHING_ENUM;
if (q == NULL)
return CMOS_OP_BAD_ENUM_VALUE;
out = q->value;
break;
case CMOS_ENTRY_HEX:
/* See if the first character of 'value_str' (excluding
* any initial whitespace) is a minus sign.
*/
for (p = value_str; isspace((int)(unsigned char)*p); p++) ;
negative = (*p == '-');
out = strtoull(value_str, (char **)&p, 0);
if (*p)
return CMOS_OP_INVALID_INT;
/* If we get this far, the user specified a valid integer.
* However we do not currently support the use of negative
* numbers as CMOS parameter values.
*/
if (negative)
return CMOS_OP_NEGATIVE_INT;
break;
case CMOS_ENTRY_STRING:
if (e->length < (8 * strlen(value_str)))
return CMOS_OP_VALUE_TOO_WIDE;
memory = malloc(e->length / 8);
memset(memory, 0, e->length / 8);
strcpy(memory, value_str);
out = (unsigned long)memory;
break;
default:
BUG();
}
if ((e->length < (8 * sizeof(*value))) && (out >= (1ull << e->length))) {
if (memory) free(memory);
return CMOS_OP_VALUE_TOO_WIDE;
}
*value = out;
return OK;
}
/****************************************************************************
* cmos_checksum_read
*
* Read the checksum for the coreboot parameters stored in CMOS and return
* this value.
****************************************************************************/
uint16_t cmos_checksum_read(void)
{
uint16_t lo, hi;
/* The checksum is stored in a big-endian format. */
hi = cmos_read_byte(cmos_checksum_index);
lo = cmos_read_byte(cmos_checksum_index + 1);
return (hi << 8) + lo;
}
/****************************************************************************
* cmos_checksum_write
*
* Set the checksum for the coreboot parameters stored in CMOS to
* 'checksum'.
****************************************************************************/
void cmos_checksum_write(uint16_t checksum)
{
unsigned char lo, hi;
/* The checksum is stored in a big-endian format. */
hi = (unsigned char)(checksum >> 8);
lo = (unsigned char)(checksum & 0x00ff);
cmos_write_byte(cmos_checksum_index, hi);
cmos_write_byte(cmos_checksum_index + 1, lo);
}
/****************************************************************************
* cmos_checksum_compute
*
* Compute a checksum for the coreboot parameter values currently stored in
* CMOS and return this checksum.
****************************************************************************/
uint16_t cmos_checksum_compute(void)
{
unsigned i, sum;
sum = 0;
for (i = cmos_checksum_start; i <= cmos_checksum_end; i++)
sum += cmos_read_byte(i);
return (uint16_t)(sum & 0xffff);
}
/****************************************************************************
* cmos_checksum_verify
*
* Verify that the coreboot CMOS checksum is valid. If checksum is not
* valid then print warning message and exit.
****************************************************************************/
void cmos_checksum_verify(void)
{
uint16_t computed, actual;
set_iopl(3);
computed = cmos_checksum_compute();
actual = cmos_checksum_read();
set_iopl(0);
if (computed != actual) {
fprintf(stderr, "%s: Warning: coreboot CMOS checksum is bad.\n",
prog_name);
fprintf(stderr, "Computed checksum: 0x%x. Stored checksum: 0x%x\n",
computed, actual);
exit(1);
}
}
|