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 addressible 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 accomodate 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 beween 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