cmos_ops.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #include "common.h" 4 #include "cmos_ops.h" 5 #include "cmos_lowlevel.h" 6 7 static int prepare_cmos_op_common(const cmos_entry_t * e); 8 9 /**************************************************************************** 10 * prepare_cmos_op_common 11 * 12 * Perform a few checks common to both reads and writes. 13 ****************************************************************************/ 14 static int prepare_cmos_op_common(const cmos_entry_t * e) 15 { 16 int result; 17 18 if (e->config == CMOS_ENTRY_RESERVED) 19 /* Access to reserved parameters is not permitted. */ 20 return CMOS_OP_RESERVED; 21 22 if ((result = verify_cmos_op(e->bit, e->length, e->config)) != OK) 23 return result; 24 25 assert(e->length > 0); 26 return OK; 27 } 28 29 /**************************************************************************** 30 * prepare_cmos_read 31 * 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) 37 { 38 int result; 39 40 if ((result = prepare_cmos_op_common(e)) != OK) 41 return result; 42 43 switch (e->config) { 44 case CMOS_ENTRY_ENUM: 45 case CMOS_ENTRY_HEX: 46 case CMOS_ENTRY_STRING: 47 break; 48 49 default: 50 BUG(); 51 } 52 53 return OK; 54 } 55 56 /**************************************************************************** 57 * prepare_cmos_write 58 * 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) 66 { 67 const cmos_enum_t *q; 68 unsigned long long out; 69 const char *p; 70 char *memory = NULL; 71 int negative, result, found_one; 72 73 if ((result = prepare_cmos_op_common(e)) != OK) 74 return result; 75 76 switch (e->config) { 77 case CMOS_ENTRY_ENUM: 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)) { 81 found_one = 1; 82 83 if (!strncmp(q->text, value_str, CMOS_MAX_TEXT_LENGTH)) 84 break; 85 } 86 87 if (!found_one) 88 return CMOS_OP_NO_MATCHING_ENUM; 89 90 if (q == NULL) 91 return CMOS_OP_BAD_ENUM_VALUE; 92 93 out = q->value; 94 break; 95 96 case CMOS_ENTRY_HEX: 97 /* See if the first character of 'value_str' (excluding 98 * any initial whitespace) is a minus sign. 99 */ 100 for (p = value_str; isspace((int)(unsigned char)*p); p++) ; 101 negative = (*p == '-'); 102 103 out = strtoull(value_str, (char **)&p, 0); 104 105 if (*p) 106 return CMOS_OP_INVALID_INT; 107 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. 111 */ 112 if (negative) 113 return CMOS_OP_NEGATIVE_INT; 114 115 break; 116 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; 124 break; 125 126 default: 127 BUG(); 128 } 129 130 if ((e->length < (8 * sizeof(*value))) && (out >= (1ull << e->length))) { 131 if (memory) free(memory); 132 return CMOS_OP_VALUE_TOO_WIDE; 133 } 134 135 *value = out; 136 return OK; 137 } 138 139 /**************************************************************************** 140 * cmos_checksum_read 141 * 142 * Read the checksum for the coreboot parameters stored in CMOS and return 143 * this value. 144 ****************************************************************************/ 145 uint16_t cmos_checksum_read(void) 146 { 147 uint16_t lo, hi; 148 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; 153 } 154 155 /**************************************************************************** 156 * cmos_checksum_write 157 * 158 * Set the checksum for the coreboot parameters stored in CMOS to 159 * 'checksum'. 160 ****************************************************************************/ 161 void cmos_checksum_write(uint16_t checksum) 162 { 163 unsigned char lo, hi; 164 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); 170 } 171 172 /**************************************************************************** 173 * cmos_checksum_compute 174 * 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) 179 { 180 unsigned i, sum; 181 182 sum = 0; 183 184 for (i = cmos_checksum_start; i <= cmos_checksum_end; i++) 185 sum += cmos_read_byte(i); 186 187 return (uint16_t)(sum & 0xffff); 188 } 189 190 /**************************************************************************** 191 * cmos_checksum_verify 192 * 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) 197 { 198 uint16_t computed, actual; 199 200 set_iopl(3); 201 computed = cmos_checksum_compute(); 202 actual = cmos_checksum_read(); 203 set_iopl(0); 204 205 if (computed != actual) { 206 fprintf(stderr, "%s: Warning: coreboot CMOS checksum is bad.\n", 207 prog_name); 208 fprintf(stderr, "Computed checksum: 0x%x. Stored checksum: 0x%x\n", 209 computed, actual); 210 exit(1); 211 } 212 }