From patchwork Tue Feb 18 01:45:21 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoffer Dall X-Patchwork-Id: 24812 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-oa0-f69.google.com (mail-oa0-f69.google.com [209.85.219.69]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 91BE120143 for ; Tue, 18 Feb 2014 01:46:23 +0000 (UTC) Received: by mail-oa0-f69.google.com with SMTP id h16sf67292634oag.4 for ; Mon, 17 Feb 2014 17:46:21 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:date :message-id:cc:subject:precedence:list-id:list-unsubscribe :list-archive:list-post:list-help:list-subscribe:errors-to:sender :x-original-sender:x-original-authentication-results:mailing-list; bh=umO08hg+FCfywS/L/AaFEqHdR9PWDTiNGNBGQi5DIYU=; b=dfjkUXBaDnQ0VRxz1Fq6K/sBr2UTwrAqK4FXb8RR5ZJZ/FACk6wByVvfRvtiIShJDs v/4kUZEpSOzz2Pte1Pizqmi2IbqFRIXvZn8j9iDXdrqUEfYq561cgWm2RdtirBQ42fyz zAKjcDGx79mWvpWfbTulK9LQJF3N7AR8qVsa8r/w6EFR3JWrNCPDSkxbT8YHdmaF/Rsv QOPARx445nf+5h/5LmT6h1RivDSnJZ0J/YBybL9FTIMMwy5MQlaE2IA3DSBLK+AtWBFf f04i+6Gq2rMNwz4FsKzqQnt44bG7jq/Gj2v2fBZfwypPjxktLd9JxRh/2JdAnijxhOuQ qFrg== X-Gm-Message-State: ALoCoQnOMtKtGdkE9f7j7WSZ0ah9ub4uvtViVItSyyhktPxOIC4F4SpgVMc9HoYQR8469TcCXOY7 X-Received: by 10.182.111.227 with SMTP id il3mr11988679obb.41.1392687981403; Mon, 17 Feb 2014 17:46:21 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.89.136 with SMTP id v8ls1176999qgd.17.gmail; Mon, 17 Feb 2014 17:46:21 -0800 (PST) X-Received: by 10.52.183.106 with SMTP id el10mr65963vdc.73.1392687981266; Mon, 17 Feb 2014 17:46:21 -0800 (PST) Received: from mail-vc0-f169.google.com (mail-vc0-f169.google.com [209.85.220.169]) by mx.google.com with ESMTPS id n17si5034993vcq.60.2014.02.17.17.46.21 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 17 Feb 2014 17:46:21 -0800 (PST) Received-SPF: neutral (google.com: 209.85.220.169 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.169; Received: by mail-vc0-f169.google.com with SMTP id hq11so12775574vcb.0 for ; Mon, 17 Feb 2014 17:46:21 -0800 (PST) X-Received: by 10.221.40.10 with SMTP id to10mr14775610vcb.22.1392687981126; Mon, 17 Feb 2014 17:46:21 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.174.196 with SMTP id u4csp180213vcz; Mon, 17 Feb 2014 17:46:20 -0800 (PST) X-Received: by 10.140.108.246 with SMTP id j109mr37161638qgf.7.1392687980493; Mon, 17 Feb 2014 17:46:20 -0800 (PST) Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id 8si9505091qak.178.2014.02.17.17.46.20 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Mon, 17 Feb 2014 17:46:20 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Received: from localhost ([::1]:45608 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WFZlM-0007i1-40 for patch@linaro.org; Mon, 17 Feb 2014 20:46:20 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35956) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WFZki-0007Ll-Ez for qemu-devel@nongnu.org; Mon, 17 Feb 2014 20:45:46 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WFZkY-0006zD-Fu for qemu-devel@nongnu.org; Mon, 17 Feb 2014 20:45:40 -0500 Received: from mail-pa0-f48.google.com ([209.85.220.48]:35569) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WFZkY-0006z5-61 for qemu-devel@nongnu.org; Mon, 17 Feb 2014 20:45:30 -0500 Received: by mail-pa0-f48.google.com with SMTP id kx10so15976322pab.7 for ; Mon, 17 Feb 2014 17:45:29 -0800 (PST) X-Received: by 10.66.232.68 with SMTP id tm4mr29544574pac.114.1392687929415; Mon, 17 Feb 2014 17:45:29 -0800 (PST) Received: from localhost.localdomain (c-67-169-181-221.hsd1.ca.comcast.net. [67.169.181.221]) by mx.google.com with ESMTPSA id e3sm50168587pbc.17.2014.02.17.17.45.26 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 17 Feb 2014 17:45:27 -0800 (PST) From: Christoffer Dall To: qemu-devel@nongnu.org Date: Mon, 17 Feb 2014 17:45:21 -0800 Message-Id: <1392687921-26921-1-git-send-email-christoffer.dall@linaro.org> X-Mailer: git-send-email 1.8.5.2 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.85.220.48 Cc: kvmarm@lists.cs.columbia.edu, Christoffer Dall Subject: [Qemu-devel] [PATCH v7] hw: arm_gic_kvm: Add KVM VGIC save/restore logic X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: qemu-devel-bounces+patch=linaro.org@nongnu.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.220.169 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 Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 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. Reviewed-by: Peter Maydell Signed-off-by: Christoffer Dall --- This is the last patch in the vgic save/restore series, the other fixup patches were already applied to qemu/master. This patch relies on the device control series sent out earlier. The patch can be picked from this tree (applied with the dependencies): git://git.linaro.org/people/cdall/qemu-arm.git migration/vgic-v7 Changelog [v3]: - Separate patch for adding the APR register state Changelog [v2]: - Remove num_irq from GIC VMstate structure - Increment GIC VMstate version number - Use extract32/deposit32 for bit-field modifications - Address other smaller review comments - Renames kvm_arm_gic_dist_[readr/writer] functions to kvm_dist_[get/put] and shortened other function names - Use concrete format for APRn hw/intc/arm_gic_kvm.c | 424 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 422 insertions(+), 2 deletions(-) diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 964d4d7..100b6bf 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -3,6 +3,7 @@ * * Copyright (c) 2012 Linaro Limited * Written by Peter Maydell + * Save/Restore logic added by Christoffer Dall. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +24,20 @@ #include "kvm_arm.h" #include "gic_internal.h" +//#define DEBUG_GIC_KVM + +#ifdef DEBUG_GIC_KVM +static const int debug_gic_kvm = 1; +#else +static const int debug_gic_kvm = 0; +#endif + +#define DPRINTF(fmt, ...) do { \ + if (debug_gic_kvm) { \ + printf("arm_gic: " fmt , ## __VA_ARGS__); \ + } \ + } while (0) + #define TYPE_KVM_ARM_GIC "kvm-arm-gic" #define KVM_ARM_GIC(obj) \ OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC) @@ -72,14 +87,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) +{ + return s->dev_fd >= 0; +} + +static void kvm_gic_access(GICState *s, int group, int offset, + int cpu, uint32_t *val, bool write) +{ + struct kvm_device_attr attr; + int type; + int err; + + 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 = (uintptr_t)val; + + if (write) { + type = KVM_SET_DEVICE_ATTR; + } else { + type = KVM_GET_DEVICE_ATTR; + } + + err = kvm_device_ioctl(s->dev_fd, type, &attr); + if (err < 0) { + fprintf(stderr, "KVM_{SET/GET}_DEVICE_ATTR failed: %s\n", + strerror(-err)); + abort(); + } +} + +static void kvm_gicd_access(GICState *s, int offset, int cpu, + uint32_t *val, bool write) +{ + kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, + offset, cpu, val, write); +} + +static void kvm_gicc_access(GICState *s, int offset, int cpu, + uint32_t *val, bool write) +{ + kvm_gic_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(s, 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_EDGE_TRIGGER(irq)) ? 0x2 : 0x0; + } else { + if (*field & 0x2) { + GIC_SET_EDGE_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(s, cpu, irq, *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_pending[irq][cpu] & 0xff; + } else { + s->sgi_pending[irq][cpu] = *field & 0xff; + } +} + +/* Read a register group from the kernel VGIC */ +static void kvm_dist_get(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_gicd_access(s, offset, cpu, ®, false); + for (j = 0; j < regsz; j++) { + field = extract32(reg, j * width, width); + translate_fn(s, irq + j, cpu, &field, false); + } + + cpu++; + } + offset += 4; + } +} + +/* Write a register group to the kernel VGIC */ +static void kvm_dist_put(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 = deposit32(reg, j * width, width, field); + } + kvm_gicd_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_gicd_access(s, 0x0, 0, ®, true); + + /* Sanity checking on GICD_TYPER and s->num_irq, s->num_cpu */ + kvm_gicd_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_dist_put(s, 0x180, 1, s->num_irq, translate_clear); + kvm_dist_put(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_dist_put(s, 0x800, 8, s->num_irq, translate_targets); + + /* irq_state[n].pending + irq_state[n].level -> GICD_ISPENDRn */ + kvm_dist_put(s, 0x280, 1, s->num_irq, translate_clear); + kvm_dist_put(s, 0x200, 1, s->num_irq, translate_pending); + + /* irq_state[n].active -> GICD_ISACTIVERn */ + kvm_dist_put(s, 0x380, 1, s->num_irq, translate_clear); + kvm_dist_put(s, 0x300, 1, s->num_irq, translate_active); + + /* irq_state[n].trigger -> GICD_ICFRn */ + kvm_dist_put(s, 0xc00, 2, s->num_irq, translate_trigger); + + /* s->priorityX[irq] -> ICD_IPRIORITYRn */ + kvm_dist_put(s, 0x400, 8, s->num_irq, translate_priority); + + /* s->sgi_pending -> ICD_CPENDSGIRn */ + kvm_dist_put(s, 0xf10, 8, GIC_NR_SGIS, translate_clear); + kvm_dist_put(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_gicc_access(s, 0x00, cpu, ®, true); + + /* s->priority_mask[cpu] -> GICC_PMR */ + reg = (s->priority_mask[cpu] & 0xff); + kvm_gicc_access(s, 0x04, cpu, ®, true); + + /* s->bpr[cpu] -> GICC_BPR */ + reg = (s->bpr[cpu] & 0x7); + kvm_gicc_access(s, 0x08, cpu, ®, true); + + /* s->abpr[cpu] -> GICC_ABPR */ + reg = (s->abpr[cpu] & 0x7); + kvm_gicc_access(s, 0x1c, cpu, ®, true); + + /* s->apr[n][cpu] -> GICC_APRn */ + for (i = 0; i < 4; i++) { + reg = s->apr[i][cpu]; + kvm_gicc_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_gicd_access(s, 0x0, 0, ®, false); + s->enabled = reg & 1; + + /* Sanity checking on GICD_TYPER -> s->num_irq, s->num_cpu */ + kvm_gicd_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_gicd_access(s, 0x8, 0, ®, false); + + /* Verify no GROUP 1 interrupts configured in the kernel */ + for_each_irq_reg(i, s->num_irq, 1) { + kvm_gicd_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_dist_get(s, 0x100, 1, s->num_irq, translate_enabled); + + /* GICD_ISPENDRn -> irq_state[n].pending + irq_state[n].level */ + kvm_dist_get(s, 0x200, 1, s->num_irq, translate_pending); + + /* GICD_ISACTIVERn -> irq_state[n].active */ + kvm_dist_get(s, 0x300, 1, s->num_irq, translate_active); + + /* GICD_ICFRn -> irq_state[n].trigger */ + kvm_dist_get(s, 0xc00, 2, s->num_irq, translate_trigger); + + /* GICD_IPRIORITYRn -> s->priorityX[irq] */ + kvm_dist_get(s, 0x400, 8, s->num_irq, translate_priority); + + /* GICD_ITARGETSRn -> s->irq_target[irq] */ + kvm_dist_get(s, 0x800, 8, s->num_irq, translate_targets); + + /* GICD_CPENDSGIRn -> s->sgi_pending */ + kvm_dist_get(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_gicc_access(s, 0x00, cpu, ®, false); + s->cpu_enabled[cpu] = (reg & 1); + + /* GICC_PMR -> s->priority_mask[cpu] */ + kvm_gicc_access(s, 0x04, cpu, ®, false); + s->priority_mask[cpu] = (reg & 0xff); + + /* GICC_BPR -> s->bpr[cpu] */ + kvm_gicc_access(s, 0x08, cpu, ®, false); + s->bpr[cpu] = (reg & 0x7); + + /* GICC_ABPR -> s->abpr[cpu] */ + kvm_gicc_access(s, 0x1c, cpu, ®, false); + s->abpr[cpu] = (reg & 0x7); + + /* GICC_APRn -> s->apr[n][cpu] */ + for (i = 0; i < 4; i++) { + kvm_gicc_access(s, 0xd0 + i * 4, cpu, ®, false); + s->apr[i][cpu] = reg; + } + } } static void kvm_arm_gic_reset(DeviceState *dev)