|
@@ -278,6 +278,57 @@ retry:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * vgic_its_save_pending_tables - Save the pending tables into guest RAM
|
|
|
+ * kvm lock and all vcpu lock must be held
|
|
|
+ */
|
|
|
+int vgic_v3_save_pending_tables(struct kvm *kvm)
|
|
|
+{
|
|
|
+ struct vgic_dist *dist = &kvm->arch.vgic;
|
|
|
+ int last_byte_offset = -1;
|
|
|
+ struct vgic_irq *irq;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
|
|
|
+ int byte_offset, bit_nr;
|
|
|
+ struct kvm_vcpu *vcpu;
|
|
|
+ gpa_t pendbase, ptr;
|
|
|
+ bool stored;
|
|
|
+ u8 val;
|
|
|
+
|
|
|
+ vcpu = irq->target_vcpu;
|
|
|
+ if (!vcpu)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
|
|
|
+
|
|
|
+ byte_offset = irq->intid / BITS_PER_BYTE;
|
|
|
+ bit_nr = irq->intid % BITS_PER_BYTE;
|
|
|
+ ptr = pendbase + byte_offset;
|
|
|
+
|
|
|
+ if (byte_offset != last_byte_offset) {
|
|
|
+ ret = kvm_read_guest(kvm, ptr, &val, 1);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ last_byte_offset = byte_offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ stored = val & (1U << bit_nr);
|
|
|
+ if (stored == irq->pending_latch)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (irq->pending_latch)
|
|
|
+ val |= 1 << bit_nr;
|
|
|
+ else
|
|
|
+ val &= ~(1 << bit_nr);
|
|
|
+
|
|
|
+ ret = kvm_write_guest(kvm, ptr, &val, 1);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/* check for overlapping regions and for regions crossing the end of memory */
|
|
|
static bool vgic_v3_check_base(struct kvm *kvm)
|
|
|
{
|