mirror of
https://github.com/a52xq-dev/kernel.git
synced 2026-10-18 21:58:11 +07:00
Second round of KVM/ARM Changes for v4.12.
Changes include:
- A fix related to the 32-bit idmap stub
- A fix to the bitmask used to deode the operands of an AArch32 CP
instruction
- We have moved the files shared between arch/arm/kvm and
arch/arm64/kvm to virt/kvm/arm
- We add support for saving/restoring the virtual ITS state to
userspace
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQEcBAABAgAGBQJZEZihAAoJEEtpOizt6ddyGDYH/jmGjDMnryORn2P2o10dUQKJ
RnHTQYnpOYqnprlkFtZFpmK+mjl/a8R1Btb7GK2EwmovTR95pMYPRqtrCTOL0aQA
4OToh7+vFGatwxsGCS6utazdhmx0UT/LhO/GEF4G1zOb7eVa4ZtS1NKLP2WjPD1E
RU3Qn8wa0pESv3tJScv8qo2+PWVX4krbFllhY2Hk0AkVQcI66ExkdVq4ikm1eUXn
rxzIayLG2bv3KEPNCzozdwoY9tDL+b40q6vN/RHGJmM05SZbbSx2/Bkw2RbslSpD
2hvhHWX7xeuEBcd5mZO7sP4WS3hM/BI8eX7q+uMeNJ9B+nM82yjGfOTtglVi2cc=
=JfvQ
-----END PGP SIGNATURE-----
Merge tag 'kvm-arm-for-v4.12-round2' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
Second round of KVM/ARM Changes for v4.12.
Changes include:
- A fix related to the 32-bit idmap stub
- A fix to the bitmask used to deode the operands of an AArch32 CP
instruction
- We have moved the files shared between arch/arm/kvm and
arch/arm64/kvm to virt/kvm/arm
- We add support for saving/restoring the virtual ITS state to
userspace
This commit is contained in:
commit
36c344f3f1
28 changed files with 1837 additions and 537 deletions
|
|
@ -32,7 +32,128 @@ Groups:
|
|||
KVM_DEV_ARM_VGIC_CTRL_INIT
|
||||
request the initialization of the ITS, no additional parameter in
|
||||
kvm_device_attr.addr.
|
||||
|
||||
KVM_DEV_ARM_ITS_SAVE_TABLES
|
||||
save the ITS table data into guest RAM, at the location provisioned
|
||||
by the guest in corresponding registers/table entries.
|
||||
|
||||
The layout of the tables in guest memory defines an ABI. The entries
|
||||
are laid out in little endian format as described in the last paragraph.
|
||||
|
||||
KVM_DEV_ARM_ITS_RESTORE_TABLES
|
||||
restore the ITS tables from guest RAM to ITS internal structures.
|
||||
|
||||
The GICV3 must be restored before the ITS and all ITS registers but
|
||||
the GITS_CTLR must be restored before restoring the ITS tables.
|
||||
|
||||
The GITS_IIDR read-only register must also be restored before
|
||||
calling KVM_DEV_ARM_ITS_RESTORE_TABLES as the IIDR revision field
|
||||
encodes the ABI revision.
|
||||
|
||||
The expected ordering when restoring the GICv3/ITS is described in section
|
||||
"ITS Restore Sequence".
|
||||
|
||||
Errors:
|
||||
-ENXIO: ITS not properly configured as required prior to setting
|
||||
this attribute
|
||||
-ENOMEM: Memory shortage when allocating ITS internal data
|
||||
-EINVAL: Inconsistent restored data
|
||||
-EFAULT: Invalid guest ram access
|
||||
-EBUSY: One or more VCPUS are running
|
||||
|
||||
KVM_DEV_ARM_VGIC_GRP_ITS_REGS
|
||||
Attributes:
|
||||
The attr field of kvm_device_attr encodes the offset of the
|
||||
ITS register, relative to the ITS control frame base address
|
||||
(ITS_base).
|
||||
|
||||
kvm_device_attr.addr points to a __u64 value whatever the width
|
||||
of the addressed register (32/64 bits). 64 bit registers can only
|
||||
be accessed with full length.
|
||||
|
||||
Writes to read-only registers are ignored by the kernel except for:
|
||||
- GITS_CREADR. It must be restored otherwise commands in the queue
|
||||
will be re-executed after restoring CWRITER. GITS_CREADR must be
|
||||
restored before restoring the GITS_CTLR which is likely to enable the
|
||||
ITS. Also it must be restored after GITS_CBASER since a write to
|
||||
GITS_CBASER resets GITS_CREADR.
|
||||
- GITS_IIDR. The Revision field encodes the table layout ABI revision.
|
||||
In the future we might implement direct injection of virtual LPIs.
|
||||
This will require an upgrade of the table layout and an evolution of
|
||||
the ABI. GITS_IIDR must be restored before calling
|
||||
KVM_DEV_ARM_ITS_RESTORE_TABLES.
|
||||
|
||||
For other registers, getting or setting a register has the same
|
||||
effect as reading/writing the register on real hardware.
|
||||
Errors:
|
||||
-ENXIO: Offset does not correspond to any supported register
|
||||
-EFAULT: Invalid user pointer for attr->addr
|
||||
-EINVAL: Offset is not 64-bit aligned
|
||||
-EBUSY: one or more VCPUS are running
|
||||
|
||||
ITS Restore Sequence:
|
||||
-------------------------
|
||||
|
||||
The following ordering must be followed when restoring the GIC and the ITS:
|
||||
a) restore all guest memory and create vcpus
|
||||
b) restore all redistributors
|
||||
c) provide the its base address
|
||||
(KVM_DEV_ARM_VGIC_GRP_ADDR)
|
||||
d) restore the ITS in the following order:
|
||||
1. Restore GITS_CBASER
|
||||
2. Restore all other GITS_ registers, except GITS_CTLR!
|
||||
3. Load the ITS table data (KVM_DEV_ARM_ITS_RESTORE_TABLES)
|
||||
4. Restore GITS_CTLR
|
||||
|
||||
Then vcpus can be started.
|
||||
|
||||
ITS Table ABI REV0:
|
||||
-------------------
|
||||
|
||||
Revision 0 of the ABI only supports the features of a virtual GICv3, and does
|
||||
not support a virtual GICv4 with support for direct injection of virtual
|
||||
interrupts for nested hypervisors.
|
||||
|
||||
The device table and ITT are indexed by the DeviceID and EventID,
|
||||
respectively. The collection table is not indexed by CollectionID, and the
|
||||
entries in the collection are listed in no particular order.
|
||||
All entries are 8 bytes.
|
||||
|
||||
Device Table Entry (DTE):
|
||||
|
||||
bits: | 63| 62 ... 49 | 48 ... 5 | 4 ... 0 |
|
||||
values: | V | next | ITT_addr | Size |
|
||||
|
||||
where;
|
||||
- V indicates whether the entry is valid. If not, other fields
|
||||
are not meaningful.
|
||||
- next: equals to 0 if this entry is the last one; otherwise it
|
||||
corresponds to the DeviceID offset to the next DTE, capped by
|
||||
2^14 -1.
|
||||
- ITT_addr matches bits [51:8] of the ITT address (256 Byte aligned).
|
||||
- Size specifies the supported number of bits for the EventID,
|
||||
minus one
|
||||
|
||||
Collection Table Entry (CTE):
|
||||
|
||||
bits: | 63| 62 .. 52 | 51 ... 16 | 15 ... 0 |
|
||||
values: | V | RES0 | RDBase | ICID |
|
||||
|
||||
where:
|
||||
- V indicates whether the entry is valid. If not, other fields are
|
||||
not meaningful.
|
||||
- RES0: reserved field with Should-Be-Zero-or-Preserved behavior.
|
||||
- RDBase is the PE number (GICR_TYPER.Processor_Number semantic),
|
||||
- ICID is the collection ID
|
||||
|
||||
Interrupt Translation Entry (ITE):
|
||||
|
||||
bits: | 63 ... 48 | 47 ... 16 | 15 ... 0 |
|
||||
values: | next | pINTID | ICID |
|
||||
|
||||
where:
|
||||
- next: equals to 0 if this entry is the last one; otherwise it corresponds
|
||||
to the EventID offset to the next ITE capped by 2^16 -1.
|
||||
- pINTID is the physical LPI ID; if zero, it means the entry is not valid
|
||||
and other fields are not meaningful.
|
||||
- ICID is the collection ID
|
||||
|
|
|
|||
|
|
@ -167,11 +167,17 @@ Groups:
|
|||
KVM_DEV_ARM_VGIC_CTRL_INIT
|
||||
request the initialization of the VGIC, no additional parameter in
|
||||
kvm_device_attr.addr.
|
||||
KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES
|
||||
save all LPI pending bits into guest RAM pending tables.
|
||||
|
||||
The first kB of the pending table is not altered by this operation.
|
||||
Errors:
|
||||
-ENXIO: VGIC not properly configured as required prior to calling
|
||||
this attribute
|
||||
-ENODEV: no online VCPU
|
||||
-ENOMEM: memory shortage when allocating vgic internal data
|
||||
-EFAULT: Invalid guest ram access
|
||||
-EBUSY: One or more VCPUS are running
|
||||
|
||||
|
||||
KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO
|
||||
|
|
|
|||
|
|
@ -196,13 +196,17 @@ struct kvm_arch_memory_slot {
|
|||
#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
|
||||
#define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6
|
||||
#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
|
||||
#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
|
||||
(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
|
||||
#define VGIC_LEVEL_INFO_LINE_LEVEL 0
|
||||
|
||||
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
||||
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
||||
#define KVM_DEV_ARM_ITS_SAVE_TABLES 1
|
||||
#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2
|
||||
#define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3
|
||||
|
||||
/* KVM_IRQ_LINE irq field index values */
|
||||
#define KVM_ARM_IRQ_TYPE_SHIFT 24
|
||||
|
|
|
|||
|
|
@ -18,9 +18,12 @@ KVM := ../../../virt/kvm
|
|||
kvm-arm-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o $(KVM)/vfio.o
|
||||
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += hyp/
|
||||
|
||||
obj-y += kvm-arm.o init.o interrupts.o
|
||||
obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
|
||||
obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o vgic-v3-coproc.o
|
||||
obj-y += handle_exit.o guest.o emulate.o reset.o
|
||||
obj-y += coproc.o coproc_a15.o coproc_a7.o vgic-v3-coproc.o
|
||||
obj-y += $(KVM)/arm/arm.o $(KVM)/arm/mmu.o $(KVM)/arm/mmio.o
|
||||
obj-y += $(KVM)/arm/psci.o $(KVM)/arm/perf.o
|
||||
obj-y += $(KVM)/arm/aarch32.o
|
||||
|
||||
obj-y += $(KVM)/arm/vgic/vgic.o
|
||||
|
|
|
|||
|
|
@ -6,133 +6,6 @@
|
|||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM kvm
|
||||
|
||||
/*
|
||||
* Tracepoints for entry/exit to guest
|
||||
*/
|
||||
TRACE_EVENT(kvm_entry,
|
||||
TP_PROTO(unsigned long vcpu_pc),
|
||||
TP_ARGS(vcpu_pc),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, vcpu_pc )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->vcpu_pc = vcpu_pc;
|
||||
),
|
||||
|
||||
TP_printk("PC: 0x%08lx", __entry->vcpu_pc)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_exit,
|
||||
TP_PROTO(int idx, unsigned int exit_reason, unsigned long vcpu_pc),
|
||||
TP_ARGS(idx, exit_reason, vcpu_pc),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( int, idx )
|
||||
__field( unsigned int, exit_reason )
|
||||
__field( unsigned long, vcpu_pc )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->idx = idx;
|
||||
__entry->exit_reason = exit_reason;
|
||||
__entry->vcpu_pc = vcpu_pc;
|
||||
),
|
||||
|
||||
TP_printk("%s: HSR_EC: 0x%04x (%s), PC: 0x%08lx",
|
||||
__print_symbolic(__entry->idx, kvm_arm_exception_type),
|
||||
__entry->exit_reason,
|
||||
__print_symbolic(__entry->exit_reason, kvm_arm_exception_class),
|
||||
__entry->vcpu_pc)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_guest_fault,
|
||||
TP_PROTO(unsigned long vcpu_pc, unsigned long hsr,
|
||||
unsigned long hxfar,
|
||||
unsigned long long ipa),
|
||||
TP_ARGS(vcpu_pc, hsr, hxfar, ipa),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, vcpu_pc )
|
||||
__field( unsigned long, hsr )
|
||||
__field( unsigned long, hxfar )
|
||||
__field( unsigned long long, ipa )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->vcpu_pc = vcpu_pc;
|
||||
__entry->hsr = hsr;
|
||||
__entry->hxfar = hxfar;
|
||||
__entry->ipa = ipa;
|
||||
),
|
||||
|
||||
TP_printk("ipa %#llx, hsr %#08lx, hxfar %#08lx, pc %#08lx",
|
||||
__entry->ipa, __entry->hsr,
|
||||
__entry->hxfar, __entry->vcpu_pc)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_access_fault,
|
||||
TP_PROTO(unsigned long ipa),
|
||||
TP_ARGS(ipa),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, ipa )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->ipa = ipa;
|
||||
),
|
||||
|
||||
TP_printk("IPA: %lx", __entry->ipa)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_irq_line,
|
||||
TP_PROTO(unsigned int type, int vcpu_idx, int irq_num, int level),
|
||||
TP_ARGS(type, vcpu_idx, irq_num, level),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, type )
|
||||
__field( int, vcpu_idx )
|
||||
__field( int, irq_num )
|
||||
__field( int, level )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->type = type;
|
||||
__entry->vcpu_idx = vcpu_idx;
|
||||
__entry->irq_num = irq_num;
|
||||
__entry->level = level;
|
||||
),
|
||||
|
||||
TP_printk("Inject %s interrupt (%d), vcpu->idx: %d, num: %d, level: %d",
|
||||
(__entry->type == KVM_ARM_IRQ_TYPE_CPU) ? "CPU" :
|
||||
(__entry->type == KVM_ARM_IRQ_TYPE_PPI) ? "VGIC PPI" :
|
||||
(__entry->type == KVM_ARM_IRQ_TYPE_SPI) ? "VGIC SPI" : "UNKNOWN",
|
||||
__entry->type, __entry->vcpu_idx, __entry->irq_num, __entry->level)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_mmio_emulate,
|
||||
TP_PROTO(unsigned long vcpu_pc, unsigned long instr,
|
||||
unsigned long cpsr),
|
||||
TP_ARGS(vcpu_pc, instr, cpsr),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, vcpu_pc )
|
||||
__field( unsigned long, instr )
|
||||
__field( unsigned long, cpsr )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->vcpu_pc = vcpu_pc;
|
||||
__entry->instr = instr;
|
||||
__entry->cpsr = cpsr;
|
||||
),
|
||||
|
||||
TP_printk("Emulate MMIO at: 0x%08lx (instr: %08lx, cpsr: %08lx)",
|
||||
__entry->vcpu_pc, __entry->instr, __entry->cpsr)
|
||||
);
|
||||
|
||||
/* Architecturally implementation defined CP15 register access */
|
||||
TRACE_EVENT(kvm_emulate_cp15_imp,
|
||||
TP_PROTO(unsigned long Op1, unsigned long Rt1, unsigned long CRn,
|
||||
|
|
@ -181,87 +54,6 @@ TRACE_EVENT(kvm_wfx,
|
|||
__entry->is_wfe ? 'e' : 'i', __entry->vcpu_pc)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_unmap_hva,
|
||||
TP_PROTO(unsigned long hva),
|
||||
TP_ARGS(hva),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, hva )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->hva = hva;
|
||||
),
|
||||
|
||||
TP_printk("mmu notifier unmap hva: %#08lx", __entry->hva)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_unmap_hva_range,
|
||||
TP_PROTO(unsigned long start, unsigned long end),
|
||||
TP_ARGS(start, end),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, start )
|
||||
__field( unsigned long, end )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->start = start;
|
||||
__entry->end = end;
|
||||
),
|
||||
|
||||
TP_printk("mmu notifier unmap range: %#08lx -- %#08lx",
|
||||
__entry->start, __entry->end)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_set_spte_hva,
|
||||
TP_PROTO(unsigned long hva),
|
||||
TP_ARGS(hva),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, hva )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->hva = hva;
|
||||
),
|
||||
|
||||
TP_printk("mmu notifier set pte hva: %#08lx", __entry->hva)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_age_hva,
|
||||
TP_PROTO(unsigned long start, unsigned long end),
|
||||
TP_ARGS(start, end),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, start )
|
||||
__field( unsigned long, end )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->start = start;
|
||||
__entry->end = end;
|
||||
),
|
||||
|
||||
TP_printk("mmu notifier age hva: %#08lx -- %#08lx",
|
||||
__entry->start, __entry->end)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_test_age_hva,
|
||||
TP_PROTO(unsigned long hva),
|
||||
TP_ARGS(hva),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, hva )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->hva = hva;
|
||||
),
|
||||
|
||||
TP_printk("mmu notifier test age hva: %#08lx", __entry->hva)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_hvc,
|
||||
TP_PROTO(unsigned long vcpu_pc, unsigned long r0, unsigned long imm),
|
||||
TP_ARGS(vcpu_pc, r0, imm),
|
||||
|
|
@ -282,45 +74,6 @@ TRACE_EVENT(kvm_hvc,
|
|||
__entry->vcpu_pc, __entry->r0, __entry->imm)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_set_way_flush,
|
||||
TP_PROTO(unsigned long vcpu_pc, bool cache),
|
||||
TP_ARGS(vcpu_pc, cache),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, vcpu_pc )
|
||||
__field( bool, cache )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->vcpu_pc = vcpu_pc;
|
||||
__entry->cache = cache;
|
||||
),
|
||||
|
||||
TP_printk("S/W flush at 0x%016lx (cache %s)",
|
||||
__entry->vcpu_pc, __entry->cache ? "on" : "off")
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_toggle_cache,
|
||||
TP_PROTO(unsigned long vcpu_pc, bool was, bool now),
|
||||
TP_ARGS(vcpu_pc, was, now),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, vcpu_pc )
|
||||
__field( bool, was )
|
||||
__field( bool, now )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->vcpu_pc = vcpu_pc;
|
||||
__entry->was = was;
|
||||
__entry->now = now;
|
||||
),
|
||||
|
||||
TP_printk("VM op at 0x%016lx (cache was %s, now %s)",
|
||||
__entry->vcpu_pc, __entry->was ? "on" : "off",
|
||||
__entry->now ? "on" : "off")
|
||||
);
|
||||
|
||||
#endif /* _TRACE_KVM_H */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
|
|
|
|||
|
|
@ -240,6 +240,12 @@ static inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu)
|
|||
return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_FSC_TYPE;
|
||||
}
|
||||
|
||||
static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u32 esr = kvm_vcpu_get_hsr(vcpu);
|
||||
return (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT;
|
||||
}
|
||||
|
||||
static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
|
||||
|
|
|
|||
|
|
@ -216,13 +216,17 @@ struct kvm_arch_memory_slot {
|
|||
#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
|
||||
#define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6
|
||||
#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
|
||||
#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
|
||||
(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
|
||||
#define VGIC_LEVEL_INFO_LINE_LEVEL 0
|
||||
|
||||
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
||||
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
||||
#define KVM_DEV_ARM_ITS_SAVE_TABLES 1
|
||||
#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2
|
||||
#define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3
|
||||
|
||||
/* Device Control API on vcpu fd */
|
||||
#define KVM_ARM_VCPU_PMU_V3_CTRL 0
|
||||
|
|
|
|||
|
|
@ -7,14 +7,13 @@ CFLAGS_arm.o := -I.
|
|||
CFLAGS_mmu.o := -I.
|
||||
|
||||
KVM=../../../virt/kvm
|
||||
ARM=../../../arch/arm/kvm
|
||||
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += kvm.o
|
||||
obj-$(CONFIG_KVM_ARM_HOST) += hyp/
|
||||
|
||||
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o $(KVM)/vfio.o
|
||||
kvm-$(CONFIG_KVM_ARM_HOST) += $(ARM)/arm.o $(ARM)/mmu.o $(ARM)/mmio.o
|
||||
kvm-$(CONFIG_KVM_ARM_HOST) += $(ARM)/psci.o $(ARM)/perf.o
|
||||
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arm.o $(KVM)/arm/mmu.o $(KVM)/arm/mmio.o
|
||||
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/psci.o $(KVM)/arm/perf.o
|
||||
|
||||
kvm-$(CONFIG_KVM_ARM_HOST) += inject_fault.o regmap.o
|
||||
kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
|
||||
|
|
|
|||
|
|
@ -1529,8 +1529,8 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
|
|||
{
|
||||
struct sys_reg_params params;
|
||||
u32 hsr = kvm_vcpu_get_hsr(vcpu);
|
||||
int Rt = (hsr >> 5) & 0xf;
|
||||
int Rt2 = (hsr >> 10) & 0xf;
|
||||
int Rt = kvm_vcpu_sys_get_rt(vcpu);
|
||||
int Rt2 = (hsr >> 10) & 0x1f;
|
||||
|
||||
params.is_aarch32 = true;
|
||||
params.is_32bit = false;
|
||||
|
|
@ -1586,7 +1586,7 @@ static int kvm_handle_cp_32(struct kvm_vcpu *vcpu,
|
|||
{
|
||||
struct sys_reg_params params;
|
||||
u32 hsr = kvm_vcpu_get_hsr(vcpu);
|
||||
int Rt = (hsr >> 5) & 0xf;
|
||||
int Rt = kvm_vcpu_sys_get_rt(vcpu);
|
||||
|
||||
params.is_aarch32 = true;
|
||||
params.is_32bit = true;
|
||||
|
|
@ -1688,7 +1688,7 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||
{
|
||||
struct sys_reg_params params;
|
||||
unsigned long esr = kvm_vcpu_get_hsr(vcpu);
|
||||
int Rt = (esr >> 5) & 0x1f;
|
||||
int Rt = kvm_vcpu_sys_get_rt(vcpu);
|
||||
int ret;
|
||||
|
||||
trace_kvm_handle_sys_reg(esr);
|
||||
|
|
|
|||
|
|
@ -148,7 +148,6 @@ struct vgic_its {
|
|||
gpa_t vgic_its_base;
|
||||
|
||||
bool enabled;
|
||||
bool initialized;
|
||||
struct vgic_io_device iodev;
|
||||
struct kvm_device *dev;
|
||||
|
||||
|
|
@ -162,6 +161,9 @@ struct vgic_its {
|
|||
u32 creadr;
|
||||
u32 cwriter;
|
||||
|
||||
/* migration ABI revision in use */
|
||||
u32 abi_rev;
|
||||
|
||||
/* Protects the device and collection lists */
|
||||
struct mutex its_lock;
|
||||
struct list_head device_list;
|
||||
|
|
@ -283,6 +285,7 @@ extern struct static_key_false vgic_v2_cpuif_trap;
|
|||
|
||||
int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
|
||||
void kvm_vgic_early_init(struct kvm *kvm);
|
||||
int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu);
|
||||
int kvm_vgic_create(struct kvm *kvm, u32 type);
|
||||
void kvm_vgic_destroy(struct kvm *kvm);
|
||||
void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
|
||||
|
|
|
|||
|
|
@ -132,6 +132,9 @@
|
|||
#define GIC_BASER_SHAREABILITY(reg, type) \
|
||||
(GIC_BASER_##type << reg##_SHAREABILITY_SHIFT)
|
||||
|
||||
/* encode a size field of width @w containing @n - 1 units */
|
||||
#define GIC_ENCODE_SZ(n, w) (((unsigned long)(n) - 1) & GENMASK_ULL(((w) - 1), 0))
|
||||
|
||||
#define GICR_PROPBASER_SHAREABILITY_SHIFT (10)
|
||||
#define GICR_PROPBASER_INNER_CACHEABILITY_SHIFT (7)
|
||||
#define GICR_PROPBASER_OUTER_CACHEABILITY_SHIFT (56)
|
||||
|
|
@ -156,6 +159,8 @@
|
|||
#define GICR_PROPBASER_RaWaWb GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWaWb)
|
||||
|
||||
#define GICR_PROPBASER_IDBITS_MASK (0x1f)
|
||||
#define GICR_PROPBASER_ADDRESS(x) ((x) & GENMASK_ULL(51, 12))
|
||||
#define GICR_PENDBASER_ADDRESS(x) ((x) & GENMASK_ULL(51, 16))
|
||||
|
||||
#define GICR_PENDBASER_SHAREABILITY_SHIFT (10)
|
||||
#define GICR_PENDBASER_INNER_CACHEABILITY_SHIFT (7)
|
||||
|
|
@ -232,12 +237,18 @@
|
|||
#define GITS_CTLR_QUIESCENT (1U << 31)
|
||||
|
||||
#define GITS_TYPER_PLPIS (1UL << 0)
|
||||
#define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT 4
|
||||
#define GITS_TYPER_IDBITS_SHIFT 8
|
||||
#define GITS_TYPER_DEVBITS_SHIFT 13
|
||||
#define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
|
||||
#define GITS_TYPER_PTA (1UL << 19)
|
||||
#define GITS_TYPER_HWCOLLCNT_SHIFT 24
|
||||
|
||||
#define GITS_IIDR_REV_SHIFT 12
|
||||
#define GITS_IIDR_REV_MASK (0xf << GITS_IIDR_REV_SHIFT)
|
||||
#define GITS_IIDR_REV(r) (((r) >> GITS_IIDR_REV_SHIFT) & 0xf)
|
||||
#define GITS_IIDR_PRODUCTID_SHIFT 24
|
||||
|
||||
#define GITS_CBASER_VALID (1ULL << 63)
|
||||
#define GITS_CBASER_SHAREABILITY_SHIFT (10)
|
||||
#define GITS_CBASER_INNER_CACHEABILITY_SHIFT (59)
|
||||
|
|
@ -290,6 +301,7 @@
|
|||
#define GITS_BASER_TYPE(r) (((r) >> GITS_BASER_TYPE_SHIFT) & 7)
|
||||
#define GITS_BASER_ENTRY_SIZE_SHIFT (48)
|
||||
#define GITS_BASER_ENTRY_SIZE(r) ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1)
|
||||
#define GITS_BASER_ENTRY_SIZE_MASK GENMASK_ULL(52, 48)
|
||||
#define GITS_BASER_SHAREABILITY_SHIFT (10)
|
||||
#define GITS_BASER_InnerShareable \
|
||||
GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable)
|
||||
|
|
@ -337,9 +349,11 @@
|
|||
#define E_ITS_INT_UNMAPPED_INTERRUPT 0x010307
|
||||
#define E_ITS_CLEAR_UNMAPPED_INTERRUPT 0x010507
|
||||
#define E_ITS_MAPD_DEVICE_OOR 0x010801
|
||||
#define E_ITS_MAPD_ITTSIZE_OOR 0x010802
|
||||
#define E_ITS_MAPC_PROCNUM_OOR 0x010902
|
||||
#define E_ITS_MAPC_COLLECTION_OOR 0x010903
|
||||
#define E_ITS_MAPTI_UNMAPPED_DEVICE 0x010a04
|
||||
#define E_ITS_MAPTI_ID_OOR 0x010a05
|
||||
#define E_ITS_MAPTI_PHYSICALID_OOR 0x010a06
|
||||
#define E_ITS_INV_UNMAPPED_INTERRUPT 0x010c07
|
||||
#define E_ITS_INVALL_UNMAPPED_COLLECTION 0x010d09
|
||||
|
|
|
|||
|
|
@ -499,6 +499,17 @@ static inline struct kvm_vcpu *kvm_get_vcpu_by_id(struct kvm *kvm, int id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline int kvm_vcpu_get_idx(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_vcpu *tmp;
|
||||
int idx;
|
||||
|
||||
kvm_for_each_vcpu(idx, tmp, vcpu->kvm)
|
||||
if (tmp == vcpu)
|
||||
return idx;
|
||||
BUG();
|
||||
}
|
||||
|
||||
#define kvm_for_each_memslot(memslot, slots) \
|
||||
for (memslot = &slots->memslots[0]; \
|
||||
memslot < slots->memslots + KVM_MEM_SLOTS_NUM && memslot->npages;\
|
||||
|
|
|
|||
1480
virt/kvm/arm/arm.c
Normal file
1480
virt/kvm/arm/arm.c
Normal file
File diff suppressed because it is too large
Load diff
217
virt/kvm/arm/mmio.c
Normal file
217
virt/kvm/arm/mmio.c
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
|
||||
* Author: Christoffer Dall <c.dall@virtualopensystems.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_mmio.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <trace/events/kvm.h>
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data)
|
||||
{
|
||||
void *datap = NULL;
|
||||
union {
|
||||
u8 byte;
|
||||
u16 hword;
|
||||
u32 word;
|
||||
u64 dword;
|
||||
} tmp;
|
||||
|
||||
switch (len) {
|
||||
case 1:
|
||||
tmp.byte = data;
|
||||
datap = &tmp.byte;
|
||||
break;
|
||||
case 2:
|
||||
tmp.hword = data;
|
||||
datap = &tmp.hword;
|
||||
break;
|
||||
case 4:
|
||||
tmp.word = data;
|
||||
datap = &tmp.word;
|
||||
break;
|
||||
case 8:
|
||||
tmp.dword = data;
|
||||
datap = &tmp.dword;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(buf, datap, len);
|
||||
}
|
||||
|
||||
unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len)
|
||||
{
|
||||
unsigned long data = 0;
|
||||
union {
|
||||
u16 hword;
|
||||
u32 word;
|
||||
u64 dword;
|
||||
} tmp;
|
||||
|
||||
switch (len) {
|
||||
case 1:
|
||||
data = *(u8 *)buf;
|
||||
break;
|
||||
case 2:
|
||||
memcpy(&tmp.hword, buf, len);
|
||||
data = tmp.hword;
|
||||
break;
|
||||
case 4:
|
||||
memcpy(&tmp.word, buf, len);
|
||||
data = tmp.word;
|
||||
break;
|
||||
case 8:
|
||||
memcpy(&tmp.dword, buf, len);
|
||||
data = tmp.dword;
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
|
||||
* or in-kernel IO emulation
|
||||
*
|
||||
* @vcpu: The VCPU pointer
|
||||
* @run: The VCPU run struct containing the mmio data
|
||||
*/
|
||||
int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
unsigned long data;
|
||||
unsigned int len;
|
||||
int mask;
|
||||
|
||||
if (!run->mmio.is_write) {
|
||||
len = run->mmio.len;
|
||||
if (len > sizeof(unsigned long))
|
||||
return -EINVAL;
|
||||
|
||||
data = kvm_mmio_read_buf(run->mmio.data, len);
|
||||
|
||||
if (vcpu->arch.mmio_decode.sign_extend &&
|
||||
len < sizeof(unsigned long)) {
|
||||
mask = 1U << ((len * 8) - 1);
|
||||
data = (data ^ mask) - mask;
|
||||
}
|
||||
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
|
||||
data);
|
||||
data = vcpu_data_host_to_guest(vcpu, data, len);
|
||||
vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_hsr(struct kvm_vcpu *vcpu, bool *is_write, int *len)
|
||||
{
|
||||
unsigned long rt;
|
||||
int access_size;
|
||||
bool sign_extend;
|
||||
|
||||
if (kvm_vcpu_dabt_iss1tw(vcpu)) {
|
||||
/* page table accesses IO mem: tell guest to fix its TTBR */
|
||||
kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
|
||||
return 1;
|
||||
}
|
||||
|
||||
access_size = kvm_vcpu_dabt_get_as(vcpu);
|
||||
if (unlikely(access_size < 0))
|
||||
return access_size;
|
||||
|
||||
*is_write = kvm_vcpu_dabt_iswrite(vcpu);
|
||||
sign_extend = kvm_vcpu_dabt_issext(vcpu);
|
||||
rt = kvm_vcpu_dabt_get_rd(vcpu);
|
||||
|
||||
*len = access_size;
|
||||
vcpu->arch.mmio_decode.sign_extend = sign_extend;
|
||||
vcpu->arch.mmio_decode.rt = rt;
|
||||
|
||||
/*
|
||||
* The MMIO instruction is emulated and should not be re-executed
|
||||
* in the guest.
|
||||
*/
|
||||
kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
||||
phys_addr_t fault_ipa)
|
||||
{
|
||||
unsigned long data;
|
||||
unsigned long rt;
|
||||
int ret;
|
||||
bool is_write;
|
||||
int len;
|
||||
u8 data_buf[8];
|
||||
|
||||
/*
|
||||
* Prepare MMIO operation. First decode the syndrome data we get
|
||||
* from the CPU. Then try if some in-kernel emulation feels
|
||||
* responsible, otherwise let user space do its magic.
|
||||
*/
|
||||
if (kvm_vcpu_dabt_isvalid(vcpu)) {
|
||||
ret = decode_hsr(vcpu, &is_write, &len);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
kvm_err("load/store instruction decoding not implemented\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
rt = vcpu->arch.mmio_decode.rt;
|
||||
|
||||
if (is_write) {
|
||||
data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt),
|
||||
len);
|
||||
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
|
||||
kvm_mmio_write_buf(data_buf, len, data);
|
||||
|
||||
ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,
|
||||
data_buf);
|
||||
} else {
|
||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len,
|
||||
fault_ipa, 0);
|
||||
|
||||
ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_ipa, len,
|
||||
data_buf);
|
||||
}
|
||||
|
||||
/* Now prepare kvm_run for the potential return to userland. */
|
||||
run->mmio.is_write = is_write;
|
||||
run->mmio.phys_addr = fault_ipa;
|
||||
run->mmio.len = len;
|
||||
|
||||
if (!ret) {
|
||||
/* We handled the access successfully in the kernel. */
|
||||
if (!is_write)
|
||||
memcpy(run->mmio.data, data_buf, len);
|
||||
vcpu->stat.mmio_exit_kernel++;
|
||||
kvm_handle_mmio_return(vcpu, run);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (is_write)
|
||||
memcpy(run->mmio.data, data_buf, len);
|
||||
vcpu->stat.mmio_exit_user++;
|
||||
run->exit_reason = KVM_EXIT_MMIO;
|
||||
return 0;
|
||||
}
|
||||
1975
virt/kvm/arm/mmu.c
Normal file
1975
virt/kvm/arm/mmu.c
Normal file
File diff suppressed because it is too large
Load diff
68
virt/kvm/arm/perf.c
Normal file
68
virt/kvm/arm/perf.c
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Based on the x86 implementation.
|
||||
*
|
||||
* Copyright (C) 2012 ARM Ltd.
|
||||
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/kvm_host.h>
|
||||
|
||||
#include <asm/kvm_emulate.h>
|
||||
|
||||
static int kvm_is_in_guest(void)
|
||||
{
|
||||
return kvm_arm_get_running_vcpu() != NULL;
|
||||
}
|
||||
|
||||
static int kvm_is_user_mode(void)
|
||||
{
|
||||
struct kvm_vcpu *vcpu;
|
||||
|
||||
vcpu = kvm_arm_get_running_vcpu();
|
||||
|
||||
if (vcpu)
|
||||
return !vcpu_mode_priv(vcpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long kvm_get_guest_ip(void)
|
||||
{
|
||||
struct kvm_vcpu *vcpu;
|
||||
|
||||
vcpu = kvm_arm_get_running_vcpu();
|
||||
|
||||
if (vcpu)
|
||||
return *vcpu_pc(vcpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct perf_guest_info_callbacks kvm_guest_cbs = {
|
||||
.is_in_guest = kvm_is_in_guest,
|
||||
.is_user_mode = kvm_is_user_mode,
|
||||
.get_guest_ip = kvm_get_guest_ip,
|
||||
};
|
||||
|
||||
int kvm_perf_init(void)
|
||||
{
|
||||
return perf_register_guest_info_callbacks(&kvm_guest_cbs);
|
||||
}
|
||||
|
||||
int kvm_perf_teardown(void)
|
||||
{
|
||||
return perf_unregister_guest_info_callbacks(&kvm_guest_cbs);
|
||||
}
|
||||
332
virt/kvm/arm/psci.c
Normal file
332
virt/kvm/arm/psci.c
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* Copyright (C) 2012 - ARM Ltd
|
||||
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/preempt.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_psci.h>
|
||||
#include <asm/kvm_host.h>
|
||||
|
||||
#include <uapi/linux/psci.h>
|
||||
|
||||
/*
|
||||
* This is an implementation of the Power State Coordination Interface
|
||||
* as described in ARM document number ARM DEN 0022A.
|
||||
*/
|
||||
|
||||
#define AFFINITY_MASK(level) ~((0x1UL << ((level) * MPIDR_LEVEL_BITS)) - 1)
|
||||
|
||||
static unsigned long psci_affinity_mask(unsigned long affinity_level)
|
||||
{
|
||||
if (affinity_level <= 3)
|
||||
return MPIDR_HWID_BITMASK & AFFINITY_MASK(affinity_level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long kvm_psci_vcpu_suspend(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* NOTE: For simplicity, we make VCPU suspend emulation to be
|
||||
* same-as WFI (Wait-for-interrupt) emulation.
|
||||
*
|
||||
* This means for KVM the wakeup events are interrupts and
|
||||
* this is consistent with intended use of StateID as described
|
||||
* in section 5.4.1 of PSCI v0.2 specification (ARM DEN 0022A).
|
||||
*
|
||||
* Further, we also treat power-down request to be same as
|
||||
* stand-by request as-per section 5.4.2 clause 3 of PSCI v0.2
|
||||
* specification (ARM DEN 0022A). This means all suspend states
|
||||
* for KVM will preserve the register state.
|
||||
*/
|
||||
kvm_vcpu_block(vcpu);
|
||||
|
||||
return PSCI_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.power_off = true;
|
||||
}
|
||||
|
||||
static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
|
||||
{
|
||||
struct kvm *kvm = source_vcpu->kvm;
|
||||
struct kvm_vcpu *vcpu = NULL;
|
||||
struct swait_queue_head *wq;
|
||||
unsigned long cpu_id;
|
||||
unsigned long context_id;
|
||||
phys_addr_t target_pc;
|
||||
|
||||
cpu_id = vcpu_get_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK;
|
||||
if (vcpu_mode_is_32bit(source_vcpu))
|
||||
cpu_id &= ~((u32) 0);
|
||||
|
||||
vcpu = kvm_mpidr_to_vcpu(kvm, cpu_id);
|
||||
|
||||
/*
|
||||
* Make sure the caller requested a valid CPU and that the CPU is
|
||||
* turned off.
|
||||
*/
|
||||
if (!vcpu)
|
||||
return PSCI_RET_INVALID_PARAMS;
|
||||
if (!vcpu->arch.power_off) {
|
||||
if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
|
||||
return PSCI_RET_ALREADY_ON;
|
||||
else
|
||||
return PSCI_RET_INVALID_PARAMS;
|
||||
}
|
||||
|
||||
target_pc = vcpu_get_reg(source_vcpu, 2);
|
||||
context_id = vcpu_get_reg(source_vcpu, 3);
|
||||
|
||||
kvm_reset_vcpu(vcpu);
|
||||
|
||||
/* Gracefully handle Thumb2 entry point */
|
||||
if (vcpu_mode_is_32bit(vcpu) && (target_pc & 1)) {
|
||||
target_pc &= ~((phys_addr_t) 1);
|
||||
vcpu_set_thumb(vcpu);
|
||||
}
|
||||
|
||||
/* Propagate caller endianness */
|
||||
if (kvm_vcpu_is_be(source_vcpu))
|
||||
kvm_vcpu_set_be(vcpu);
|
||||
|
||||
*vcpu_pc(vcpu) = target_pc;
|
||||
/*
|
||||
* NOTE: We always update r0 (or x0) because for PSCI v0.1
|
||||
* the general puspose registers are undefined upon CPU_ON.
|
||||
*/
|
||||
vcpu_set_reg(vcpu, 0, context_id);
|
||||
vcpu->arch.power_off = false;
|
||||
smp_mb(); /* Make sure the above is visible */
|
||||
|
||||
wq = kvm_arch_vcpu_wq(vcpu);
|
||||
swake_up(wq);
|
||||
|
||||
return PSCI_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int i, matching_cpus = 0;
|
||||
unsigned long mpidr;
|
||||
unsigned long target_affinity;
|
||||
unsigned long target_affinity_mask;
|
||||
unsigned long lowest_affinity_level;
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
struct kvm_vcpu *tmp;
|
||||
|
||||
target_affinity = vcpu_get_reg(vcpu, 1);
|
||||
lowest_affinity_level = vcpu_get_reg(vcpu, 2);
|
||||
|
||||
/* Determine target affinity mask */
|
||||
target_affinity_mask = psci_affinity_mask(lowest_affinity_level);
|
||||
if (!target_affinity_mask)
|
||||
return PSCI_RET_INVALID_PARAMS;
|
||||
|
||||
/* Ignore other bits of target affinity */
|
||||
target_affinity &= target_affinity_mask;
|
||||
|
||||
/*
|
||||
* If one or more VCPU matching target affinity are running
|
||||
* then ON else OFF
|
||||
*/
|
||||
kvm_for_each_vcpu(i, tmp, kvm) {
|
||||
mpidr = kvm_vcpu_get_mpidr_aff(tmp);
|
||||
if ((mpidr & target_affinity_mask) == target_affinity) {
|
||||
matching_cpus++;
|
||||
if (!tmp->arch.power_off)
|
||||
return PSCI_0_2_AFFINITY_LEVEL_ON;
|
||||
}
|
||||
}
|
||||
|
||||
if (!matching_cpus)
|
||||
return PSCI_RET_INVALID_PARAMS;
|
||||
|
||||
return PSCI_0_2_AFFINITY_LEVEL_OFF;
|
||||
}
|
||||
|
||||
static void kvm_prepare_system_event(struct kvm_vcpu *vcpu, u32 type)
|
||||
{
|
||||
int i;
|
||||
struct kvm_vcpu *tmp;
|
||||
|
||||
/*
|
||||
* The KVM ABI specifies that a system event exit may call KVM_RUN
|
||||
* again and may perform shutdown/reboot at a later time that when the
|
||||
* actual request is made. Since we are implementing PSCI and a
|
||||
* caller of PSCI reboot and shutdown expects that the system shuts
|
||||
* down or reboots immediately, let's make sure that VCPUs are not run
|
||||
* after this call is handled and before the VCPUs have been
|
||||
* re-initialized.
|
||||
*/
|
||||
kvm_for_each_vcpu(i, tmp, vcpu->kvm) {
|
||||
tmp->arch.power_off = true;
|
||||
kvm_vcpu_kick(tmp);
|
||||
}
|
||||
|
||||
memset(&vcpu->run->system_event, 0, sizeof(vcpu->run->system_event));
|
||||
vcpu->run->system_event.type = type;
|
||||
vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
|
||||
}
|
||||
|
||||
static void kvm_psci_system_off(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_SHUTDOWN);
|
||||
}
|
||||
|
||||
static void kvm_psci_system_reset(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET);
|
||||
}
|
||||
|
||||
int kvm_psci_version(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
|
||||
return KVM_ARM_PSCI_0_2;
|
||||
|
||||
return KVM_ARM_PSCI_0_1;
|
||||
}
|
||||
|
||||
static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
|
||||
unsigned long val;
|
||||
int ret = 1;
|
||||
|
||||
switch (psci_fn) {
|
||||
case PSCI_0_2_FN_PSCI_VERSION:
|
||||
/*
|
||||
* Bits[31:16] = Major Version = 0
|
||||
* Bits[15:0] = Minor Version = 2
|
||||
*/
|
||||
val = 2;
|
||||
break;
|
||||
case PSCI_0_2_FN_CPU_SUSPEND:
|
||||
case PSCI_0_2_FN64_CPU_SUSPEND:
|
||||
val = kvm_psci_vcpu_suspend(vcpu);
|
||||
break;
|
||||
case PSCI_0_2_FN_CPU_OFF:
|
||||
kvm_psci_vcpu_off(vcpu);
|
||||
val = PSCI_RET_SUCCESS;
|
||||
break;
|
||||
case PSCI_0_2_FN_CPU_ON:
|
||||
case PSCI_0_2_FN64_CPU_ON:
|
||||
mutex_lock(&kvm->lock);
|
||||
val = kvm_psci_vcpu_on(vcpu);
|
||||
mutex_unlock(&kvm->lock);
|
||||
break;
|
||||
case PSCI_0_2_FN_AFFINITY_INFO:
|
||||
case PSCI_0_2_FN64_AFFINITY_INFO:
|
||||
val = kvm_psci_vcpu_affinity_info(vcpu);
|
||||
break;
|
||||
case PSCI_0_2_FN_MIGRATE_INFO_TYPE:
|
||||
/*
|
||||
* Trusted OS is MP hence does not require migration
|
||||
* or
|
||||
* Trusted OS is not present
|
||||
*/
|
||||
val = PSCI_0_2_TOS_MP;
|
||||
break;
|
||||
case PSCI_0_2_FN_SYSTEM_OFF:
|
||||
kvm_psci_system_off(vcpu);
|
||||
/*
|
||||
* We should'nt be going back to guest VCPU after
|
||||
* receiving SYSTEM_OFF request.
|
||||
*
|
||||
* If user space accidently/deliberately resumes
|
||||
* guest VCPU after SYSTEM_OFF request then guest
|
||||
* VCPU should see internal failure from PSCI return
|
||||
* value. To achieve this, we preload r0 (or x0) with
|
||||
* PSCI return value INTERNAL_FAILURE.
|
||||
*/
|
||||
val = PSCI_RET_INTERNAL_FAILURE;
|
||||
ret = 0;
|
||||
break;
|
||||
case PSCI_0_2_FN_SYSTEM_RESET:
|
||||
kvm_psci_system_reset(vcpu);
|
||||
/*
|
||||
* Same reason as SYSTEM_OFF for preloading r0 (or x0)
|
||||
* with PSCI return value INTERNAL_FAILURE.
|
||||
*/
|
||||
val = PSCI_RET_INTERNAL_FAILURE;
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
val = PSCI_RET_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
vcpu_set_reg(vcpu, 0, val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
|
||||
unsigned long val;
|
||||
|
||||
switch (psci_fn) {
|
||||
case KVM_PSCI_FN_CPU_OFF:
|
||||
kvm_psci_vcpu_off(vcpu);
|
||||
val = PSCI_RET_SUCCESS;
|
||||
break;
|
||||
case KVM_PSCI_FN_CPU_ON:
|
||||
mutex_lock(&kvm->lock);
|
||||
val = kvm_psci_vcpu_on(vcpu);
|
||||
mutex_unlock(&kvm->lock);
|
||||
break;
|
||||
default:
|
||||
val = PSCI_RET_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
vcpu_set_reg(vcpu, 0, val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_psci_call - handle PSCI call if r0 value is in range
|
||||
* @vcpu: Pointer to the VCPU struct
|
||||
*
|
||||
* Handle PSCI calls from guests through traps from HVC instructions.
|
||||
* The calling convention is similar to SMC calls to the secure world
|
||||
* where the function number is placed in r0.
|
||||
*
|
||||
* This function returns: > 0 (success), 0 (success but exit to user
|
||||
* space), and < 0 (errors)
|
||||
*
|
||||
* Errors:
|
||||
* -EINVAL: Unrecognized PSCI function
|
||||
*/
|
||||
int kvm_psci_call(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
switch (kvm_psci_version(vcpu)) {
|
||||
case KVM_ARM_PSCI_0_2:
|
||||
return kvm_psci_0_2_call(vcpu);
|
||||
case KVM_ARM_PSCI_0_1:
|
||||
return kvm_psci_0_1_call(vcpu);
|
||||
default:
|
||||
return -EINVAL;
|
||||
};
|
||||
}
|
||||
|
|
@ -7,26 +7,250 @@
|
|||
#define TRACE_SYSTEM kvm
|
||||
|
||||
/*
|
||||
* Tracepoints for vgic
|
||||
* Tracepoints for entry/exit to guest
|
||||
*/
|
||||
TRACE_EVENT(vgic_update_irq_pending,
|
||||
TP_PROTO(unsigned long vcpu_id, __u32 irq, bool level),
|
||||
TP_ARGS(vcpu_id, irq, level),
|
||||
TRACE_EVENT(kvm_entry,
|
||||
TP_PROTO(unsigned long vcpu_pc),
|
||||
TP_ARGS(vcpu_pc),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, vcpu_id )
|
||||
__field( __u32, irq )
|
||||
__field( bool, level )
|
||||
__field( unsigned long, vcpu_pc )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->vcpu_id = vcpu_id;
|
||||
__entry->irq = irq;
|
||||
__entry->vcpu_pc = vcpu_pc;
|
||||
),
|
||||
|
||||
TP_printk("PC: 0x%08lx", __entry->vcpu_pc)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_exit,
|
||||
TP_PROTO(int idx, unsigned int exit_reason, unsigned long vcpu_pc),
|
||||
TP_ARGS(idx, exit_reason, vcpu_pc),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( int, idx )
|
||||
__field( unsigned int, exit_reason )
|
||||
__field( unsigned long, vcpu_pc )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->idx = idx;
|
||||
__entry->exit_reason = exit_reason;
|
||||
__entry->vcpu_pc = vcpu_pc;
|
||||
),
|
||||
|
||||
TP_printk("%s: HSR_EC: 0x%04x (%s), PC: 0x%08lx",
|
||||
__print_symbolic(__entry->idx, kvm_arm_exception_type),
|
||||
__entry->exit_reason,
|
||||
__print_symbolic(__entry->exit_reason, kvm_arm_exception_class),
|
||||
__entry->vcpu_pc)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_guest_fault,
|
||||
TP_PROTO(unsigned long vcpu_pc, unsigned long hsr,
|
||||
unsigned long hxfar,
|
||||
unsigned long long ipa),
|
||||
TP_ARGS(vcpu_pc, hsr, hxfar, ipa),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, vcpu_pc )
|
||||
__field( unsigned long, hsr )
|
||||
__field( unsigned long, hxfar )
|
||||
__field( unsigned long long, ipa )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->vcpu_pc = vcpu_pc;
|
||||
__entry->hsr = hsr;
|
||||
__entry->hxfar = hxfar;
|
||||
__entry->ipa = ipa;
|
||||
),
|
||||
|
||||
TP_printk("ipa %#llx, hsr %#08lx, hxfar %#08lx, pc %#08lx",
|
||||
__entry->ipa, __entry->hsr,
|
||||
__entry->hxfar, __entry->vcpu_pc)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_access_fault,
|
||||
TP_PROTO(unsigned long ipa),
|
||||
TP_ARGS(ipa),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, ipa )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->ipa = ipa;
|
||||
),
|
||||
|
||||
TP_printk("IPA: %lx", __entry->ipa)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_irq_line,
|
||||
TP_PROTO(unsigned int type, int vcpu_idx, int irq_num, int level),
|
||||
TP_ARGS(type, vcpu_idx, irq_num, level),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, type )
|
||||
__field( int, vcpu_idx )
|
||||
__field( int, irq_num )
|
||||
__field( int, level )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->type = type;
|
||||
__entry->vcpu_idx = vcpu_idx;
|
||||
__entry->irq_num = irq_num;
|
||||
__entry->level = level;
|
||||
),
|
||||
|
||||
TP_printk("VCPU: %ld, IRQ %d, level: %d",
|
||||
__entry->vcpu_id, __entry->irq, __entry->level)
|
||||
TP_printk("Inject %s interrupt (%d), vcpu->idx: %d, num: %d, level: %d",
|
||||
(__entry->type == KVM_ARM_IRQ_TYPE_CPU) ? "CPU" :
|
||||
(__entry->type == KVM_ARM_IRQ_TYPE_PPI) ? "VGIC PPI" :
|
||||
(__entry->type == KVM_ARM_IRQ_TYPE_SPI) ? "VGIC SPI" : "UNKNOWN",
|
||||
__entry->type, __entry->vcpu_idx, __entry->irq_num, __entry->level)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_mmio_emulate,
|
||||
TP_PROTO(unsigned long vcpu_pc, unsigned long instr,
|
||||
unsigned long cpsr),
|
||||
TP_ARGS(vcpu_pc, instr, cpsr),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, vcpu_pc )
|
||||
__field( unsigned long, instr )
|
||||
__field( unsigned long, cpsr )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->vcpu_pc = vcpu_pc;
|
||||
__entry->instr = instr;
|
||||
__entry->cpsr = cpsr;
|
||||
),
|
||||
|
||||
TP_printk("Emulate MMIO at: 0x%08lx (instr: %08lx, cpsr: %08lx)",
|
||||
__entry->vcpu_pc, __entry->instr, __entry->cpsr)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_unmap_hva,
|
||||
TP_PROTO(unsigned long hva),
|
||||
TP_ARGS(hva),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, hva )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->hva = hva;
|
||||
),
|
||||
|
||||
TP_printk("mmu notifier unmap hva: %#08lx", __entry->hva)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_unmap_hva_range,
|
||||
TP_PROTO(unsigned long start, unsigned long end),
|
||||
TP_ARGS(start, end),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, start )
|
||||
__field( unsigned long, end )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->start = start;
|
||||
__entry->end = end;
|
||||
),
|
||||
|
||||
TP_printk("mmu notifier unmap range: %#08lx -- %#08lx",
|
||||
__entry->start, __entry->end)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_set_spte_hva,
|
||||
TP_PROTO(unsigned long hva),
|
||||
TP_ARGS(hva),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, hva )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->hva = hva;
|
||||
),
|
||||
|
||||
TP_printk("mmu notifier set pte hva: %#08lx", __entry->hva)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_age_hva,
|
||||
TP_PROTO(unsigned long start, unsigned long end),
|
||||
TP_ARGS(start, end),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, start )
|
||||
__field( unsigned long, end )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->start = start;
|
||||
__entry->end = end;
|
||||
),
|
||||
|
||||
TP_printk("mmu notifier age hva: %#08lx -- %#08lx",
|
||||
__entry->start, __entry->end)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_test_age_hva,
|
||||
TP_PROTO(unsigned long hva),
|
||||
TP_ARGS(hva),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, hva )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->hva = hva;
|
||||
),
|
||||
|
||||
TP_printk("mmu notifier test age hva: %#08lx", __entry->hva)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_set_way_flush,
|
||||
TP_PROTO(unsigned long vcpu_pc, bool cache),
|
||||
TP_ARGS(vcpu_pc, cache),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, vcpu_pc )
|
||||
__field( bool, cache )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->vcpu_pc = vcpu_pc;
|
||||
__entry->cache = cache;
|
||||
),
|
||||
|
||||
TP_printk("S/W flush at 0x%016lx (cache %s)",
|
||||
__entry->vcpu_pc, __entry->cache ? "on" : "off")
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_toggle_cache,
|
||||
TP_PROTO(unsigned long vcpu_pc, bool was, bool now),
|
||||
TP_ARGS(vcpu_pc, was, now),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, vcpu_pc )
|
||||
__field( bool, was )
|
||||
__field( bool, now )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->vcpu_pc = vcpu_pc;
|
||||
__entry->was = was;
|
||||
__entry->now = now;
|
||||
),
|
||||
|
||||
TP_printk("VM op at 0x%016lx (cache was %s, now %s)",
|
||||
__entry->vcpu_pc, __entry->was ? "on" : "off",
|
||||
__entry->now ? "on" : "off")
|
||||
);
|
||||
|
||||
/*
|
||||
|
|
|
|||
37
virt/kvm/arm/vgic/trace.h
Normal file
37
virt/kvm/arm/vgic/trace.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#if !defined(_TRACE_VGIC_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _TRACE_VGIC_H
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM kvm
|
||||
|
||||
TRACE_EVENT(vgic_update_irq_pending,
|
||||
TP_PROTO(unsigned long vcpu_id, __u32 irq, bool level),
|
||||
TP_ARGS(vcpu_id, irq, level),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, vcpu_id )
|
||||
__field( __u32, irq )
|
||||
__field( bool, level )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->vcpu_id = vcpu_id;
|
||||
__entry->irq = irq;
|
||||
__entry->level = level;
|
||||
),
|
||||
|
||||
TP_printk("VCPU: %ld, IRQ %d, level: %d",
|
||||
__entry->vcpu_id, __entry->irq, __entry->level)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_VGIC_H */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH ../../../virt/kvm/arm/vgic
|
||||
#undef TRACE_INCLUDE_FILE
|
||||
#define TRACE_INCLUDE_FILE trace
|
||||
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
||||
|
|
@ -227,10 +227,27 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
|
|||
}
|
||||
|
||||
/**
|
||||
* kvm_vgic_vcpu_init() - Enable the VCPU interface
|
||||
* @vcpu: the VCPU which's VGIC should be enabled
|
||||
* kvm_vgic_vcpu_init() - Register VCPU-specific KVM iodevs
|
||||
* @vcpu: pointer to the VCPU being created and initialized
|
||||
*/
|
||||
static void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
|
||||
int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int ret = 0;
|
||||
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
|
||||
|
||||
if (!irqchip_in_kernel(vcpu->kvm))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If we are creating a VCPU with a GICv3 we must also register the
|
||||
* KVM io device for the redistributor that belongs to this VCPU.
|
||||
*/
|
||||
if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
|
||||
ret = vgic_register_redist_iodev(vcpu);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void kvm_vgic_vcpu_enable(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_vgic_global_state.type == VGIC_V2)
|
||||
vgic_v2_enable(vcpu);
|
||||
|
|
@ -269,7 +286,7 @@ int vgic_init(struct kvm *kvm)
|
|||
dist->msis_require_devid = true;
|
||||
|
||||
kvm_for_each_vcpu(i, vcpu, kvm)
|
||||
kvm_vgic_vcpu_init(vcpu);
|
||||
kvm_vgic_vcpu_enable(vcpu);
|
||||
|
||||
ret = kvm_vgic_setup_default_irq_routing(kvm);
|
||||
if (ret)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue