1#
2# Basic validation of x86 versioned CPU models and CPU model aliases
3#
4#  Copyright (c) 2019 Red Hat Inc
5#
6# Author:
7#  Eduardo Habkost <ehabkost@redhat.com>
8#
9# This library is free software; you can redistribute it and/or
10# modify it under the terms of the GNU Lesser General Public
11# License as published by the Free Software Foundation; either
12# version 2.1 of the License, or (at your option) any later version.
13#
14# This library is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17# Lesser General Public License for more details.
18#
19# You should have received a copy of the GNU Lesser General Public
20# License along with this library; if not, see <http://www.gnu.org/licenses/>.
21#
22
23
24import avocado_qemu
25import re
26
27class X86CPUModelAliases(avocado_qemu.QemuSystemTest):
28    """
29    Validation of PC CPU model versions and CPU model aliases
30
31    :avocado: tags=arch:x86_64
32    """
33    def validate_aliases(self, cpus):
34        for c in cpus.values():
35            if 'alias-of' in c:
36                # all aliases must point to a valid CPU model name:
37                self.assertIn(c['alias-of'], cpus,
38                              '%s.alias-of (%s) is not a valid CPU model name' % (c['name'], c['alias-of']))
39                # aliases must not point to aliases
40                self.assertNotIn('alias-of', cpus[c['alias-of']],
41                                 '%s.alias-of (%s) points to another alias' % (c['name'], c['alias-of']))
42
43                # aliases must not be static
44                self.assertFalse(c['static'])
45
46    def validate_variant_aliases(self, cpus):
47        # -noTSX, -IBRS and -IBPB variants of CPU models are special:
48        # they shouldn't have their own versions:
49        self.assertNotIn("Haswell-noTSX-v1", cpus,
50                         "Haswell-noTSX shouldn't be versioned")
51        self.assertNotIn("Broadwell-noTSX-v1", cpus,
52                         "Broadwell-noTSX shouldn't be versioned")
53        self.assertNotIn("Nehalem-IBRS-v1", cpus,
54                         "Nehalem-IBRS shouldn't be versioned")
55        self.assertNotIn("Westmere-IBRS-v1", cpus,
56                         "Westmere-IBRS shouldn't be versioned")
57        self.assertNotIn("SandyBridge-IBRS-v1", cpus,
58                         "SandyBridge-IBRS shouldn't be versioned")
59        self.assertNotIn("IvyBridge-IBRS-v1", cpus,
60                         "IvyBridge-IBRS shouldn't be versioned")
61        self.assertNotIn("Haswell-noTSX-IBRS-v1", cpus,
62                         "Haswell-noTSX-IBRS shouldn't be versioned")
63        self.assertNotIn("Haswell-IBRS-v1", cpus,
64                         "Haswell-IBRS shouldn't be versioned")
65        self.assertNotIn("Broadwell-noTSX-IBRS-v1", cpus,
66                         "Broadwell-noTSX-IBRS shouldn't be versioned")
67        self.assertNotIn("Broadwell-IBRS-v1", cpus,
68                         "Broadwell-IBRS shouldn't be versioned")
69        self.assertNotIn("Skylake-Client-IBRS-v1", cpus,
70                         "Skylake-Client-IBRS shouldn't be versioned")
71        self.assertNotIn("Skylake-Server-IBRS-v1", cpus,
72                         "Skylake-Server-IBRS shouldn't be versioned")
73        self.assertNotIn("EPYC-IBPB-v1", cpus,
74                         "EPYC-IBPB shouldn't be versioned")
75
76    def test_4_0_alias_compatibility(self):
77        """
78        Check if pc-*-4.0 unversioned CPU model won't be reported as aliases
79
80        :avocado: tags=machine:pc-i440fx-4.0
81        """
82        # pc-*-4.0 won't expose non-versioned CPU models as aliases
83        # We do this to help management software to keep compatibility
84        # with older QEMU versions that didn't have the versioned CPU model
85        self.vm.add_args('-S')
86        self.vm.launch()
87        cpus = dict((m['name'], m) for m in
88                    self.vm.cmd('query-cpu-definitions'))
89
90        self.assertFalse(cpus['Cascadelake-Server']['static'],
91                         'unversioned Cascadelake-Server CPU model must not be static')
92        self.assertNotIn('alias-of', cpus['Cascadelake-Server'],
93                         'Cascadelake-Server must not be an alias')
94        self.assertNotIn('alias-of', cpus['Cascadelake-Server-v1'],
95                         'Cascadelake-Server-v1 must not be an alias')
96
97        self.assertFalse(cpus['qemu64']['static'],
98                         'unversioned qemu64 CPU model must not be static')
99        self.assertNotIn('alias-of', cpus['qemu64'],
100                         'qemu64 must not be an alias')
101        self.assertNotIn('alias-of', cpus['qemu64-v1'],
102                         'qemu64-v1 must not be an alias')
103
104        self.validate_variant_aliases(cpus)
105
106        # On pc-*-4.0, no CPU model should be reported as an alias:
107        for name,c in cpus.items():
108            self.assertNotIn('alias-of', c, "%s shouldn't be an alias" % (name))
109
110    def test_4_1_alias(self):
111        """
112        Check if unversioned CPU model is an alias pointing to right version
113
114        :avocado: tags=machine:pc-i440fx-4.1
115        """
116        self.vm.add_args('-S')
117        self.vm.launch()
118
119        cpus = dict((m['name'], m) for m in
120                    self.vm.cmd('query-cpu-definitions'))
121
122        self.assertFalse(cpus['Cascadelake-Server']['static'],
123                         'unversioned Cascadelake-Server CPU model must not be static')
124        self.assertEqual(cpus['Cascadelake-Server'].get('alias-of'),
125                         'Cascadelake-Server-v1',
126                         'Cascadelake-Server must be an alias of Cascadelake-Server-v1')
127        self.assertNotIn('alias-of', cpus['Cascadelake-Server-v1'],
128                         'Cascadelake-Server-v1 must not be an alias')
129
130        self.assertFalse(cpus['qemu64']['static'],
131                         'unversioned qemu64 CPU model must not be static')
132        self.assertEqual(cpus['qemu64'].get('alias-of'), 'qemu64-v1',
133                         'qemu64 must be an alias of qemu64-v1')
134        self.assertNotIn('alias-of', cpus['qemu64-v1'],
135                         'qemu64-v1 must not be an alias')
136
137        self.validate_variant_aliases(cpus)
138
139        # On pc-*-4.1, -noTSX and -IBRS models should be aliases:
140        self.assertEqual(cpus["Haswell"].get('alias-of'),
141                         "Haswell-v1",
142                         "Haswell must be an alias")
143        self.assertEqual(cpus["Haswell-noTSX"].get('alias-of'),
144                         "Haswell-v2",
145                         "Haswell-noTSX must be an alias")
146        self.assertEqual(cpus["Haswell-IBRS"].get('alias-of'),
147                         "Haswell-v3",
148                         "Haswell-IBRS must be an alias")
149        self.assertEqual(cpus["Haswell-noTSX-IBRS"].get('alias-of'),
150                         "Haswell-v4",
151                         "Haswell-noTSX-IBRS must be an alias")
152
153        self.assertEqual(cpus["Broadwell"].get('alias-of'),
154                         "Broadwell-v1",
155                         "Broadwell must be an alias")
156        self.assertEqual(cpus["Broadwell-noTSX"].get('alias-of'),
157                         "Broadwell-v2",
158                         "Broadwell-noTSX must be an alias")
159        self.assertEqual(cpus["Broadwell-IBRS"].get('alias-of'),
160                         "Broadwell-v3",
161                         "Broadwell-IBRS must be an alias")
162        self.assertEqual(cpus["Broadwell-noTSX-IBRS"].get('alias-of'),
163                         "Broadwell-v4",
164                         "Broadwell-noTSX-IBRS must be an alias")
165
166        self.assertEqual(cpus["Nehalem"].get('alias-of'),
167                         "Nehalem-v1",
168                         "Nehalem must be an alias")
169        self.assertEqual(cpus["Nehalem-IBRS"].get('alias-of'),
170                         "Nehalem-v2",
171                         "Nehalem-IBRS must be an alias")
172
173        self.assertEqual(cpus["Westmere"].get('alias-of'),
174                         "Westmere-v1",
175                         "Westmere must be an alias")
176        self.assertEqual(cpus["Westmere-IBRS"].get('alias-of'),
177                         "Westmere-v2",
178                         "Westmere-IBRS must be an alias")
179
180        self.assertEqual(cpus["SandyBridge"].get('alias-of'),
181                         "SandyBridge-v1",
182                         "SandyBridge must be an alias")
183        self.assertEqual(cpus["SandyBridge-IBRS"].get('alias-of'),
184                         "SandyBridge-v2",
185                         "SandyBridge-IBRS must be an alias")
186
187        self.assertEqual(cpus["IvyBridge"].get('alias-of'),
188                         "IvyBridge-v1",
189                         "IvyBridge must be an alias")
190        self.assertEqual(cpus["IvyBridge-IBRS"].get('alias-of'),
191                         "IvyBridge-v2",
192                         "IvyBridge-IBRS must be an alias")
193
194        self.assertEqual(cpus["Skylake-Client"].get('alias-of'),
195                         "Skylake-Client-v1",
196                         "Skylake-Client must be an alias")
197        self.assertEqual(cpus["Skylake-Client-IBRS"].get('alias-of'),
198                         "Skylake-Client-v2",
199                         "Skylake-Client-IBRS must be an alias")
200
201        self.assertEqual(cpus["Skylake-Server"].get('alias-of'),
202                         "Skylake-Server-v1",
203                         "Skylake-Server must be an alias")
204        self.assertEqual(cpus["Skylake-Server-IBRS"].get('alias-of'),
205                         "Skylake-Server-v2",
206                         "Skylake-Server-IBRS must be an alias")
207
208        self.assertEqual(cpus["EPYC"].get('alias-of'),
209                         "EPYC-v1",
210                         "EPYC must be an alias")
211        self.assertEqual(cpus["EPYC-IBPB"].get('alias-of'),
212                         "EPYC-v2",
213                         "EPYC-IBPB must be an alias")
214
215        self.validate_aliases(cpus)
216
217    def test_none_alias(self):
218        """
219        Check if unversioned CPU model is an alias pointing to some version
220
221        :avocado: tags=machine:none
222        """
223        self.vm.add_args('-S')
224        self.vm.launch()
225
226        cpus = dict((m['name'], m) for m in
227                    self.vm.cmd('query-cpu-definitions'))
228
229        self.assertFalse(cpus['Cascadelake-Server']['static'],
230                         'unversioned Cascadelake-Server CPU model must not be static')
231        self.assertTrue(re.match('Cascadelake-Server-v[0-9]+', cpus['Cascadelake-Server']['alias-of']),
232                        'Cascadelake-Server must be an alias of versioned CPU model')
233        self.assertNotIn('alias-of', cpus['Cascadelake-Server-v1'],
234                         'Cascadelake-Server-v1 must not be an alias')
235
236        self.assertFalse(cpus['qemu64']['static'],
237                         'unversioned qemu64 CPU model must not be static')
238        self.assertTrue(re.match('qemu64-v[0-9]+', cpus['qemu64']['alias-of']),
239                        'qemu64 must be an alias of versioned CPU model')
240        self.assertNotIn('alias-of', cpus['qemu64-v1'],
241                         'qemu64-v1 must not be an alias')
242
243        self.validate_aliases(cpus)
244
245
246class CascadelakeArchCapabilities(avocado_qemu.QemuSystemTest):
247    """
248    Validation of Cascadelake arch-capabilities
249
250    :avocado: tags=arch:x86_64
251    """
252    def get_cpu_prop(self, prop):
253        cpu_path = self.vm.cmd('query-cpus-fast')[0].get('qom-path')
254        return self.vm.cmd('qom-get', path=cpu_path, property=prop)
255
256    def test_4_1(self):
257        """
258        :avocado: tags=machine:pc-i440fx-4.1
259        :avocado: tags=cpu:Cascadelake-Server
260        """
261        # machine-type only:
262        self.vm.add_args('-S')
263        self.set_vm_arg('-cpu',
264                        'Cascadelake-Server,x-force-features=on,check=off,'
265                        'enforce=off')
266        self.vm.launch()
267        self.assertFalse(self.get_cpu_prop('arch-capabilities'),
268                         'pc-i440fx-4.1 + Cascadelake-Server should not have arch-capabilities')
269
270    def test_4_0(self):
271        """
272        :avocado: tags=machine:pc-i440fx-4.0
273        :avocado: tags=cpu:Cascadelake-Server
274        """
275        self.vm.add_args('-S')
276        self.set_vm_arg('-cpu',
277                        'Cascadelake-Server,x-force-features=on,check=off,'
278                        'enforce=off')
279        self.vm.launch()
280        self.assertFalse(self.get_cpu_prop('arch-capabilities'),
281                         'pc-i440fx-4.0 + Cascadelake-Server should not have arch-capabilities')
282
283    def test_set_4_0(self):
284        """
285        :avocado: tags=machine:pc-i440fx-4.0
286        :avocado: tags=cpu:Cascadelake-Server
287        """
288        # command line must override machine-type if CPU model is not versioned:
289        self.vm.add_args('-S')
290        self.set_vm_arg('-cpu',
291                        'Cascadelake-Server,x-force-features=on,check=off,'
292                        'enforce=off,+arch-capabilities')
293        self.vm.launch()
294        self.assertTrue(self.get_cpu_prop('arch-capabilities'),
295                        'pc-i440fx-4.0 + Cascadelake-Server,+arch-capabilities should have arch-capabilities')
296
297    def test_unset_4_1(self):
298        """
299        :avocado: tags=machine:pc-i440fx-4.1
300        :avocado: tags=cpu:Cascadelake-Server
301        """
302        self.vm.add_args('-S')
303        self.set_vm_arg('-cpu',
304                        'Cascadelake-Server,x-force-features=on,check=off,'
305                        'enforce=off,-arch-capabilities')
306        self.vm.launch()
307        self.assertFalse(self.get_cpu_prop('arch-capabilities'),
308                         'pc-i440fx-4.1 + Cascadelake-Server,-arch-capabilities should not have arch-capabilities')
309
310    def test_v1_4_0(self):
311        """
312        :avocado: tags=machine:pc-i440fx-4.0
313        :avocado: tags=cpu:Cascadelake-Server
314        """
315        # versioned CPU model overrides machine-type:
316        self.vm.add_args('-S')
317        self.set_vm_arg('-cpu',
318                        'Cascadelake-Server-v1,x-force-features=on,check=off,'
319                        'enforce=off')
320        self.vm.launch()
321        self.assertFalse(self.get_cpu_prop('arch-capabilities'),
322                         'pc-i440fx-4.0 + Cascadelake-Server-v1 should not have arch-capabilities')
323
324    def test_v2_4_0(self):
325        """
326        :avocado: tags=machine:pc-i440fx-4.0
327        :avocado: tags=cpu:Cascadelake-Server
328        """
329        self.vm.add_args('-S')
330        self.set_vm_arg('-cpu',
331                        'Cascadelake-Server-v2,x-force-features=on,check=off,'
332                        'enforce=off')
333        self.vm.launch()
334        self.assertTrue(self.get_cpu_prop('arch-capabilities'),
335                        'pc-i440fx-4.0 + Cascadelake-Server-v2 should have arch-capabilities')
336
337    def test_v1_set_4_0(self):
338        """
339        :avocado: tags=machine:pc-i440fx-4.0
340        :avocado: tags=cpu:Cascadelake-Server
341        """
342        # command line must override machine-type and versioned CPU model:
343        self.vm.add_args('-S')
344        self.set_vm_arg('-cpu',
345                        'Cascadelake-Server-v1,x-force-features=on,check=off,'
346                        'enforce=off,+arch-capabilities')
347        self.vm.launch()
348        self.assertTrue(self.get_cpu_prop('arch-capabilities'),
349                        'pc-i440fx-4.0 + Cascadelake-Server-v1,+arch-capabilities should have arch-capabilities')
350
351    def test_v2_unset_4_1(self):
352        """
353        :avocado: tags=machine:pc-i440fx-4.1
354        :avocado: tags=cpu:Cascadelake-Server
355        """
356        self.vm.add_args('-S')
357        self.set_vm_arg('-cpu',
358                        'Cascadelake-Server-v2,x-force-features=on,check=off,'
359                        'enforce=off,-arch-capabilities')
360        self.vm.launch()
361        self.assertFalse(self.get_cpu_prop('arch-capabilities'),
362                         'pc-i440fx-4.1 + Cascadelake-Server-v2,-arch-capabilities should not have arch-capabilities')
363