]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
x86: coreboot: Add a command to check and update CMOS RAM
authorSimon Glass <sjg@chromium.org>
Mon, 14 Oct 2024 22:32:10 +0000 (16:32 -0600)
committerTom Rini <trini@konsulko.com>
Mon, 4 Nov 2024 03:27:12 +0000 (21:27 -0600)
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>
cmd/Kconfig
cmd/x86/Makefile
cmd/x86/cbcmos.c [new file with mode: 0644]
doc/usage/cmd/cbcmos.rst [new file with mode: 0644]
doc/usage/index.rst
test/cmd/coreboot.c

index 4fba9fe670348b7f82d85ccaf370d333bbd4cd34..636833646f6ef54659bef9aa70c39fc82b38fae9 100644 (file)
@@ -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
index 925215235d3bfbb3699236a0a3e2df9fa27e1166..5f3f5be2882f0b6399a0d43ad573a7f0df0c5317 100644 (file)
@@ -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
diff --git a/cmd/x86/cbcmos.c b/cmd/x86/cbcmos.c
new file mode 100644 (file)
index 0000000..fe5582f
--- /dev/null
@@ -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));
diff --git a/doc/usage/cmd/cbcmos.rst b/doc/usage/cmd/cbcmos.rst
new file mode 100644 (file)
index 0000000..156521d
--- /dev/null
@@ -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
+    =>
index db71711c3938efbfb5cc321492e6ccb2e5aa9044..b7c80ef3b12e7d4dff0d2ed49eb8ce88f29feefa 100644 (file)
@@ -43,6 +43,7 @@ Shell commands
    cmd/bootz
    cmd/button
    cmd/cat
+   cmd/cbcmos
    cmd/cbsysinfo
    cmd/cedit
    cmd/cli
index 0fcf66ac71bcdb85c2f9b29843a2de73ad6f5086..e1acf8697e879bb6ec41013cc671eacd6eedbbb4 100644 (file)
@@ -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);