From patchwork Fri Aug 23 20:10:24 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoffer Dall X-Patchwork-Id: 19516 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ve0-f198.google.com (mail-ve0-f198.google.com [209.85.128.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 078FB25BDE for ; Fri, 23 Aug 2013 20:10:46 +0000 (UTC) Received: by mail-ve0-f198.google.com with SMTP id 15sf861504vea.1 for ; Fri, 23 Aug 2013 13:10:45 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:x-gm-message-state:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=MmglWh7Igyc6bHrOAProQ0vqyEbD+3gHBiLZwguvkEU=; b=QfdthUWut4mInrQ2ZaTwUi6/X0hAfH2DQaCAB5uRTfkRqnG6OHylsSxrt+Q88hfq6V 05yCsUjOzjSXL3JNuReKTqkFy3wc0GKLcwepWZYfYSuBeTSIYi0hDD0+CBmrJZnYXI1A lMDdUTIsVaVQCh089hVh8B9M8OsqfpdK/0O0J9qHCLH/J4gy6k/Qi2n29MLG1P0JHi07 qV4pCaj6TXtb12v/HrJQ9CDkGIUIx2l1SZnI/wxjU4+9YpA5qRjRZIq1w/NHBofqxjFB JbNx0rg2WjE5WAUcFCU0ZzkkbHv/RcscCDi/icS72S+q549XbcRTHHr+AyQt2kC6ApbN mXyQ== X-Received: by 10.236.24.195 with SMTP id x43mr506255yhx.3.1377288645731; Fri, 23 Aug 2013 13:10:45 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.58.244 with SMTP id u20ls1596307qeq.74.gmail; Fri, 23 Aug 2013 13:10:45 -0700 (PDT) X-Received: by 10.52.103.101 with SMTP id fv5mr782251vdb.31.1377288645634; Fri, 23 Aug 2013 13:10:45 -0700 (PDT) Received: from mail-vb0-f52.google.com (mail-vb0-f52.google.com [209.85.212.52]) by mx.google.com with ESMTPS id dp3si468122vcb.96.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 23 Aug 2013 13:10:45 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.212.52 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.212.52; Received: by mail-vb0-f52.google.com with SMTP id f12so720324vbg.25 for ; Fri, 23 Aug 2013 13:10:45 -0700 (PDT) X-Gm-Message-State: ALoCoQkf4Z3vx5tWG6FtNwqV/V0paZfoQy09uT6/EfApT3S9xF0u78bEVC4LuFMELn3EYhybiByM X-Received: by 10.220.166.19 with SMTP id k19mr23021vcy.42.1377288645525; Fri, 23 Aug 2013 13:10:45 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp113360vcz; Fri, 23 Aug 2013 13:10:44 -0700 (PDT) X-Received: by 10.66.233.195 with SMTP id ty3mr806150pac.70.1377288643981; Fri, 23 Aug 2013 13:10:43 -0700 (PDT) Received: from mail-pa0-f43.google.com (mail-pa0-f43.google.com [209.85.220.43]) by mx.google.com with ESMTPS id or6si1335044pac.160.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 23 Aug 2013 13:10:43 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.220.43 is neither permitted nor denied by best guess record for domain of christoffer.dall@linaro.org) client-ip=209.85.220.43; Received: by mail-pa0-f43.google.com with SMTP id hz10so1081352pad.2 for ; Fri, 23 Aug 2013 13:10:43 -0700 (PDT) X-Received: by 10.68.12.97 with SMTP id x1mr1411289pbb.150.1377288643445; Fri, 23 Aug 2013 13:10:43 -0700 (PDT) Received: from localhost.localdomain (c-67-169-183-77.hsd1.ca.comcast.net. [67.169.183.77]) by mx.google.com with ESMTPSA id py4sm1590135pbc.14.1969.12.31.16.00.00 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 23 Aug 2013 13:10:42 -0700 (PDT) From: Christoffer Dall To: qemu-devel@nongnu.org Cc: linaro-kernel@lists.linaro.org, patches@linaro.org, kvmarm@lists.cs.columbia.edu, Christoffer Dall Subject: [PATCH 5/5] hw: arm_gic_kvm: Add KVM VGIC save/restore logic Date: Fri, 23 Aug 2013 13:10:24 -0700 Message-Id: <1377288624-7418-6-git-send-email-christoffer.dall@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1377288624-7418-1-git-send-email-christoffer.dall@linaro.org> References: <1377288624-7418-1-git-send-email-christoffer.dall@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: christoffer.dall@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.212.52 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Save and restore the ARM KVM VGIC state from the kernel. We rely on QEMU to marshal the GICState data structure and therefore simply synchronize the kernel state with the QEMU emulated state in both directions. We take some care on the restore path to check the VGIC has been configured with enough IRQs and CPU interfaces that we can properly restore the state, and for separate set/clear registers we first fully clear the registers and then set the required bits. Signed-off-by: Christoffer Dall --- hw/intc/arm_gic_common.c | 2 + hw/intc/arm_gic_kvm.c | 418 ++++++++++++++++++++++++++++++++++++++++++- hw/intc/gic_internal.h | 1 + include/migration/vmstate.h | 6 + 4 files changed, 425 insertions(+), 2 deletions(-) diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index a50ded2..f39bdc1 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -77,6 +77,8 @@ static const VMStateDescription vmstate_gic = { VMSTATE_UINT16_ARRAY(running_priority, GICState, NCPU), VMSTATE_UINT16_ARRAY(current_pending, GICState, NCPU), VMSTATE_UINT8_2DARRAY(binary_point, GICState, 2, NCPU), + VMSTATE_UINT32_2DARRAY(active_prio, GICState, 4, NCPU), + VMSTATE_UINT32(num_irq, GICState), VMSTATE_END_OF_LIST() } }; diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 9f0a852..9785281 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -23,6 +23,15 @@ #include "kvm_arm.h" #include "gic_internal.h" +//#define DEBUG_GIC_KVM + +#ifdef DEBUG_GIC_KVM +#define DPRINTF(fmt, ...) \ +do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) do {} while(0) +#endif + #define TYPE_KVM_ARM_GIC "kvm-arm-gic" #define KVM_ARM_GIC(obj) \ OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC) @@ -73,14 +82,419 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level) kvm_set_irq(kvm_state, kvm_irq, !!level); } +static bool kvm_arm_gic_can_save_restore(GICState *s) +{ + KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s); + return kgc->dev_fd >= 0; +} + +static void kvm_arm_gic_reg_access(GICState *s, int group, int offset, + int cpu, uint32_t *val, bool write) +{ + KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s); + struct kvm_device_attr attr; + int type; + + cpu = cpu & 0xff; + + attr.flags = 0; + attr.group = group; + attr.attr = (((uint64_t)cpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) & + KVM_DEV_ARM_VGIC_CPUID_MASK) | + (((uint64_t)offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) & + KVM_DEV_ARM_VGIC_OFFSET_MASK); + attr.addr = (uint64_t)(long)val; + + if (write) { + type = KVM_SET_DEVICE_ATTR; + } else { + type = KVM_GET_DEVICE_ATTR; + } + + if (kvm_device_ioctl(kgc->dev_fd, type, &attr) < 0) { + fprintf(stderr, "KVM_{SET/GET}_DEVICE_ATTR failed: %s\n", + strerror(errno)); + abort(); + } +} + +static void kvm_arm_gic_dist_reg_access(GICState *s, int offset, int cpu, + uint32_t *val, bool write) +{ + kvm_arm_gic_reg_access(s, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, + offset, cpu, val, write); +} + +static void kvm_arm_gic_cpu_reg_access(GICState *s, int offset, int cpu, + uint32_t *val, bool write) +{ + kvm_arm_gic_reg_access(s, KVM_DEV_ARM_VGIC_GRP_CPU_REGS, + offset, cpu, val, write); +} + +#define for_each_irq_reg(_ctr, _max_irq, _field_width) \ + for (_ctr = 0; _ctr < ((_max_irq) / (32 / (_field_width))); _ctr++) + +/* + * Translate from the in-kernel field for an IRQ value to/from the qemu + * representation. + */ +typedef void (*vgic_translate_fn)(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel); + +/* synthetic translate function used for clear/set registers to completely + * clear a setting using a clear-register before setting the remaing bits + * using a set-register */ +static void translate_clear(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + if (to_kernel) { + *field = ~0; + } else { + /* does not make sense: qemu model doesn't use set/clear regs */ + abort(); + } +} + +static void translate_enabled(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; + + if (to_kernel) { + *field = GIC_TEST_ENABLED(irq, cm); + } else { + if (*field & 1) { + GIC_SET_ENABLED(irq, cm); + } + } +} + +static void translate_pending(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; + + if (to_kernel) { + *field = GIC_TEST_PENDING(irq, cm); + } else { + if (*field & 1) { + GIC_SET_PENDING(irq, cm); + /* TODO: Capture is level-line is held high in the kernel */ + } + } +} + +static void translate_active(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; + + if (to_kernel) { + *field = GIC_TEST_ACTIVE(irq, cm); + } else { + if (*field & 1) { + GIC_SET_ACTIVE(irq, cm); + } + } +} + +static void translate_trigger(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + if (to_kernel) { + *field = (GIC_TEST_TRIGGER(irq)) ? 0x2 : 0x0; + } else { + if (*field & 0x2) { + GIC_SET_TRIGGER(irq); + } + } +} + +static void translate_priority(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + if (to_kernel) { + *field = GIC_GET_PRIORITY(irq, cpu) & 0xff; + } else { + GIC_SET_PRIORITY(irq, cpu, *field & 0xff); + } +} + +static void translate_targets(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + if (to_kernel) { + *field = s->irq_target[irq] & 0xff; + } else { + s->irq_target[irq] = *field & 0xff; + } +} + +static void translate_sgisource(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + if (to_kernel) { + *field = s->sgi_source[irq][cpu] & 0xff; + } else { + s->sgi_source[irq][cpu] = *field & 0xff; + } +} + +/* Read a register group from the kernel VGIC */ +static void kvm_arm_gic_dist_readr(GICState *s, uint32_t offset, int width, + int maxirq, vgic_translate_fn translate_fn) +{ + uint32_t reg; + int i; + int j; + int irq; + int cpu; + int regsz = 32 / width; /* irqs per kernel register */ + uint32_t field; + + for_each_irq_reg(i, maxirq, width) { + irq = i * regsz; + cpu = 0; + while ((cpu < s->num_cpu && irq < GIC_INTERNAL) || cpu == 0) { + kvm_arm_gic_dist_reg_access(s, offset, cpu, ®, false); + for (j = 0; j < regsz; j++) { + field = reg >> (j * width) & ((1 << width) - 1); + translate_fn(s, irq + j, cpu, &field, false); + } + + cpu++; + } + offset += 4; + } +} + +/* Write a register group to the kernel VGIC */ +static void kvm_arm_gic_dist_writer(GICState *s, uint32_t offset, int width, + int maxirq, vgic_translate_fn translate_fn) +{ + uint32_t reg; + int i; + int j; + int irq; + int cpu; + int regsz = 32 / width; /* irqs per kernel register */ + uint32_t field; + + for_each_irq_reg(i, maxirq, width) { + irq = i * regsz; + cpu = 0; + while ((cpu < s->num_cpu && irq < GIC_INTERNAL) || cpu == 0) { + reg = 0; + for (j = 0; j < regsz; j++) { + translate_fn(s, irq + j, cpu, &field, true); + reg |= (field & ((1 << width) - 1)) << (j * width); + } + kvm_arm_gic_dist_reg_access(s, offset, cpu, ®, true); + + cpu++; + } + offset += 4; + } +} + static void kvm_arm_gic_put(GICState *s) { - /* TODO: there isn't currently a kernel interface to set the GIC state */ + uint32_t reg; + int i; + int cpu; + int num_cpu; + int num_irq; + + if (!kvm_arm_gic_can_save_restore(s)) { + DPRINTF("Cannot put kernel gic state, no kernel interface"); + return; + } + + /* Note: We do the restore in a slightly different order than the save + * (where the order doesn't matter and is simply ordered according to the + * register offset values */ + + /***************************************************************** + * Distributor State + */ + + /* s->enabled -> GICD_CTLR */ + reg = s->enabled; + kvm_arm_gic_dist_reg_access(s, 0x0, 0, ®, true); + + /* Sanity checking on GICD_TYPER and s->num_irq, s->num_cpu */ + kvm_arm_gic_dist_reg_access(s, 0x4, 0, ®, false); + num_irq = ((reg & 0x1f) + 1) * 32; + num_cpu = ((reg & 0xe0) >> 5) + 1; + + if (num_irq < s->num_irq) { + fprintf(stderr, "Restoring %u IRQs, but kernel supports max %d\n", + s->num_irq, num_irq); + abort(); + } else if (num_cpu != s->num_cpu ) { + fprintf(stderr, "Restoring %u CPU interfaces, kernel only has %d\n", + s->num_cpu, num_cpu); + /* Did we not create the VCPUs in the kernel yet? */ + abort(); + } + + /* TODO: Consider checking compatibility with the IIDR ? */ + + /* irq_state[n].enabled -> GICD_ISENABLERn */ + kvm_arm_gic_dist_writer(s, 0x180, 1, s->num_irq, translate_clear); + kvm_arm_gic_dist_writer(s, 0x100, 1, s->num_irq, translate_enabled); + + /* s->irq_target[irq] -> GICD_ITARGETSRn + * (restore targets before pending to ensure the pending state is set on + * the appropriate CPU interfaces in the kernel) */ + kvm_arm_gic_dist_writer(s, 0x800, 8, s->num_irq, translate_targets); + + /* irq_state[n].pending + irq_state[n].level -> GICD_ISPENDRn */ + kvm_arm_gic_dist_writer(s, 0x280, 1, s->num_irq, translate_clear); + kvm_arm_gic_dist_writer(s, 0x200, 1, s->num_irq, translate_pending); + + /* irq_state[n].active -> GICD_ISACTIVERn */ + kvm_arm_gic_dist_writer(s, 0x380, 1, s->num_irq, translate_clear); + kvm_arm_gic_dist_writer(s, 0x300, 1, s->num_irq, translate_active); + + /* irq_state[n].trigger -> GICD_ICFRn */ + kvm_arm_gic_dist_writer(s, 0xc00, 2, s->num_irq, translate_trigger); + + /* s->priorityX[irq] -> ICD_IPRIORITYRn */ + kvm_arm_gic_dist_writer(s, 0x400, 8, s->num_irq, translate_priority); + + /* s->sgi_source -> ICD_CPENDSGIRn */ + kvm_arm_gic_dist_writer(s, 0xf10, 8, GIC_NR_SGIS, translate_clear); + kvm_arm_gic_dist_writer(s, 0xf20, 8, GIC_NR_SGIS, translate_sgisource); + + + /***************************************************************** + * CPU Interface(s) State + */ + + for (cpu = 0; cpu < s->num_cpu; cpu++) { + /* s->cpu_enabled[cpu] -> GICC_CTLR */ + reg = s->cpu_enabled[cpu]; + kvm_arm_gic_cpu_reg_access(s, 0x00, cpu, ®, true); + + /* s->priority_mask[cpu] -> GICC_PMR */ + reg = (s->priority_mask[cpu] & 0xff); + kvm_arm_gic_cpu_reg_access(s, 0x04, cpu, ®, true); + + /* s->binary_point[cpu][0] -> GICC_BPR */ + reg = (s->binary_point[0][cpu] & 0x7); + kvm_arm_gic_cpu_reg_access(s, 0x08, cpu, ®, true); + + /* s->binary_point[cpu][1] -> GICC_ABPR */ + reg = (s->binary_point[1][cpu] & 0x7); + kvm_arm_gic_cpu_reg_access(s, 0x1c, cpu, ®, true); + + /* s->active_prio[n][cpu] -> GICC_APRn */ + for (i = 0; i < 4; i++) { + reg = s->active_prio[i][cpu]; + kvm_arm_gic_cpu_reg_access(s, 0xd0 + i * 4, cpu, ®, true); + } + } } static void kvm_arm_gic_get(GICState *s) { - /* TODO: there isn't currently a kernel interface to get the GIC state */ + uint32_t reg; + int i; + int cpu; + + if (!kvm_arm_gic_can_save_restore(s)) { + DPRINTF("Cannot get kernel gic state, no kernel interface"); + return; + } + + /***************************************************************** + * Distributor State + */ + + /* GICD_CTLR -> s->enabled */ + kvm_arm_gic_dist_reg_access(s, 0x0, 0, ®, false); + s->enabled = reg & 1; + + /* Sanity checking on GICD_TYPER -> s->num_irq, s->num_cpu */ + kvm_arm_gic_dist_reg_access(s, 0x4, 0, ®, false); + s->num_irq = ((reg & 0x1f) + 1) * 32; + s->num_cpu = ((reg & 0xe0) >> 5) + 1; + + if (s->num_irq > GIC_MAXIRQ) { + fprintf(stderr, "Too many IRQs reported from the kernel: %d\n", + s->num_irq); + abort(); + } + + /* GICD_IIDR -> ? */ + kvm_arm_gic_dist_reg_access(s, 0x8, 0, ®, false); + + /* Verify no GROUP 1 interrupts configured in the kernel */ + for_each_irq_reg(i, s->num_irq, 1) { + kvm_arm_gic_dist_reg_access(s, 0x80 + (i * 4), 0, ®, false); + if (reg != 0) { + fprintf(stderr, "Unsupported GICD_IGROUPRn value: %08x\n", + reg); + abort(); + } + } + + /* Clear all the IRQ settings */ + for (i = 0; i < s->num_irq; i++) { + memset(&s->irq_state[i], 0, sizeof(s->irq_state[0])); + } + + /* GICD_ISENABLERn -> irq_state[n].enabled */ + kvm_arm_gic_dist_readr(s, 0x100, 1, s->num_irq, translate_enabled); + + /* GICD_ISPENDRn -> irq_state[n].pending + irq_state[n].level */ + kvm_arm_gic_dist_readr(s, 0x200, 1, s->num_irq, translate_pending); + + /* GICD_ISACTIVERn -> irq_state[n].active */ + kvm_arm_gic_dist_readr(s, 0x300, 1, s->num_irq, translate_active); + + /* GICD_ICFRn -> irq_state[n].trigger */ + kvm_arm_gic_dist_readr(s, 0xc00, 2, s->num_irq, translate_trigger); + + /* GICD_IPRIORITYRn -> s->priorityX[irq] */ + kvm_arm_gic_dist_readr(s, 0x400, 8, s->num_irq, translate_priority); + + /* GICD_ITARGETSRn -> s->irq_target[irq] */ + kvm_arm_gic_dist_readr(s, 0x800, 8, s->num_irq, translate_targets); + + /* GICD_CPENDSGIRn -> s->sgi_source */ + kvm_arm_gic_dist_readr(s, 0xf10, 8, GIC_NR_SGIS, translate_sgisource); + + + /***************************************************************** + * CPU Interface(s) State + */ + + for (cpu = 0; cpu < s->num_cpu; cpu++) { + /* GICC_CTLR -> s->cpu_enabled[cpu] */ + kvm_arm_gic_cpu_reg_access(s, 0x00, cpu, ®, false); + s->cpu_enabled[cpu] = (reg & 1); + + /* GICC_PMR -> s->priority_mask[cpu] */ + kvm_arm_gic_cpu_reg_access(s, 0x04, cpu, ®, false); + s->priority_mask[cpu] = (reg & 0xff); + + /* GICC_BPR -> s->binary_point[cpu][0] */ + kvm_arm_gic_cpu_reg_access(s, 0x08, cpu, ®, false); + s->binary_point[0][cpu] = (reg & 0x7); + + /* GICC_ABPR -> s->binary_point[cpu][1] */ + kvm_arm_gic_cpu_reg_access(s, 0x1c, cpu, ®, false); + s->binary_point[1][cpu] = (reg & 0x7); + + /* GICC_APRn -> s->active_prio[n][cpu] */ + for (i = 0; i < 4; i++) { + kvm_arm_gic_cpu_reg_access(s, 0xd0 + i * 4, cpu, ®, false); + s->active_prio[i][cpu] = reg; + } + } } static void kvm_arm_gic_reset(DeviceState *dev) diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index 424a41f..9771163 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -100,6 +100,7 @@ typedef struct GICState { /* these registers are mainly used for save/restore of KVM state */ uint8_t binary_point[2][NCPU]; /* [0]: group 0, [1]: group 1 */ + uint32_t active_prio[4][NCPU]; /* implementation defined layout */ uint32_t num_cpu; diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 1c31b5d..e5538c7 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -633,9 +633,15 @@ extern const VMStateInfo vmstate_info_bitmap; #define VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v) \ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint32, uint32_t) +#define VMSTATE_UINT32_2DARRAY_V(_f, _s, _n1, _n2, _v) \ + VMSTATE_2DARRAY(_f, _s, _n1, _n2, _v, vmstate_info_uint32, uint32_t) + #define VMSTATE_UINT32_ARRAY(_f, _s, _n) \ VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0) +#define VMSTATE_UINT32_2DARRAY(_f, _s, _n1, _n2) \ + VMSTATE_UINT32_2DARRAY_V(_f, _s, _n1, _n2, 0) + #define VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v) \ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint64, uint64_t)