Patchwork [v2,5/6] backdoor: [i386] provide and implement intruction-based backdoor interface

login
register
mail settings
Submitter =?utf-8?Q?Llu=C3=ADs?=
Date Nov. 4, 2010, 10:36 p.m.
Message ID <20101104223614.16669.69856.stgit@ginnungagap.bsc.es>
Download mbox | patch
Permalink /patch/70180/
State New
Headers show

Comments

=?utf-8?Q?Llu=C3=ADs?= - Nov. 4, 2010, 10:36 p.m.
Take the unused CPUID 0x40001xxx range as the backdoor instruction.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 backdoor/guest.h        |   21 +++++++++++++++++++++
 target-i386/cpuid.c     |   27 +++++++++++++++++++++++++++
 target-i386/helper.h    |    4 ++++
 target-i386/translate.c |    4 ++++
 4 files changed, 56 insertions(+), 0 deletions(-)
Gleb Natapov - Nov. 7, 2010, 12:36 p.m.
On Thu, Nov 04, 2010 at 11:36:15PM +0100, Lluís wrote:
> Take the unused CPUID 0x40001xxx range as the backdoor instruction.
> 
In KVM (and it fits the spec nicely) cpuid is defined in terms of
tables.  There is no callback that is called when particular cpuid is
queried, so such backdoor interface will be impossible to implement
in KVM. Furthermore any interface that changes/looks at vcpu state in
userspace is broken for KVM. Look at vmware backdoor interface for
instance. KVM  has a hack in emulator code to make it work.

> Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
> ---
>  backdoor/guest.h        |   21 +++++++++++++++++++++
>  target-i386/cpuid.c     |   27 +++++++++++++++++++++++++++
>  target-i386/helper.h    |    4 ++++
>  target-i386/translate.c |    4 ++++
>  4 files changed, 56 insertions(+), 0 deletions(-)
> 
> diff --git a/backdoor/guest.h b/backdoor/guest.h
> index 8373762..3edcbc6 100644
> --- a/backdoor/guest.h
> +++ b/backdoor/guest.h
> @@ -26,8 +26,29 @@
>   * - v32: value of 32 bits
>   */
>  
> +#include <stdint.h>
> +
> +#if __i386__ || __i486__ || __x86_64__
> +
> +#define _BACKDOOR(t, i8, v32)                                           \
> +    ({                                                                  \
> +        uint32_t eax, ebx, ecx, edx;                                    \
> +        uint32_t index = (uint32_t)0x40001000 + (t<<8) + (uint8_t)i8;   \
> +        uint32_t count = (uint32_t)v32;                                 \
> +        asm volatile ("cpuid"                                           \
> +                      : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)      \
> +                      : "0"(index), "2"(count)                          \
> +            );                                                          \
> +        eax;                                                            \
> +    })
> +
> +#define BACKDOOR_i8(i)        _BACKDOOR(0, i, 0)
> +#define BACKDOOR_i8_v32(i, v) _BACKDOOR(1, i, v)
> +
> +#else
>  
>  #error Undefined instruction-based backdoor interface for guest architecture
>  
> +#endif
>  
>  #endif /* BACKDOOR__GUEST_H */
> diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
> index 650a719..03fc973 100644
> --- a/target-i386/cpuid.c
> +++ b/target-i386/cpuid.c
> @@ -27,6 +27,9 @@
>  #include "qemu-option.h"
>  #include "qemu-config.h"
>  
> +#include "helper.h"
> +
> +
>  /* feature flags taken from "Intel Processor Identification and the CPUID
>   * Instruction" and AMD's "CPUID Specification".  In cases of disagreement
>   * between feature naming conventions, aliases may be added.
> @@ -1033,6 +1036,30 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
>                     uint32_t *eax, uint32_t *ebx,
>                     uint32_t *ecx, uint32_t *edx)
>  {
> +#if defined(CONFIG_BACKDOOR)            /* synched with "backdoor/guest.h" */
> +    if ((index & ~0xfff) == 0x40001000) {
> +        int type = (index >> 8) & 0xf;
> +        uint8_t i8 = index & 0x0ff;
> +        uint32_t v32 = count;
> +        switch (type) {
> +        case 0:
> +            helper_backdoor_i8(i8);
> +            break;
> +        case 1:
> +            helper_backdoor_i8_v32(i8, v32);
> +            break;
> +        default:
> +            printf("invalid backdoor request\n");
> +            abort();
> +        }
> +        *eax = 0;
> +        *ebx = 0;
> +        *ecx = 0;
> +        *edx = 0;
> +        return;
> +    }
> +#endif
> +
>      /* test if maximum index reached */
>      if (index & 0x80000000) {
>          if (index > env->cpuid_xlevel)
> diff --git a/target-i386/helper.h b/target-i386/helper.h
> index 6b518ad..979d94e 100644
> --- a/target-i386/helper.h
> +++ b/target-i386/helper.h
> @@ -217,4 +217,8 @@ DEF_HELPER_2(rclq, tl, tl, tl)
>  DEF_HELPER_2(rcrq, tl, tl, tl)
>  #endif
>  
> +#if defined(CONFIG_BACKDOOR)
> +#include "backdoor/helper.h"
> +#endif
> +
>  #include "def-helper.h"
> diff --git a/target-i386/translate.c b/target-i386/translate.c
> index 7b6e3c2..dfdc2f0 100644
> --- a/target-i386/translate.c
> +++ b/target-i386/translate.c
> @@ -6941,6 +6941,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
>              gen_op_set_cc_op(s->cc_op);
>          gen_jmp_im(pc_start - s->cs_base);
>          gen_helper_cpuid();
> +#if defined(CONFIG_BACKDOOR)
> +        gen_jmp_im(s->pc);
> +        gen_eob(s);
> +#endif
>          break;
>      case 0xf4: /* hlt */
>          if (s->cpl != 0) {
> 

--
			Gleb.
=?utf-8?Q?Llu=C3=ADs?= - Nov. 8, 2010, 2:16 p.m.
Gleb Natapov writes:

> On Thu, Nov 04, 2010 at 11:36:15PM +0100, Lluís wrote:
>> Take the unused CPUID 0x40001xxx range as the backdoor instruction.
>> 
> In KVM (and it fits the spec nicely) cpuid is defined in terms of
> tables.  There is no callback that is called when particular cpuid is
> queried, so such backdoor interface will be impossible to implement
> in KVM. Furthermore any interface that changes/looks at vcpu state in
> userspace is broken for KVM. Look at vmware backdoor interface for
> instance. KVM  has a hack in emulator code to make it work.

I know. I looked into the KVM implementation and neither CPUID nor
VMCALL/VMMCALL (these two are, in fact, obsoleted) are implemented as
calls to the hypervisor (although the hardware supports it).

The only interfaces exported by KVM to that purpose are through
MMIO/PIO, but these are OS-dependant (aka, KVM-dependant).

As such, there is currently no generic, OS-independant and low-overhead
method for providing a backdoor communication channel from the guest
directly into QEMU.

As I see this is very tied to my setup, I'll move this patch series down
below the tracing series so that it does not interfere with the other
patches.

Lluis

Patch

diff --git a/backdoor/guest.h b/backdoor/guest.h
index 8373762..3edcbc6 100644
--- a/backdoor/guest.h
+++ b/backdoor/guest.h
@@ -26,8 +26,29 @@ 
  * - v32: value of 32 bits
  */
 
+#include <stdint.h>
+
+#if __i386__ || __i486__ || __x86_64__
+
+#define _BACKDOOR(t, i8, v32)                                           \
+    ({                                                                  \
+        uint32_t eax, ebx, ecx, edx;                                    \
+        uint32_t index = (uint32_t)0x40001000 + (t<<8) + (uint8_t)i8;   \
+        uint32_t count = (uint32_t)v32;                                 \
+        asm volatile ("cpuid"                                           \
+                      : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)      \
+                      : "0"(index), "2"(count)                          \
+            );                                                          \
+        eax;                                                            \
+    })
+
+#define BACKDOOR_i8(i)        _BACKDOOR(0, i, 0)
+#define BACKDOOR_i8_v32(i, v) _BACKDOOR(1, i, v)
+
+#else
 
 #error Undefined instruction-based backdoor interface for guest architecture
 
+#endif
 
 #endif /* BACKDOOR__GUEST_H */
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index 650a719..03fc973 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -27,6 +27,9 @@ 
 #include "qemu-option.h"
 #include "qemu-config.h"
 
+#include "helper.h"
+
+
 /* feature flags taken from "Intel Processor Identification and the CPUID
  * Instruction" and AMD's "CPUID Specification".  In cases of disagreement
  * between feature naming conventions, aliases may be added.
@@ -1033,6 +1036,30 @@  void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
                    uint32_t *eax, uint32_t *ebx,
                    uint32_t *ecx, uint32_t *edx)
 {
+#if defined(CONFIG_BACKDOOR)            /* synched with "backdoor/guest.h" */
+    if ((index & ~0xfff) == 0x40001000) {
+        int type = (index >> 8) & 0xf;
+        uint8_t i8 = index & 0x0ff;
+        uint32_t v32 = count;
+        switch (type) {
+        case 0:
+            helper_backdoor_i8(i8);
+            break;
+        case 1:
+            helper_backdoor_i8_v32(i8, v32);
+            break;
+        default:
+            printf("invalid backdoor request\n");
+            abort();
+        }
+        *eax = 0;
+        *ebx = 0;
+        *ecx = 0;
+        *edx = 0;
+        return;
+    }
+#endif
+
     /* test if maximum index reached */
     if (index & 0x80000000) {
         if (index > env->cpuid_xlevel)
diff --git a/target-i386/helper.h b/target-i386/helper.h
index 6b518ad..979d94e 100644
--- a/target-i386/helper.h
+++ b/target-i386/helper.h
@@ -217,4 +217,8 @@  DEF_HELPER_2(rclq, tl, tl, tl)
 DEF_HELPER_2(rcrq, tl, tl, tl)
 #endif
 
+#if defined(CONFIG_BACKDOOR)
+#include "backdoor/helper.h"
+#endif
+
 #include "def-helper.h"
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 7b6e3c2..dfdc2f0 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -6941,6 +6941,10 @@  static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
             gen_op_set_cc_op(s->cc_op);
         gen_jmp_im(pc_start - s->cs_base);
         gen_helper_cpuid();
+#if defined(CONFIG_BACKDOOR)
+        gen_jmp_im(s->pc);
+        gen_eob(s);
+#endif
         break;
     case 0xf4: /* hlt */
         if (s->cpl != 0) {