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