a73b93157f
It encourages users from writing to the FSF without giving an address. Linux also prefers to drop that and their checkpatch.pl (that we imported) looks out for that. This is the result of util/scripts/no-fsf-addresses.sh with no further editing. Change-Id: Ie96faea295fe001911d77dbc51e9a6789558fbd6 Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Reviewed-on: http://review.coreboot.org/11888 Tested-by: build bot (Jenkins) Reviewed-by: Alexandru Gagniuc <mr.nuke.me@gmail.com> Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
234 lines
6.8 KiB
C
234 lines
6.8 KiB
C
/*****************************************************************************\
|
|
* cmos_ops.c
|
|
*****************************************************************************
|
|
* Copyright (C) 2002-2005 The Regents of the University of California.
|
|
* Produced at the Lawrence Livermore National Laboratory.
|
|
* Written by David S. Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>.
|
|
* UCRL-CODE-2003-012
|
|
* All rights reserved.
|
|
*
|
|
* This file is part of nvramtool, a utility for reading/writing coreboot
|
|
* parameters and displaying information from the coreboot table.
|
|
* For details, see http://coreboot.org/nvramtool.
|
|
*
|
|
* Please also read the file DISCLAIMER which is included in this software
|
|
* distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License (as published by the
|
|
* Free Software Foundation) version 2, dated June 1991.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
|
|
* conditions of the GNU General Public License for more details.
|
|
\*****************************************************************************/
|
|
|
|
#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);
|
|
exit(1);
|
|
}
|
|
}
|