mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-11 07:24:46 +00:00
x86: coreboot: Add a command to check and update CMOS RAM
Coreboot tables provide information about the CMOS-RAM checksum. Add a command which can check and update this. With this it is possible to adjust CMOS-RAM settings and tidy up the checksum afterwards. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
00815be924
commit
e25c34ddb5
6 changed files with 235 additions and 0 deletions
11
cmd/Kconfig
11
cmd/Kconfig
|
@ -2871,6 +2871,17 @@ config CMD_CBSYSINFO
|
|||
memory by coreboot before jumping to U-Boot. It can be useful for
|
||||
debugging the beaaviour of coreboot or U-Boot.
|
||||
|
||||
config CMD_CBCMOS
|
||||
bool "cbcmos"
|
||||
depends on X86
|
||||
default y if SYS_COREBOOT
|
||||
help
|
||||
This provides information options to check the CMOS RAM checksum,
|
||||
if present, as well as to update it.
|
||||
|
||||
It is useful when coreboot CMOS-RAM settings must be examined or
|
||||
updated.
|
||||
|
||||
config CMD_CYCLIC
|
||||
bool "cyclic - Show information about cyclic functions"
|
||||
depends on CYCLIC
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
obj-$(CONFIG_CMD_CBSYSINFO) += cbsysinfo.o
|
||||
obj-y += cpuid.o msr.o mtrr.o
|
||||
obj-$(CONFIG_CMD_CBCMOS) += cbcmos.o
|
||||
obj-$(CONFIG_CMD_EXCEPTION) += exception.o
|
||||
obj-$(CONFIG_USE_HOB) += hob.o
|
||||
obj-$(CONFIG_HAVE_FSP) += fsp.o
|
||||
|
|
139
cmd/x86/cbcmos.c
Normal file
139
cmd/x86/cbcmos.c
Normal file
|
@ -0,0 +1,139 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Support for booting from coreboot
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY UCLASS_RTC
|
||||
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <rtc.h>
|
||||
#include <asm/cb_sysinfo.h>
|
||||
#include <asm/global_data.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
const struct sysinfo_t *get_table(void)
|
||||
{
|
||||
if (!gd->arch.coreboot_table) {
|
||||
printf("No coreboot sysinfo table found\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &lib_sysinfo;
|
||||
}
|
||||
|
||||
static int calc_sum(struct udevice *dev, uint start_bit, uint bit_count)
|
||||
{
|
||||
uint start_byte = start_bit / 8;
|
||||
uint byte_count = bit_count / 8;
|
||||
int ret, i;
|
||||
uint sum;
|
||||
|
||||
log_debug("Calc sum from %x: %x bytes\n", start_byte, byte_count);
|
||||
sum = 0;
|
||||
for (i = 0; i < bit_count / 8; i++) {
|
||||
ret = rtc_read8(dev, start_bit / 8 + i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
sum += ret;
|
||||
}
|
||||
|
||||
return (sum & 0xff) << 8 | (sum & 0xff00) >> 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* prep_cbcmos() - Prepare for a CMOS-RAM command
|
||||
*
|
||||
* @tab: coreboot table
|
||||
* @devnum: RTC device name to use, or NULL for the first one
|
||||
* @dep: Returns RTC device on success
|
||||
* Return: calculated checksum for CMOS RAM or -ve on error
|
||||
*/
|
||||
static int prep_cbcmos(const struct sysinfo_t *tab, const char *devname,
|
||||
struct udevice **devp)
|
||||
{
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
if (!tab)
|
||||
return CMD_RET_FAILURE;
|
||||
if (devname)
|
||||
ret = uclass_get_device_by_name(UCLASS_RTC, devname, &dev);
|
||||
else
|
||||
ret = uclass_first_device_err(UCLASS_RTC, &dev);
|
||||
if (ret) {
|
||||
printf("Failed to get RTC device: %dE\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = calc_sum(dev, tab->cmos_range_start,
|
||||
tab->cmos_range_end + 1 - tab->cmos_range_start);
|
||||
if (ret < 0) {
|
||||
printf("Failed to read RTC device: %dE\n", ret);
|
||||
return ret;
|
||||
}
|
||||
*devp = dev;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_cbcmos_check(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
const struct sysinfo_t *tab = get_table();
|
||||
struct udevice *dev;
|
||||
u16 cur, sum;
|
||||
int ret;
|
||||
|
||||
ret = prep_cbcmos(tab, argv[1], &dev);
|
||||
if (ret < 0)
|
||||
return CMD_RET_FAILURE;
|
||||
sum = ret;
|
||||
|
||||
ret = rtc_read16(dev, tab->cmos_checksum_location / 8, &cur);
|
||||
if (ret < 0) {
|
||||
printf("Failed to read RTC device: %dE\n", ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
if (sum != cur) {
|
||||
printf("Checksum %04x error: calculated %04x\n", cur, sum);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_cbcmos_update(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
const struct sysinfo_t *tab = get_table();
|
||||
struct udevice *dev;
|
||||
u16 sum;
|
||||
int ret;
|
||||
|
||||
ret = prep_cbcmos(tab, argv[1], &dev);
|
||||
if (ret < 0)
|
||||
return CMD_RET_FAILURE;
|
||||
sum = ret;
|
||||
|
||||
ret = rtc_write16(dev, tab->cmos_checksum_location / 8, sum);
|
||||
if (ret < 0) {
|
||||
printf("Failed to read RTC device: %dE\n", ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
printf("Checksum %04x written\n", sum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_LONGHELP(cbcmos,
|
||||
"check - check CMOS RAM\n"
|
||||
"cbcmos update - Update CMOS-RAM checksum";
|
||||
);
|
||||
|
||||
U_BOOT_CMD_WITH_SUBCMDS(cbcmos, "coreboot CMOS RAM", cbcmos_help_text,
|
||||
U_BOOT_SUBCMD_MKENT(check, 2, 1, do_cbcmos_check),
|
||||
U_BOOT_SUBCMD_MKENT(update, 2, 1, do_cbcmos_update));
|
42
doc/usage/cmd/cbcmos.rst
Normal file
42
doc/usage/cmd/cbcmos.rst
Normal file
|
@ -0,0 +1,42 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
cbcmos
|
||||
======
|
||||
|
||||
Synopis
|
||||
-------
|
||||
|
||||
::
|
||||
|
||||
cbcmos check [<dev>]
|
||||
cbcmos update [<dev>]
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This checks or updates the CMOS-RAM checksum value against the CMOS-RAM
|
||||
contents. It is used with coreboot, which provides information about where to
|
||||
find the checksum and what part of the CMOS RAM it covers.
|
||||
|
||||
If `<dev>` is provided then the named real-time clock (RTC) device is used.
|
||||
Otherwise the default RTC is used.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
This shows checking and updating a checksum across bytes 38 and 39 of the
|
||||
CMOS RAM::
|
||||
|
||||
=> rtc read 38 2
|
||||
00000038: 71 00 q.
|
||||
=> cbc check
|
||||
=> rtc write 38 66
|
||||
=> rtc read 38 2
|
||||
00000038: 66 00 f.
|
||||
=> cbc check
|
||||
Checksum 7100 error: calculated 6600
|
||||
=> cbc update
|
||||
Checksum 6600 written
|
||||
=> cbc check
|
||||
=>
|
|
@ -43,6 +43,7 @@ Shell commands
|
|||
cmd/bootz
|
||||
cmd/button
|
||||
cmd/cat
|
||||
cmd/cbcmos
|
||||
cmd/cbsysinfo
|
||||
cmd/cedit
|
||||
cmd/cli
|
||||
|
|
|
@ -7,10 +7,16 @@
|
|||
*/
|
||||
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <rtc.h>
|
||||
#include <test/cmd.h>
|
||||
#include <test/test.h>
|
||||
#include <test/ut.h>
|
||||
|
||||
enum {
|
||||
CSUM_LOC = 0x3f0 / 8,
|
||||
};
|
||||
|
||||
/**
|
||||
* test_cmd_cbsysinfo() - test the cbsysinfo command produces expected output
|
||||
*
|
||||
|
@ -41,3 +47,38 @@ static int test_cmd_cbsysinfo(struct unit_test_state *uts)
|
|||
return 0;
|
||||
}
|
||||
CMD_TEST(test_cmd_cbsysinfo, UTF_CONSOLE);
|
||||
|
||||
/* test cbcmos command */
|
||||
static int test_cmd_cbcmos(struct unit_test_state *uts)
|
||||
{
|
||||
u16 old_csum, new_csum;
|
||||
struct udevice *dev;
|
||||
|
||||
/* initially the checksum should be correct */
|
||||
ut_assertok(run_command("cbcmos check", 0));
|
||||
ut_assert_console_end();
|
||||
|
||||
/* make a change to the checksum */
|
||||
ut_assertok(uclass_first_device_err(UCLASS_RTC, &dev));
|
||||
ut_assertok(rtc_read16(dev, CSUM_LOC, &old_csum));
|
||||
ut_assertok(rtc_write16(dev, CSUM_LOC, old_csum + 1));
|
||||
|
||||
/* now the command should fail */
|
||||
ut_asserteq(1, run_command("cbcmos check", 0));
|
||||
ut_assert_nextline("Checksum %04x error: calculated %04x",
|
||||
old_csum + 1, old_csum);
|
||||
ut_assert_console_end();
|
||||
|
||||
/* now get it to fix the checksum */
|
||||
ut_assertok(run_command("cbcmos update", 0));
|
||||
ut_assert_nextline("Checksum %04x written", old_csum);
|
||||
ut_assert_console_end();
|
||||
|
||||
/* check the RTC looks right */
|
||||
ut_assertok(rtc_read16(dev, CSUM_LOC, &new_csum));
|
||||
ut_asserteq(old_csum, new_csum);
|
||||
ut_assert_console_end();
|
||||
|
||||
return 0;
|
||||
}
|
||||
CMD_TEST(test_cmd_cbcmos, UTF_CONSOLE);
|
||||
|
|
Loading…
Add table
Reference in a new issue