grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2 2/2] Add new MSR modules (rdmsr/wrmsr)


From: Jesús Diéguez Fernández
Subject: [PATCH v2 2/2] Add new MSR modules (rdmsr/wrmsr)
Date: Fri, 1 Mar 2019 18:17:42 +0100

In order to be able to read and write from/to model-specific registers,
two new modules are added. They are i386 specific, as the cpuid module.

rdmsr module registers the command rdmsr that allows reading from a MSR.
wrmsr module registers the command wrmsr that allows writing to a MSR.

wrmsr module is disabled if UEFI secure boot is enabled.

Please note that on SMP systems, interacting with a MSR that has a
scope per hardware thread, implies that the value only applies to
the particular cpu/core/thread that ran the command.

Changelog v1 -> v2:

    - Patch all source code files with s/__asm__ __volatile__/asm volatile/g.
    - Split the module in two (rdmsr/wrmsr).
    - Include the wrmsr module in the forbidden modules efi list.
    - Code indentation and cleanup.
    - Copyright year update.
    - Implicit casting mask removed.
    - Use the same assembly code for x86 and x86_64.
    - Add missing documentation.
    - Patch submited with Signed-off-by.

Signed-off-by: Jesús Diéguez Fernández <address@hidden>
---
 docs/grub.texi                     | 45 ++++++++++++++--
 grub-core/Makefile.core.def        | 16 ++++++
 grub-core/commands/efi/shim_lock.c |  2 +-
 grub-core/commands/i386/rdmsr.c    | 84 ++++++++++++++++++++++++++++++
 grub-core/commands/i386/wrmsr.c    | 75 ++++++++++++++++++++++++++
 include/grub/i386/rdmsr.h          | 32 ++++++++++++
 include/grub/i386/wrmsr.h          | 29 +++++++++++
 7 files changed, 277 insertions(+), 6 deletions(-)
 create mode 100644 grub-core/commands/i386/rdmsr.c
 create mode 100644 grub-core/commands/i386/wrmsr.c
 create mode 100644 include/grub/i386/rdmsr.h
 create mode 100644 include/grub/i386/wrmsr.h

diff --git a/docs/grub.texi b/docs/grub.texi
index ecaba9d5c..1d792b636 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -3931,6 +3931,7 @@ you forget a command, you can run the command 
@command{help}
 * play::                        Play a tune
 * probe::                       Retrieve device info
 * pxe_unload::                  Unload the PXE environment
+* rdmsr::                       Read values from model-specific registers
 * read::                        Read user input
 * reboot::                      Reboot your computer
 * regexp::                      Test if regular expression matches string
@@ -3953,6 +3954,7 @@ you forget a command, you can run the command 
@command{help}
 * verify_detached::             Verify detached digital signature
 * videoinfo::                   List available video modes
 @comment * xen_*::              Xen boot commands for AArch64
+* wrmsr::                       Write values to model-specific registers
 * xen_hypervisor::              Load xen hypervisor binary (only on AArch64)
 * xen_module::                  Load xen modules for xen hypervisor (only on 
AArch64)
 @end menu
@@ -4785,6 +4787,20 @@ This command is only available on PC BIOS systems.
 @end deffn
 
 
address@hidden rdmsr
address@hidden rdmsr
+
address@hidden Command: rdmsr 0xADDR [-v VARNAME]
+Read a model-specific register at address 0xADDR. If the parameter
address@hidden is used and an environment variable @var{VARNAME} is 
+given, set that environment variable to the value that was read.
+
+Please note that on SMP systems, reading from a MSR that has a
+scope per hardware thread, implies that the value that is returned
+only applies to the particular cpu/core/thread that runs the command.
address@hidden deffn
+
+
 @node read
 @subsection read
 
@@ -5223,6 +5239,17 @@ successfully.  If validation fails, it is set to a 
non-zero value.
 List available video modes. If resolution is given, show only matching modes.
 @end deffn
 
