blob: 8873633cb54aaaf0b8ad266bc956535d8e643a70 [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.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000025\*****************************************************************************/
26
27#include "common.h"
28#include "cmos_ops.h"
29#include "cmos_lowlevel.h"
30
Stefan Reinauer90b96b62010-01-13 21:00:23 +000031static int prepare_cmos_op_common(const cmos_entry_t * e);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000032
33/****************************************************************************
34 * prepare_cmos_op_common
35 *
36 * Perform a few checks common to both reads and writes.
37 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +000038static int prepare_cmos_op_common(const cmos_entry_t * e)
39{
40 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000041
Stefan Reinauer90b96b62010-01-13 21:00:23 +000042 if (e->config == CMOS_ENTRY_RESERVED)
43 /* Access to reserved parameters is not permitted. */
44 return CMOS_OP_RESERVED;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000045
Stefan Reinauer90b96b62010-01-13 21:00:23 +000046 if ((result = verify_cmos_op(e->bit, e->length, e->config)) != OK)
47 return result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000048
Stefan Reinauer90b96b62010-01-13 21:00:23 +000049 assert(e->length > 0);
50 return OK;
51}
Stefan Reinauer6540ae52007-07-12 16:35:42 +000052
53/****************************************************************************
54 * prepare_cmos_read
55 *
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +000060int prepare_cmos_read(const cmos_entry_t * e)
61{
62 int result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000063
Stefan Reinauer90b96b62010-01-13 21:00:23 +000064 if ((result = prepare_cmos_op_common(e)) != OK)
65 return result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000066
Stefan Reinauer90b96b62010-01-13 21:00:23 +000067 switch (e->config) {
68 case CMOS_ENTRY_ENUM:
69 case CMOS_ENTRY_HEX:
70 case CMOS_ENTRY_STRING:
71 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000072
Stefan Reinauer90b96b62010-01-13 21:00:23 +000073 default:
74 BUG();
75 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +000076
Stefan Reinauer90b96b62010-01-13 21:00:23 +000077 return OK;
78}
Stefan Reinauer6540ae52007-07-12 16:35:42 +000079
80/****************************************************************************
81 * prepare_cmos_write
82 *
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +000088int prepare_cmos_write(const cmos_entry_t * e, const char value_str[],
89 unsigned long long *value)
90{
91 const cmos_enum_t *q;
92 unsigned long long out;
93 const char *p;
Patrick Georgidd1aab92014-08-09 17:06:20 +020094 char *memory = NULL;
Stefan Reinauer90b96b62010-01-13 21:00:23 +000095 int negative, result, found_one;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000096
Stefan Reinauer90b96b62010-01-13 21:00:23 +000097 if ((result = prepare_cmos_op_common(e)) != OK)
98 return result;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000099
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000100 switch (e->config) {
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)) {
105 found_one = 1;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000106
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000107 if (!strncmp(q->text, value_str, CMOS_MAX_TEXT_LENGTH))
108 break;
109 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000110
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000111 if (!found_one)
112 return CMOS_OP_NO_MATCHING_ENUM;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000113
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000114 if (q == NULL)
115 return CMOS_OP_BAD_ENUM_VALUE;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000116
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000117 out = q->value;
118 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000119
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000120 case CMOS_ENTRY_HEX:
Stefan Reinauer14e22772010-04-27 06:56:47 +0000121 /* See if the first character of 'value_str' (excluding
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000122 * any initial whitespace) is a minus sign.
123 */
Jonathan Kollasch1571dc92011-04-19 19:34:25 +0000124 for (p = value_str; isspace((int)(unsigned char)*p); p++) ;
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000125 negative = (*p == '-');
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000126
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000127 out = strtoull(value_str, (char **)&p, 0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000128
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000129 if (*p)
130 return CMOS_OP_INVALID_INT;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000131
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000132 /* 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.
135 */
136 if (negative)
137 return CMOS_OP_NEGATIVE_INT;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000138
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000139 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000140
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000141 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;
148 break;
Stefan Reinauera67aab72008-09-27 10:08:28 +0000149
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000150 default:
151 BUG();
152 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000153
Patrick Georgidd1aab92014-08-09 17:06:20 +0200154 if ((e->length < (8 * sizeof(*value))) && (out >= (1ull << e->length))) {
155 if (memory) free(memory);
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000156 return CMOS_OP_VALUE_TOO_WIDE;
Patrick Georgidd1aab92014-08-09 17:06:20 +0200157 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000158
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000159 *value = out;
160 return OK;
161}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000162
163/****************************************************************************
164 * cmos_checksum_read
165 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000166 * Read the checksum for the coreboot parameters stored in CMOS and return
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000167 * this value.
168 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000169uint16_t cmos_checksum_read(void)
170{
171 uint16_t lo, hi;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000172
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000173 /* 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}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000178
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 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000185void cmos_checksum_write(uint16_t checksum)
186{
187 unsigned char lo, hi;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000188
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000189 /* 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);
194}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000195
196/****************************************************************************
197 * cmos_checksum_compute
198 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000199 * Compute a checksum for the coreboot parameter values currently stored in
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000200 * CMOS and return this checksum.
201 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000202uint16_t cmos_checksum_compute(void)
203{
204 unsigned i, sum;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000205
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000206 sum = 0;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000207
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000208 for (i = cmos_checksum_start; i <= cmos_checksum_end; i++)
209 sum += cmos_read_byte(i);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000210
Stefan Reinauerc31c4de2011-10-17 08:58:27 -0700211 return (uint16_t)(sum & 0xffff);
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000212}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000213
214/****************************************************************************
215 * cmos_checksum_verify
216 *
Stefan Reinauerf527e702008-01-18 15:33:49 +0000217 * Verify that the coreboot CMOS checksum is valid. If checksum is not
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000218 * valid then print warning message and exit.
219 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000220void cmos_checksum_verify(void)
221{
222 uint16_t computed, actual;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000223
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000224 set_iopl(3);
225 computed = cmos_checksum_compute();
226 actual = cmos_checksum_read();
227 set_iopl(0);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000228
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000229 if (computed != actual) {
230 fprintf(stderr, "%s: Warning: Coreboot CMOS checksum is bad.\n",
231 prog_name);
232 exit(1);
233 }
234}