With some coreboot configs setting a byte to a magic value changes behaviour on next boot. Setting bit-by-bit is possible but not convenient. Add cmosread and cmoswrite for convenience.
Signed-off-by: Vladimir Serbinenko <phco...@gmail.com> --- grub-core/commands/i386/cmostest.c | 72 +++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/grub-core/commands/i386/cmostest.c b/grub-core/commands/i386/cmostest.c index 1f0c5341d..814df0f43 100644 --- a/grub-core/commands/i386/cmostest.c +++ b/grub-core/commands/i386/cmostest.c @@ -18,9 +18,12 @@ #include <grub/dl.h> #include <grub/command.h> +#include <grub/extcmd.h> #include <grub/misc.h> #include <grub/cmos.h> #include <grub/i18n.h> +#include <grub/mm.h> +#include <grub/env.h> GRUB_MOD_LICENSE ("GPLv3+"); @@ -99,7 +102,66 @@ grub_cmd_cmosset (struct grub_command *cmd __attribute__ ((unused)), return grub_cmos_write (byte, value | (1 << bit)); } -static grub_command_t cmd, cmd_clean, cmd_set; +static grub_err_t +grub_cmd_cmoswrite (struct grub_command *cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + unsigned long byte, value; + const char *end; + + if (argc != 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected")); + + byte = grub_strtoul (argv[0], &end, 0); + if (byte >= 0x100 || argv[0][0] == '\0' || *end != '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid address")); + + value = grub_strtoul (argv[1], &end, 0); + if (value >= 0x100 || argv[1][0] == '\0' || *end != '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid value")); + + return grub_cmos_write (byte, value); +} + +static grub_err_t +grub_cmd_cmosread (grub_extcmd_context_t ctxt, int argc, char **argv) +{ + unsigned long byte; + grub_uint8_t value = 0; + grub_err_t err; + const char *end; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); + + byte = grub_strtoul (argv[0], &end, 0); + if (byte >= 0x100 || argv[0][0] == '\0' || *end != '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid address")); + + err = grub_cmos_read (byte, &value); + if (err) + return err; + + if (ctxt->state[0].set) + { + char buf[sizeof ("XX")]; + grub_snprintf (buf, sizeof (buf), "%x", value); + grub_env_set(ctxt->state[0].arg, buf); + } + else + grub_printf_("CMOS value at 0x%lx is 0x%x\n", byte, value); + return GRUB_ERR_NONE; +} + +static const struct grub_arg_option read_options[] = + { + {0, 's', 0, N_("Save read value into variable VARNAME."), + N_("VARNAME"), ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + +static grub_command_t cmd, cmd_clean, cmd_set, cmd_write; +static grub_extcmd_t cmd_read; GRUB_MOD_INIT(cmostest) @@ -114,6 +176,12 @@ GRUB_MOD_INIT(cmostest) N_("BYTE:BIT"), /* TRANSLATORS: A bit may be either set (1) or clear (0). */ N_("Set bit at BYTE:BIT in CMOS.")); + cmd_read = grub_register_extcmd_lockdown ("cmosread", grub_cmd_cmosread, 0, + N_("[-s VAR] ADDR"), + N_("Read CMOS byte at ADDR."), read_options); + cmd_write = grub_register_command_lockdown ("cmoswrite", grub_cmd_cmoswrite, + N_("ADDR VALUE"), + N_("Set CMOS byte at ADDR to VALUE.")); } GRUB_MOD_FINI(cmostest) @@ -121,4 +189,6 @@ GRUB_MOD_FINI(cmostest) grub_unregister_command (cmd); grub_unregister_command (cmd_clean); grub_unregister_command (cmd_set); + grub_unregister_extcmd (cmd_read); + grub_unregister_command (cmd_write); } -- 2.39.2 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel