x86/cpuid: Handle leaf 0x80000008 in guest_cpuid()
authorAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 20 Jan 2017 13:00:32 +0000 (13:00 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Wed, 25 Jan 2017 10:26:05 +0000 (10:26 +0000)
The entirety of edx is reserved.

Intel only defines the lower 16 bits of eax, although ebx is covered by the
featureset ABI, so left unclobbered.

AMD uses 24 bits in eax, although nothing thus far has ever exposed a non-zero
guest maxphysaddr to HVM guests.  Its semantics are not clearly expressed, so
it is explicitly clobbered.  ecx contains some reserved bits, and several
pieces of static topology information, which are left as the toolstack
chooses.

A side effect of the common recalculation of maxlinaddr is that 32bit PV
guests see a maximum linear address of 32, which is consistent with the hiding
of other long mode information from them.

Finally, the call to guest_cpuid() in mtrr_var_range_msr_set() (introduced in
c/s fff8160a) can be dropped, now that maxphysaddr can be read straight out of
the cpuid_policy block.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
xen/arch/x86/cpuid.c
xen/arch/x86/hvm/mtrr.c
xen/include/asm-x86/cpuid.h

index 333804572c5c6caa7f07d21ecf4d9eb1bdc0dd94..b806cc5f07f97e97ad51e6f6e261e9375b9c4bac 100644 (file)
@@ -170,6 +170,8 @@ static void recalculate_misc(struct cpuid_policy *p)
     /* Most of Power/RAS hidden from guests. */
     p->extd.raw[0x7].a = p->extd.raw[0x7].b = p->extd.raw[0x7].c = 0;
 
+    p->extd.raw[0x8].d = 0;
+
     switch ( p->x86_vendor )
     {
     case X86_VENDOR_INTEL:
@@ -185,6 +187,9 @@ static void recalculate_misc(struct cpuid_policy *p)
 
         p->extd.raw[0x5] = EMPTY_LEAF;
         p->extd.raw[0x6].a = p->extd.raw[0x6].b = p->extd.raw[0x6].d = 0;
+
+        p->extd.raw[0x8].a &= 0x0000ffff;
+        p->extd.raw[0x8].c = 0;
         break;
 
     case X86_VENDOR_AMD:
@@ -198,6 +203,9 @@ static void recalculate_misc(struct cpuid_policy *p)
         p->extd.raw_fms = p->basic.raw_fms;
         p->extd.raw[0x1].b &= 0xff00ffff;
         p->extd.e1d |= p->basic._1d & CPUID_COMMON_1D_FEATURES;
+
+        p->extd.raw[0x8].a &= 0x0000ffff; /* GuestMaxPhysAddr hidden. */
+        p->extd.raw[0x8].c &= 0x0003f0ff;
         break;
     }
 }
@@ -469,6 +477,15 @@ void recalculate_cpuid_policy(struct domain *d)
                            special_features[FEATURESET_7b0]);
 
     cpuid_featureset_to_policy(fs, p);
+
+    p->extd.maxphysaddr = min(p->extd.maxphysaddr, max->extd.maxphysaddr);
+    p->extd.maxphysaddr = min_t(uint8_t, p->extd.maxphysaddr,
+                                d->arch.paging.gfn_bits + PAGE_SHIFT);
+    p->extd.maxphysaddr = max_t(uint8_t, p->extd.maxphysaddr,
+                                (p->basic.pae || p->basic.pse36) ? 36 : 32);
+
+    p->extd.maxlinaddr = p->extd.lm ? 48 : 32;
+
     recalculate_xstate(p);
     recalculate_misc(p);
 }
@@ -682,11 +699,6 @@ static void pv_cpuid(uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *res)
             res->a = (res->a & ~0xff) | 3;
         break;
 
-    case 0x80000008:
-        res->a = paddr_bits | (vaddr_bits << 8);
-        res->b = p->extd.e8b;
-        break;
-
     case 0x00000005: /* MONITOR/MWAIT */
     case 0x0000000b: /* Extended Topology Enumeration */
     case 0x8000000a: /* SVM revision and features */
@@ -700,7 +712,7 @@ static void pv_cpuid(uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *res)
     case 0x2 ... 0x3:
     case 0x7 ... 0x9:
     case 0xc ... XSTATE_CPUID:
-    case 0x80000000 ... 0x80000007:
+    case 0x80000000 ... 0x80000008:
         ASSERT_UNREACHABLE();
         /* Now handled in guest_cpuid(). */
     }
@@ -716,8 +728,6 @@ static void hvm_cpuid(uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *res)
 
     switch ( leaf )
     {
-        unsigned int tmp;
-
     case 0x1:
         /* Fix up VLAPIC details. */
         res->b &= 0x00FFFFFFu;
@@ -780,21 +790,6 @@ static void hvm_cpuid(uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *res)
             res->a = (res->a & ~0xff) | 3;
         break;
 
-    case 0x80000008:
-        res->a &= 0xff;
-        tmp = d->arch.paging.gfn_bits + PAGE_SHIFT;
-        if ( res->a > tmp )
-            res->a = tmp;
-
-        tmp = (p->basic.pae || p->basic.pse36) ? 36 : 32;
-        if ( res->a < tmp )
-            res->a = tmp;
-
-        res->a |= (p->extd.lm ? vaddr_bits : 32) << 8;
-
-        res->b = p->extd.e8b;
-        break;
-
     case 0x8000001c:
         if ( !cpu_has_svm )
         {
@@ -813,7 +808,7 @@ static void hvm_cpuid(uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *res)
     case 0x2 ... 0x3:
     case 0x7 ... 0x9:
     case 0xc ... XSTATE_CPUID:
-    case 0x80000000 ... 0x80000007:
+    case 0x80000000 ... 0x80000008:
         ASSERT_UNREACHABLE();
         /* Now handled in guest_cpuid(). */
     }
@@ -896,7 +891,7 @@ void guest_cpuid(const struct vcpu *v, uint32_t leaf,
         default:
             goto legacy;
 
-        case 0x80000000 ... 0x80000007:
+        case 0x80000000 ... 0x80000008:
             *res = p->extd.raw[leaf & 0xffff];
             break;
         }
index 709759c5fb690d788dbdb98d7b05b86e43a8a3fe..9ea1fdc6618d665d8a19bf003d1932360be9614d 100644 (file)
@@ -452,12 +452,7 @@ bool_t mtrr_var_range_msr_set(
         return 0;
 
     if ( d == current->domain )
-    {
-        struct cpuid_leaf res;
-
-        guest_cpuid(current, 0x80000008, 0, &res);
-        phys_addr = (uint8_t)res.a ?: 36;
-    }
+        phys_addr = d->arch.cpuid->extd.maxphysaddr;
     else
         phys_addr = paddr_bits;
     msr_mask = ~((((uint64_t)1) << phys_addr) - 1);
index be76ed47d57b141568e1ab7c307608bcd5519ff6..6cc23aa5a3332115278825f0b1155fdf02130a09 100644 (file)
@@ -198,7 +198,7 @@ struct cpuid_policy
             };
 
             /* Leaf 0x80000008 - Misc addr/feature info. */
-            uint32_t /* a */:32;
+            uint8_t maxphysaddr, maxlinaddr, :8, :8;
             union {
                 uint32_t e8b;
                 struct { DECL_BITFIELD(e8b); };