1# Check for crash when using memory beyond the available guest processor
2# address space.
3#
4# Copyright (c) 2023 Red Hat, Inc.
5#
6# Author:
7#  Ani Sinha <anisinha@redhat.com>
8#
9# SPDX-License-Identifier: GPL-2.0-or-later
10
11from avocado_qemu import QemuSystemTest
12import signal
13import time
14
15class MemAddrCheck(QemuSystemTest):
16    # after launch, in order to generate the logs from QEMU we need to
17    # wait for some time. Launching and then immediately shutting down
18    # the VM generates empty logs. A delay of 1 second is added for
19    # this reason.
20    DELAY_Q35_BOOT_SEQUENCE = 1
21
22    # first, lets test some 32-bit processors.
23    # for all 32-bit cases, pci64_hole_size is 0.
24    def test_phybits_low_pse36(self):
25        """
26        :avocado: tags=machine:q35
27        :avocado: tags=arch:x86_64
28
29        With pse36 feature ON, a processor has 36 bits of addressing. So it can
30        access up to a maximum of 64GiB of memory. Memory hotplug region begins
31        at 4 GiB boundary when "above_4g_mem_size" is 0 (this would be true when
32        we have 0.5 GiB of VM memory, see pc_q35_init()). This means total
33        hotpluggable memory size is 60 GiB. Per slot, we reserve 1 GiB of memory
34        for dimm alignment for all newer machines (see enforce_aligned_dimm
35        property for pc machines and pc_get_device_memory_range()). That leaves
36        total hotpluggable actual memory size of 59 GiB. If the VM is started
37        with 0.5 GiB of memory, maxmem should be set to a maximum value of
38        59.5 GiB to ensure that the processor can address all memory directly.
39        Note that 64-bit pci hole size is 0 in this case. If maxmem is set to
40        59.6G, QEMU should fail to start with a message "phy-bits are too low".
41        If maxmem is set to 59.5G with all other QEMU parameters identical, QEMU
42        should start fine.
43        """
44        self.vm.add_args('-S', '-machine', 'q35', '-m',
45                         '512,slots=1,maxmem=59.6G',
46                         '-cpu', 'pentium,pse36=on', '-display', 'none',
47                         '-object', 'memory-backend-ram,id=mem1,size=1G',
48                         '-device', 'pc-dimm,id=vm0,memdev=mem1')
49        self.vm.set_qmp_monitor(enabled=False)
50        self.vm.launch()
51        self.vm.wait()
52        self.assertEqual(self.vm.exitcode(), 1, "QEMU exit code should be 1")
53        self.assertRegex(self.vm.get_log(), r'phys-bits too low')
54
55    def test_phybits_low_pae(self):
56        """
57        :avocado: tags=machine:q35
58        :avocado: tags=arch:x86_64
59
60        With pae feature ON, a processor has 36 bits of addressing. So it can
61        access up to a maximum of 64GiB of memory. Rest is the same as the case
62        with pse36 above.
63        """
64        self.vm.add_args('-S', '-machine', 'q35', '-m',
65                         '512,slots=1,maxmem=59.6G',
66                         '-cpu', 'pentium,pae=on', '-display', 'none',
67                         '-object', 'memory-backend-ram,id=mem1,size=1G',
68                         '-device', 'pc-dimm,id=vm0,memdev=mem1')
69        self.vm.set_qmp_monitor(enabled=False)
70        self.vm.launch()
71        self.vm.wait()
72        self.assertEqual(self.vm.exitcode(), 1, "QEMU exit code should be 1")
73        self.assertRegex(self.vm.get_log(), r'phys-bits too low')
74
75    def test_phybits_ok_pentium_pse36(self):
76        """
77        :avocado: tags=machine:q35
78        :avocado: tags=arch:x86_64
79
80        Setting maxmem to 59.5G and making sure that QEMU can start with the
81        same options as the failing case above with pse36 cpu feature.
82        """
83        self.vm.add_args('-machine', 'q35', '-m',
84                         '512,slots=1,maxmem=59.5G',
85                         '-cpu', 'pentium,pse36=on', '-display', 'none',
86                         '-object', 'memory-backend-ram,id=mem1,size=1G',
87                         '-device', 'pc-dimm,id=vm0,memdev=mem1')
88        self.vm.set_qmp_monitor(enabled=False)
89        self.vm.launch()
90        time.sleep(self.DELAY_Q35_BOOT_SEQUENCE)
91        self.vm.shutdown()
92        self.assertNotRegex(self.vm.get_log(), r'phys-bits too low')
93
94    def test_phybits_ok_pentium_pae(self):
95        """
96        :avocado: tags=machine:q35
97        :avocado: tags=arch:x86_64
98
99        Test is same as above but now with pae cpu feature turned on.
100        Setting maxmem to 59.5G and making sure that QEMU can start fine
101        with the same options as the case above.
102        """
103        self.vm.add_args('-machine', 'q35', '-m',
104                         '512,slots=1,maxmem=59.5G',
105                         '-cpu', 'pentium,pae=on', '-display', 'none',
106                         '-object', 'memory-backend-ram,id=mem1,size=1G',
107                         '-device', 'pc-dimm,id=vm0,memdev=mem1')
108        self.vm.set_qmp_monitor(enabled=False)
109        self.vm.launch()
110        time.sleep(self.DELAY_Q35_BOOT_SEQUENCE)
111        self.vm.shutdown()
112        self.assertNotRegex(self.vm.get_log(), r'phys-bits too low')
113
114    def test_phybits_ok_pentium2(self):
115        """
116        :avocado: tags=machine:q35
117        :avocado: tags=arch:x86_64
118
119        Pentium2 has 36 bits of addressing, so its same as pentium
120        with pse36 ON.
121        """
122        self.vm.add_args('-machine', 'q35', '-m',
123                         '512,slots=1,maxmem=59.5G',
124                         '-cpu', 'pentium2', '-display', 'none',
125                         '-object', 'memory-backend-ram,id=mem1,size=1G',
126                         '-device', 'pc-dimm,id=vm0,memdev=mem1')
127        self.vm.set_qmp_monitor(enabled=False)
128        self.vm.launch()
129        time.sleep(self.DELAY_Q35_BOOT_SEQUENCE)
130        self.vm.shutdown()
131        self.assertNotRegex(self.vm.get_log(), r'phys-bits too low')
132
133    def test_phybits_low_nonpse36(self):
134        """
135        :avocado: tags=machine:q35
136        :avocado: tags=arch:x86_64
137
138        Pentium processor has 32 bits of addressing without pse36 or pae
139        so it can access physical address up to 4 GiB. Setting maxmem to
140        4 GiB should make QEMU fail to start with "phys-bits too low"
141        message because the region for memory hotplug is always placed
142        above 4 GiB due to the PCI hole and simplicity.
143        """
144        self.vm.add_args('-S', '-machine', 'q35', '-m',
145                         '512,slots=1,maxmem=4G',
146                         '-cpu', 'pentium', '-display', 'none',
147                         '-object', 'memory-backend-ram,id=mem1,size=1G',
148                         '-device', 'pc-dimm,id=vm0,memdev=mem1')
149        self.vm.set_qmp_monitor(enabled=False)
150        self.vm.launch()
151        self.vm.wait()
152        self.assertEqual(self.vm.exitcode(), 1, "QEMU exit code should be 1")
153        self.assertRegex(self.vm.get_log(), r'phys-bits too low')
154
155    # now lets test some 64-bit CPU cases.
156    def test_phybits_low_tcg_q35_70_amd(self):
157        """
158        :avocado: tags=machine:q35
159        :avocado: tags=arch:x86_64
160
161        For q35 7.1 machines and above, there is a HT window that starts at
162        1024 GiB and ends at 1 TiB - 1. If the max GPA falls in this range,
163        "above_4G" memory is adjusted to start at 1 TiB boundary for AMD cpus
164        in the default case. Lets test without that case for machines 7.0.
165        For q35-7.0 machines, "above 4G" memory starts are 4G.
166        pci64_hole size is 32 GiB. Since TCG_PHYS_ADDR_BITS is defined to
167        be 40, TCG emulated CPUs have maximum of 1 TiB (1024 GiB) of
168        directly addressable memory.
169        Hence, maxmem value at most can be
170        1024 GiB - 4 GiB - 1 GiB per slot for alignment - 32 GiB + 0.5 GiB
171        which is equal to 987.5 GiB. Setting the value to 988 GiB should
172        make QEMU fail with the error message.
173        """
174        self.vm.add_args('-S', '-machine', 'pc-q35-7.0', '-m',
175                         '512,slots=1,maxmem=988G',
176                         '-display', 'none',
177                         '-object', 'memory-backend-ram,id=mem1,size=1G',
178                         '-device', 'pc-dimm,id=vm0,memdev=mem1')
179        self.vm.set_qmp_monitor(enabled=False)
180        self.vm.launch()
181        self.vm.wait()
182        self.assertEqual(self.vm.exitcode(), 1, "QEMU exit code should be 1")
183        self.assertRegex(self.vm.get_log(), r'phys-bits too low')
184
185    def test_phybits_low_tcg_q35_71_amd(self):
186        """
187        :avocado: tags=machine:q35
188        :avocado: tags=arch:x86_64
189
190        AMD_HT_START is defined to be at 1012 GiB. So for q35 machines
191        version > 7.0 and AMD cpus, instead of 1024 GiB limit for 40 bit
192        processor address space, it has to be 1012 GiB , that is 12 GiB
193        less than the case above in order to accommodate HT hole.
194        Make sure QEMU fails when maxmem size is 976 GiB (12 GiB less
195        than 988 GiB).
196        """
197        self.vm.add_args('-S', '-machine', 'pc-q35-7.1', '-m',
198                         '512,slots=1,maxmem=976G',
199                         '-display', 'none',
200                         '-object', 'memory-backend-ram,id=mem1,size=1G',
201                         '-device', 'pc-dimm,id=vm0,memdev=mem1')
202        self.vm.set_qmp_monitor(enabled=False)
203        self.vm.launch()
204        self.vm.wait()
205        self.assertEqual(self.vm.exitcode(), 1, "QEMU exit code should be 1")
206        self.assertRegex(self.vm.get_log(), r'phys-bits too low')
207
208    def test_phybits_ok_tcg_q35_70_amd(self):
209        """
210        :avocado: tags=machine:q35
211        :avocado: tags=arch:x86_64
212
213        Same as q35-7.0 AMD case except that here we check that QEMU can
214        successfully start when maxmem is < 988G.
215        """
216        self.vm.add_args('-S', '-machine', 'pc-q35-7.0', '-m',
217                         '512,slots=1,maxmem=987.5G',
218                         '-display', 'none',
219                         '-object', 'memory-backend-ram,id=mem1,size=1G',
220                         '-device', 'pc-dimm,id=vm0,memdev=mem1')
221        self.vm.set_qmp_monitor(enabled=False)
222        self.vm.launch()
223        time.sleep(self.DELAY_Q35_BOOT_SEQUENCE)
224        self.vm.shutdown()
225        self.assertNotRegex(self.vm.get_log(), r'phys-bits too low')
226
227    def test_phybits_ok_tcg_q35_71_amd(self):
228        """
229        :avocado: tags=machine:q35
230        :avocado: tags=arch:x86_64
231
232        Same as q35-7.1 AMD case except that here we check that QEMU can
233        successfully start when maxmem is < 976G.
234        """
235        self.vm.add_args('-S', '-machine', 'pc-q35-7.1', '-m',
236                         '512,slots=1,maxmem=975.5G',
237                         '-display', 'none',
238                         '-object', 'memory-backend-ram,id=mem1,size=1G',
239                         '-device', 'pc-dimm,id=vm0,memdev=mem1')
240        self.vm.set_qmp_monitor(enabled=False)
241        self.vm.launch()
242        time.sleep(self.DELAY_Q35_BOOT_SEQUENCE)
243        self.vm.shutdown()
244        self.assertNotRegex(self.vm.get_log(), r'phys-bits too low')
245
246    def test_phybits_ok_tcg_q35_71_intel(self):
247        """
248        :avocado: tags=machine:q35
249        :avocado: tags=arch:x86_64
250
251        Same parameters as test_phybits_low_tcg_q35_71_amd() but use
252        Intel cpu instead. QEMU should start fine in this case as
253        "above_4G" memory starts at 4G.
254        """
255        self.vm.add_args('-S', '-cpu', 'Skylake-Server',
256                         '-machine', 'pc-q35-7.1', '-m',
257                         '512,slots=1,maxmem=976G',
258                         '-display', 'none',
259                         '-object', 'memory-backend-ram,id=mem1,size=1G',
260                         '-device', 'pc-dimm,id=vm0,memdev=mem1')
261        self.vm.set_qmp_monitor(enabled=False)
262        self.vm.launch()
263        time.sleep(self.DELAY_Q35_BOOT_SEQUENCE)
264        self.vm.shutdown()
265        self.assertNotRegex(self.vm.get_log(), r'phys-bits too low')
266
267    def test_phybits_low_tcg_q35_71_amd_41bits(self):
268        """
269        :avocado: tags=machine:q35
270        :avocado: tags=arch:x86_64
271
272        AMD processor with 41 bits. Max cpu hw address = 2 TiB.
273        By setting maxram above 1012 GiB  - 32 GiB - 4 GiB = 976 GiB, we can
274        force "above_4G" memory to start at 1 TiB for q35-7.1 machines
275        (max GPA will be above AMD_HT_START which is defined as 1012 GiB).
276
277        With pci_64_hole size at 32 GiB, in this case, maxmem should be 991.5
278        GiB with 1 GiB per slot for alignment and 0.5 GiB as non-hotplug
279        memory for the VM (1024 - 32 - 1 + 0.5). With 992 GiB, QEMU should
280        fail to start.
281        """
282        self.vm.add_args('-S', '-cpu', 'EPYC-v4,phys-bits=41',
283                         '-machine', 'pc-q35-7.1', '-m',
284                         '512,slots=1,maxmem=992G',
285                         '-display', 'none',
286                         '-object', 'memory-backend-ram,id=mem1,size=1G',
287                         '-device', 'pc-dimm,id=vm0,memdev=mem1')
288        self.vm.set_qmp_monitor(enabled=False)
289        self.vm.launch()
290        self.vm.wait()
291        self.assertEqual(self.vm.exitcode(), 1, "QEMU exit code should be 1")
292        self.assertRegex(self.vm.get_log(), r'phys-bits too low')
293
294    def test_phybits_ok_tcg_q35_71_amd_41bits(self):
295        """
296        :avocado: tags=machine:q35
297        :avocado: tags=arch:x86_64
298
299        AMD processor with 41 bits. Max cpu hw address = 2 TiB.
300        Same as above but by setting maxram between 976 GiB and 992 Gib,
301        QEMU should start fine.
302        """
303        self.vm.add_args('-S', '-cpu', 'EPYC-v4,phys-bits=41',
304                         '-machine', 'pc-q35-7.1', '-m',
305                         '512,slots=1,maxmem=990G',
306                         '-display', 'none',
307                         '-object', 'memory-backend-ram,id=mem1,size=1G',
308                         '-device', 'pc-dimm,id=vm0,memdev=mem1')
309        self.vm.set_qmp_monitor(enabled=False)
310        self.vm.launch()
311        time.sleep(self.DELAY_Q35_BOOT_SEQUENCE)
312        self.vm.shutdown()
313        self.assertNotRegex(self.vm.get_log(), r'phys-bits too low')
314
315    def test_phybits_low_tcg_q35_intel_cxl(self):
316        """
317        :avocado: tags=machine:q35
318        :avocado: tags=arch:x86_64
319
320        cxl memory window starts after memory device range. Here, we use 1 GiB
321        of cxl window memory. 4G_mem end aligns at 4G. pci64_hole is 32 GiB and
322        starts after the cxl memory window.
323        So maxmem here should be at most 986 GiB considering all memory boundary
324        alignment constraints with 40 bits (1 TiB) of processor physical bits.
325        """
326        self.vm.add_args('-S', '-cpu', 'Skylake-Server,phys-bits=40',
327                         '-machine', 'q35,cxl=on', '-m',
328                         '512,slots=1,maxmem=987G',
329                         '-display', 'none',
330                         '-device', 'pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1',
331                         '-M', 'cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=1G')
332        self.vm.set_qmp_monitor(enabled=False)
333        self.vm.launch()
334        self.vm.wait()
335        self.assertEqual(self.vm.exitcode(), 1, "QEMU exit code should be 1")
336        self.assertRegex(self.vm.get_log(), r'phys-bits too low')
337
338    def test_phybits_ok_tcg_q35_intel_cxl(self):
339        """
340        :avocado: tags=machine:q35
341        :avocado: tags=arch:x86_64
342
343        Same as above but here we do not reserve any cxl memory window. Hence,
344        with the exact same parameters as above, QEMU should start fine even
345        with cxl enabled.
346        """
347        self.vm.add_args('-S', '-cpu', 'Skylake-Server,phys-bits=40',
348                         '-machine', 'q35,cxl=on', '-m',
349                         '512,slots=1,maxmem=987G',
350                         '-display', 'none',
351                         '-device', 'pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1')
352        self.vm.set_qmp_monitor(enabled=False)
353        self.vm.launch()
354        time.sleep(self.DELAY_Q35_BOOT_SEQUENCE)
355        self.vm.shutdown()
356        self.assertNotRegex(self.vm.get_log(), r'phys-bits too low')
357