diff mbox

[v2,17/30] xen/x86: setup PVHv2 Dom0 CPUs

Message ID 1474991845-27962-18-git-send-email-roger.pau@citrix.com (mailing list archive)
State New, archived
Headers show

Commit Message

Roger Pau Monné Sept. 27, 2016, 3:57 p.m. UTC
Initialize Dom0 BSP/APs and setup the memory and IO permissions.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Cc: Jan Beulich <jbeulich@suse.com>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
---
The logic used to setup the CPUID leaves is extremely simplistic (and
probably wrong for hardware different than mine). I'm not sure what's the
best way to deal with this, the code that currently sets the CPUID leaves
for HVM guests lives in libxc, maybe moving it xen/common would be better?
---
 xen/arch/x86/domain_build.c | 103 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

Comments

Jan Beulich Oct. 6, 2016, 3:20 p.m. UTC | #1
>>> On 27.09.16 at 17:57, <roger.pau@citrix.com> wrote:
> The logic used to setup the CPUID leaves is extremely simplistic (and
> probably wrong for hardware different than mine). I'm not sure what's the
> best way to deal with this, the code that currently sets the CPUID leaves
> for HVM guests lives in libxc, maybe moving it xen/common would be better?

Yeah, a pre-populated array of leaves certainly won't do.

> +    rc = arch_set_info_hvm_guest(v, &cpu_ctx);
> +    if ( rc )
> +    {
> +        printk("Unable to setup Dom0 BSP context: %d\n", rc);
> +        return rc;
> +    }
> +    clear_bit(_VPF_down, &v->pause_flags);

Even if it may not matter right away, I think you want to clear this
flag later, after having completed all setup.

> +    for ( i = 0; i < ARRAY_SIZE(cpuid_leaves); i++ )
> +    {
> +        d->arch.cpuids[i].input[0] = cpuid_leaves[i].index;
> +        d->arch.cpuids[i].input[1] = cpuid_leaves[i].count;
> +        if ( d->arch.cpuids[i].input[1] == XEN_CPUID_INPUT_UNUSED )
> +            cpuid(d->arch.cpuids[i].input[0], &d->arch.cpuids[i].eax,
> +                  &d->arch.cpuids[i].ebx, &d->arch.cpuids[i].ecx,
> +                  &d->arch.cpuids[i].edx);
> +        else
> +            cpuid_count(d->arch.cpuids[i].input[0], d->arch.cpuids[i].input[1],
> +                        &d->arch.cpuids[i].eax, &d->arch.cpuids[i].ebx,
> +                        &d->arch.cpuids[i].ecx, &d->arch.cpuids[i].edx);

Why this if/else? It is always fine to use cpuid_count().

Jan
Roger Pau Monné Oct. 12, 2016, 11:06 a.m. UTC | #2
On Thu, Oct 06, 2016 at 09:20:07AM -0600, Jan Beulich wrote:
> >>> On 27.09.16 at 17:57, <roger.pau@citrix.com> wrote:
> > The logic used to setup the CPUID leaves is extremely simplistic (and
> > probably wrong for hardware different than mine). I'm not sure what's the
> > best way to deal with this, the code that currently sets the CPUID leaves
> > for HVM guests lives in libxc, maybe moving it xen/common would be better?
> 
> Yeah, a pre-populated array of leaves certainly won't do.

This is what current HVM guests use, and TBH, I would prefer to don't 
diverge from HVM. Would it make sense to leave this as-is, until all this 
cpuid stuff is fixed? (IIRC Andrew is still working on this).

> > +    rc = arch_set_info_hvm_guest(v, &cpu_ctx);
> > +    if ( rc )
> > +    {
> > +        printk("Unable to setup Dom0 BSP context: %d\n", rc);
> > +        return rc;
> > +    }
> > +    clear_bit(_VPF_down, &v->pause_flags);
> 
> Even if it may not matter right away, I think you want to clear this
> flag later, after having completed all setup.

Right, I've now moved the clear_bit to the end of construct_dom0_hvm.

> > +    for ( i = 0; i < ARRAY_SIZE(cpuid_leaves); i++ )
> > +    {
> > +        d->arch.cpuids[i].input[0] = cpuid_leaves[i].index;
> > +        d->arch.cpuids[i].input[1] = cpuid_leaves[i].count;
> > +        if ( d->arch.cpuids[i].input[1] == XEN_CPUID_INPUT_UNUSED )
> > +            cpuid(d->arch.cpuids[i].input[0], &d->arch.cpuids[i].eax,
> > +                  &d->arch.cpuids[i].ebx, &d->arch.cpuids[i].ecx,
> > +                  &d->arch.cpuids[i].edx);
> > +        else
> > +            cpuid_count(d->arch.cpuids[i].input[0], d->arch.cpuids[i].input[1],
> > +                        &d->arch.cpuids[i].eax, &d->arch.cpuids[i].ebx,
> > +                        &d->arch.cpuids[i].ecx, &d->arch.cpuids[i].edx);
> 
> Why this if/else? It is always fine to use cpuid_count().

Done, now it's cpuid_count.

Roger.
Andrew Cooper Oct. 12, 2016, 11:32 a.m. UTC | #3
On 12/10/16 12:06, Roger Pau Monne wrote:
> On Thu, Oct 06, 2016 at 09:20:07AM -0600, Jan Beulich wrote:
>>>>> On 27.09.16 at 17:57, <roger.pau@citrix.com> wrote:
>>> The logic used to setup the CPUID leaves is extremely simplistic (and
>>> probably wrong for hardware different than mine). I'm not sure what's the
>>> best way to deal with this, the code that currently sets the CPUID leaves
>>> for HVM guests lives in libxc, maybe moving it xen/common would be better?
>> Yeah, a pre-populated array of leaves certainly won't do.
> This is what current HVM guests use, and TBH, I would prefer to don't 
> diverge from HVM. Would it make sense to leave this as-is, until all this 
> cpuid stuff is fixed? (IIRC Andrew is still working on this).

My CPUID work will remove the need for any of this, (and indeed, is a
prerequisite for an HVM Control domain to build further HVM domains).

At boot, where we currently calculate the featuresets, we will also
calculate maximum full policies.  domain_create() will clone the
appropriate default policy (pv or hvm) as a starting point.

A regular domU will have the toolstack optionally reduce the policy via
the domctl interface, but in the absence of any changes, the domain will
get the maximum supported featureset available on the hardware.

~Andrew
Jan Beulich Oct. 12, 2016, 12:02 p.m. UTC | #4
>>> On 12.10.16 at 13:06, <roger.pau@citrix.com> wrote:
> On Thu, Oct 06, 2016 at 09:20:07AM -0600, Jan Beulich wrote:
>> >>> On 27.09.16 at 17:57, <roger.pau@citrix.com> wrote:
>> > The logic used to setup the CPUID leaves is extremely simplistic (and
>> > probably wrong for hardware different than mine). I'm not sure what's the
>> > best way to deal with this, the code that currently sets the CPUID leaves
>> > for HVM guests lives in libxc, maybe moving it xen/common would be better?
>> 
>> Yeah, a pre-populated array of leaves certainly won't do.
> 
> This is what current HVM guests use, and TBH, I would prefer to don't 
> diverge from HVM. Would it make sense to leave this as-is, until all this 
> cpuid stuff is fixed? (IIRC Andrew is still working on this).

Leaving it as is makes little sense to me. What would make sense
is to make Andrew's work a prereq for this patch.

Jan
diff mbox

Patch

diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c
index effebf1..8ea54ae 100644
--- a/xen/arch/x86/domain_build.c
+++ b/xen/arch/x86/domain_build.c
@@ -40,6 +40,7 @@ 
 
 #include <public/version.h>
 #include <public/arch-x86/hvm/start_info.h>
+#include <public/hvm/hvm_vcpu.h>
 
 static long __initdata dom0_nrpages;
 static long __initdata dom0_min_nrpages;
@@ -2015,6 +2016,101 @@  out:
     return rc;
 }
 
+static int __init hvm_setup_cpus(struct domain *d, paddr_t entry,
+                                 paddr_t start_info)
+{
+    vcpu_hvm_context_t cpu_ctx;
+    struct vcpu *v = d->vcpu[0];
+    int cpu, i, rc;
+    struct {
+        uint32_t index;
+        uint32_t count;
+    } cpuid_leaves[] = {
+        {0, XEN_CPUID_INPUT_UNUSED},
+        {1, XEN_CPUID_INPUT_UNUSED},
+        {2, XEN_CPUID_INPUT_UNUSED},
+        {4, 0},
+        {4, 1},
+        {4, 2},
+        {4, 3},
+        {4, 4},
+        {7, 0},
+        {0xa, XEN_CPUID_INPUT_UNUSED},
+        {0xd, 0},
+        {0x80000000, XEN_CPUID_INPUT_UNUSED},
+        {0x80000001, XEN_CPUID_INPUT_UNUSED},
+        {0x80000002, XEN_CPUID_INPUT_UNUSED},
+        {0x80000003, XEN_CPUID_INPUT_UNUSED},
+        {0x80000004, XEN_CPUID_INPUT_UNUSED},
+        {0x80000005, XEN_CPUID_INPUT_UNUSED},
+        {0x80000006, XEN_CPUID_INPUT_UNUSED},
+        {0x80000007, XEN_CPUID_INPUT_UNUSED},
+        {0x80000008, XEN_CPUID_INPUT_UNUSED},
+    };
+
+    printk("** Setting up BSP/APs **\n");
+
+    cpu = v->processor;
+    for ( i = 1; i < d->max_vcpus; i++ )
+    {
+        cpu = cpumask_cycle(cpu, &dom0_cpus);
+        setup_dom0_vcpu(d, i, cpu);
+    }
+
+    memset(&cpu_ctx, 0, sizeof(cpu_ctx));
+
+    cpu_ctx.mode = VCPU_HVM_MODE_32B;
+
+    cpu_ctx.cpu_regs.x86_32.ebx = start_info;
+    cpu_ctx.cpu_regs.x86_32.eip = entry;
+    cpu_ctx.cpu_regs.x86_32.cr0 = X86_CR0_PE | X86_CR0_ET;
+
+    cpu_ctx.cpu_regs.x86_32.cs_limit = ~0u;
+    cpu_ctx.cpu_regs.x86_32.ds_limit = ~0u;
+    cpu_ctx.cpu_regs.x86_32.ss_limit = ~0u;
+    cpu_ctx.cpu_regs.x86_32.tr_limit = 0x67;
+    cpu_ctx.cpu_regs.x86_32.cs_ar = 0xc9b;
+    cpu_ctx.cpu_regs.x86_32.ds_ar = 0xc93;
+    cpu_ctx.cpu_regs.x86_32.ss_ar = 0xc93;
+    cpu_ctx.cpu_regs.x86_32.tr_ar = 0x8b;
+
+    rc = arch_set_info_hvm_guest(v, &cpu_ctx);
+    if ( rc )
+    {
+        printk("Unable to setup Dom0 BSP context: %d\n", rc);
+        return rc;
+    }
+    clear_bit(_VPF_down, &v->pause_flags);
+
+    for ( i = 0; i < ARRAY_SIZE(cpuid_leaves); i++ )
+    {
+        d->arch.cpuids[i].input[0] = cpuid_leaves[i].index;
+        d->arch.cpuids[i].input[1] = cpuid_leaves[i].count;
+        if ( d->arch.cpuids[i].input[1] == XEN_CPUID_INPUT_UNUSED )
+            cpuid(d->arch.cpuids[i].input[0], &d->arch.cpuids[i].eax,
+                  &d->arch.cpuids[i].ebx, &d->arch.cpuids[i].ecx,
+                  &d->arch.cpuids[i].edx);
+        else
+            cpuid_count(d->arch.cpuids[i].input[0], d->arch.cpuids[i].input[1],
+                        &d->arch.cpuids[i].eax, &d->arch.cpuids[i].ebx,
+                        &d->arch.cpuids[i].ecx, &d->arch.cpuids[i].edx);
+        /* XXX: we need to do much more filtering here. */
+        if ( d->arch.cpuids[i].input[0] == 1 )
+            d->arch.cpuids[i].ecx &= ~X86_FEATURE_VMX;
+    }
+
+    rc = setup_permissions(d);
+    if ( rc )
+    {
+        panic("Unable to setup Dom0 permissions: %d\n", rc);
+        return rc;
+    }
+
+    update_domain_wallclock_time(d);
+
+    return 0;
+}
+
 static int __init construct_dom0_hvm(struct domain *d, const module_t *image,
                                      unsigned long image_headroom,
                                      module_t *initrd,
@@ -2049,6 +2145,13 @@  static int __init construct_dom0_hvm(struct domain *d, const module_t *image,
         return rc;
     }
 
+    rc = hvm_setup_cpus(d, entry, start_info);
+    if ( rc )
+    {
+        printk("Failed to setup Dom0 CPUs: %d\n", rc);
+        return rc;
+    }
+
     return 0;
 }