diff mbox series

[5/8] x86/hyperv: provide Hyper-V hypercall functions

Message ID 20191229183341.14877-6-liuwe@microsoft.com (mailing list archive)
State Superseded
Headers show
Series More Hyper-V infrastructure | expand

Commit Message

Wei Liu Dec. 29, 2019, 6:33 p.m. UTC
These functions will be used later to make hypercalls to Hyper-V.

I couldn't find reference in TLFS that Hyper-V clobbers flags and
r9-r11, but Linux's commit message says it does. Err on the safe side.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
---
 xen/include/asm-x86/guest/hyperv-hypercall.h | 105 +++++++++++++++++++
 1 file changed, 105 insertions(+)
 create mode 100644 xen/include/asm-x86/guest/hyperv-hypercall.h

Comments

Andrew Cooper Dec. 30, 2019, 1:04 p.m. UTC | #1
On 29/12/2019 18:33, Wei Liu wrote:
> These functions will be used later to make hypercalls to Hyper-V.
>
> I couldn't find reference in TLFS that Hyper-V clobbers flags and
> r9-r11, but Linux's commit message says it does. Err on the safe side.
>
> Signed-off-by: Wei Liu <liuwe@microsoft.com>
> ---
>  xen/include/asm-x86/guest/hyperv-hypercall.h | 105 +++++++++++++++++++
>  1 file changed, 105 insertions(+)
>  create mode 100644 xen/include/asm-x86/guest/hyperv-hypercall.h
>
> diff --git a/xen/include/asm-x86/guest/hyperv-hypercall.h b/xen/include/asm-x86/guest/hyperv-hypercall.h
> new file mode 100644
> index 0000000000..6017123be5
> --- /dev/null
> +++ b/xen/include/asm-x86/guest/hyperv-hypercall.h
> @@ -0,0 +1,105 @@
> +/******************************************************************************
> + * asm-x86/guest/hyperv-hypercall.h
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms and conditions of the GNU General Public
> + * License, version 2, as published by the Free Software Foundation.
> + *
> + * This program 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 this program; If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Copyright (c) 2019 Microsoft.
> + */
> +
> +#ifndef __X86_HYPERV_HYPERCALL_H__
> +#define __X86_HYPERV_HYPERCALL_H__
> +
> +#include <xen/types.h>
> +
> +#include <asm/asm_defns.h>
> +#include <asm/guest/hyperv-tlfs.h>
> +#include <asm/page.h>
> +
> +extern void *hv_hypercall;
> +
> +static inline uint64_t hv_do_hypercall(uint64_t control, paddr_t input, paddr_t output)
> +{
> +    uint64_t status;
> +
> +    if ( !hv_hypercall )
> +        return ~0ULL;
> +
> +    asm volatile ("mov %[output], %%r8\n"
> +                  "call *%[hypercall_page]"
> +                  : "=a" (status), "+c" (control),
> +                    "+d" (input) ASM_CALL_CONSTRAINT
> +                  : [output] "rm" (output),
> +                    [hypercall_page] "m" (hv_hypercall)
> +                  : "cc", "memory", "r8", "r9", "r10", "r11");
> +
> +    return status;
> +}

Indirect calls are expensive these days due to retpoline/IBRS, and in
this case, unnecessary.

You want something like:

asm ( ".pushsection \".text.page_aligned\", \"ax\", @progbits\n\t"
      ".align 4096\n\t"
      ".globl hyperv_hypercall\n\t"
      "hyperv_hypercall:\n\t"
      "mov -1, %rax\n\t"
      "ret\n\t"
      ".align 4096;\n\t" );

Which will put one page worth of space in .text.page_aligned (so it gets
mapped executable), at a location the linker can evaluate (so you can
use a direct call, and the disassembly will be easier to follow), which
is initialised to the "not ready yet" code so you don't need a runtime
check in every hypercall that you didn't get the order of initialisation
wrong at boot.

Alternatively, initialise to ud2 if some form of console can be reliably
be arranged to work from the very start.

~Andrew
Wei Liu Dec. 30, 2019, 1:36 p.m. UTC | #2
On Mon, Dec 30, 2019 at 01:04:33PM +0000, Andrew Cooper wrote:
> On 29/12/2019 18:33, Wei Liu wrote:
> > These functions will be used later to make hypercalls to Hyper-V.
> >
> > I couldn't find reference in TLFS that Hyper-V clobbers flags and
> > r9-r11, but Linux's commit message says it does. Err on the safe side.
> >
> > Signed-off-by: Wei Liu <liuwe@microsoft.com>
> > ---
> >  xen/include/asm-x86/guest/hyperv-hypercall.h | 105 +++++++++++++++++++
> >  1 file changed, 105 insertions(+)
> >  create mode 100644 xen/include/asm-x86/guest/hyperv-hypercall.h
> >
> > diff --git a/xen/include/asm-x86/guest/hyperv-hypercall.h b/xen/include/asm-x86/guest/hyperv-hypercall.h
> > new file mode 100644
> > index 0000000000..6017123be5
> > --- /dev/null
> > +++ b/xen/include/asm-x86/guest/hyperv-hypercall.h
> > @@ -0,0 +1,105 @@
> > +/******************************************************************************
> > + * asm-x86/guest/hyperv-hypercall.h
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms and conditions of the GNU General Public
> > + * License, version 2, as published by the Free Software Foundation.
> > + *
> > + * This program 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 this program; If not, see <http://www.gnu.org/licenses/>.
> > + *
> > + * Copyright (c) 2019 Microsoft.
> > + */
> > +
> > +#ifndef __X86_HYPERV_HYPERCALL_H__
> > +#define __X86_HYPERV_HYPERCALL_H__
> > +
> > +#include <xen/types.h>
> > +
> > +#include <asm/asm_defns.h>
> > +#include <asm/guest/hyperv-tlfs.h>
> > +#include <asm/page.h>
> > +
> > +extern void *hv_hypercall;
> > +
> > +static inline uint64_t hv_do_hypercall(uint64_t control, paddr_t input, paddr_t output)
> > +{
> > +    uint64_t status;
> > +
> > +    if ( !hv_hypercall )
> > +        return ~0ULL;
> > +
> > +    asm volatile ("mov %[output], %%r8\n"
> > +                  "call *%[hypercall_page]"
> > +                  : "=a" (status), "+c" (control),
> > +                    "+d" (input) ASM_CALL_CONSTRAINT
> > +                  : [output] "rm" (output),
> > +                    [hypercall_page] "m" (hv_hypercall)
> > +                  : "cc", "memory", "r8", "r9", "r10", "r11");
> > +
> > +    return status;
> > +}
> 
> Indirect calls are expensive these days due to retpoline/IBRS, and in
> this case, unnecessary.
> 
> You want something like:
> 
> asm ( ".pushsection \".text.page_aligned\", \"ax\", @progbits\n\t"
>       ".align 4096\n\t"
>       ".globl hyperv_hypercall\n\t"
>       "hyperv_hypercall:\n\t"
>       "mov -1, %rax\n\t"
>       "ret\n\t"
>       ".align 4096;\n\t" );
> 
> Which will put one page worth of space in .text.page_aligned (so it gets
> mapped executable), at a location the linker can evaluate (so you can
> use a direct call, and the disassembly will be easier to follow), which
> is initialised to the "not ready yet" code so you don't need a runtime
> check in every hypercall that you didn't get the order of initialisation
> wrong at boot.

This works for me. Thanks.

Wei.
diff mbox series

Patch

diff --git a/xen/include/asm-x86/guest/hyperv-hypercall.h b/xen/include/asm-x86/guest/hyperv-hypercall.h
new file mode 100644
index 0000000000..6017123be5
--- /dev/null
+++ b/xen/include/asm-x86/guest/hyperv-hypercall.h
@@ -0,0 +1,105 @@ 
+/******************************************************************************
+ * asm-x86/guest/hyperv-hypercall.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms and conditions of the GNU General Public
+ * License, version 2, as published by the Free Software Foundation.
+ *
+ * This program 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 this program; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (c) 2019 Microsoft.
+ */
+
+#ifndef __X86_HYPERV_HYPERCALL_H__
+#define __X86_HYPERV_HYPERCALL_H__
+
+#include <xen/types.h>
+
+#include <asm/asm_defns.h>
+#include <asm/guest/hyperv-tlfs.h>
+#include <asm/page.h>
+
+extern void *hv_hypercall;
+
+static inline uint64_t hv_do_hypercall(uint64_t control, paddr_t input, paddr_t output)
+{
+    uint64_t status;
+
+    if ( !hv_hypercall )
+        return ~0ULL;
+
+    asm volatile ("mov %[output], %%r8\n"
+                  "call *%[hypercall_page]"
+                  : "=a" (status), "+c" (control),
+                    "+d" (input) ASM_CALL_CONSTRAINT
+                  : [output] "rm" (output),
+                    [hypercall_page] "m" (hv_hypercall)
+                  : "cc", "memory", "r8", "r9", "r10", "r11");
+
+    return status;
+}
+
+static inline uint64_t hv_do_fast_hypercall(uint16_t code,
+                                            uint64_t input1, uint64_t input2)
+{
+    uint64_t status;
+    uint64_t control = (uint64_t)code | HV_HYPERCALL_FAST_BIT;
+
+    if ( !hv_hypercall )
+        return ~0ULL;
+
+    asm volatile ("mov %[input2], %%r8\n"
+                  "call *%[hypercall_page]"
+                  : "=a" (status), "+c" (control),
+                    "+d" (input1) ASM_CALL_CONSTRAINT
+                  : [input2] "rm" (input2),
+                    [hypercall_page] "m" (hv_hypercall)
+                  : "cc", "r8", "r9", "r10", "r11");
+
+    return status;
+}
+
+static inline uint64_t hv_do_rep_hypercall(uint16_t code, uint16_t rep_count,
+                                           uint16_t varhead_size,
+                                           paddr_t input, paddr_t output)
+{
+    uint64_t control = code;
+    uint64_t status;
+    uint16_t rep_comp;
+
+    control |= (uint64_t)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET;
+    control |= (uint64_t)rep_count << HV_HYPERCALL_REP_COMP_OFFSET;
+
+    do {
+        status = hv_do_hypercall(control, input, output);
+        if ( (status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS )
+            break;
+
+        rep_comp = (status & HV_HYPERCALL_REP_COMP_MASK) >>
+            HV_HYPERCALL_REP_COMP_OFFSET;
+
+        control &= ~HV_HYPERCALL_REP_START_MASK;
+        control |= (uint64_t)rep_comp << HV_HYPERCALL_REP_COMP_OFFSET;
+
+    } while ( rep_comp < rep_count );
+
+    return status;
+}
+
+#endif /* __X86_HYPERV_HYPERCALL_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */