diff mbox series

[for-next,v2,9/9] x86: introduce CONFIG_HYPERV and detection code

Message ID 20190930150044.5734-10-liuwe@microsoft.com (mailing list archive)
State Superseded
Headers show
Series Port Xen to Hyper-V | expand

Commit Message

Wei Liu Sept. 30, 2019, 3 p.m. UTC
We use the same code structure as we die for Xen.

As starters, detect Hyper-V in probe routine. More complex
functionalities will be added later.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
---
 xen/arch/x86/Kconfig               |  9 ++++
 xen/arch/x86/guest/Makefile        |  1 +
 xen/arch/x86/guest/hyperv/Makefile |  1 +
 xen/arch/x86/guest/hyperv/hyperv.c | 69 ++++++++++++++++++++++++++++++
 xen/arch/x86/guest/hypervisor.c    |  5 +++
 xen/include/asm-x86/guest.h        |  1 +
 xen/include/asm-x86/guest/hyperv.h | 45 +++++++++++++++++++
 7 files changed, 131 insertions(+)
 create mode 100644 xen/arch/x86/guest/hyperv/Makefile
 create mode 100644 xen/arch/x86/guest/hyperv/hyperv.c
 create mode 100644 xen/include/asm-x86/guest/hyperv.h

Comments

Wei Liu Sept. 30, 2019, 3:04 p.m. UTC | #1
On Mon, Sep 30, 2019 at 04:00:43PM +0100, Wei Liu wrote:
> We use the same code structure as we die for Xen.

Urgh. There is a rather unfortunate typo. No software is worth dying
for. :-)