address@hidden wrmsr
address@hidden wrmsr
+
address@hidden Command: wrmsr 0xADDR 0xVALUE
+Write a 0xVALUE to a model-specific register at address 0xADDR.
+
+Please note that on SMP systems, writing to a MSR that has a scope 
+per hardware thread, implies that the value that is written
+only applies to the particular cpu/core/thread that runs the command.
address@hidden deffn
+
 @node xen_hypervisor
 @subsection xen_hypervisor
 
@@ -5716,11 +5743,11 @@ boot and the shim. This functionality is provided by 
the shim_lock module. It
 is recommend to build in this and other required modules into the 
@file{core.img}.
 All modules not stored in the @file{core.img} and the ACPI tables for the
 @command{acpi} command have to be signed, e.g. using PGP. Additionally, the
address@hidden and the @command{memrw} commands are prohibited if the UEFI
-secure boot is enabled. This is done due to security reasons. All above
-mentioned requirements are enforced by the shim_lock module. And itself it
-is a persistent module which means that it cannot be unloaded if it was
-loaded into the memory.
address@hidden, the @command{memrw} and the @command{wrmsr} commands are 
+prohibited if the UEFI secure boot is enabled.  This is done due to 
+security reasons.  All above mentioned requirements are enforced by the 
+shim_lock module. And itself it is a persistent module which means that 
+it cannot be unloaded if it was loaded into the memory.
 
 @node Measured Boot
 @section Measuring boot components
@@ -5831,6 +5858,8 @@ to install to is specified, UUID is used instead as well.
 @item USB                @tab yes     @tab yes      @tab yes          @tab yes
 @item chainloader        @tab local   @tab yes      @tab yes          @tab no
 @item cpuid              @tab partial @tab partial  @tab partial      @tab 
partial
address@hidden rdmsr              @tab partial @tab partial  @tab partial      
@tab partial
address@hidden wrmsr              @tab partial @tab partial  @tab partial      
@tab partial
 @item hints              @tab guess   @tab guess    @tab guess        @tab 
guess
 @item PCI                @tab yes     @tab yes      @tab yes          @tab yes
 @item badram             @tab yes     @tab yes      @tab yes          @tab yes
@@ -5850,6 +5879,8 @@ to install to is specified, UUID is used instead as well.
 @item USB                @tab yes         @tab yes       @tab yes           
@tab no
 @item chainloader        @tab local       @tab local     @tab no            
@tab local
 @item cpuid              @tab partial     @tab partial   @tab partial       
@tab no
address@hidden rdmsr              @tab partial     @tab partial   @tab partial  
     @tab no
address@hidden wrmsr              @tab partial     @tab partial   @tab partial  
     @tab no
 @item hints              @tab guess       @tab guess     @tab good          
@tab guess
 @item PCI                @tab yes         @tab yes       @tab yes           
@tab no
 @item badram             @tab yes         @tab yes       @tab no            
@tab yes
@@ -5869,6 +5900,8 @@ to install to is specified, UUID is used instead as well.
 @item USB                @tab yes         @tab no      @tab no      @tab no
 @item chainloader        @tab yes         @tab no      @tab no      @tab no
 @item cpuid              @tab no          @tab no      @tab no      @tab no
address@hidden rdmsr              @tab no          @tab no      @tab no      
@tab no
address@hidden wrmsr              @tab no          @tab no      @tab no      
@tab no
 @item hints              @tab good        @tab good    @tab good    @tab no
 @item PCI                @tab yes         @tab no      @tab no      @tab no
 @item badram             @tab yes (*)     @tab no      @tab no      @tab no
@@ -5888,6 +5921,8 @@ to install to is specified, UUID is used instead as well.
 @item USB                @tab N/A       @tab yes         @tab no
 @item chainloader        @tab yes       @tab no          @tab yes
 @item cpuid              @tab no        @tab no          @tab yes
address@hidden rdmsr              @tab no        @tab no          @tab yes
address@hidden wrmsr              @tab no        @tab no          @tab yes
 @item hints              @tab guess     @tab no          @tab no
 @item PCI                @tab no        @tab no          @tab no
 @item badram             @tab yes (*)   @tab no          @tab no
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 2346bd291..a966a8f28 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2484,3 +2484,19 @@ module = {
   common = loader/i386/xen_file64.c;
   extra_dist = loader/i386/xen_fileXX.c;
 };
+module = {
+  name = rdmsr;
+  common = commands/i386/rdmsr.c;
+  enable = x86;
+  enable = i386_xen_pvh;
+  enable = i386_xen;
+  enable = x86_64_xen;
+};
+module = {
+  name = wrmsr;
+  common = commands/i386/wrmsr.c;
+  enable = x86;
+  enable = i386_xen_pvh;
+  enable = i386_xen;
+  enable = x86_64_xen;
+};
diff --git a/grub-core/commands/efi/shim_lock.c 
b/grub-core/commands/efi/shim_lock.c
index 83568cb2b..764098cfc 100644
--- a/grub-core/commands/efi/shim_lock.c
+++ b/grub-core/commands/efi/shim_lock.c
@@ -43,7 +43,7 @@ static grub_efi_guid_t shim_lock_guid = 
GRUB_EFI_SHIM_LOCK_GUID;
 static grub_efi_shim_lock_protocol_t *sl;
 
 /* List of modules which cannot be loaded if UEFI secure boot mode is enabled. 
*/
-static const char * const disabled_mods[] = {"iorw", "memrw", NULL};
+static const char * const disabled_mods[] = {"iorw", "memrw", "wrmsr", NULL};
 
 static grub_err_t
 shim_lock_init (grub_file_t io, enum grub_file_type type,
diff --git a/grub-core/commands/i386/rdmsr.c b/grub-core/commands/i386/rdmsr.c
new file mode 100644
index 000000000..08e5aee0b
--- /dev/null
+++ b/grub-core/commands/i386/rdmsr.c
@@ -0,0 +1,84 @@
+/* rdmsr.c - Read CPU model-specific registers */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2019  Free Software Foundation, Inc.
+ *  Based on gcc/gcc/config/i386/driver-i386.c
+ *
+ *  GRUB 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, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/env.h>
+#include <grub/command.h>
+#include <grub/extcmd.h>
+#include <grub/i386/rdmsr.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE("GPLv3+");
+
+static grub_extcmd_t cmd_read;
+
+static const struct grub_arg_option options[] =
+{
+    {0, 'v', 0, N_("Save read value into variable VARNAME."),
+    N_("VARNAME"), ARG_TYPE_STRING},
+    {0, 0, 0, 0, 0, 0}
+};
+
+static grub_err_t
+grub_cmd_msr_read (grub_extcmd_context_t ctxt, int argc, char **argv)
+{
+    grub_uint64_t addr, value;
+    char *ptr;
+    char buf[sizeof("XXXXXXXX")];
+
+    if (argc != 1)
+        return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+
+    grub_errno = GRUB_ERR_NONE;
+    ptr = argv[0];
+    addr = grub_strtoul (ptr, &ptr, 0);
+
+    if (grub_errno != GRUB_ERR_NONE)
+        return grub_errno;
+    if (*ptr != '\0')
+        return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid argument"));
+
+    value = grub_msr_read (addr);
+
+    if (ctxt->state[0].set)
+    {
+        grub_snprintf (buf, sizeof(buf), "%llx", value);
+        grub_env_set (ctxt->state[0].arg, buf);
+    }
+    else
+        grub_printf ("0x%llx\n", value);
+
+    return GRUB_ERR_NONE;
+}
+
+GRUB_MOD_INIT(rdmsr)
+{
+    cmd_read = grub_register_extcmd ("rdmsr", grub_cmd_msr_read, 0,
+                                    N_("ADDR"),
+                                    N_("Read a CPU model specific register."),
+                                    options);
+}
+
+GRUB_MOD_FINI(rdmsr)
+{
+    grub_unregister_extcmd (cmd_read);
+}
diff --git a/grub-core/commands/i386/wrmsr.c b/grub-core/commands/i386/wrmsr.c
new file mode 100644
index 000000000..351b93f93
--- /dev/null
+++ b/grub-core/commands/i386/wrmsr.c
@@ -0,0 +1,75 @@
+/* wrmsr.c - Write CPU model-specific registers */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2019  Free Software Foundation, Inc.
+ *  Based on gcc/gcc/config/i386/driver-i386.c
+ *
+ *  GRUB 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, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/env.h>
+#include <grub/command.h>
+#include <grub/extcmd.h>
+#include <grub/i386/wrmsr.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE("GPLv3+");
+
+static grub_command_t cmd_write;
+
+static grub_err_t
+grub_cmd_msr_write (grub_command_t cmd, int argc, char **argv)
+{
+    grub_uint64_t addr, value;
+    char *ptr;
+
+    if (argc != 2)
+        return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments 
expected"));
+
+    grub_errno = GRUB_ERR_NONE;
+    ptr = argv[0];
+    addr = grub_strtoul (ptr, &ptr, 0);
+
+    if (grub_errno != GRUB_ERR_NONE)
+        return grub_errno;
+    if (*ptr != '\0')
+        return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid argument"));
+
+    ptr = argv[1];
+    value = grub_strtoul (ptr, &ptr, 0);
+
+    if (grub_errno != GRUB_ERR_NONE)
+        return grub_errno;
+    if (*ptr != '\0')
+        return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid argument"));
+
+    grub_msr_write (addr, value);
+
+    return GRUB_ERR_NONE;
+}
+
+GRUB_MOD_INIT(wrmsr)
+{
+    cmd_write = grub_register_command ("wrmsr", grub_cmd_msr_write,
+                                      N_("ADDR VALUE"),
+                                      N_("Write a value to a CPU model 
specific register."));
+}
+
+GRUB_MOD_FINI(wrmsr)
+{
+    grub_unregister_command (cmd_write);
+}
diff --git a/include/grub/i386/rdmsr.h b/include/grub/i386/rdmsr.h
new file mode 100644
index 000000000..e907f1052
--- /dev/null
+++ b/include/grub/i386/rdmsr.h
@@ -0,0 +1,32 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2019  Free Software Foundation, Inc.
+ *
+ *  GRUB 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, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_CPU_MSR_READ_HEADER
+#define GRUB_CPU_MSR_READ_HEADER 1
+#endif
+
+extern __inline grub_uint64_t grub_msr_read (grub_uint64_t msr_id)
+{
+    grub_uint32_t low_id = msr_id, low, high;
+
+    asm volatile ( "rdmsr"  : "=a"(low), "=d"(high) : "c"(low_id) );
+
+    return ((grub_uint64_t)high << 32) | low;
+}
+
+
diff --git a/include/grub/i386/wrmsr.h b/include/grub/i386/wrmsr.h
new file mode 100644
index 000000000..2e535b8fe
--- /dev/null
+++ b/include/grub/i386/wrmsr.h
@@ -0,0 +1,29 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2019  Free Software Foundation, Inc.
+ *
+ *  GRUB 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, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_CPU_MSR_WRITE_HEADER
+#define GRUB_CPU_MSR_WRITE_HEADER 1
+#endif
+
+extern __inline void grub_msr_write(grub_uint64_t msr_id, grub_uint64_t 
msr_value)
+{
+    grub_uint32_t low_id = msr_id, low = msr_value, high = msr_value >> 32;
+
+    asm volatile ( "wrmsr" : : "c"(low_id), "a"(low), "d"(high) );
+}
+
-- 
2.17.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]