#include "vgic.h"
#include "vgic-mmio.h"
+static unsigned long vgic_mmio_read_v2_misc(struct vcpu *vcpu,
+ paddr_t addr, unsigned int len)
+{
+ uint32_t value;
+
+ switch ( addr & 0x0c ) /* filter for the 4 registers handled here */
+ {
+ case GICD_CTLR:
+ value = vcpu->domain->arch.vgic.enabled ? GICD_CTL_ENABLE : 0;
+ break;
+ case GICD_TYPER:
+ value = vcpu->domain->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+ value = (value >> 5) - 1; /* stored as multiples of 32 */
+ value |= (vcpu->domain->max_vcpus - 1) << GICD_TYPE_CPUS_SHIFT;
+ break;
+ case GICD_IIDR:
+ value = (PRODUCT_ID_KVM << 24) |
+ (VARIANT_ID_XEN << 16) |
+ (IMPLEMENTER_ARM << 0);
+ break;
+ default:
+ return 0;
+ }
+
+ return value;
+}
+
+static void vgic_mmio_write_v2_misc(struct vcpu *vcpu,
+ paddr_t addr, unsigned int len,
+ unsigned long val)
+{
+ struct vgic_dist *dist = &vcpu->domain->arch.vgic;
+ bool enabled;
+
+ switch ( addr & 0x0c ) /* filter for the 4 registers handled here */
+ {
+ case GICD_CTLR:
+ domain_lock(vcpu->domain);
+
+ /*
+ * Store the new enabled state in our distributor structure.
+ * Work out whether it was disabled before and now got enabled,
+ * so that we signal all VCPUs to check for interrupts to be injected.
+ */
+ enabled = dist->enabled;
+ dist->enabled = val & GICD_CTL_ENABLE;
+ enabled = !enabled && dist->enabled;
+
+ domain_unlock(vcpu->domain);
+
+ if ( enabled )
+ vgic_kick_vcpus(vcpu->domain);
+
+ break;
+ case GICD_TYPER:
+ case GICD_IIDR:
+ /* read-only, writes ignored */
+ return;
+ }
+}
+
static const struct vgic_register_region vgic_v2_dist_registers[] = {
REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
- vgic_mmio_read_raz, vgic_mmio_write_wi, 12,
+ vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12,
VGIC_ACCESS_32bit),
REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IGROUPR,
vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
#ifndef __XEN_ARM_VGIC_VGIC_H__
#define __XEN_ARM_VGIC_VGIC_H__
+/*
+ * We piggy-back on the already used KVM product ID, but use a different
+ * variant (major revision) for Xen.
+ */
+#define PRODUCT_ID_KVM 0x4b /* ASCII code K */
+#define VARIANT_ID_XEN 0x01
+#define IMPLEMENTER_ARM 0x43b
+
#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
static inline bool irq_is_pending(struct vgic_irq *irq)
void vgic_put_irq(struct domain *d, struct vgic_irq *irq);
void vgic_queue_irq_unlock(struct domain *d, struct vgic_irq *irq,
unsigned long flags);
+void vgic_kick_vcpus(struct domain *d);
static inline void vgic_get_irq_kref(struct vgic_irq *irq)
{