hi ,

I used libvirt upstream code version v7.3.0-135-gc6989ed929 and applied the patch. It failed to compile the code with below errors,  can you please check them?

../src/conf/domain_conf.c: In function ‘virDomainIOMMUDefCheckABIStability’:
../src/conf/domain_conf.c:22064:12: error: ‘virDomainIOMMUDef’ {aka ‘struct _virDomainIOMMUDef’} has no member named ‘mem’
22064 |     if (src->mem.max_ram_below_4g != dst->mem.max_ram_below_4g) {
      |            ^~
../src/conf/domain_conf.c:22064:41: error: ‘virDomainIOMMUDef’ {aka ‘struct _virDomainIOMMUDef’} has no member named ‘mem’
22064 |     if (src->mem.max_ram_below_4g != dst->mem.max_ram_below_4g) {
      |                                         ^~
In file included from ../src/conf/domain_conf.c:31:
../src/conf/domain_conf.c:22068:27: error: ‘virDomainIOMMUDef’ {aka ‘struct _virDomainIOMMUDef’} has no member named ‘mem’
22068 |                        dst->mem.max_ram_below_4g,
      |                           ^~
../src/util/virerror.h:177:50: note: in definition of macro ‘virReportError’
  177 |                          __FUNCTION__, __LINE__, __VA_ARGS__)
      |                                                  ^~~~~~~~~~~
../src/conf/domain_conf.c:22069:27: error: ‘virDomainIOMMUDef’ {aka ‘struct _virDomainIOMMUDef’} has no member named ‘mem’
22069 |                        src->mem.max_ram_below_4g);
      |                           ^~
../src/util/virerror.h:177:50: note: in definition of macro ‘virReportError’
  177 |                          __FUNCTION__, __LINE__, __VA_ARGS__)
      |                                                  ^~~~~~~~~~~

Thanks,
Jing Qi

On Thu, May 6, 2021 at 4:29 PM Zhiyong Ye <yezhiyong@bytedance.com> wrote:
The 'below4g' attribute added in 'memory' element can be used to specify
the low memory area, which allows to get a larger PCI I/O window below
4G when reduce it to a smaller value, and when raise value allows legacy
non-PAE guests to have as much memory as possible in the 32bit address
space below 4G. It does not share the 'unit' parameter with the actual
memory size and its unit defaults to "KiB".

Signed-off-by: Zhiyong Ye <yezhiyong@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
Signed-off-by: zhangruien <zhangruien@bytedance.com>
---
 docs/formatdomain.rst                       | 10 ++++++--
 docs/schemas/domaincommon.rng               |  5 ++++
 src/conf/domain_conf.c                      | 15 ++++++++++++
 src/conf/domain_conf.h                      |  3 +++
 src/conf/domain_validate.c                  | 13 ++++++++++
 src/qemu/qemu_command.c                     |  4 ++++
 tests/qemuxml2argvdata/memory-below4g.args  | 29 ++++++++++++++++++++++
 tests/qemuxml2argvdata/memory-below4g.xml   | 26 ++++++++++++++++++++
 tests/qemuxml2argvtest.c                    |  1 +
 tests/qemuxml2xmloutdata/memory-below4g.xml | 37 +++++++++++++++++++++++++++++
 tests/qemuxml2xmltest.c                     |  1 +
 11 files changed, 142 insertions(+), 2 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/memory-below4g.args
 create mode 100644 tests/qemuxml2argvdata/memory-below4g.xml
 create mode 100644 tests/qemuxml2xmloutdata/memory-below4g.xml

diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index fa5c14febc..a71a716f5b 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -940,8 +940,14 @@ Memory Allocation
    `NUMA <#elementsCPU>`__ is configured for the guest the ``memory`` element
    can be omitted. In the case of crash, optional attribute ``dumpCore`` can be
    used to control whether the guest memory should be included in the generated
-   coredump or not (values "on", "off"). ``unit`` :since:`since 0.9.11` ,
-   ``dumpCore`` :since:`since 0.10.2 (QEMU only)`
+   coredump or not (values "on", "off"). Besides, the optional ``below4g``
+   attribute can be used to specify the low memory area, which allows to get a
+   larger PCI I/O window below 4G when reduce it to a smaller value, and when
+   raise value allows legacy non-PAE guests to have as much memory as possible
+   in the 32bit address space below 4G. It does not share the ``unit`` parameter
+   with the actual memory size and its unit defaults to "KiB". ``unit`` :
+   since:`since 0.9.11` , ``dumpCore`` : since:`since 0.10.2 (QEMU only)`,
+   ``below4g`` :since:`since 7.3.0 (QEMU only)`.
 ``maxMemory``
    The run time maximum memory allocation of the guest. The initial memory
    specified by either the ``<memory>`` element or the NUMA cell size
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index a2e5c50c1d..8f2ac1ad33 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -643,6 +643,11 @@
               <ref name="virOnOff"/>
             </attribute>
           </optional>
+          <optional>
+            <attribute name="below4g">
+              <ref name="unsignedLong"/>
+            </attribute>
+          </optional>
         </element>
       </optional>
       <optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 77105e6a07..8573967c4b 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -19239,6 +19239,10 @@ virDomainDefParseMemory(virDomainDef *def,
                              &def->mem.max_memory, false, false) < 0)
         goto error;

+    if (virDomainParseMemory("./memory[1]/@below4g", NULL, ctxt,
+                             &def->mem.max_ram_below_4g, false, true) < 0)
+        goto error;
+
     if (virXPathUInt("string(./maxMemory[1]/@slots)", ctxt, &def->mem.memory_slots) == -2) {
         virReportError(VIR_ERR_XML_ERROR, "%s",
                        _("Failed to parse memory slot count"));
@@ -22374,6 +22378,15 @@ virDomainIOMMUDefCheckABIStability(virDomainIOMMUDef *src,
         return false;
     }

+    if (src->mem.max_ram_below_4g != dst->mem.max_ram_below_4g) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Target domain maximum memory below the 4GiB boundary "
+                         "'%llu' doesn't match source '%llu'"),
+                       dst->mem.max_ram_below_4g,
+                       src->mem.max_ram_below_4g);
+        return false;
+    }
+
     return true;
 }

@@ -28297,6 +28310,8 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def,
     if (def->mem.dump_core)
         virBufferAsprintf(buf, " dumpCore='%s'",
                           virTristateSwitchTypeToString(def->mem.dump_core));
+    if (def->mem.max_ram_below_4g > 0)
+        virBufferAsprintf(buf, " below4g='%llu'", def->mem.max_ram_below_4g);
     virBufferAsprintf(buf, " unit='KiB'>%llu</memory>\n",
                       virDomainDefGetMemoryTotal(def));

diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 95d0516279..d0418eb9ed 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2597,6 +2597,9 @@ struct _virDomainMemtune {
     unsigned long long max_memory; /* in kibibytes */
     unsigned int memory_slots; /* maximum count of RAM memory slots */

+    /* maximum memory below the 4GiB boundary (32bit boundary) */
+    unsigned long long max_ram_below_4g; /* in kibibytes */
+
     bool nosharepages;
     bool locked;
     int dump_core; /* enum virTristateSwitch */
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index 686b9e8d16..afa9e2e821 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -1384,6 +1384,19 @@ virDomainDefMemtuneValidate(const virDomainDef *def)
         }
     }

+    if (mem->max_ram_below_4g &&
+        mem->max_ram_below_4g < 1024) {
+        virReportError(VIR_ERR_XML_DETAIL, "%s",
+                       _("maximum memory size below the 4GiB boundary must be "
+                         "greater than or equal to 1MiB"));
+        return -1;
+    } else if (mem->max_ram_below_4g > 4 * 1024 * 1024) {
+        virReportError(VIR_ERR_XML_DETAIL, "%s",
+                       _("maximum memory size below the 4GiB boundary must be "
+                         "less than or equal to 4GiB"));
+        return -1;
+    }
+
     return 0;
 }

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index ca2265cc90..97c65a6bf1 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -6849,6 +6849,10 @@ qemuBuildMachineCommandLine(virCommand *cmd,
                           cfg->dumpGuestCore ? "on" : "off");
     }

+    if (def->mem.max_ram_below_4g > 0)
+        virBufferAsprintf(&buf, ",max-ram-below-4g=%llu",
+                          def->mem.max_ram_below_4g * 1024);
+
     if (def->mem.nosharepages)
         virBufferAddLit(&buf, ",mem-merge=off");

diff --git a/tests/qemuxml2argvdata/memory-below4g.args b/tests/qemuxml2argvdata/memory-below4g.args
new file mode 100644
index 0000000000..f55386a2a2
--- /dev/null
+++ b/tests/qemuxml2argvdata/memory-below4g.args
@@ -0,0 +1,29 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/tmp/lib/domain--1-QEMUGuest1 \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \
+XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \
+XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-i386 \
+-name QEMUGuest1 \
+-S \
+-machine pc,accel=tcg,usb=off,dump-guest-core=off,max-ram-below-4g=112197632 \
+-m 214 \
+-realtime mlock=off \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server=on,wait=off \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-no-acpi \
+-usb \
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \
+-device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvdata/memory-below4g.xml b/tests/qemuxml2argvdata/memory-below4g.xml
new file mode 100644
index 0000000000..a843ef72a2
--- /dev/null
+++ b/tests/qemuxml2argvdata/memory-below4g.xml
@@ -0,0 +1,26 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory below4g='109568' unit='MiB'>214</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-i386</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <controller type='usb' index='0'/>
+    <controller type='ide' index='0'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index a9dafe226e..131ebde9e4 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1055,6 +1055,7 @@ mymain(void)
     driver.config->dumpGuestCore = true;
     DO_TEST("machine-core-off", NONE);
     driver.config->dumpGuestCore = false;
+    DO_TEST("memory-below4g", NONE);
     DO_TEST("machine-smm-opt",
             QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE,
             QEMU_CAPS_DEVICE_PCI_BRIDGE,
diff --git a/tests/qemuxml2xmloutdata/memory-below4g.xml b/tests/qemuxml2xmloutdata/memory-below4g.xml
new file mode 100644
index 0000000000..44f58fc93b
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/memory-below4g.xml
@@ -0,0 +1,37 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory below4g='109568' unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-i386</emulator>
+    <disk type='block' device='disk'>
+      <driver name='qemu' type='raw'/>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <controller type='usb' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='ide' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <audio id='1' type='none'/>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </memballoon>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 7af6f90aee..7a139489c3 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -220,6 +220,7 @@ mymain(void)
     DO_TEST_CAPS_LATEST("genid-auto");
     DO_TEST("machine-core-on", NONE);
     DO_TEST("machine-core-off", NONE);
+    DO_TEST("memory-below4g", NONE);
     DO_TEST("machine-loadparm-multiple-disks-nets-s390", NONE);
     DO_TEST("default-kvm-host-arch", NONE);
     DO_TEST("default-qemu-host-arch", NONE);
--
2.11.0



--
Thanks & Regards,
Jing,Qi