From 1d345354fcc0682e1e054863a6118a80f4ad72f0 Mon Sep 17 00:00:00 2001
From: xiangwencheng <xiangwencheng@lanxincomputing.com>
Date: Thu, 4 Sep 2025 16:11:26 +0800
Subject: [PATCH v3 1/3] qemu: support riscv-aia feature for RISC-V KVM

riscv-aia feature was introduced in qemu-8.2 to specify the
KVM AIA mode. The "riscv-aia" parameter is passed along with
-accel in QEMU command-line.
1) "riscv-aia=emul": IMSIC is emulated by hypervisor
2) "riscv-aia=hwaccel": use hardware guest IMSIC
3) "riscv-aia=auto": use the hardware guest IMSICs whenever available
otherwise we fallback to software emulation.

This patch add the corresponding feature named 'riscv-aia'.

Signed-off-by: BillXiang <xiangwencheng@lanxincomputing.com>
---
 src/conf/domain_conf.c            | 28 +++++++++++++++++++++++++++-
 src/conf/domain_conf.h            | 11 +++++++++++
 src/conf/schemas/domaincommon.rng | 12 ++++++++++++
 src/libvirt_private.syms          |  2 ++
 src/qemu/qemu_command.c           | 13 ++++++++++---
 5 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 7766e302ec..a9f1161133 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -224,6 +224,14 @@ VIR_ENUM_IMPL(virDomainKVM,
               "poll-control",
               "pv-ipi",
               "dirty-ring",
+              "riscv-aia",
+);
+
+VIR_ENUM_IMPL(virDomainKVMRiscvAIAMode,
+              VIR_DOMAIN_KVM_TISCV_AIA_MODE_LAST,
+              "auto",
+              "emul",
+              "hwaccel",
 );
 
 VIR_ENUM_IMPL(virDomainXen,
@@ -17183,6 +17191,15 @@ virDomainFeaturesKVMDefParse(virDomainDef *def,
                 return -1;
             }
         }
+
+        if (feature == VIR_DOMAIN_KVM_RISCV_AIA &&
+            value == VIR_TRISTATE_SWITCH_ON) {
+            if (virXMLPropEnum(feat, "mode",
+                            virDomainKVMRiscvAIAModeTypeFromString,
+                            VIR_XML_PROP_REQUIRED,
+                            &def->kvm_features->kvm_riscv_aia_mode) < 0)
+                return -1;
+        }
     }
 
     def->features[VIR_DOMAIN_FEATURE_KVM] = VIR_TRISTATE_SWITCH_ON;
@@ -21697,6 +21714,7 @@ virDomainDefFeaturesCheckABIStability(virDomainDef *src,
             case VIR_DOMAIN_KVM_POLLCONTROL:
             case VIR_DOMAIN_KVM_PVIPI:
             case VIR_DOMAIN_KVM_DIRTY_RING:
+            case VIR_DOMAIN_KVM_RISCV_AIA:
                 if (src->kvm_features->features[i] != dst->kvm_features->features[i]) {
                     virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                    _("State of KVM feature '%1$s' differs: source: '%2$s', destination: '%3$s'"),
@@ -28752,7 +28770,15 @@ virDomainDefFormatFeatures(virBuffer *buf,
                         }
                     }
                     break;
-
+                case VIR_DOMAIN_KVM_RISCV_AIA:
+                    if (def->kvm_features->features[j] != VIR_TRISTATE_SWITCH_ABSENT) {
+                        virBufferAsprintf(&childBuf, "<%s state='%s'",
+                                          virDomainKVMTypeToString(j),
+                                          virTristateSwitchTypeToString(def->kvm_features->features[j]));
+                        virBufferAsprintf(&childBuf, " mode='%s'/>\n",
+                                            virDomainKVMRiscvAIAModeTypeToString(def->kvm_features->kvm_riscv_aia_mode));
+                    }
+                    break;
                 case VIR_DOMAIN_KVM_LAST:
                     break;
                 }
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index eca820892e..0250b3db49 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2270,10 +2270,20 @@ typedef enum {
     VIR_DOMAIN_KVM_POLLCONTROL,
     VIR_DOMAIN_KVM_PVIPI,
     VIR_DOMAIN_KVM_DIRTY_RING,
+    VIR_DOMAIN_KVM_RISCV_AIA,
 
     VIR_DOMAIN_KVM_LAST
 } virDomainKVM;
 
+typedef enum {
+    VIR_DOMAIN_KVM_TISCV_AIA_MODE_AUTO = 0,
+    VIR_DOMAIN_KVM_TISCV_AIA_MODE_EMUL,
+    VIR_DOMAIN_KVM_TISCV_AIA_MODE_HWACCEL,
+
+    VIR_DOMAIN_KVM_TISCV_AIA_MODE_LAST
+} virDomainKVMRiscvAIAMode;
+VIR_ENUM_DECL(virDomainKVMRiscvAIAMode);
+
 typedef enum {
     VIR_DOMAIN_MSRS_UNKNOWN = 0,
 
@@ -2476,6 +2486,7 @@ struct _virDomainFeatureKVM {
     int features[VIR_DOMAIN_KVM_LAST];
 
     unsigned int dirty_ring_size; /* size of dirty ring for each vCPU, no units */
+    virDomainKVMRiscvAIAMode kvm_riscv_aia_mode;
 };
 
 typedef struct _virDomainFeatureTCG virDomainFeatureTCG;
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index e369fb6e81..02771a6b7b 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -8192,6 +8192,18 @@
             </optional>
           </element>
         </optional>
+        <optional>
+          <element name="riscv-aia">
+            <ref name="featurestate"/>
+            <optional>
+              <attribute name="mode">
+                <data type="string">
+                  <param name="pattern">(auto|emul|hwaccel)</param>
+                </data>
+              </attribute>
+            </optional>
+          </element>
+        </optional>
       </interleave>
     </element>
   </define>
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index b846011f0f..f540bdbd5b 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -501,6 +501,8 @@ virDomainIOThreadIDDel;
 virDomainIOThreadIDFind;
 virDomainKeyWrapCipherNameTypeFromString;
 virDomainKeyWrapCipherNameTypeToString;
+virDomainKVMRiscvAIAModeTypeFromString;
+virDomainKVMRiscvAIAModeTypeToString;
 virDomainLaunchSecurityTypeFromString;
 virDomainLaunchSecurityTypeToString;
 virDomainLeaseDefFree;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index e8de386f30..9f34b5a37d 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -6679,6 +6679,9 @@ qemuBuildCpuCommandLine(virCommand *cmd,
 
             case VIR_DOMAIN_KVM_DIRTY_RING:
                 break;
+            
+            case VIR_DOMAIN_KVM_RISCV_AIA:
+                break;
 
             case VIR_DOMAIN_KVM_LAST:
                 break;
@@ -7314,9 +7317,13 @@ qemuBuildAccelCommandLine(virCommand *cmd,
          * not that either kvm or tcg can be specified by libvirt
          * so do not worry about the conflict of specifying both
          * */
-        if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON &&
-            def->kvm_features->features[VIR_DOMAIN_KVM_DIRTY_RING] == VIR_TRISTATE_SWITCH_ON) {
-            virBufferAsprintf(&buf, ",dirty-ring-size=%d", def->kvm_features->dirty_ring_size);
+        if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) {
+            if (def->kvm_features->features[VIR_DOMAIN_KVM_DIRTY_RING] == VIR_TRISTATE_SWITCH_ON) {
+                virBufferAsprintf(&buf, ",dirty-ring-size=%d", def->kvm_features->dirty_ring_size);
+            }
+            if (def->kvm_features->features[VIR_DOMAIN_KVM_RISCV_AIA] == VIR_TRISTATE_SWITCH_ON) {
+                virBufferAsprintf(&buf, ",riscv-aia=%s", virDomainKVMRiscvAIAModeTypeToString(def->kvm_features->kvm_riscv_aia_mode));
+            }
         }
         break;
 
-- 
2.34.1

