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