Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/firecracker
Path: blob/main/tests/integration_tests/functional/test_cpu_features.py
1958 views
1
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
# SPDX-License-Identifier: Apache-2.0
3
"""Tests for the CPU topology emulation feature."""
4
5
import platform
6
import re
7
import pytest
8
9
import framework.utils_cpuid as utils
10
import host_tools.network as net_tools
11
12
PLATFORM = platform.machine()
13
14
15
def _check_cpuid_x86(test_microvm, expected_cpu_count, expected_htt):
16
expected_cpu_features = {
17
"cpu count": '{} ({})'.format(hex(expected_cpu_count),
18
expected_cpu_count),
19
"CLFLUSH line size": "0x8 (8)",
20
"hypervisor guest status": "true",
21
"hyper-threading / multi-core supported": expected_htt
22
}
23
24
utils.check_guest_cpuid_output(test_microvm, "cpuid -1", None, '=',
25
expected_cpu_features)
26
27
28
def _check_cpu_features_arm(test_microvm):
29
expected_cpu_features = {
30
"Flags": "fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp "
31
"asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs",
32
}
33
34
utils.check_guest_cpuid_output(test_microvm, "lscpu", None, ':',
35
expected_cpu_features)
36
37
38
@pytest.mark.skipif(
39
PLATFORM != "x86_64",
40
reason="CPUID is only supported on x86_64."
41
)
42
@pytest.mark.parametrize(
43
"num_vcpus",
44
[1, 2, 16],
45
)
46
@pytest.mark.parametrize(
47
"htt",
48
[True, False],
49
)
50
def test_cpuid(test_microvm_with_ssh, network_config, num_vcpus, htt):
51
"""Check the CPUID for a microvm with the specified config."""
52
vm = test_microvm_with_ssh
53
vm.spawn()
54
vm.basic_config(vcpu_count=num_vcpus, ht_enabled=htt)
55
_tap, _, _ = vm.ssh_network_config(network_config, '1')
56
vm.start()
57
_check_cpuid_x86(vm, num_vcpus, "true" if num_vcpus > 1 else "false")
58
59
60
@pytest.mark.skipif(
61
PLATFORM != "aarch64",
62
reason="The CPU features on x86 are tested as part of the CPU templates."
63
)
64
def test_cpu_features(test_microvm_with_ssh, network_config):
65
"""Check the CPU features for a microvm with the specified config."""
66
vm = test_microvm_with_ssh
67
vm.spawn()
68
vm.basic_config()
69
_tap, _, _ = vm.ssh_network_config(network_config, '1')
70
vm.start()
71
_check_cpu_features_arm(vm)
72
73
74
@pytest.mark.skipif(
75
PLATFORM != "x86_64",
76
reason="The CPU brand string is masked only on x86_64."
77
)
78
def test_brand_string(test_microvm_with_ssh, network_config):
79
"""Ensure good formatting for the guest band string.
80
81
* For Intel CPUs, the guest brand string should be:
82
Intel(R) Xeon(R) Processor @ {host frequency}
83
where {host frequency} is the frequency reported by the host CPUID
84
(e.g. 4.01GHz)
85
* For AMD CPUs, the guest brand string should be:
86
AMD EPYC
87
* For other CPUs, the guest brand string should be:
88
""
89
"""
90
cif = open('/proc/cpuinfo', 'r')
91
host_brand_string = None
92
while True:
93
line = cif.readline()
94
if line == '':
95
break
96
mo = re.search("^model name\\s+:\\s+(.+)$", line)
97
if mo:
98
host_brand_string = mo.group(1)
99
cif.close()
100
assert host_brand_string is not None
101
102
test_microvm = test_microvm_with_ssh
103
test_microvm.spawn()
104
105
test_microvm.basic_config(vcpu_count=1)
106
_tap, _, _ = test_microvm.ssh_network_config(network_config, '1')
107
test_microvm.start()
108
109
ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)
110
111
guest_cmd = "cat /proc/cpuinfo | grep 'model name' | head -1"
112
_, stdout, stderr = ssh_connection.execute_command(guest_cmd)
113
assert stderr.read() == ''
114
115
line = stdout.readline().rstrip()
116
mo = re.search("^model name\\s+:\\s+(.+)$", line)
117
assert mo
118
guest_brand_string = mo.group(1)
119
assert guest_brand_string
120
121
cpu_vendor = utils.get_cpu_vendor()
122
expected_guest_brand_string = ""
123
if cpu_vendor == utils.CpuVendor.AMD:
124
expected_guest_brand_string += "AMD EPYC"
125
elif cpu_vendor == utils.CpuVendor.INTEL:
126
expected_guest_brand_string = "Intel(R) Xeon(R) Processor"
127
mo = re.search("[.0-9]+[MG]Hz", host_brand_string)
128
if mo:
129
expected_guest_brand_string += " @ " + mo.group(0)
130
131
assert guest_brand_string == expected_guest_brand_string
132
133
134
@pytest.mark.skipif(
135
PLATFORM != "x86_64",
136
reason="CPU features are masked only on x86_64."
137
)
138
@pytest.mark.parametrize("cpu_template", ["T2", "C3"])
139
def test_cpu_template(test_microvm_with_ssh, network_config, cpu_template):
140
"""Check that AVX2 & AVX512 instructions are disabled.
141
142
This is a rather dummy test for checking that some features are not
143
exposed by mistake. It is a first step into checking the t2 & c3
144
templates. In a next iteration we should check **all** cpuid entries, not
145
just these features. We can achieve this with a template
146
containing all features on a t2/c3 instance and check that the cpuid in
147
the guest is an exact match of the template.
148
"""
149
common_masked_features_lscpu = ["dtes64", "monitor", "ds_cpl", "tm2",
150
"cnxt-id", "sdbg", "xtpr", "pdcm",
151
"osxsave",
152
"psn", "ds", "acpi", "tm", "ss", "pbe",
153
"fpdp", "rdt_m", "rdt_a", "mpx", "avx512f",
154
"intel_pt",
155
"avx512_vpopcntdq",
156
"3dnowprefetch", "pdpe1gb"]
157
158
common_masked_features_cpuid = {"SGX": "false", "HLE": "false",
159
"RTM": "false", "RDSEED": "false",
160
"ADX": "false", "AVX512IFMA": "false",
161
"CLFLUSHOPT": "false", "CLWB": "false",
162
"AVX512PF": "false", "AVX512ER": "false",
163
"AVX512CD": "false", "SHA": "false",
164
"AVX512BW": "false", "AVX512VL": "false",
165
"AVX512VBMI": "false", "PKU": "false",
166
"OSPKE": "false", "RDPID": "false",
167
"SGX_LC": "false",
168
"AVX512_4VNNIW": "false",
169
"AVX512_4FMAPS": "false",
170
"XSAVEC": "false", "XGETBV": "false",
171
"XSAVES": "false"}
172
173
# These are all discoverable by cpuid -1.
174
c3_masked_features = {"FMA": "false", "MOVBE": "false", "BMI": "false",
175
"AVX2": "false", "BMI2": "false", "INVPCID": "false"}
176
177
test_microvm = test_microvm_with_ssh
178
test_microvm.spawn()
179
180
test_microvm.basic_config(vcpu_count=1)
181
# Set template as specified in the `cpu_template` parameter.
182
response = test_microvm.machine_cfg.put(
183
vcpu_count=1,
184
mem_size_mib=256,
185
ht_enabled=False,
186
cpu_template=cpu_template,
187
)
188
assert test_microvm.api_session.is_status_no_content(response.status_code)
189
_tap, _, _ = test_microvm.ssh_network_config(network_config, '1')
190
191
response = test_microvm.actions.put(action_type='InstanceStart')
192
if utils.get_cpu_vendor() != utils.CpuVendor.INTEL:
193
# We shouldn't be able to apply Intel templates on AMD hosts
194
assert test_microvm.api_session.is_status_bad_request(
195
response.status_code)
196
return
197
198
assert test_microvm.api_session.is_status_no_content(
199
response.status_code)
200
201
# Check that all common features discoverable with lscpu
202
# are properly masked.
203
ssh_connection = net_tools.SSHConnection(test_microvm.ssh_config)
204
guest_cmd = "cat /proc/cpuinfo | grep 'flags' | head -1"
205
_, stdout, stderr = ssh_connection.execute_command(guest_cmd)
206
assert stderr.read() == ''
207
208
cpu_flags_output = stdout.readline().rstrip().split(' ')
209
210
for feature in common_masked_features_lscpu:
211
assert feature not in cpu_flags_output, feature
212
213
# Check that all common features discoverable with cpuid
214
# are properly masked.
215
utils.check_guest_cpuid_output(test_microvm, "cpuid -1", None, '=',
216
common_masked_features_cpuid)
217
218
if cpu_template == "C3":
219
utils.check_guest_cpuid_output(test_microvm, "cpuid -1", None, '=',
220
c3_masked_features)
221
222
# Check if XSAVE PKRU is masked for T3/C2.
223
expected_cpu_features = {
224
"XCR0 supported: PKRU state": "false"
225
}
226
227
utils.check_guest_cpuid_output(test_microvm, "cpuid -1", None, '=',
228
expected_cpu_features)
229
230