Wei.
Roger Pau Monne Oct. 21, 2019, 10:22 a.m. UTC | #2
On Mon, Sep 30, 2019 at 04:00:43PM +0100, Wei Liu wrote:
> We use the same code structure as we die for Xen.
> 
> As starters, detect Hyper-V in probe routine. More complex
> functionalities will be added later.
> 
> Signed-off-by: Wei Liu <liuwe@microsoft.com>
> ---
>  xen/arch/x86/Kconfig               |  9 ++++
>  xen/arch/x86/guest/Makefile        |  1 +
>  xen/arch/x86/guest/hyperv/Makefile |  1 +
>  xen/arch/x86/guest/hyperv/hyperv.c | 69 ++++++++++++++++++++++++++++++
>  xen/arch/x86/guest/hypervisor.c    |  5 +++
>  xen/include/asm-x86/guest.h        |  1 +
>  xen/include/asm-x86/guest/hyperv.h | 45 +++++++++++++++++++
>  7 files changed, 131 insertions(+)
>  create mode 100644 xen/arch/x86/guest/hyperv/Makefile
>  create mode 100644 xen/arch/x86/guest/hyperv/hyperv.c
>  create mode 100644 xen/include/asm-x86/guest/hyperv.h
> 
> diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig
> index 584bdc1bb8..c5a93babfe 100644
> --- a/xen/arch/x86/Kconfig
> +++ b/xen/arch/x86/Kconfig
> @@ -163,6 +163,15 @@ endchoice
>  config GUEST
>  	bool
>  
> +config HYPERV_GUEST
> +	def_bool n
> +	select GUEST
> +	prompt "Hyper-V Guest"
> +	---help---
> +	  Support for Xen detecting when it is running under Hyper-V.
> +
> +	  If unsure, say N.
> +
>  config XEN_GUEST
>  	def_bool n
>  	select GUEST
> diff --git a/xen/arch/x86/guest/Makefile b/xen/arch/x86/guest/Makefile
> index f63d64bbee..f164196772 100644
> --- a/xen/arch/x86/guest/Makefile
> +++ b/xen/arch/x86/guest/Makefile
> @@ -1,3 +1,4 @@
>  obj-y += hypervisor.o
>  
> +subdir-$(CONFIG_HYPERV_GUEST) += hyperv
>  subdir-$(CONFIG_XEN_GUEST) += xen
> diff --git a/xen/arch/x86/guest/hyperv/Makefile b/xen/arch/x86/guest/hyperv/Makefile
> new file mode 100644
> index 0000000000..68170109a9
> --- /dev/null
> +++ b/xen/arch/x86/guest/hyperv/Makefile
> @@ -0,0 +1 @@
> +obj-y += hyperv.o
> diff --git a/xen/arch/x86/guest/hyperv/hyperv.c b/xen/arch/x86/guest/hyperv/hyperv.c
> new file mode 100644
> index 0000000000..4494b87fe8
> --- /dev/null
> +++ b/xen/arch/x86/guest/hyperv/hyperv.c
> @@ -0,0 +1,69 @@
> +/******************************************************************************
> + * arch/x86/guest/hyperv/hyperv.c
> + *
> + * Support for detecting and running under Hyper-V.
> + *
> + * This program 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 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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.
> + */
> +#include <xen/init.h>
> +
> +#include <asm/guest.h>
> +
> +bool __init hyperv_probe(void)
> +{
> +    uint32_t eax, ebx, ecx, edx;
> +    bool hyperv_guest = false;

I don't think you need this local variable, you can return true in if
the if condition matches, and false otherwise.

> +
> +    cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
> +    if ( (ebx == 0x7263694d) && /* "Micr" */
> +         (ecx == 0x666f736f) && /* "osof" */
> +         (edx == 0x76482074) )  /* "t Hv" */

I guess there are no HyperV headers to import that have those values
defined?

Alternatively you could do something like the following I think:

static const char hyperv_sig[] __initconst = "Microsoft Hv";

bool __init hyperv_probe(void)
{
    uint32_t eax, sig[3];

    cpuid(0x40000000, &eax, &sig[0], &sig[1], &sig[2]);
    if ( !strncmp(hyperv_sig, sig, strncmp(hyperv_sig) )
        return true;

    return false;
}

> +        hyperv_guest = true;
> +
> +    return hyperv_guest;
> +}
> +
> +void __init hyperv_setup(void)
> +{
> +    /* Nothing yet */
> +}
> +
> +void hyperv_ap_setup(void)
> +{
> +    /* Nothing yet */
> +}
> +
> +void hyperv_resume(void)
> +{
> +    /* Nothing yet */
> +}

There's no need to introduce such dummy functions, just leaving the
pointers as NULL should work fine, and the functions can be introduced
when there's logic in them.

> +
> +struct hypervisor_ops hyperv_hypervisor_ops = {
> +    .name = "Hyper-V",
> +    .setup = hyperv_setup,
> +    .ap_setup = hyperv_ap_setup,
> +    .resume = hyperv_resume,
> +};
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * tab-width: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/arch/x86/guest/hypervisor.c b/xen/arch/x86/guest/hypervisor.c
> index 8161b26c5a..87a195e888 100644
> --- a/xen/arch/x86/guest/hypervisor.c
> +++ b/xen/arch/x86/guest/hypervisor.c
> @@ -40,6 +40,11 @@ bool hypervisor_probe(void)
>          hops = &xen_hypervisor_ops;
>  #endif
>  
> +#ifdef CONFIG_HYPERV_GUEST
> +    if ( hyperv_probe() )
> +        hops = &hyperv_hypervisor_ops;
> +#endif

This won't work correctly if Xen has viridian extensions enabled,
since the HyperV probe will overwrite the Xen one.

> +
>      return !!hops;
>  }
>  
> diff --git a/xen/include/asm-x86/guest.h b/xen/include/asm-x86/guest.h
> index 8e167165ae..94448606d4 100644
> --- a/xen/include/asm-x86/guest.h
> +++ b/xen/include/asm-x86/guest.h
> @@ -20,6 +20,7 @@
>  #define __X86_GUEST_H__
>  
>  #include <asm/guest/hypercall.h>
> +#include <asm/guest/hyperv.h>
>  #include <asm/guest/hypervisor.h>
>  #include <asm/guest/pvh-boot.h>
>  #include <asm/guest/xen.h>
> diff --git a/xen/include/asm-x86/guest/hyperv.h b/xen/include/asm-x86/guest/hyperv.h
> new file mode 100644
> index 0000000000..a2d8ee8987
> --- /dev/null
> +++ b/xen/include/asm-x86/guest/hyperv.h
> @@ -0,0 +1,45 @@
> +/******************************************************************************
> + * asm-x86/guest/hyperv.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_GUEST_HYPERV_H__
> +#define __X86_GUEST_HYPERV_H__
> +
> +#ifdef CONFIG_HYPERV_GUEST
> +
> +#include <asm/guest/hypervisor.h>
> +
> +extern struct hypervisor_ops hyperv_hypervisor_ops;

hyperv_ops would be fine by me, seems kind of redundant to have
'hyper' twice in a name.

Thanks, Roger.
Roger Pau Monne Oct. 21, 2019, 10:26 a.m. UTC | #3
On Mon, Oct 21, 2019 at 12:22:25PM +0200, Roger Pau Monné wrote:
> On Mon, Sep 30, 2019 at 04:00:43PM +0100, Wei Liu wrote:
> > We use the same code structure as we die for Xen.
> > 
> > As starters, detect Hyper-V in probe routine. More complex
> > functionalities will be added later.
> > 
> > Signed-off-by: Wei Liu <liuwe@microsoft.com>
> > ---
> >  xen/arch/x86/Kconfig               |  9 ++++
> >  xen/arch/x86/guest/Makefile        |  1 +
> >  xen/arch/x86/guest/hyperv/Makefile |  1 +
> >  xen/arch/x86/guest/hyperv/hyperv.c | 69 ++++++++++++++++++++++++++++++
> >  xen/arch/x86/guest/hypervisor.c    |  5 +++
> >  xen/include/asm-x86/guest.h        |  1 +
> >  xen/include/asm-x86/guest/hyperv.h | 45 +++++++++++++++++++
> >  7 files changed, 131 insertions(+)
> >  create mode 100644 xen/arch/x86/guest/hyperv/Makefile
> >  create mode 100644 xen/arch/x86/guest/hyperv/hyperv.c
> >  create mode 100644 xen/include/asm-x86/guest/hyperv.h
> > 
> > diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig
> > index 584bdc1bb8..c5a93babfe 100644
> > --- a/xen/arch/x86/Kconfig
> > +++ b/xen/arch/x86/Kconfig
> > @@ -163,6 +163,15 @@ endchoice
> >  config GUEST
> >  	bool
> >  
> > +config HYPERV_GUEST
> > +	def_bool n
> > +	select GUEST
> > +	prompt "Hyper-V Guest"
> > +	---help---
> > +	  Support for Xen detecting when it is running under Hyper-V.
> > +
> > +	  If unsure, say N.
> > +
> >  config XEN_GUEST
> >  	def_bool n
> >  	select GUEST
> > diff --git a/xen/arch/x86/guest/Makefile b/xen/arch/x86/guest/Makefile
> > index f63d64bbee..f164196772 100644
> > --- a/xen/arch/x86/guest/Makefile
> > +++ b/xen/arch/x86/guest/Makefile
> > @@ -1,3 +1,4 @@
> >  obj-y += hypervisor.o
> >  
> > +subdir-$(CONFIG_HYPERV_GUEST) += hyperv
> >  subdir-$(CONFIG_XEN_GUEST) += xen
> > diff --git a/xen/arch/x86/guest/hyperv/Makefile b/xen/arch/x86/guest/hyperv/Makefile
> > new file mode 100644
> > index 0000000000..68170109a9
> > --- /dev/null
> > +++ b/xen/arch/x86/guest/hyperv/Makefile
> > @@ -0,0 +1 @@
> > +obj-y += hyperv.o
> > diff --git a/xen/arch/x86/guest/hyperv/hyperv.c b/xen/arch/x86/guest/hyperv/hyperv.c
> > new file mode 100644
> > index 0000000000..4494b87fe8
> > --- /dev/null
> > +++ b/xen/arch/x86/guest/hyperv/hyperv.c
> > @@ -0,0 +1,69 @@
> > +/******************************************************************************
> > + * arch/x86/guest/hyperv/hyperv.c
> > + *
> > + * Support for detecting and running under Hyper-V.
> > + *
> > + * This program 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 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * 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.
> > + */
> > +#include <xen/init.h>
> > +
> > +#include <asm/guest.h>
> > +
> > +bool __init hyperv_probe(void)
> > +{
> > +    uint32_t eax, ebx, ecx, edx;
> > +    bool hyperv_guest = false;
> 
> I don't think you need this local variable, you can return true in if
> the if condition matches, and false otherwise.
> 
> > +
> > +    cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
> > +    if ( (ebx == 0x7263694d) && /* "Micr" */
> > +         (ecx == 0x666f736f) && /* "osof" */
> > +         (edx == 0x76482074) )  /* "t Hv" */
> 
> I guess there are no HyperV headers to import that have those values
> defined?
> 
> Alternatively you could do something like the following I think:
> 
> static const char hyperv_sig[] __initconst = "Microsoft Hv";
> 
> bool __init hyperv_probe(void)
> {
>     uint32_t eax, sig[3];
> 
>     cpuid(0x40000000, &eax, &sig[0], &sig[1], &sig[2]);
>     if ( !strncmp(hyperv_sig, sig, strncmp(hyperv_sig) )

Urg, I've made a mistake here, the line should be:

!strncmp(hyperv_sig, sig, strlen(hyperv_sig))

And you can likely declare hyperv_sig inside the probe function also.

Roger.
Wei Liu Oct. 21, 2019, 2:56 p.m. UTC | #4
On Mon, Oct 21, 2019 at 12:22:25PM +0200, Roger Pau Monné wrote:
[...]
> > +bool __init hyperv_probe(void)
> > +{
> > +    uint32_t eax, ebx, ecx, edx;
> > +    bool hyperv_guest = false;
> 
> I don't think you need this local variable, you can return true in if
> the if condition matches, and false otherwise.
> 

Sure. I can drop it for now and reintroduce it when necessary.

> > +
> > +    cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
> > +    if ( (ebx == 0x7263694d) && /* "Micr" */
> > +         (ecx == 0x666f736f) && /* "osof" */
> > +         (edx == 0x76482074) )  /* "t Hv" */
> 
> I guess there are no HyperV headers to import that have those values
> defined?
> 

Not yet. I have plan to import a header from Linux. When that's done
these will be replaced by some macros.

So I will keep this as-is for now.

[...]
> > +#ifndef __X86_GUEST_HYPERV_H__
> > +#define __X86_GUEST_HYPERV_H__
> > +
> > +#ifdef CONFIG_HYPERV_GUEST
> > +
> > +#include <asm/guest/hypervisor.h>
> > +
> > +extern struct hypervisor_ops hyperv_hypervisor_ops;
> 
> hyperv_ops would be fine by me, seems kind of redundant to have
> 'hyper' twice in a name.
> 

In that case I will also change xen_hypervisor_ops to xen_ops to remain
consistent.

Wei.

> Thanks, Roger.
Andrew Cooper Oct. 21, 2019, 3:02 p.m. UTC | #5
On 21/10/2019 11:26, Roger Pau Monné wrote:
>>> +
>>> +    cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
>>> +    if ( (ebx == 0x7263694d) && /* "Micr" */
>>> +         (ecx == 0x666f736f) && /* "osof" */
>>> +         (edx == 0x76482074) )  /* "t Hv" */
>> I guess there are no HyperV headers to import that have those values
>> defined?
>>
>> Alternatively you could do something like the following I think:
>>
>> static const char hyperv_sig[] __initconst = "Microsoft Hv";
>>
>> bool __init hyperv_probe(void)
>> {
>>     uint32_t eax, sig[3];
>>
>>     cpuid(0x40000000, &eax, &sig[0], &sig[1], &sig[2]);
>>     if ( !strncmp(hyperv_sig, sig, strncmp(hyperv_sig) )
> Urg, I've made a mistake here, the line should be:
>
> !strncmp(hyperv_sig, sig, strlen(hyperv_sig))

Just because the leaves form an ascii string, doesn't mean that using
string comparisons are the sane way to check.  3x 32bit compares are
substantially more efficient, and far harder to get wrong.

Wei: On your detection algorithm, you also need to find HV#1 in
0x40000001.eax to detect conformance to the viridian spec.

~Andrew
Roger Pau Monne Oct. 21, 2019, 3:11 p.m. UTC | #6
On Mon, Oct 21, 2019 at 03:56:51PM +0100, Wei Liu wrote:
> On Mon, Oct 21, 2019 at 12:22:25PM +0200, Roger Pau Monné wrote:
> [...]
> > > +bool __init hyperv_probe(void)
> > > +{
> > > +    uint32_t eax, ebx, ecx, edx;
> > > +    bool hyperv_guest = false;
> > 
> > I don't think you need this local variable, you can return true in if
> > the if condition matches, and false otherwise.
> > 
> 
> Sure. I can drop it for now and reintroduce it when necessary.
> 
> > > +
> > > +    cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
> > > +    if ( (ebx == 0x7263694d) && /* "Micr" */
> > > +         (ecx == 0x666f736f) && /* "osof" */
> > > +         (edx == 0x76482074) )  /* "t Hv" */
> > 
> > I guess there are no HyperV headers to import that have those values
> > defined?
> > 
> 
> Not yet. I have plan to import a header from Linux. When that's done
> these will be replaced by some macros.
> 
> So I will keep this as-is for now.

Is it really cumbersome to introduce the header now?

IMO it would be better to avoid deferring this to when you introduce
the header, since it's easy to miss it.

Thanks, Roger.
Wei Liu Oct. 21, 2019, 3:20 p.m. UTC | #7
On Mon, Oct 21, 2019 at 05:11:26PM +0200, Roger Pau Monné wrote:
> On Mon, Oct 21, 2019 at 03:56:51PM +0100, Wei Liu wrote:
> > On Mon, Oct 21, 2019 at 12:22:25PM +0200, Roger Pau Monné wrote:
> > [...]
> > > > +bool __init hyperv_probe(void)
> > > > +{
> > > > +    uint32_t eax, ebx, ecx, edx;
> > > > +    bool hyperv_guest = false;
> > > 
> > > I don't think you need this local variable, you can return true in if
> > > the if condition matches, and false otherwise.
> > > 
> > 
> > Sure. I can drop it for now and reintroduce it when necessary.
> > 
> > > > +
> > > > +    cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
> > > > +    if ( (ebx == 0x7263694d) && /* "Micr" */
> > > > +         (ecx == 0x666f736f) && /* "osof" */
> > > > +         (edx == 0x76482074) )  /* "t Hv" */
> > > 
> > > I guess there are no HyperV headers to import that have those values
> > > defined?
> > > 
> > 
> > Not yet. I have plan to import a header from Linux. When that's done
> > these will be replaced by some macros.
> > 
> > So I will keep this as-is for now.
> 
> Is it really cumbersome to introduce the header now?
> 
> IMO it would be better to avoid deferring this to when you introduce
> the header, since it's easy to miss it.

The header in Linux is not without its problems. It certainly doesn't
have the signature values in it yet, so whether importing it now or
later is immaterial to this issue at hand. I will have to go through
that header file first but -ETIME.

Wei.

> 
> Thanks, Roger.
Wei Liu Oct. 21, 2019, 3:26 p.m. UTC | #8
On Mon, Oct 21, 2019 at 04:02:33PM +0100, Andrew Cooper wrote:
> On 21/10/2019 11:26, Roger Pau Monné wrote:
> >>> +
> >>> +    cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
> >>> +    if ( (ebx == 0x7263694d) && /* "Micr" */
> >>> +         (ecx == 0x666f736f) && /* "osof" */
> >>> +         (edx == 0x76482074) )  /* "t Hv" */
> >> I guess there are no HyperV headers to import that have those values
> >> defined?
> >>
> >> Alternatively you could do something like the following I think:
> >>
> >> static const char hyperv_sig[] __initconst = "Microsoft Hv";
> >>
> >> bool __init hyperv_probe(void)
> >> {
> >>     uint32_t eax, sig[3];
> >>
> >>     cpuid(0x40000000, &eax, &sig[0], &sig[1], &sig[2]);
> >>     if ( !strncmp(hyperv_sig, sig, strncmp(hyperv_sig) )
> > Urg, I've made a mistake here, the line should be:
> >
> > !strncmp(hyperv_sig, sig, strlen(hyperv_sig))
> 
> Just because the leaves form an ascii string, doesn't mean that using
> string comparisons are the sane way to check.  3x 32bit compares are
> substantially more efficient, and far harder to get wrong.
> 
> Wei: On your detection algorithm, you also need to find HV#1 in
> 0x40000001.eax to detect conformance to the viridian spec.

Sure I can do that.

I'm not sure it matters that much in practice though.

Wei.

> 
> ~Andrew
diff mbox series

Patch

diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig
index 584bdc1bb8..c5a93babfe 100644
--- a/xen/arch/x86/Kconfig
+++ b/xen/arch/x86/Kconfig
@@ -163,6 +163,15 @@  endchoice
 config GUEST
 	bool
 
+config HYPERV_GUEST
+	def_bool n
+	select GUEST
+	prompt "Hyper-V Guest"
+	---help---
+	  Support for Xen detecting when it is running under Hyper-V.
+
+	  If unsure, say N.
+
 config XEN_GUEST
 	def_bool n
 	select GUEST
diff --git a/xen/arch/x86/guest/Makefile b/xen/arch/x86/guest/Makefile
index f63d64bbee..f164196772 100644
--- a/xen/arch/x86/guest/Makefile
+++ b/xen/arch/x86/guest/Makefile
@@ -1,3 +1,4 @@ 
 obj-y += hypervisor.o
 
+subdir-$(CONFIG_HYPERV_GUEST) += hyperv
 subdir-$(CONFIG_XEN_GUEST) += xen
diff --git a/xen/arch/x86/guest/hyperv/Makefile b/xen/arch/x86/guest/hyperv/Makefile
new file mode 100644
index 0000000000..68170109a9
--- /dev/null
+++ b/xen/arch/x86/guest/hyperv/Makefile
@@ -0,0 +1 @@ 
+obj-y += hyperv.o
diff --git a/xen/arch/x86/guest/hyperv/hyperv.c b/xen/arch/x86/guest/hyperv/hyperv.c
new file mode 100644
index 0000000000..4494b87fe8
--- /dev/null
+++ b/xen/arch/x86/guest/hyperv/hyperv.c
@@ -0,0 +1,69 @@ 
+/******************************************************************************
+ * arch/x86/guest/hyperv/hyperv.c
+ *
+ * Support for detecting and running under Hyper-V.
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+#include <xen/init.h>
+
+#include <asm/guest.h>
+
+bool __init hyperv_probe(void)
+{
+    uint32_t eax, ebx, ecx, edx;
+    bool hyperv_guest = false;
+
+    cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
+    if ( (ebx == 0x7263694d) && /* "Micr" */
+         (ecx == 0x666f736f) && /* "osof" */
+         (edx == 0x76482074) )  /* "t Hv" */
+        hyperv_guest = true;
+
+    return hyperv_guest;
+}
+
+void __init hyperv_setup(void)
+{
+    /* Nothing yet */
+}
+
+void hyperv_ap_setup(void)
+{
+    /* Nothing yet */
+}
+
+void hyperv_resume(void)
+{
+    /* Nothing yet */
+}
+
+struct hypervisor_ops hyperv_hypervisor_ops = {
+    .name = "Hyper-V",
+    .setup = hyperv_setup,
+    .ap_setup = hyperv_ap_setup,
+    .resume = hyperv_resume,
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/x86/guest/hypervisor.c b/xen/arch/x86/guest/hypervisor.c
index 8161b26c5a..87a195e888 100644
--- a/xen/arch/x86/guest/hypervisor.c
+++ b/xen/arch/x86/guest/hypervisor.c
@@ -40,6 +40,11 @@  bool hypervisor_probe(void)
         hops = &xen_hypervisor_ops;
 #endif
 
+#ifdef CONFIG_HYPERV_GUEST
+    if ( hyperv_probe() )
+        hops = &hyperv_hypervisor_ops;
+#endif
+
     return !!hops;
 }
 
diff --git a/xen/include/asm-x86/guest.h b/xen/include/asm-x86/guest.h
index 8e167165ae..94448606d4 100644
--- a/xen/include/asm-x86/guest.h
+++ b/xen/include/asm-x86/guest.h
@@ -20,6 +20,7 @@ 
 #define __X86_GUEST_H__
 
 #include <asm/guest/hypercall.h>
+#include <asm/guest/hyperv.h>
 #include <asm/guest/hypervisor.h>
 #include <asm/guest/pvh-boot.h>
 #include <asm/guest/xen.h>
diff --git a/xen/include/asm-x86/guest/hyperv.h b/xen/include/asm-x86/guest/hyperv.h
new file mode 100644
index 0000000000..a2d8ee8987
--- /dev/null
+++ b/xen/include/asm-x86/guest/hyperv.h
@@ -0,0 +1,45 @@ 
+/******************************************************************************
+ * asm-x86/guest/hyperv.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_GUEST_HYPERV_H__
+#define __X86_GUEST_HYPERV_H__
+
+#ifdef CONFIG_HYPERV_GUEST
+
+#include <asm/guest/hypervisor.h>
+
+extern struct hypervisor_ops hyperv_hypervisor_ops;
+
+bool hyperv_probe(void);
+
+#else
+
+static inline bool hyperv_probe(void) { return false; }
+
+#endif /* CONFIG_HYPERV_GUEST */
+#endif /* __X86_GUEST_HYPERV_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */