Add GICv3BatchEntry typedef and three helper functions for batch register access to KVM ARM64 VGICv3: - kvm_arm_gic_batch_add: Accumulates register operations into a dynamic array - kvm_arm_gic_batch_commit: Submits the batch array to kernel via a single ioctl - kvm_arm_gic_batch_supported: Probes kernel support for the batch interface
These helpers will be used by kvm_arm_gicv3_get and kvm_arm_gicv3_put in subsequent patches to enable efficient batch register access. Signed-off-by: Chuan Zheng <[email protected]> Signed-off-by: Yize Wang <[email protected]> --- hw/intc/arm_gicv3_kvm.c | 95 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 22fcac1668..ea6c8462c7 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -118,6 +118,101 @@ static inline void kvm_gic_line_level_access(GICv3State *s, int irq, int cpu, val, write, &error_abort); } +typedef struct { + uint32_t group; + uint64_t attr; + uint32_t *val; +} GICv3BatchEntry; + +/* Accumulates register operations into a dynamic array. */ +static void kvm_arm_gic_batch_add(GICv3BatchEntry **entries, int *n, + int *capacity, uint32_t group, + uint64_t attr, uint32_t *val) +{ + if (*n >= *capacity) { + *capacity = MAX(*capacity * 2, 256); + *entries = g_renew(GICv3BatchEntry, *entries, *capacity); + } + (*entries)[*n].group = group; + (*entries)[*n].attr = attr; + /* Store the pointer, not the value, to avoid copying data now. */ + (*entries)[*n].val = val; + (*n)++; +} + +/* + * Submit the batched GIC register operations to the kernel via a single ioctl. + * + * Workflow: + * 1. Allocate a kernel-compatible structure array + * (kvm_dev_arm_vgic_batch_entry). + * 2. Convert QEMU's internal format to the kernel's expected format. + * - For WRITE: Copy the actual values from QEMU's buffers into the + * kernel struct. + * - For READ: Only set the register IDs; the kernel will fill in + * the values. + * 3. Perform a single ioctl() to send/receive all data at once. + * 4. For READ: Copy the values returned by the kernel back into QEMU's + * buffers. + */ +static void kvm_arm_gic_batch_commit(int dev_fd, GICv3BatchEntry *entries, + int n, bool write) +{ + struct kvm_dev_arm_vgic_batch_entry *batch; + struct kvm_device_attr attr; + int i, ret; + + if (!n) { + return; + } + + batch = g_new0(struct kvm_dev_arm_vgic_batch_entry, n); + for (i = 0; i < n; i++) { + batch[i].group = entries[i].group; + batch[i].attr = entries[i].attr; + if (write) { + batch[i].val = *entries[i].val; + } + } + + attr.group = KVM_DEV_ARM_VGIC_GRP_BATCH_REGS; + attr.addr = (uint64_t)batch; + attr.attr = n; + + if (write) { + ret = kvm_device_ioctl(dev_fd, KVM_SET_DEVICE_ATTR, &attr); + } else { + ret = kvm_device_ioctl(dev_fd, KVM_GET_DEVICE_ATTR, &attr); + } + + if (ret < 0) { + error_report("KVM_%s_DEVICE_ATTR failed on batch regs: %s", + write ? "SET" : "GET", strerror(-ret)); + abort(); + } + + if (!write) { + for (i = 0; i < n; i++) { + *entries[i].val = batch[i].val; + } + } + + g_free(batch); +} + +/* + * Check if the kernel supports GIC batch register operations. + * Returns: true if the kernel supports the BATCH_REGS group, + * false otherwise. + */ +static bool kvm_arm_gic_batch_supported(int dev_fd) +{ + struct kvm_device_attr attr = { + .group = KVM_DEV_ARM_VGIC_GRP_BATCH_REGS, + }; + return kvm_device_ioctl(dev_fd, KVM_HAS_DEVICE_ATTR, &attr) == 0; +} + /* Loop through each distributor IRQ related register; since bits * corresponding to SPIs and PPIs are RAZ/WI when affinity routing * is enabled, we skip those. -- 2.43.0
