Skip to content

Commit 1ae92d9

Browse files
[cpuid] fix bug in T2 and C3 template
Additional CPU features need to be disable on Skylake. Signed-off-by: Andreea Florescu <[email protected]>
1 parent 47f8372 commit 1ae92d9

File tree

4 files changed

+90
-28
lines changed

4 files changed

+90
-28
lines changed

cpuid/src/cpu_leaf.rs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ pub mod leaf_0x7 {
124124
// Intel® Resource Director Technology (Intel® RDT) Monitoring
125125
pub const RDT_M_SHIFT: u32 = 12;
126126
// 13 = Deprecates FPU CS and FPU DS values if 1
127-
// 14 = MPX (Intel® Memory Protection Extensions)
127+
// Memory Protection Extensions
128+
pub const MPX_SHIFT: u32 = 14;
128129
// RDT = Intel® Resource Director Technology
129130
pub const RDT_A_SHIFT: u32 = 15;
130131
// AVX-512 Foundation instructions
@@ -137,8 +138,11 @@ pub mod leaf_0x7 {
137138
// AVX512IFMA = AVX-512 Integer Fused Multiply-Add Instructions
138139
pub const AVX512IFMA_SHIFT: u32 = 21;
139140
// 21 = PCOMMIT intruction
140-
// 23 = CLFLUSH_OPT (flushing multiple cache lines in parallel within a single logical processor)
141-
// 24 = CLWB (Cache Line Write Back)
141+
// 22 reserved
142+
// CLFLUSHOPT (flushing multiple cache lines in parallel within a single logical processor)
143+
pub const CLFLUSHOPT_SHIFT: u32 = 23;
144+
// CLWB = Cache Line Write Back
145+
pub const CLWB_SHIFT: u32 = 24;
142146
// PT = Intel Processor Trace
143147
pub const PT_SHIFT: u32 = 25;
144148
// AVX512PF = AVX512 Prefetch Instructions
@@ -160,8 +164,10 @@ pub mod leaf_0x7 {
160164
// AVX512_VBMI = AVX-512 Vector Byte Manipulation Instructions
161165
pub const AVX512_VBMI_SHIFT: u32 = 1;
162166
// 2 = UMIP (User Mode Instruction Prevention)
163-
// 3 = PKU (Protection Keys for user-mode pages)
164-
// 4 = OSPKE (If 1, OS has set CR4.PKE to enable protection keys)
167+
// PKU = Protection Keys for user-mode pages
168+
pub const PKU_SHIFT: u32 = 3;
169+
// OSPKE = If 1, OS has set CR4.PKE to enable protection keys
170+
pub const OSPKE_SHIFT: u32 = 4;
165171
// 5 = WAITPKG
166172
// 7-6 reserved
167173
// 8 = GFNI
@@ -227,11 +233,23 @@ pub mod leaf_0xb {
227233
pub mod leaf_0xd {
228234
pub const LEAF_NUM: u32 = 0xd;
229235

230-
pub mod eax {
231-
use bit_helper::BitRange;
236+
pub mod index0 {
237+
pub mod eax {
238+
use bit_helper::BitRange;
239+
240+
pub const MPX_STATE_BITRANGE: BitRange = bit_range!(4, 3);
241+
pub const AVX512_STATE_BITRANGE: BitRange = bit_range!(7, 5);
242+
}
243+
}
232244

233-
pub const AVX512_STATE_BITRANGE: BitRange = bit_range!(7, 5);
245+
pub mod index1 {
246+
pub mod eax {
247+
pub const XSAVEC_SHIFT: u32 = 1;
248+
pub const XGETBV_SHIFT: u32 = 2;
249+
pub const XSAVES_SHIFT: u32 = 3;
250+
}
234251
}
252+
235253
}
236254

237255
pub mod leaf_0x80000000 {

cpuid/src/template/c3.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,14 @@ pub fn set_cpuid_entries(entries: &mut [kvm_cpuid_entry2]) {
6666
entry.ebx &= !(1 << leaf_0x7::index0::ebx::RTM_SHIFT);
6767
entry.ebx &= !(1 << leaf_0x7::index0::ebx::RDT_M_SHIFT);
6868
entry.ebx &= !(1 << leaf_0x7::index0::ebx::RDT_A_SHIFT);
69+
entry.ebx &= !(1 << leaf_0x7::index0::ebx::MPX_SHIFT);
6970
entry.ebx &= !(1 << leaf_0x7::index0::ebx::AVX512F_SHIFT);
7071
entry.ebx &= !(1 << leaf_0x7::index0::ebx::AVX512DQ_SHIFT);
7172
entry.ebx &= !(1 << leaf_0x7::index0::ebx::RDSEED_SHIFT);
7273
entry.ebx &= !(1 << leaf_0x7::index0::ebx::ADX_SHIFT);
7374
entry.ebx &= !(1 << leaf_0x7::index0::ebx::AVX512IFMA_SHIFT);
75+
entry.ebx &= !(1 << leaf_0x7::index0::ebx::CLFLUSHOPT_SHIFT);
76+
entry.ebx &= !(1 << leaf_0x7::index0::ebx::CLWB_SHIFT);
7477
entry.ebx &= !(1 << leaf_0x7::index0::ebx::PT_SHIFT);
7578
entry.ebx &= !(1 << leaf_0x7::index0::ebx::AVX512PF_SHIFT);
7679
entry.ebx &= !(1 << leaf_0x7::index0::ebx::AVX512ER_SHIFT);
@@ -80,6 +83,8 @@ pub fn set_cpuid_entries(entries: &mut [kvm_cpuid_entry2]) {
8083
entry.ebx &= !(1 << leaf_0x7::index0::ebx::AVX512VL_SHIFT);
8184

8285
entry.ecx &= !(1 << leaf_0x7::index0::ecx::AVX512_VBMI_SHIFT);
86+
entry.ecx &= !(1 << leaf_0x7::index0::ecx::PKU_SHIFT);
87+
entry.ecx &= !(1 << leaf_0x7::index0::ecx::OSPKE_SHIFT);
8388
entry.ecx &= !(1 << leaf_0x7::index0::ecx::AVX512_VPOPCNTDQ_SHIFT);
8489
entry.ecx &= !(1 << leaf_0x7::index0::ecx::RDPID_SHIFT);
8590
entry.ecx &= !(1 << leaf_0x7::index0::ecx::SGX_LC_SHIFT);
@@ -89,11 +94,25 @@ pub fn set_cpuid_entries(entries: &mut [kvm_cpuid_entry2]) {
8994
}
9095
}
9196
leaf_0xd::LEAF_NUM => {
92-
// AVX-512 instructions are masked out with the C3 template so the size in bytes
93-
// of the save area should be 0 (or invalid).
94-
entry
95-
.eax
96-
.write_bits_in_range(&leaf_0xd::eax::AVX512_STATE_BITRANGE, 0);
97+
if entry.index == 0 {
98+
// MPX is masked out with the C3 template so the size in in bytes of the save
99+
// area should be 0 (or invalid).
100+
entry
101+
.eax
102+
.write_bits_in_range(&leaf_0xd::index0::eax::MPX_STATE_BITRANGE, 0);
103+
104+
// AVX-512 instructions are masked out with the C3 template so the size in bytes
105+
// of the save area should be 0 (or invalid).
106+
entry
107+
.eax
108+
.write_bits_in_range(&leaf_0xd::index0::eax::AVX512_STATE_BITRANGE, 0);
109+
}
110+
111+
if entry.index == 1 {
112+
entry.eax &= !(1 << leaf_0xd::index1::eax::XSAVEC_SHIFT);
113+
entry.eax &= !(1 << leaf_0xd::index1::eax::XGETBV_SHIFT);
114+
entry.eax &= !(1 << leaf_0xd::index1::eax::XSAVES_SHIFT);
115+
}
97116
}
98117
leaf_0x80000001::LEAF_NUM => {
99118
entry.ecx &= !(1 << leaf_0x80000001::ecx::PREFETCH_SHIFT);

cpuid/src/template/t2.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,14 @@ pub fn set_cpuid_entries(entries: &mut [kvm_cpuid_entry2]) {
5959
entry.ebx &= !(1 << leaf_0x7::index0::ebx::RTM_SHIFT);
6060
entry.ebx &= !(1 << leaf_0x7::index0::ebx::RDT_M_SHIFT);
6161
entry.ebx &= !(1 << leaf_0x7::index0::ebx::RDT_A_SHIFT);
62+
entry.ebx &= !(1 << leaf_0x7::index0::ebx::MPX_SHIFT);
6263
entry.ebx &= !(1 << leaf_0x7::index0::ebx::AVX512F_SHIFT);
6364
entry.ebx &= !(1 << leaf_0x7::index0::ebx::AVX512DQ_SHIFT);
6465
entry.ebx &= !(1 << leaf_0x7::index0::ebx::RDSEED_SHIFT);
6566
entry.ebx &= !(1 << leaf_0x7::index0::ebx::ADX_SHIFT);
6667
entry.ebx &= !(1 << leaf_0x7::index0::ebx::AVX512IFMA_SHIFT);
68+
entry.ebx &= !(1 << leaf_0x7::index0::ebx::CLFLUSHOPT_SHIFT);
69+
entry.ebx &= !(1 << leaf_0x7::index0::ebx::CLWB_SHIFT);
6770
entry.ebx &= !(1 << leaf_0x7::index0::ebx::PT_SHIFT);
6871
entry.ebx &= !(1 << leaf_0x7::index0::ebx::AVX512PF_SHIFT);
6972
entry.ebx &= !(1 << leaf_0x7::index0::ebx::AVX512ER_SHIFT);
@@ -73,6 +76,8 @@ pub fn set_cpuid_entries(entries: &mut [kvm_cpuid_entry2]) {
7376
entry.ebx &= !(1 << leaf_0x7::index0::ebx::AVX512VL_SHIFT);
7477

7578
entry.ecx &= !(1 << leaf_0x7::index0::ecx::AVX512_VBMI_SHIFT);
79+
entry.ecx &= !(1 << leaf_0x7::index0::ecx::PKU_SHIFT);
80+
entry.ecx &= !(1 << leaf_0x7::index0::ecx::OSPKE_SHIFT);
7681
entry.ecx &= !(1 << leaf_0x7::index0::ecx::AVX512_VPOPCNTDQ_SHIFT);
7782
entry.ecx &= !(1 << leaf_0x7::index0::ecx::RDPID_SHIFT);
7883
entry.ecx &= !(1 << leaf_0x7::index0::ecx::SGX_LC_SHIFT);
@@ -82,11 +87,25 @@ pub fn set_cpuid_entries(entries: &mut [kvm_cpuid_entry2]) {
8287
}
8388
}
8489
leaf_0xd::LEAF_NUM => {
85-
// AVX-512 instructions are masked out with the T2 template so the size in bytes
86-
// of the save area should be 0 (or invalid).
87-
entry
88-
.eax
89-
.write_bits_in_range(&leaf_0xd::eax::AVX512_STATE_BITRANGE, 0);
90+
if entry.index == 0 {
91+
// MPX is masked out with the T2 template so the size in in bytes of the save
92+
// area should be 0 (or invalid).
93+
entry
94+
.eax
95+
.write_bits_in_range(&leaf_0xd::index0::eax::MPX_STATE_BITRANGE, 0);
96+
97+
// AVX-512 instructions are masked out with the T2 template so the size in bytes
98+
// of the save area should be 0 (or invalid).
99+
entry
100+
.eax
101+
.write_bits_in_range(&leaf_0xd::index0::eax::AVX512_STATE_BITRANGE, 0);
102+
}
103+
104+
if entry.index == 1 {
105+
entry.eax &= !(1 << leaf_0xd::index1::eax::XSAVEC_SHIFT);
106+
entry.eax &= !(1 << leaf_0xd::index1::eax::XGETBV_SHIFT);
107+
entry.eax &= !(1 << leaf_0xd::index1::eax::XSAVES_SHIFT);
108+
}
90109
}
91110
leaf_0x80000001::LEAF_NUM => {
92111
entry.ecx &= !(1 << leaf_0x80000001::ecx::PREFETCH_SHIFT);

tests/integration_tests/functional/test_cpu_features.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -305,24 +305,28 @@ def test_brand_string(test_microvm_with_ssh, network_config):
305305

306306
@pytest.mark.skipif(
307307
platform.machine() != "x86_64",
308-
reason="AVX features are available only on x86_64."
308+
reason="CPU features are masked only on x86_64."
309309
)
310310
@pytest.mark.parametrize("cpu_template", ["T2", "C3"])
311-
def test_avx_disabled(test_microvm_with_ssh, network_config, cpu_template):
311+
def test_cpu_template(test_microvm_with_ssh, network_config, cpu_template):
312312
"""Check that AVX2 & AVX512 instructions are disabled.
313313
314-
This is a rather dummy test for checking that no AVX2 or AVX512
315-
instructions are exposed. It is a first step into checking the t2 & c3
314+
This is a rather dummy test for checking that some features are not
315+
exposed by mistake. It is a first step into checking the t2 & c3
316316
templates. In a next iteration we should check **all** cpuid entries, not
317-
just the AVX family instructions. We can achieve this with a template
317+
just these features. We can achieve this with a template
318318
containing all features on a t2/c3 instance and check that the cpuid in
319319
the guest is an exact match of the template.
320320
"""
321+
common_masked_features = ["avx512", "mpx", "clflushopt", "clwb", "xsavec",
322+
"xgetbv1", "xsaves", "pku", "ospke"]
323+
c3_masked_features = ["avx2"]
324+
321325
test_microvm = test_microvm_with_ssh
322326
test_microvm.spawn()
323327

324328
test_microvm.basic_config(vcpu_count=1)
325-
# Set the template to T2.
329+
# Set template as specified in the `cpu_template` parameter.
326330
response = test_microvm.machine_cfg.put(
327331
vcpu_count=1,
328332
mem_size_mib=256,
@@ -339,8 +343,10 @@ def test_avx_disabled(test_microvm_with_ssh, network_config, cpu_template):
339343
assert stderr.read().decode("utf-8") == ''
340344

341345
cpu_flags_output = stdout.readline().decode('utf-8').rstrip()
342-
# On C3 there's no AVX2. Check that it is masked out.
346+
343347
if cpu_template == "C3":
344-
assert not "avx2" in cpu_flags_output
345-
# Check that AVX-512 is masked out with both C3 and T2 templates
346-
assert not "avx512" in cpu_flags_output
348+
for feature in c3_masked_features:
349+
assert feature not in cpu_flags_output
350+
# Check that all features in `common_masked_features` are properly masked.
351+
for feature in common_masked_features:
352+
assert feature not in cpu_flags_output

0 commit comments

Comments
 (0)