[Top][All Lists]

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

[PATCH] Expose i386 model specific registers via HMP

From: Elias Djossou
Subject: [PATCH] Expose i386 model specific registers via HMP
Date: Sun, 7 Feb 2021 00:20:58 +0100

This patch aims to expose certain model specific registers on i386 to the HMP.

To achieve this a new HMP command "info msr-registers" is added. Since
this is only relevant for i386 an "#if defined(TARGET_I386)" ensures it stays 
The corrsponding function "hmp_info_msr_registers()" is then implemented
in target/i386/monitor.c which uses the helper function
"x86_print_msr_registers()" in the same file where the print
itself happens.

Signed-of-by: Elias Djossou <elias-djossou.git@gmx.de>


This feature can be crucial in certain Debug scenarios since the MSR
registers maintain acceas to highly relevant data structures on the i386 
(e.g. on x86_64 LSTAR stores the OS's system call entrance point) Being
able to access these can immensly enhance introspection capabilities.
Also providing this functionality via the HMP makes the feature available to
both the QEMU Monitor itself as well as utilities like for example GDB
(via the "monitor info msr-registers" command).


This patch follows up on an idea of Mar 2017
(see https://lists.gnu.org/archive/html/qemu-devel/2017-03/msg01559.html)
but is intended to be more light-weight.

While working on this I came across a problem i would like to get your opinion 
I would really much like to expose more of the MSRs in struct CPUX86State
(ideally all of them) at sometime in a future patch.
I decided to limit myself to these ones for this one for the following reason:

While these registers would in principle be easily available. Problem
is that there is no function available that allows to read MSRs.
The only related function seems to be "helper_rdmsr()" from target/i386/tcg
which doesn't return the value but writes it directly into R_EAX / R_EDX 

So my only options to realize this seem to be:

  1. copy the content of the individual cases from
     helper_rdmsr() to my helper x86_print_msr_registers()

  2. backup R_EAX and R_EDX - call helper_rdmsr() - copy R_EAX, R_EDX
     - apply backup (seems much too hacky to me)

  3. write a new interface similar to helper_rdmsr that really returns the value
     - maybe rewrite helper_rdmsr() to use that helper function as well
     (such a function existed back in the times of the above referenced patch
     as "x86_cpu_rdmsr()" in target/i386/misc_helper.c)

I would really appreciate your opinions on this
 hmp-commands-info.hx         | 15 ++++++++++
 include/monitor/hmp-target.h |  1 +
 target/i386/monitor.c        | 55 ++++++++++++++++++++++++++++++++++++
 3 files changed, 71 insertions(+)

diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 117ba25f91..d78c3e799d 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -893,3 +893,18 @@ SRST
   ``info replay``
     Display the record/replay information: mode and the current icount.
+#if defined(TARGET_I386)
+    {
+        .name       = "msr-registers",
+        .args_type  = "cpustate_all:-a",
+        .params     = "[-a]",
+        .help       = "show the cpu msr registers (-a: all - show msr register 
info for all cpus)",
+        .cmd        = hmp_info_msr_registers,
+    },
+  ``info msr-registers``
+    Show the cpu msr registers.
diff --git a/include/monitor/hmp-target.h b/include/monitor/hmp-target.h
index 60fc92722a..756102a773 100644
--- a/include/monitor/hmp-target.h
+++ b/include/monitor/hmp-target.h
@@ -49,5 +49,6 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict);
 void hmp_mce(Monitor *mon, const QDict *qdict);
 void hmp_info_local_apic(Monitor *mon, const QDict *qdict);
 void hmp_info_io_apic(Monitor *mon, const QDict *qdict);
+void hmp_info_msr_registers(Monitor *mon, const QDict *qdict);

 #endif /* MONITOR_HMP_TARGET_H */
diff --git a/target/i386/monitor.c b/target/i386/monitor.c
index 1bc91442b1..b274c42bf3 100644
--- a/target/i386/monitor.c
+++ b/target/i386/monitor.c
@@ -736,3 +736,58 @@ void qmp_sev_inject_launch_secret(const char *packet_hdr,
     sev_inject_launch_secret(packet_hdr, secret, gpa, errp);
+static void x86_print_msr_registers(Monitor *mon, CPUState *cs)
+    X86CPU *cpu = X86_CPU(cs);
+    CPUX86State *env = &cpu->env;
+    monitor_printf(mon,
+                "MSR_IA32_SYSENTER_CS=%08x\n"
+                "MSR_IA32_SYSENTER_ESP=%016lx\n"
+                "MSR_IA32_SYSENTER_EIP=%016lx\n"
+                "MSR_STAR=%016lx\n",
+                env->sysenter_cs,
+                env->sysenter_esp,
+                env->sysenter_eip,
+                env->star);
+#ifdef TARGET_X86_64
+    monitor_printf(mon,
+                "MSR_LSTAR=%016lx\n"
+                "MSR_CSTAR=%016lx\n"
+                "MSR_FMASK=%016lx\n"
+                "MSR_FSBASE=%016lx\n"
+                "MSR_GSBASE=%016lx\n"
+                "MSR_KERNELGSBASE=%016lx\n",
+                env->lstar,
+                env->cstar,
+                env->fmask,
+                env->segs[R_FS].base,
+                env->segs[R_GS].base,
+                env->kernelgsbase);
+void hmp_info_msr_registers(Monitor *mon, const QDict *qdict)
+    bool all_cpus = qdict_get_try_bool(qdict, "cpustate_all", false);
+    CPUState *cs;
+    if (all_cpus) {
+        CPU_FOREACH(cs) {
+            monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index);
+            x86_print_msr_registers(mon, cs);
+        }
+    } else {
+        cs = mon_get_cpu(mon);
+        if (!cs) {
+            monitor_printf(mon, "No CPU available\n");
+            return;
+        }
+        x86_print_msr_registers(mon, cs);
+    }

reply via email to

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