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