Mostly bugfixes, but also:
- s390 support for KVM selftests - LAPIC timer offloading to housekeeping CPUs - Extend an s390 optimization for overcommitted hosts to all architectures - Debugging cleanups and improvements -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQEcBAABAgAGBQJdMr1FAAoJEL/70l94x66DvIkH/iVuUX9jO1NoQ7qhxeo04MnT GP9mX3XnWoI/iN0zAIRfQSP2/9a6+KblgdiziABhju58j5dCfAZGb5793TQppweb 3ubl11vy7YkzaXJ0b35K7CFhOU9oSlHHGyi5Uh+yyje5qWNxwmHpizxjynbFTKb6 +/S7O2Ua1VrAVvx0i0IRtwanIK/jF4dStVButgVaVdUva3zLaQmeI71iaJl9ddXY bh50xoYua5Ek6+ENi+nwCNVy4OF152AwDbXlxrU0QbeA1B888Qio7nIqb3bwwPpZ /8wMVvPzQgL7RmgtY5E5Z4cCYuu7mK8wgGxhuk3oszlVwZJ5rmnaYwGEl4x1s7o= =giag -----END PGP SIGNATURE----- Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm Pull more KVM updates from Paolo Bonzini: "Mostly bugfixes, but also: - s390 support for KVM selftests - LAPIC timer offloading to housekeeping CPUs - Extend an s390 optimization for overcommitted hosts to all architectures - Debugging cleanups and improvements" * tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (25 commits) KVM: x86: Add fixed counters to PMU filter KVM: nVMX: do not use dangling shadow VMCS after guest reset KVM: VMX: dump VMCS on failed entry KVM: x86/vPMU: refine kvm_pmu err msg when event creation failed KVM: s390: Use kvm_vcpu_wake_up in kvm_s390_vcpu_wakeup KVM: Boost vCPUs that are delivering interrupts KVM: selftests: Remove superfluous define from vmx.c KVM: SVM: Fix detection of AMD Errata 1096 KVM: LAPIC: Inject timer interrupt via posted interrupt KVM: LAPIC: Make lapic timer unpinned KVM: x86/vPMU: reset pmc->counter to 0 for pmu fixed_counters KVM: nVMX: Ignore segment base for VMX memory operand when segment not FS or GS kvm: x86: ioapic and apic debug macros cleanup kvm: x86: some tsc debug cleanup kvm: vmx: fix coccinelle warnings x86: kvm: avoid constant-conversion warning x86: kvm: avoid -Wsometimes-uninitized warning KVM: x86: expose AVX512_BF16 feature to guest KVM: selftests: enable pgste option for the linker on s390 KVM: selftests: Move kvm_create_max_vcpus test to generic code ...
This commit is contained in:
commit
07ab9d5bc5
|
@ -4090,17 +4090,22 @@ Parameters: struct kvm_pmu_event_filter (in)
|
|||
Returns: 0 on success, -1 on error
|
||||
|
||||
struct kvm_pmu_event_filter {
|
||||
__u32 action;
|
||||
__u32 nevents;
|
||||
__u64 events[0];
|
||||
__u32 action;
|
||||
__u32 nevents;
|
||||
__u32 fixed_counter_bitmap;
|
||||
__u32 flags;
|
||||
__u32 pad[4];
|
||||
__u64 events[0];
|
||||
};
|
||||
|
||||
This ioctl restricts the set of PMU events that the guest can program.
|
||||
The argument holds a list of events which will be allowed or denied.
|
||||
The eventsel+umask of each event the guest attempts to program is compared
|
||||
against the events field to determine whether the guest should have access.
|
||||
This only affects general purpose counters; fixed purpose counters can
|
||||
be disabled by changing the perfmon CPUID leaf.
|
||||
The events field only controls general purpose counters; fixed purpose
|
||||
counters are controlled by the fixed_counter_bitmap.
|
||||
|
||||
No flags are defined yet, the field must be zero.
|
||||
|
||||
Valid values for 'action':
|
||||
#define KVM_PMU_EVENT_ALLOW 0
|
||||
|
|
|
@ -8878,6 +8878,8 @@ F: arch/s390/include/asm/gmap.h
|
|||
F: arch/s390/include/asm/kvm*
|
||||
F: arch/s390/kvm/
|
||||
F: arch/s390/mm/gmap.c
|
||||
F: tools/testing/selftests/kvm/s390x/
|
||||
F: tools/testing/selftests/kvm/*/s390x/
|
||||
|
||||
KERNEL VIRTUAL MACHINE FOR X86 (KVM/x86)
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
|
|
|
@ -1224,28 +1224,11 @@ no_timer:
|
|||
|
||||
void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* We cannot move this into the if, as the CPU might be already
|
||||
* in kvm_vcpu_block without having the waitqueue set (polling)
|
||||
*/
|
||||
vcpu->valid_wakeup = true;
|
||||
kvm_vcpu_wake_up(vcpu);
|
||||
|
||||
/*
|
||||
* This is mostly to document, that the read in swait_active could
|
||||
* be moved before other stores, leading to subtle races.
|
||||
* All current users do not store or use an atomic like update
|
||||
*/
|
||||
smp_mb__after_atomic();
|
||||
if (swait_active(&vcpu->wq)) {
|
||||
/*
|
||||
* The vcpu gave up the cpu voluntarily, mark it as a good
|
||||
* yield-candidate.
|
||||
*/
|
||||
vcpu->preempted = true;
|
||||
swake_up_one(&vcpu->wq);
|
||||
vcpu->stat.halt_wakeup++;
|
||||
}
|
||||
/*
|
||||
* The VCPU might not be sleeping but is executing the VSIE. Let's
|
||||
* The VCPU might not be sleeping but rather executing VSIE. Let's
|
||||
* kick it, so it leaves the SIE to process the request.
|
||||
*/
|
||||
kvm_s390_vsie_kick(vcpu);
|
||||
|
|
|
@ -435,9 +435,12 @@ struct kvm_nested_state {
|
|||
|
||||
/* for KVM_CAP_PMU_EVENT_FILTER */
|
||||
struct kvm_pmu_event_filter {
|
||||
__u32 action;
|
||||
__u32 nevents;
|
||||
__u64 events[0];
|
||||
__u32 action;
|
||||
__u32 nevents;
|
||||
__u32 fixed_counter_bitmap;
|
||||
__u32 flags;
|
||||
__u32 pad[4];
|
||||
__u64 events[0];
|
||||
};
|
||||
|
||||
#define KVM_PMU_EVENT_ALLOW 0
|
||||
|
|
|
@ -368,9 +368,13 @@ static inline void do_cpuid_7_mask(struct kvm_cpuid_entry2 *entry, int index)
|
|||
F(SPEC_CTRL_SSBD) | F(ARCH_CAPABILITIES) | F(INTEL_STIBP) |
|
||||
F(MD_CLEAR);
|
||||
|
||||
/* cpuid 7.1.eax */
|
||||
const u32 kvm_cpuid_7_1_eax_x86_features =
|
||||
F(AVX512_BF16);
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
entry->eax = 0;
|
||||
entry->eax = min(entry->eax, 1u);
|
||||
entry->ebx &= kvm_cpuid_7_0_ebx_x86_features;
|
||||
cpuid_mask(&entry->ebx, CPUID_7_0_EBX);
|
||||
/* TSC_ADJUST is emulated */
|
||||
|
@ -394,6 +398,12 @@ static inline void do_cpuid_7_mask(struct kvm_cpuid_entry2 *entry, int index)
|
|||
*/
|
||||
entry->edx |= F(ARCH_CAPABILITIES);
|
||||
break;
|
||||
case 1:
|
||||
entry->eax &= kvm_cpuid_7_1_eax_x86_features;
|
||||
entry->ebx = 0;
|
||||
entry->ecx = 0;
|
||||
entry->edx = 0;
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
entry->eax = 0;
|
||||
|
|
|
@ -1594,7 +1594,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
|
|||
{
|
||||
u64 param, ingpa, outgpa, ret = HV_STATUS_SUCCESS;
|
||||
uint16_t code, rep_idx, rep_cnt;
|
||||
bool fast, longmode, rep;
|
||||
bool fast, rep;
|
||||
|
||||
/*
|
||||
* hypercall generates UD from non zero cpl and real mode
|
||||
|
@ -1605,9 +1605,14 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
|
|||
return 1;
|
||||
}
|
||||
|
||||
longmode = is_64_bit_mode(vcpu);
|
||||
|
||||
if (!longmode) {
|
||||
#ifdef CONFIG_X86_64
|
||||
if (is_64_bit_mode(vcpu)) {
|
||||
param = kvm_rcx_read(vcpu);
|
||||
ingpa = kvm_rdx_read(vcpu);
|
||||
outgpa = kvm_r8_read(vcpu);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
param = ((u64)kvm_rdx_read(vcpu) << 32) |
|
||||
(kvm_rax_read(vcpu) & 0xffffffff);
|
||||
ingpa = ((u64)kvm_rbx_read(vcpu) << 32) |
|
||||
|
@ -1615,13 +1620,6 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
|
|||
outgpa = ((u64)kvm_rdi_read(vcpu) << 32) |
|
||||
(kvm_rsi_read(vcpu) & 0xffffffff);
|
||||
}
|
||||
#ifdef CONFIG_X86_64
|
||||
else {
|
||||
param = kvm_rcx_read(vcpu);
|
||||
ingpa = kvm_rdx_read(vcpu);
|
||||
outgpa = kvm_r8_read(vcpu);
|
||||
}
|
||||
#endif
|
||||
|
||||
code = param & 0xffff;
|
||||
fast = !!(param & HV_HYPERCALL_FAST_BIT);
|
||||
|
|
|
@ -45,11 +45,6 @@
|
|||
#include "lapic.h"
|
||||
#include "irq.h"
|
||||
|
||||
#if 0
|
||||
#define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg)
|
||||
#else
|
||||
#define ioapic_debug(fmt, arg...)
|
||||
#endif
|
||||
static int ioapic_service(struct kvm_ioapic *vioapic, int irq,
|
||||
bool line_status);
|
||||
|
||||
|
@ -294,7 +289,6 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
|
|||
default:
|
||||
index = (ioapic->ioregsel - 0x10) >> 1;
|
||||
|
||||
ioapic_debug("change redir index %x val %x\n", index, val);
|
||||
if (index >= IOAPIC_NUM_PINS)
|
||||
return;
|
||||
e = &ioapic->redirtbl[index];
|
||||
|
@ -343,12 +337,6 @@ static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
|
|||
entry->fields.remote_irr))
|
||||
return -1;
|
||||
|
||||
ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
|
||||
"vector=%x trig_mode=%x\n",
|
||||
entry->fields.dest_id, entry->fields.dest_mode,
|
||||
entry->fields.delivery_mode, entry->fields.vector,
|
||||
entry->fields.trig_mode);
|
||||
|
||||
irqe.dest_id = entry->fields.dest_id;
|
||||
irqe.vector = entry->fields.vector;
|
||||
irqe.dest_mode = entry->fields.dest_mode;
|
||||
|
@ -515,7 +503,6 @@ static int ioapic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
|
|||
if (!ioapic_in_range(ioapic, addr))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ioapic_debug("addr %lx\n", (unsigned long)addr);
|
||||
ASSERT(!(addr & 0xf)); /* check alignment */
|
||||
|
||||
addr &= 0xff;
|
||||
|
@ -558,8 +545,6 @@ static int ioapic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
|
|||
if (!ioapic_in_range(ioapic, addr))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ioapic_debug("ioapic_mmio_write addr=%p len=%d val=%p\n",
|
||||
(void*)addr, len, val);
|
||||
ASSERT(!(addr & 0xf)); /* check alignment */
|
||||
|
||||
switch (len) {
|
||||
|
|
|
@ -52,9 +52,6 @@
|
|||
#define PRIu64 "u"
|
||||
#define PRIo64 "o"
|
||||
|
||||
/* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */
|
||||
#define apic_debug(fmt, arg...) do {} while (0)
|
||||
|
||||
/* 14 is the version for Xeon and Pentium 8.4.8*/
|
||||
#define APIC_VERSION (0x14UL | ((KVM_APIC_LVT_NUM - 1) << 16))
|
||||
#define LAPIC_MMIO_LENGTH (1 << 12)
|
||||
|
@ -121,6 +118,17 @@ static inline u32 kvm_x2apic_id(struct kvm_lapic *apic)
|
|||
return apic->vcpu->vcpu_id;
|
||||
}
|
||||
|
||||
bool kvm_can_post_timer_interrupt(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return pi_inject_timer && kvm_vcpu_apicv_active(vcpu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_can_post_timer_interrupt);
|
||||
|
||||
static bool kvm_use_posted_timer_interrupt(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_can_post_timer_interrupt(vcpu) && vcpu->mode == IN_GUEST_MODE;
|
||||
}
|
||||
|
||||
static inline bool kvm_apic_map_get_logical_dest(struct kvm_apic_map *map,
|
||||
u32 dest_id, struct kvm_lapic ***cluster, u16 *mask) {
|
||||
switch (map->mode) {
|
||||
|
@ -627,7 +635,7 @@ static bool pv_eoi_get_pending(struct kvm_vcpu *vcpu)
|
|||
{
|
||||
u8 val;
|
||||
if (pv_eoi_get_user(vcpu, &val) < 0)
|
||||
apic_debug("Can't read EOI MSR value: 0x%llx\n",
|
||||
printk(KERN_WARNING "Can't read EOI MSR value: 0x%llx\n",
|
||||
(unsigned long long)vcpu->arch.pv_eoi.msr_val);
|
||||
return val & 0x1;
|
||||
}
|
||||
|
@ -635,7 +643,7 @@ static bool pv_eoi_get_pending(struct kvm_vcpu *vcpu)
|
|||
static void pv_eoi_set_pending(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (pv_eoi_put_user(vcpu, KVM_PV_EOI_ENABLED) < 0) {
|
||||
apic_debug("Can't set EOI MSR value: 0x%llx\n",
|
||||
printk(KERN_WARNING "Can't set EOI MSR value: 0x%llx\n",
|
||||
(unsigned long long)vcpu->arch.pv_eoi.msr_val);
|
||||
return;
|
||||
}
|
||||
|
@ -645,7 +653,7 @@ static void pv_eoi_set_pending(struct kvm_vcpu *vcpu)
|
|||
static void pv_eoi_clr_pending(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (pv_eoi_put_user(vcpu, KVM_PV_EOI_DISABLED) < 0) {
|
||||
apic_debug("Can't clear EOI MSR value: 0x%llx\n",
|
||||
printk(KERN_WARNING "Can't clear EOI MSR value: 0x%llx\n",
|
||||
(unsigned long long)vcpu->arch.pv_eoi.msr_val);
|
||||
return;
|
||||
}
|
||||
|
@ -679,9 +687,6 @@ static bool __apic_update_ppr(struct kvm_lapic *apic, u32 *new_ppr)
|
|||
else
|
||||
ppr = isrv & 0xf0;
|
||||
|
||||
apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x",
|
||||
apic, ppr, isr, isrv);
|
||||
|
||||
*new_ppr = ppr;
|
||||
if (old_ppr != ppr)
|
||||
kvm_lapic_set_reg(apic, APIC_PROCPRI, ppr);
|
||||
|
@ -758,8 +763,6 @@ static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda)
|
|||
return ((logical_id >> 4) == (mda >> 4))
|
||||
&& (logical_id & mda & 0xf) != 0;
|
||||
default:
|
||||
apic_debug("Bad DFR vcpu %d: %08x\n",
|
||||
apic->vcpu->vcpu_id, kvm_lapic_get_reg(apic, APIC_DFR));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -798,10 +801,6 @@ bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
|
|||
struct kvm_lapic *target = vcpu->arch.apic;
|
||||
u32 mda = kvm_apic_mda(vcpu, dest, source, target);
|
||||
|
||||
apic_debug("target %p, source %p, dest 0x%x, "
|
||||
"dest_mode 0x%x, short_hand 0x%x\n",
|
||||
target, source, dest, dest_mode, short_hand);
|
||||
|
||||
ASSERT(target);
|
||||
switch (short_hand) {
|
||||
case APIC_DEST_NOSHORT:
|
||||
|
@ -816,8 +815,6 @@ bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
|
|||
case APIC_DEST_ALLBUT:
|
||||
return target != source;
|
||||
default:
|
||||
apic_debug("kvm: apic: Bad dest shorthand value %x\n",
|
||||
short_hand);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1095,15 +1092,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
|
|||
smp_wmb();
|
||||
kvm_make_request(KVM_REQ_EVENT, vcpu);
|
||||
kvm_vcpu_kick(vcpu);
|
||||
} else {
|
||||
apic_debug("Ignoring de-assert INIT to vcpu %d\n",
|
||||
vcpu->vcpu_id);
|
||||
}
|
||||
break;
|
||||
|
||||
case APIC_DM_STARTUP:
|
||||
apic_debug("SIPI to vcpu %d vector 0x%02x\n",
|
||||
vcpu->vcpu_id, vector);
|
||||
result = 1;
|
||||
apic->sipi_vector = vector;
|
||||
/* make sure sipi_vector is visible for the receiver */
|
||||
|
@ -1221,14 +1213,6 @@ static void apic_send_ipi(struct kvm_lapic *apic)
|
|||
|
||||
trace_kvm_apic_ipi(icr_low, irq.dest_id);
|
||||
|
||||
apic_debug("icr_high 0x%x, icr_low 0x%x, "
|
||||
"short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
|
||||
"dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x, "
|
||||
"msi_redir_hint 0x%x\n",
|
||||
icr_high, icr_low, irq.shorthand, irq.dest_id,
|
||||
irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode,
|
||||
irq.vector, irq.msi_redir_hint);
|
||||
|
||||
kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq, NULL);
|
||||
}
|
||||
|
||||
|
@ -1282,7 +1266,6 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
|
|||
|
||||
switch (offset) {
|
||||
case APIC_ARBPRI:
|
||||
apic_debug("Access APIC ARBPRI register which is for P6\n");
|
||||
break;
|
||||
|
||||
case APIC_TMCCT: /* Timer CCR */
|
||||
|
@ -1349,11 +1332,8 @@ int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
|
|||
if (!apic_x2apic_mode(apic))
|
||||
valid_reg_mask |= APIC_REG_MASK(APIC_ARBPRI);
|
||||
|
||||
if (offset > 0x3f0 || !(valid_reg_mask & APIC_REG_MASK(offset))) {
|
||||
apic_debug("KVM_APIC_READ: read reserved register %x\n",
|
||||
offset);
|
||||
if (offset > 0x3f0 || !(valid_reg_mask & APIC_REG_MASK(offset)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = __apic_read(apic, offset & ~0xf);
|
||||
|
||||
|
@ -1411,9 +1391,6 @@ static void update_divide_count(struct kvm_lapic *apic)
|
|||
tmp1 = tdcr & 0xf;
|
||||
tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
|
||||
apic->divide_count = 0x1 << (tmp2 & 0x7);
|
||||
|
||||
apic_debug("timer divide count is 0x%x\n",
|
||||
apic->divide_count);
|
||||
}
|
||||
|
||||
static void limit_periodic_timer_frequency(struct kvm_lapic *apic)
|
||||
|
@ -1455,29 +1432,6 @@ static void apic_update_lvtt(struct kvm_lapic *apic)
|
|||
}
|
||||
}
|
||||
|
||||
static void apic_timer_expired(struct kvm_lapic *apic)
|
||||
{
|
||||
struct kvm_vcpu *vcpu = apic->vcpu;
|
||||
struct swait_queue_head *q = &vcpu->wq;
|
||||
struct kvm_timer *ktimer = &apic->lapic_timer;
|
||||
|
||||
if (atomic_read(&apic->lapic_timer.pending))
|
||||
return;
|
||||
|
||||
atomic_inc(&apic->lapic_timer.pending);
|
||||
kvm_set_pending_timer(vcpu);
|
||||
|
||||
/*
|
||||
* For x86, the atomic_inc() is serialized, thus
|
||||
* using swait_active() is safe.
|
||||
*/
|
||||
if (swait_active(q))
|
||||
swake_up_one(q);
|
||||
|
||||
if (apic_lvtt_tscdeadline(apic) || ktimer->hv_timer_in_use)
|
||||
ktimer->expired_tscdeadline = ktimer->tscdeadline;
|
||||
}
|
||||
|
||||
/*
|
||||
* On APICv, this test will cause a busy wait
|
||||
* during a higher-priority task.
|
||||
|
@ -1551,7 +1505,7 @@ static inline void adjust_lapic_timer_advance(struct kvm_vcpu *vcpu,
|
|||
apic->lapic_timer.timer_advance_ns = timer_advance_ns;
|
||||
}
|
||||
|
||||
void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu)
|
||||
static void __kvm_wait_lapic_expire(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_lapic *apic = vcpu->arch.apic;
|
||||
u64 guest_tsc, tsc_deadline;
|
||||
|
@ -1559,9 +1513,6 @@ void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu)
|
|||
if (apic->lapic_timer.expired_tscdeadline == 0)
|
||||
return;
|
||||
|
||||
if (!lapic_timer_int_injected(vcpu))
|
||||
return;
|
||||
|
||||
tsc_deadline = apic->lapic_timer.expired_tscdeadline;
|
||||
apic->lapic_timer.expired_tscdeadline = 0;
|
||||
guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());
|
||||
|
@ -1573,8 +1524,57 @@ void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu)
|
|||
if (unlikely(!apic->lapic_timer.timer_advance_adjust_done))
|
||||
adjust_lapic_timer_advance(vcpu, apic->lapic_timer.advance_expire_delta);
|
||||
}
|
||||
|
||||
void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (lapic_timer_int_injected(vcpu))
|
||||
__kvm_wait_lapic_expire(vcpu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_wait_lapic_expire);
|
||||
|
||||
static void kvm_apic_inject_pending_timer_irqs(struct kvm_lapic *apic)
|
||||
{
|
||||
struct kvm_timer *ktimer = &apic->lapic_timer;
|
||||
|
||||
kvm_apic_local_deliver(apic, APIC_LVTT);
|
||||
if (apic_lvtt_tscdeadline(apic))
|
||||
ktimer->tscdeadline = 0;
|
||||
if (apic_lvtt_oneshot(apic)) {
|
||||
ktimer->tscdeadline = 0;
|
||||
ktimer->target_expiration = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void apic_timer_expired(struct kvm_lapic *apic)
|
||||
{
|
||||
struct kvm_vcpu *vcpu = apic->vcpu;
|
||||
struct swait_queue_head *q = &vcpu->wq;
|
||||
struct kvm_timer *ktimer = &apic->lapic_timer;
|
||||
|
||||
if (atomic_read(&apic->lapic_timer.pending))
|
||||
return;
|
||||
|
||||
if (apic_lvtt_tscdeadline(apic) || ktimer->hv_timer_in_use)
|
||||
ktimer->expired_tscdeadline = ktimer->tscdeadline;
|
||||
|
||||
if (kvm_use_posted_timer_interrupt(apic->vcpu)) {
|
||||
if (apic->lapic_timer.timer_advance_ns)
|
||||
__kvm_wait_lapic_expire(vcpu);
|
||||
kvm_apic_inject_pending_timer_irqs(apic);
|
||||
return;
|
||||
}
|
||||
|
||||
atomic_inc(&apic->lapic_timer.pending);
|
||||
kvm_set_pending_timer(vcpu);
|
||||
|
||||
/*
|
||||
* For x86, the atomic_inc() is serialized, thus
|
||||
* using swait_active() is safe.
|
||||
*/
|
||||
if (swait_active(q))
|
||||
swake_up_one(q);
|
||||
}
|
||||
|
||||
static void start_sw_tscdeadline(struct kvm_lapic *apic)
|
||||
{
|
||||
struct kvm_timer *ktimer = &apic->lapic_timer;
|
||||
|
@ -1601,7 +1601,7 @@ static void start_sw_tscdeadline(struct kvm_lapic *apic)
|
|||
likely(ns > apic->lapic_timer.timer_advance_ns)) {
|
||||
expire = ktime_add_ns(now, ns);
|
||||
expire = ktime_sub_ns(expire, ktimer->timer_advance_ns);
|
||||
hrtimer_start(&ktimer->timer, expire, HRTIMER_MODE_ABS_PINNED);
|
||||
hrtimer_start(&ktimer->timer, expire, HRTIMER_MODE_ABS);
|
||||
} else
|
||||
apic_timer_expired(apic);
|
||||
|
||||
|
@ -1648,16 +1648,6 @@ static bool set_target_expiration(struct kvm_lapic *apic)
|
|||
|
||||
limit_periodic_timer_frequency(apic);
|
||||
|
||||
apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
|
||||
PRIx64 ", "
|
||||
"timer initial count 0x%x, period %lldns, "
|
||||
"expire @ 0x%016" PRIx64 ".\n", __func__,
|
||||
APIC_BUS_CYCLE_NS, ktime_to_ns(now),
|
||||
kvm_lapic_get_reg(apic, APIC_TMICT),
|
||||
apic->lapic_timer.period,
|
||||
ktime_to_ns(ktime_add_ns(now,
|
||||
apic->lapic_timer.period)));
|
||||
|
||||
apic->lapic_timer.tscdeadline = kvm_read_l1_tsc(apic->vcpu, tscl) +
|
||||
nsec_to_cycles(apic->vcpu, apic->lapic_timer.period);
|
||||
apic->lapic_timer.target_expiration = ktime_add_ns(now, apic->lapic_timer.period);
|
||||
|
@ -1703,7 +1693,7 @@ static void start_sw_period(struct kvm_lapic *apic)
|
|||
|
||||
hrtimer_start(&apic->lapic_timer.timer,
|
||||
apic->lapic_timer.target_expiration,
|
||||
HRTIMER_MODE_ABS_PINNED);
|
||||
HRTIMER_MODE_ABS);
|
||||
}
|
||||
|
||||
bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu)
|
||||
|
@ -1860,8 +1850,6 @@ static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val)
|
|||
if (apic->lvt0_in_nmi_mode != lvt0_in_nmi_mode) {
|
||||
apic->lvt0_in_nmi_mode = lvt0_in_nmi_mode;
|
||||
if (lvt0_in_nmi_mode) {
|
||||
apic_debug("Receive NMI setting on APIC_LVT0 "
|
||||
"for cpu %d\n", apic->vcpu->vcpu_id);
|
||||
atomic_inc(&apic->vcpu->kvm->arch.vapics_in_nmi_mode);
|
||||
} else
|
||||
atomic_dec(&apic->vcpu->kvm->arch.vapics_in_nmi_mode);
|
||||
|
@ -1975,8 +1963,6 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
|
|||
case APIC_TDCR: {
|
||||
uint32_t old_divisor = apic->divide_count;
|
||||
|
||||
if (val & 4)
|
||||
apic_debug("KVM_WRITE:TDCR %x\n", val);
|
||||
kvm_lapic_set_reg(apic, APIC_TDCR, val);
|
||||
update_divide_count(apic);
|
||||
if (apic->divide_count != old_divisor &&
|
||||
|
@ -1988,10 +1974,8 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
|
|||
break;
|
||||
}
|
||||
case APIC_ESR:
|
||||
if (apic_x2apic_mode(apic) && val != 0) {
|
||||
apic_debug("KVM_WRITE:ESR not zero %x\n", val);
|
||||
if (apic_x2apic_mode(apic) && val != 0)
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case APIC_SELF_IPI:
|
||||
|
@ -2004,8 +1988,7 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
|
|||
ret = 1;
|
||||
break;
|
||||
}
|
||||
if (ret)
|
||||
apic_debug("Local APIC Write to read-only register %x\n", reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_lapic_reg_write);
|
||||
|
@ -2033,20 +2016,12 @@ static int apic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
|
|||
* 32/64/128 bits registers must be accessed thru 32 bits.
|
||||
* Refer SDM 8.4.1
|
||||
*/
|
||||
if (len != 4 || (offset & 0xf)) {
|
||||
/* Don't shout loud, $infamous_os would cause only noise. */
|
||||
apic_debug("apic write: bad size=%d %lx\n", len, (long)address);
|
||||
if (len != 4 || (offset & 0xf))
|
||||
return 0;
|
||||
}
|
||||
|
||||
val = *(u32*)data;
|
||||
|
||||
/* too common printing */
|
||||
if (offset != APIC_EOI)
|
||||
apic_debug("%s: offset 0x%x with length 0x%x, and value is "
|
||||
"0x%x\n", __func__, offset, len, val);
|
||||
|
||||
kvm_lapic_reg_write(apic, offset, val);
|
||||
kvm_lapic_reg_write(apic, offset & 0xff0, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2178,11 +2153,6 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
|
|||
if ((value & MSR_IA32_APICBASE_ENABLE) &&
|
||||
apic->base_address != APIC_DEFAULT_PHYS_BASE)
|
||||
pr_warn_once("APIC base relocation is unsupported by KVM");
|
||||
|
||||
/* with FSB delivery interrupt, we can restart APIC functionality */
|
||||
apic_debug("apic base msr is 0x%016" PRIx64 ", and base address is "
|
||||
"0x%lx.\n", apic->vcpu->arch.apic_base, apic->base_address);
|
||||
|
||||
}
|
||||
|
||||
void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
|
||||
|
@ -2193,8 +2163,6 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
|
|||
if (!apic)
|
||||
return;
|
||||
|
||||
apic_debug("%s\n", __func__);
|
||||
|
||||
/* Stop the timer in case it's a reset to an active apic */
|
||||
hrtimer_cancel(&apic->lapic_timer.timer);
|
||||
|
||||
|
@ -2247,11 +2215,6 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
|
|||
|
||||
vcpu->arch.apic_arb_prio = 0;
|
||||
vcpu->arch.apic_attention = 0;
|
||||
|
||||
apic_debug("%s: vcpu=%p, id=0x%x, base_msr="
|
||||
"0x%016" PRIx64 ", base_address=0x%0lx.\n", __func__,
|
||||
vcpu, kvm_lapic_get_reg(apic, APIC_ID),
|
||||
vcpu->arch.apic_base, apic->base_address);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2323,7 +2286,6 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu, int timer_advance_ns)
|
|||
struct kvm_lapic *apic;
|
||||
|
||||
ASSERT(vcpu != NULL);
|
||||
apic_debug("apic_init %d\n", vcpu->vcpu_id);
|
||||
|
||||
apic = kzalloc(sizeof(*apic), GFP_KERNEL_ACCOUNT);
|
||||
if (!apic)
|
||||
|
@ -2340,7 +2302,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu, int timer_advance_ns)
|
|||
apic->vcpu = vcpu;
|
||||
|
||||
hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC,
|
||||
HRTIMER_MODE_ABS_PINNED);
|
||||
HRTIMER_MODE_ABS);
|
||||
apic->lapic_timer.timer.function = apic_timer_fn;
|
||||
if (timer_advance_ns == -1) {
|
||||
apic->lapic_timer.timer_advance_ns = LAPIC_TIMER_ADVANCE_ADJUST_INIT;
|
||||
|
@ -2397,13 +2359,7 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
|
|||
struct kvm_lapic *apic = vcpu->arch.apic;
|
||||
|
||||
if (atomic_read(&apic->lapic_timer.pending) > 0) {
|
||||
kvm_apic_local_deliver(apic, APIC_LVTT);
|
||||
if (apic_lvtt_tscdeadline(apic))
|
||||
apic->lapic_timer.tscdeadline = 0;
|
||||
if (apic_lvtt_oneshot(apic)) {
|
||||
apic->lapic_timer.tscdeadline = 0;
|
||||
apic->lapic_timer.target_expiration = 0;
|
||||
}
|
||||
kvm_apic_inject_pending_timer_irqs(apic);
|
||||
atomic_set(&apic->lapic_timer.pending, 0);
|
||||
}
|
||||
}
|
||||
|
@ -2525,12 +2481,13 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
|
|||
{
|
||||
struct hrtimer *timer;
|
||||
|
||||
if (!lapic_in_kernel(vcpu))
|
||||
if (!lapic_in_kernel(vcpu) ||
|
||||
kvm_can_post_timer_interrupt(vcpu))
|
||||
return;
|
||||
|
||||
timer = &vcpu->arch.apic->lapic_timer.timer;
|
||||
if (hrtimer_cancel(timer))
|
||||
hrtimer_start_expires(timer, HRTIMER_MODE_ABS_PINNED);
|
||||
hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2678,11 +2635,8 @@ int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
|
|||
if (!lapic_in_kernel(vcpu) || !apic_x2apic_mode(apic))
|
||||
return 1;
|
||||
|
||||
if (reg == APIC_DFR || reg == APIC_ICR2) {
|
||||
apic_debug("KVM_APIC_READ: read x2apic reserved register %x\n",
|
||||
reg);
|
||||
if (reg == APIC_DFR || reg == APIC_ICR2)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (kvm_lapic_reg_read(apic, reg, 4, &low))
|
||||
return 1;
|
||||
|
@ -2780,8 +2734,6 @@ void kvm_apic_accept_events(struct kvm_vcpu *vcpu)
|
|||
/* evaluate pending_events before reading the vector */
|
||||
smp_rmb();
|
||||
sipi_vector = apic->sipi_vector;
|
||||
apic_debug("vcpu %d received sipi with vector # %x\n",
|
||||
vcpu->vcpu_id, sipi_vector);
|
||||
kvm_vcpu_deliver_sipi_vector(vcpu, sipi_vector);
|
||||
vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
|
||||
}
|
||||
|
|
|
@ -236,6 +236,7 @@ void kvm_lapic_switch_to_hv_timer(struct kvm_vcpu *vcpu);
|
|||
void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu);
|
||||
bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu);
|
||||
void kvm_lapic_restart_hv_timer(struct kvm_vcpu *vcpu);
|
||||
bool kvm_can_post_timer_interrupt(struct kvm_vcpu *vcpu);
|
||||
|
||||
static inline enum lapic_mode kvm_apic_mode(u64 apic_base)
|
||||
{
|
||||
|
|
|
@ -4597,11 +4597,11 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu,
|
|||
*/
|
||||
|
||||
/* Faults from writes to non-writable pages */
|
||||
u8 wf = (pfec & PFERR_WRITE_MASK) ? ~w : 0;
|
||||
u8 wf = (pfec & PFERR_WRITE_MASK) ? (u8)~w : 0;
|
||||
/* Faults from user mode accesses to supervisor pages */
|
||||
u8 uf = (pfec & PFERR_USER_MASK) ? ~u : 0;
|
||||
u8 uf = (pfec & PFERR_USER_MASK) ? (u8)~u : 0;
|
||||
/* Faults from fetches of non-executable pages*/
|
||||
u8 ff = (pfec & PFERR_FETCH_MASK) ? ~x : 0;
|
||||
u8 ff = (pfec & PFERR_FETCH_MASK) ? (u8)~x : 0;
|
||||
/* Faults from kernel mode fetches of user pages */
|
||||
u8 smepf = 0;
|
||||
/* Faults from kernel mode accesses of user pages */
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include "lapic.h"
|
||||
#include "pmu.h"
|
||||
|
||||
/* This keeps the total size of the filter under 4k. */
|
||||
#define KVM_PMU_EVENT_FILTER_MAX_EVENTS 63
|
||||
/* This is enough to filter the vast majority of currently defined events. */
|
||||
#define KVM_PMU_EVENT_FILTER_MAX_EVENTS 300
|
||||
|
||||
/* NOTE:
|
||||
* - Each perf counter is defined as "struct kvm_pmc";
|
||||
|
@ -131,8 +131,8 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type,
|
|||
intr ? kvm_perf_overflow_intr :
|
||||
kvm_perf_overflow, pmc);
|
||||
if (IS_ERR(event)) {
|
||||
printk_once("kvm_pmu: event creation failed %ld\n",
|
||||
PTR_ERR(event));
|
||||
pr_debug_ratelimited("kvm_pmu: event creation failed %ld for pmc->idx = %d\n",
|
||||
PTR_ERR(event), pmc->idx);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -206,12 +206,24 @@ void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int idx)
|
|||
{
|
||||
unsigned en_field = ctrl & 0x3;
|
||||
bool pmi = ctrl & 0x8;
|
||||
struct kvm_pmu_event_filter *filter;
|
||||
struct kvm *kvm = pmc->vcpu->kvm;
|
||||
|
||||
pmc_stop_counter(pmc);
|
||||
|
||||
if (!en_field || !pmc_is_enabled(pmc))
|
||||
return;
|
||||
|
||||
filter = srcu_dereference(kvm->arch.pmu_event_filter, &kvm->srcu);
|
||||
if (filter) {
|
||||
if (filter->action == KVM_PMU_EVENT_DENY &&
|
||||
test_bit(idx, (ulong *)&filter->fixed_counter_bitmap))
|
||||
return;
|
||||
if (filter->action == KVM_PMU_EVENT_ALLOW &&
|
||||
!test_bit(idx, (ulong *)&filter->fixed_counter_bitmap))
|
||||
return;
|
||||
}
|
||||
|
||||
pmc_reprogram_counter(pmc, PERF_TYPE_HARDWARE,
|
||||
kvm_x86_ops->pmu_ops->find_fixed_event(idx),
|
||||
!(en_field & 0x2), /* exclude user */
|
||||
|
@ -385,6 +397,9 @@ int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp)
|
|||
tmp.action != KVM_PMU_EVENT_DENY)
|
||||
return -EINVAL;
|
||||
|
||||
if (tmp.flags != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (tmp.nevents > KVM_PMU_EVENT_FILTER_MAX_EVENTS)
|
||||
return -E2BIG;
|
||||
|
||||
|
@ -406,8 +421,8 @@ int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp)
|
|||
mutex_unlock(&kvm->lock);
|
||||
|
||||
synchronize_srcu_expedited(&kvm->srcu);
|
||||
r = 0;
|
||||
r = 0;
|
||||
cleanup:
|
||||
kfree(filter);
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -7128,13 +7128,41 @@ static int nested_enable_evmcs(struct kvm_vcpu *vcpu,
|
|||
|
||||
static bool svm_need_emulation_on_page_fault(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
bool is_user, smap;
|
||||
|
||||
is_user = svm_get_cpl(vcpu) == 3;
|
||||
smap = !kvm_read_cr4_bits(vcpu, X86_CR4_SMAP);
|
||||
unsigned long cr4 = kvm_read_cr4(vcpu);
|
||||
bool smep = cr4 & X86_CR4_SMEP;
|
||||
bool smap = cr4 & X86_CR4_SMAP;
|
||||
bool is_user = svm_get_cpl(vcpu) == 3;
|
||||
|
||||
/*
|
||||
* Detect and workaround Errata 1096 Fam_17h_00_0Fh
|
||||
* Detect and workaround Errata 1096 Fam_17h_00_0Fh.
|
||||
*
|
||||
* Errata:
|
||||
* When CPU raise #NPF on guest data access and vCPU CR4.SMAP=1, it is
|
||||
* possible that CPU microcode implementing DecodeAssist will fail
|
||||
* to read bytes of instruction which caused #NPF. In this case,
|
||||
* GuestIntrBytes field of the VMCB on a VMEXIT will incorrectly
|
||||
* return 0 instead of the correct guest instruction bytes.
|
||||
*
|
||||
* This happens because CPU microcode reading instruction bytes
|
||||
* uses a special opcode which attempts to read data using CPL=0
|
||||
* priviledges. The microcode reads CS:RIP and if it hits a SMAP
|
||||
* fault, it gives up and returns no instruction bytes.
|
||||
*
|
||||
* Detection:
|
||||
* We reach here in case CPU supports DecodeAssist, raised #NPF and
|
||||
* returned 0 in GuestIntrBytes field of the VMCB.
|
||||
* First, errata can only be triggered in case vCPU CR4.SMAP=1.
|
||||
* Second, if vCPU CR4.SMEP=1, errata could only be triggered
|
||||
* in case vCPU CPL==3 (Because otherwise guest would have triggered
|
||||
* a SMEP fault instead of #NPF).
|
||||
* Otherwise, vCPU CR4.SMEP=0, errata could be triggered by any vCPU CPL.
|
||||
* As most guests enable SMAP if they have also enabled SMEP, use above
|
||||
* logic in order to attempt minimize false-positive of detecting errata
|
||||
* while still preserving all cases semantic correctness.
|
||||
*
|
||||
* Workaround:
|
||||
* To determine what instruction the guest was executing, the hypervisor
|
||||
* will have to decode the instruction at the instruction pointer.
|
||||
*
|
||||
* In non SEV guest, hypervisor will be able to read the guest
|
||||
* memory to decode the instruction pointer when insn_len is zero
|
||||
|
@ -7145,11 +7173,11 @@ static bool svm_need_emulation_on_page_fault(struct kvm_vcpu *vcpu)
|
|||
* instruction pointer so we will not able to workaround it. Lets
|
||||
* print the error and request to kill the guest.
|
||||
*/
|
||||
if (is_user && smap) {
|
||||
if (smap && (!smep || is_user)) {
|
||||
if (!sev_guest(vcpu->kvm))
|
||||
return true;
|
||||
|
||||
pr_err_ratelimited("KVM: Guest triggered AMD Erratum 1096\n");
|
||||
pr_err_ratelimited("KVM: SEV Guest triggered AMD Erratum 1096\n");
|
||||
kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
|
||||
}
|
||||
|
||||
|
|
|
@ -194,6 +194,7 @@ static void vmx_disable_shadow_vmcs(struct vcpu_vmx *vmx)
|
|||
{
|
||||
secondary_exec_controls_clearbit(vmx, SECONDARY_EXEC_SHADOW_VMCS);
|
||||
vmcs_write64(VMCS_LINK_POINTER, -1ull);
|
||||
vmx->nested.need_vmcs12_to_shadow_sync = false;
|
||||
}
|
||||
|
||||
static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
|
||||
|
@ -1341,6 +1342,9 @@ static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx)
|
|||
unsigned long val;
|
||||
int i;
|
||||
|
||||
if (WARN_ON(!shadow_vmcs))
|
||||
return;
|
||||
|
||||
preempt_disable();
|
||||
|
||||
vmcs_load(shadow_vmcs);
|
||||
|
@ -1373,6 +1377,9 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
|
|||
unsigned long val;
|
||||
int i, q;
|
||||
|
||||
if (WARN_ON(!shadow_vmcs))
|
||||
return;
|
||||
|
||||
vmcs_load(shadow_vmcs);
|
||||
|
||||
for (q = 0; q < ARRAY_SIZE(fields); q++) {
|
||||
|
@ -4194,7 +4201,10 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
|
|||
* mode, e.g. a 32-bit address size can yield a 64-bit virtual
|
||||
* address when using FS/GS with a non-zero base.
|
||||
*/
|
||||
*ret = s.base + off;
|
||||
if (seg_reg == VCPU_SREG_FS || seg_reg == VCPU_SREG_GS)
|
||||
*ret = s.base + off;
|
||||
else
|
||||
*ret = off;
|
||||
|
||||
/* Long mode: #GP(0)/#SS(0) if the memory address is in a
|
||||
* non-canonical form. This is the only check on the memory
|
||||
|
@ -4433,7 +4443,6 @@ static inline void nested_release_vmcs12(struct kvm_vcpu *vcpu)
|
|||
/* copy to memory all shadowed fields in case
|
||||
they were modified */
|
||||
copy_shadow_to_vmcs12(vmx);
|
||||
vmx->nested.need_vmcs12_to_shadow_sync = false;
|
||||
vmx_disable_shadow_vmcs(vmx);
|
||||
}
|
||||
vmx->nested.posted_intr_nv = -1;
|
||||
|
|
|
@ -337,17 +337,22 @@ static void intel_pmu_init(struct kvm_vcpu *vcpu)
|
|||
static void intel_pmu_reset(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
|
||||
struct kvm_pmc *pmc = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
|
||||
struct kvm_pmc *pmc = &pmu->gp_counters[i];
|
||||
pmc = &pmu->gp_counters[i];
|
||||
|
||||
pmc_stop_counter(pmc);
|
||||
pmc->counter = pmc->eventsel = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < INTEL_PMC_MAX_FIXED; i++)
|
||||
pmc_stop_counter(&pmu->fixed_counters[i]);
|
||||
for (i = 0; i < INTEL_PMC_MAX_FIXED; i++) {
|
||||
pmc = &pmu->fixed_counters[i];
|
||||
|
||||
pmc_stop_counter(pmc);
|
||||
pmc->counter = 0;
|
||||
}
|
||||
|
||||
pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status =
|
||||
pmu->global_ovf_ctrl = 0;
|
||||
|
|
|
@ -5829,6 +5829,7 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
|
|||
}
|
||||
|
||||
if (unlikely(vmx->fail)) {
|
||||
dump_vmcs();
|
||||
vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY;
|
||||
vcpu->run->fail_entry.hardware_entry_failure_reason
|
||||
= vmcs_read32(VM_INSTRUCTION_ERROR);
|
||||
|
@ -7064,7 +7065,8 @@ static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc,
|
|||
u64 tscl, guest_tscl, delta_tsc, lapic_timer_advance_cycles;
|
||||
struct kvm_timer *ktimer = &vcpu->arch.apic->lapic_timer;
|
||||
|
||||
if (kvm_mwait_in_guest(vcpu->kvm))
|
||||
if (kvm_mwait_in_guest(vcpu->kvm) ||
|
||||
kvm_can_post_timer_interrupt(vcpu))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
vmx = to_vmx(vcpu);
|
||||
|
@ -7453,7 +7455,7 @@ static int enable_smi_window(struct kvm_vcpu *vcpu)
|
|||
|
||||
static bool vmx_need_emulation_on_page_fault(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static __init int hardware_setup(void)
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include <linux/kvm_irqfd.h>
|
||||
#include <linux/irqbypass.h>
|
||||
#include <linux/sched/stat.h>
|
||||
#include <linux/sched/isolation.h>
|
||||
#include <linux/mem_encrypt.h>
|
||||
|
||||
#include <trace/events/kvm.h>
|
||||
|
@ -153,6 +154,9 @@ EXPORT_SYMBOL_GPL(enable_vmware_backdoor);
|
|||
static bool __read_mostly force_emulation_prefix = false;
|
||||
module_param(force_emulation_prefix, bool, S_IRUGO);
|
||||
|
||||
int __read_mostly pi_inject_timer = -1;
|
||||
module_param(pi_inject_timer, bint, S_IRUGO | S_IWUSR);
|
||||
|
||||
#define KVM_NR_SHARED_MSRS 16
|
||||
|
||||
struct kvm_shared_msrs_global {
|
||||
|
@ -1456,12 +1460,8 @@ static void update_pvclock_gtod(struct timekeeper *tk)
|
|||
|
||||
void kvm_set_pending_timer(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
* Note: KVM_REQ_PENDING_TIMER is implicitly checked in
|
||||
* vcpu_enter_guest. This function is only called from
|
||||
* the physical CPU that is running vcpu.
|
||||
*/
|
||||
kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
|
||||
kvm_vcpu_kick(vcpu);
|
||||
}
|
||||
|
||||
static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
|
||||
|
@ -1540,9 +1540,6 @@ static void kvm_get_time_scale(uint64_t scaled_hz, uint64_t base_hz,
|
|||
|
||||
*pshift = shift;
|
||||
*pmultiplier = div_frac(scaled64, tps32);
|
||||
|
||||
pr_debug("%s: base_hz %llu => %llu, shift %d, mul %u\n",
|
||||
__func__, base_hz, scaled_hz, shift, *pmultiplier);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
|
@ -1785,12 +1782,10 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
|
|||
vcpu->arch.virtual_tsc_khz == kvm->arch.last_tsc_khz) {
|
||||
if (!kvm_check_tsc_unstable()) {
|
||||
offset = kvm->arch.cur_tsc_offset;
|
||||
pr_debug("kvm: matched tsc offset for %llu\n", data);
|
||||
} else {
|
||||
u64 delta = nsec_to_cycles(vcpu, elapsed);
|
||||
data += delta;
|
||||
offset = kvm_compute_tsc_offset(vcpu, data);
|
||||
pr_debug("kvm: adjusted tsc offset by %llu\n", delta);
|
||||
}
|
||||
matched = true;
|
||||
already_matched = (vcpu->arch.this_tsc_generation == kvm->arch.cur_tsc_generation);
|
||||
|
@ -1809,8 +1804,6 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
|
|||
kvm->arch.cur_tsc_write = data;
|
||||
kvm->arch.cur_tsc_offset = offset;
|
||||
matched = false;
|
||||
pr_debug("kvm: new tsc generation %llu, clock %llu\n",
|
||||
kvm->arch.cur_tsc_generation, data);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -6911,7 +6904,6 @@ static void kvm_timer_init(void)
|
|||
cpufreq_register_notifier(&kvmclock_cpufreq_notifier_block,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
pr_debug("kvm: max_tsc_khz = %ld\n", max_tsc_khz);
|
||||
|
||||
cpuhp_setup_state(CPUHP_AP_X86_KVM_CLK_ONLINE, "x86/kvm/clk:online",
|
||||
kvmclock_cpu_online, kvmclock_cpu_down_prep);
|
||||
|
@ -7070,6 +7062,8 @@ int kvm_arch_init(void *opaque)
|
|||
host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
|
||||
|
||||
kvm_lapic_init();
|
||||
if (pi_inject_timer == -1)
|
||||
pi_inject_timer = housekeeping_enabled(HK_FLAG_TIMER);
|
||||
#ifdef CONFIG_X86_64
|
||||
pvclock_gtod_register_notifier(&pvclock_gtod_notifier);
|
||||
|
||||
|
|
|
@ -301,6 +301,8 @@ extern unsigned int min_timer_period_us;
|
|||
|
||||
extern bool enable_vmware_backdoor;
|
||||
|
||||
extern int pi_inject_timer;
|
||||
|
||||
extern struct static_key kvm_no_apic_vcpu;
|
||||
|
||||
static inline u64 nsec_to_cycles(struct kvm_vcpu *vcpu, u64 nsec)
|
||||
|
|
|
@ -318,6 +318,7 @@ struct kvm_vcpu {
|
|||
} spin_loop;
|
||||
#endif
|
||||
bool preempted;
|
||||
bool ready;
|
||||
struct kvm_vcpu_arch arch;
|
||||
struct dentry *debugfs_dentry;
|
||||
};
|
||||
|
|
|
@ -19,6 +19,7 @@ enum hk_flags {
|
|||
DECLARE_STATIC_KEY_FALSE(housekeeping_overridden);
|
||||
extern int housekeeping_any_cpu(enum hk_flags flags);
|
||||
extern const struct cpumask *housekeeping_cpumask(enum hk_flags flags);
|
||||
extern bool housekeeping_enabled(enum hk_flags flags);
|
||||
extern void housekeeping_affine(struct task_struct *t, enum hk_flags flags);
|
||||
extern bool housekeeping_test_cpu(int cpu, enum hk_flags flags);
|
||||
extern void __init housekeeping_init(void);
|
||||
|
@ -35,6 +36,11 @@ static inline const struct cpumask *housekeeping_cpumask(enum hk_flags flags)
|
|||
return cpu_possible_mask;
|
||||
}
|
||||
|
||||
static inline bool housekeeping_enabled(enum hk_flags flags)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void housekeeping_affine(struct task_struct *t,
|
||||
enum hk_flags flags) { }
|
||||
static inline void housekeeping_init(void) { }
|
||||
|
|
|
@ -14,6 +14,12 @@ EXPORT_SYMBOL_GPL(housekeeping_overridden);
|
|||
static cpumask_var_t housekeeping_mask;
|
||||
static unsigned int housekeeping_flags;
|
||||
|
||||
bool housekeeping_enabled(enum hk_flags flags)
|
||||
{
|
||||
return !!(housekeeping_flags & flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(housekeeping_enabled);
|
||||
|
||||
int housekeeping_any_cpu(enum hk_flags flags)
|
||||
{
|
||||
if (static_branch_unlikely(&housekeeping_overridden))
|
||||
|
|
|
@ -10,11 +10,11 @@ UNAME_M := $(shell uname -m)
|
|||
LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/ucall.c lib/sparsebit.c
|
||||
LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c
|
||||
LIBKVM_aarch64 = lib/aarch64/processor.c
|
||||
LIBKVM_s390x = lib/s390x/processor.c
|
||||
|
||||
TEST_GEN_PROGS_x86_64 = x86_64/cr4_cpuid_sync_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/kvm_create_max_vcpus
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/set_sregs_test
|
||||
|
@ -26,9 +26,14 @@ TEST_GEN_PROGS_x86_64 += x86_64/vmx_set_nested_state_test
|
|||
TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test
|
||||
TEST_GEN_PROGS_x86_64 += clear_dirty_log_test
|
||||
TEST_GEN_PROGS_x86_64 += dirty_log_test
|
||||
TEST_GEN_PROGS_x86_64 += kvm_create_max_vcpus
|
||||
|
||||
TEST_GEN_PROGS_aarch64 += clear_dirty_log_test
|
||||
TEST_GEN_PROGS_aarch64 += dirty_log_test
|
||||
TEST_GEN_PROGS_aarch64 += kvm_create_max_vcpus
|
||||
|
||||
TEST_GEN_PROGS_s390x += s390x/sync_regs_test
|
||||
TEST_GEN_PROGS_s390x += kvm_create_max_vcpus
|
||||
|
||||
TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M))
|
||||
LIBKVM += $(LIBKVM_$(UNAME_M))
|
||||
|
@ -43,7 +48,12 @@ CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -O2 -g -std=gnu99 \
|
|||
no-pie-option := $(call try-run, echo 'int main() { return 0; }' | \
|
||||
$(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -no-pie -x c - -o "$$TMP", -no-pie)
|
||||
|
||||
LDFLAGS += -pthread $(no-pie-option)
|
||||
# On s390, build the testcases KVM-enabled
|
||||
pgste-option = $(call try-run, echo 'int main() { return 0; }' | \
|
||||
$(CC) -Werror -Wl$(comma)--s390-pgste -x c - -o "$$TMP",-Wl$(comma)--s390-pgste)
|
||||
|
||||
|
||||
LDFLAGS += -pthread $(no-pie-option) $(pgste-option)
|
||||
|
||||
# After inclusion, $(OUTPUT) is defined and
|
||||
# $(TEST_GEN_PROGS) starts with $(OUTPUT)/
|
||||
|
|
|
@ -41,6 +41,12 @@ enum vm_guest_mode {
|
|||
NUM_VM_MODES,
|
||||
};
|
||||
|
||||
#ifdef __aarch64__
|
||||
#define VM_MODE_DEFAULT VM_MODE_P40V48_4K
|
||||
#else
|
||||
#define VM_MODE_DEFAULT VM_MODE_P52V48_4K
|
||||
#endif
|
||||
|
||||
#define vm_guest_mode_string(m) vm_guest_mode_string[m]
|
||||
extern const char * const vm_guest_mode_string[];
|
||||
|
||||
|
@ -111,10 +117,12 @@ void vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid,
|
|||
struct kvm_sregs *sregs);
|
||||
int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid,
|
||||
struct kvm_sregs *sregs);
|
||||
#ifdef __KVM_HAVE_VCPU_EVENTS
|
||||
void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid,
|
||||
struct kvm_vcpu_events *events);
|
||||
void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid,
|
||||
struct kvm_vcpu_events *events);
|
||||
#endif
|
||||
#ifdef __x86_64__
|
||||
void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid,
|
||||
struct kvm_nested_state *state);
|
||||
|
|
22
tools/testing/selftests/kvm/include/s390x/processor.h
Normal file
22
tools/testing/selftests/kvm/include/s390x/processor.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* s390x processor specific defines
|
||||
*/
|
||||
#ifndef SELFTEST_KVM_PROCESSOR_H
|
||||
#define SELFTEST_KVM_PROCESSOR_H
|
||||
|
||||
/* Bits in the region/segment table entry */
|
||||
#define REGION_ENTRY_ORIGIN ~0xfffUL /* region/segment table origin */
|
||||
#define REGION_ENTRY_PROTECT 0x200 /* region protection bit */
|
||||
#define REGION_ENTRY_NOEXEC 0x100 /* region no-execute bit */
|
||||
#define REGION_ENTRY_OFFSET 0xc0 /* region table offset */
|
||||
#define REGION_ENTRY_INVALID 0x20 /* invalid region table entry */
|
||||
#define REGION_ENTRY_TYPE 0x0c /* region/segment table type mask */
|
||||
#define REGION_ENTRY_LENGTH 0x03 /* region third length */
|
||||
|
||||
/* Bits in the page table entry */
|
||||
#define PAGE_INVALID 0x400 /* HW invalid bit */
|
||||
#define PAGE_PROTECT 0x200 /* HW read-only bit */
|
||||
#define PAGE_NOEXEC 0x100 /* HW no-execute bit */
|
||||
|
||||
#endif
|
|
@ -27,7 +27,7 @@ void test_vcpu_creation(int first_vcpu_id, int num_vcpus)
|
|||
printf("Testing creating %d vCPUs, with IDs %d...%d.\n",
|
||||
num_vcpus, first_vcpu_id, first_vcpu_id + num_vcpus - 1);
|
||||
|
||||
vm = vm_create(VM_MODE_P52V48_4K, DEFAULT_GUEST_PHY_PAGES, O_RDWR);
|
||||
vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR);
|
||||
|
||||
for (i = 0; i < num_vcpus; i++) {
|
||||
int vcpu_id = first_vcpu_id + i;
|
|
@ -227,7 +227,7 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages,
|
|||
uint64_t extra_pg_pages = (extra_mem_pages / ptrs_per_4k_pte) * 2;
|
||||
struct kvm_vm *vm;
|
||||
|
||||
vm = vm_create(VM_MODE_P40V48_4K, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR);
|
||||
vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR);
|
||||
|
||||
kvm_vm_elf_load(vm, program_invocation_name, 0, 0);
|
||||
vm_vcpu_add_default(vm, vcpuid, guest_code);
|
||||
|
|
|
@ -556,6 +556,7 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm,
|
|||
int ret;
|
||||
struct userspace_mem_region *region;
|
||||
size_t huge_page_size = KVM_UTIL_PGS_PER_HUGEPG * vm->page_size;
|
||||
size_t alignment;
|
||||
|
||||
TEST_ASSERT((guest_paddr % vm->page_size) == 0, "Guest physical "
|
||||
"address not on a page boundary.\n"
|
||||
|
@ -605,9 +606,20 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm,
|
|||
TEST_ASSERT(region != NULL, "Insufficient Memory");
|
||||
region->mmap_size = npages * vm->page_size;
|
||||
|
||||
/* Enough memory to align up to a huge page. */
|
||||
#ifdef __s390x__
|
||||
/* On s390x, the host address must be aligned to 1M (due to PGSTEs) */
|
||||
alignment = 0x100000;
|
||||
#else
|
||||
alignment = 1;
|
||||
#endif
|
||||
|
||||
if (src_type == VM_MEM_SRC_ANONYMOUS_THP)
|
||||
region->mmap_size += huge_page_size;
|
||||
alignment = max(huge_page_size, alignment);
|
||||
|
||||
/* Add enough memory to align up if necessary */
|
||||
if (alignment > 1)
|
||||
region->mmap_size += alignment;
|
||||
|
||||
region->mmap_start = mmap(NULL, region->mmap_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS
|
||||
|
@ -617,9 +629,8 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm,
|
|||
"test_malloc failed, mmap_start: %p errno: %i",
|
||||
region->mmap_start, errno);
|
||||
|
||||
/* Align THP allocation up to start of a huge page. */
|
||||
region->host_mem = align(region->mmap_start,
|
||||
src_type == VM_MEM_SRC_ANONYMOUS_THP ? huge_page_size : 1);
|
||||
/* Align host address */
|
||||
region->host_mem = align(region->mmap_start, alignment);
|
||||
|
||||
/* As needed perform madvise */
|
||||
if (src_type == VM_MEM_SRC_ANONYMOUS || src_type == VM_MEM_SRC_ANONYMOUS_THP) {
|
||||
|
@ -1218,6 +1229,7 @@ void vcpu_regs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs)
|
|||
ret, errno);
|
||||
}
|
||||
|
||||
#ifdef __KVM_HAVE_VCPU_EVENTS
|
||||
void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid,
|
||||
struct kvm_vcpu_events *events)
|
||||
{
|
||||
|
@ -1243,6 +1255,7 @@ void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid,
|
|||
TEST_ASSERT(ret == 0, "KVM_SET_VCPU_EVENTS, failed, rc: %i errno: %i",
|
||||
ret, errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __x86_64__
|
||||
void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid,
|
||||
|
|
278
tools/testing/selftests/kvm/lib/s390x/processor.c
Normal file
278
tools/testing/selftests/kvm/lib/s390x/processor.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* KVM selftest s390x library code - CPU-related functions (page tables...)
|
||||
*
|
||||
* Copyright (C) 2019, Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* for program_invocation_name */
|
||||
|
||||
#include "processor.h"
|
||||
#include "kvm_util.h"
|
||||
#include "../kvm_util_internal.h"
|
||||
|
||||
#define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000
|
||||
|
||||
#define PAGES_PER_REGION 4
|
||||
|
||||
void virt_pgd_alloc(struct kvm_vm *vm, uint32_t memslot)
|
||||
{
|
||||
vm_paddr_t paddr;
|
||||
|
||||
TEST_ASSERT(vm->page_size == 4096, "Unsupported page size: 0x%x",
|
||||
vm->page_size);
|
||||
|
||||
if (vm->pgd_created)
|
||||
return;
|
||||
|
||||
paddr = vm_phy_pages_alloc(vm, PAGES_PER_REGION,
|
||||
KVM_GUEST_PAGE_TABLE_MIN_PADDR, memslot);
|
||||
memset(addr_gpa2hva(vm, paddr), 0xff, PAGES_PER_REGION * vm->page_size);
|
||||
|
||||
vm->pgd = paddr;
|
||||
vm->pgd_created = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate 4 pages for a region/segment table (ri < 4), or one page for
|
||||
* a page table (ri == 4). Returns a suitable region/segment table entry
|
||||
* which points to the freshly allocated pages.
|
||||
*/
|
||||
static uint64_t virt_alloc_region(struct kvm_vm *vm, int ri, uint32_t memslot)
|
||||
{
|
||||
uint64_t taddr;
|
||||
|
||||
taddr = vm_phy_pages_alloc(vm, ri < 4 ? PAGES_PER_REGION : 1,
|
||||
KVM_GUEST_PAGE_TABLE_MIN_PADDR, memslot);
|
||||
memset(addr_gpa2hva(vm, taddr), 0xff, PAGES_PER_REGION * vm->page_size);
|
||||
|
||||
return (taddr & REGION_ENTRY_ORIGIN)
|
||||
| (((4 - ri) << 2) & REGION_ENTRY_TYPE)
|
||||
| ((ri < 4 ? (PAGES_PER_REGION - 1) : 0) & REGION_ENTRY_LENGTH);
|
||||
}
|
||||
|
||||
/*
|
||||
* VM Virtual Page Map
|
||||
*
|
||||
* Input Args:
|
||||
* vm - Virtual Machine
|
||||
* gva - VM Virtual Address
|
||||
* gpa - VM Physical Address
|
||||
* memslot - Memory region slot for new virtual translation tables
|
||||
*
|
||||
* Output Args: None
|
||||
*
|
||||
* Return: None
|
||||
*
|
||||
* Within the VM given by vm, creates a virtual translation for the page
|
||||
* starting at vaddr to the page starting at paddr.
|
||||
*/
|
||||
void virt_pg_map(struct kvm_vm *vm, uint64_t gva, uint64_t gpa,
|
||||
uint32_t memslot)
|
||||
{
|
||||
int ri, idx;
|
||||
uint64_t *entry;
|
||||
|
||||
TEST_ASSERT((gva % vm->page_size) == 0,
|
||||
"Virtual address not on page boundary,\n"
|
||||
" vaddr: 0x%lx vm->page_size: 0x%x",
|
||||
gva, vm->page_size);
|
||||
TEST_ASSERT(sparsebit_is_set(vm->vpages_valid,
|
||||
(gva >> vm->page_shift)),
|
||||
"Invalid virtual address, vaddr: 0x%lx",
|
||||
gva);
|
||||
TEST_ASSERT((gpa % vm->page_size) == 0,
|
||||
"Physical address not on page boundary,\n"
|
||||
" paddr: 0x%lx vm->page_size: 0x%x",
|
||||
gva, vm->page_size);
|
||||
TEST_ASSERT((gpa >> vm->page_shift) <= vm->max_gfn,
|
||||
"Physical address beyond beyond maximum supported,\n"
|
||||
" paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x",
|
||||
gva, vm->max_gfn, vm->page_size);
|
||||
|
||||
/* Walk through region and segment tables */
|
||||
entry = addr_gpa2hva(vm, vm->pgd);
|
||||
for (ri = 1; ri <= 4; ri++) {
|
||||
idx = (gva >> (64 - 11 * ri)) & 0x7ffu;
|
||||
if (entry[idx] & REGION_ENTRY_INVALID)
|
||||
entry[idx] = virt_alloc_region(vm, ri, memslot);
|
||||
entry = addr_gpa2hva(vm, entry[idx] & REGION_ENTRY_ORIGIN);
|
||||
}
|
||||
|
||||
/* Fill in page table entry */
|
||||
idx = (gva >> 12) & 0x0ffu; /* page index */
|
||||
if (!(entry[idx] & PAGE_INVALID))
|
||||
fprintf(stderr,
|
||||
"WARNING: PTE for gpa=0x%"PRIx64" already set!\n", gpa);
|
||||
entry[idx] = gpa;
|
||||
}
|
||||
|
||||
/*
|
||||
* Address Guest Virtual to Guest Physical
|
||||
*
|
||||
* Input Args:
|
||||
* vm - Virtual Machine
|
||||
* gpa - VM virtual address
|
||||
*
|
||||
* Output Args: None
|
||||
*
|
||||
* Return:
|
||||
* Equivalent VM physical address
|
||||
*
|
||||
* Translates the VM virtual address given by gva to a VM physical
|
||||
* address and then locates the memory region containing the VM
|
||||
* physical address, within the VM given by vm. When found, the host
|
||||
* virtual address providing the memory to the vm physical address is
|
||||
* returned.
|
||||
* A TEST_ASSERT failure occurs if no region containing translated
|
||||
* VM virtual address exists.
|
||||
*/
|
||||
vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
|
||||
{
|
||||
int ri, idx;
|
||||
uint64_t *entry;
|
||||
|
||||
TEST_ASSERT(vm->page_size == 4096, "Unsupported page size: 0x%x",
|
||||
vm->page_size);
|
||||
|
||||
entry = addr_gpa2hva(vm, vm->pgd);
|
||||
for (ri = 1; ri <= 4; ri++) {
|
||||
idx = (gva >> (64 - 11 * ri)) & 0x7ffu;
|
||||
TEST_ASSERT(!(entry[idx] & REGION_ENTRY_INVALID),
|
||||
"No region mapping for vm virtual address 0x%lx",
|
||||
gva);
|
||||
entry = addr_gpa2hva(vm, entry[idx] & REGION_ENTRY_ORIGIN);
|
||||
}
|
||||
|
||||
idx = (gva >> 12) & 0x0ffu; /* page index */
|
||||
|
||||
TEST_ASSERT(!(entry[idx] & PAGE_INVALID),
|
||||
"No page mapping for vm virtual address 0x%lx", gva);
|
||||
|
||||
return (entry[idx] & ~0xffful) + (gva & 0xffful);
|
||||
}
|
||||
|
||||
static void virt_dump_ptes(FILE *stream, struct kvm_vm *vm, uint8_t indent,
|
||||
uint64_t ptea_start)
|
||||
{
|
||||
uint64_t *pte, ptea;
|
||||
|
||||
for (ptea = ptea_start; ptea < ptea_start + 0x100 * 8; ptea += 8) {
|
||||
pte = addr_gpa2hva(vm, ptea);
|
||||
if (*pte & PAGE_INVALID)
|
||||
continue;
|
||||
fprintf(stream, "%*spte @ 0x%lx: 0x%016lx\n",
|
||||
indent, "", ptea, *pte);
|
||||
}
|
||||
}
|
||||
|
||||
static void virt_dump_region(FILE *stream, struct kvm_vm *vm, uint8_t indent,
|
||||
uint64_t reg_tab_addr)
|
||||
{
|
||||
uint64_t addr, *entry;
|
||||
|
||||
for (addr = reg_tab_addr; addr < reg_tab_addr + 0x400 * 8; addr += 8) {
|
||||
entry = addr_gpa2hva(vm, addr);
|
||||
if (*entry & REGION_ENTRY_INVALID)
|
||||
continue;
|
||||
fprintf(stream, "%*srt%lde @ 0x%lx: 0x%016lx\n",
|
||||
indent, "", 4 - ((*entry & REGION_ENTRY_TYPE) >> 2),
|
||||
addr, *entry);
|
||||
if (*entry & REGION_ENTRY_TYPE) {
|
||||
virt_dump_region(stream, vm, indent + 2,
|
||||
*entry & REGION_ENTRY_ORIGIN);
|
||||
} else {
|
||||
virt_dump_ptes(stream, vm, indent + 2,
|
||||
*entry & REGION_ENTRY_ORIGIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
|
||||
{
|
||||
if (!vm->pgd_created)
|
||||
return;
|
||||
|
||||
virt_dump_region(stream, vm, indent, vm->pgd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a VM with reasonable defaults
|
||||
*
|
||||
* Input Args:
|
||||
* vcpuid - The id of the single VCPU to add to the VM.
|
||||
* extra_mem_pages - The size of extra memories to add (this will
|
||||
* decide how much extra space we will need to
|
||||
* setup the page tables using mem slot 0)
|
||||
* guest_code - The vCPU's entry point
|
||||
*
|
||||
* Output Args: None
|
||||
*
|
||||
* Return:
|
||||
* Pointer to opaque structure that describes the created VM.
|
||||
*/
|
||||
struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages,
|
||||
void *guest_code)
|
||||
{
|
||||
/*
|
||||
* The additional amount of pages required for the page tables is:
|
||||
* 1 * n / 256 + 4 * (n / 256) / 2048 + 4 * (n / 256) / 2048^2 + ...
|
||||
* which is definitely smaller than (n / 256) * 2.
|
||||
*/
|
||||
uint64_t extra_pg_pages = extra_mem_pages / 256 * 2;
|
||||
struct kvm_vm *vm;
|
||||
|
||||
vm = vm_create(VM_MODE_DEFAULT,
|
||||
DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR);
|
||||
|
||||
kvm_vm_elf_load(vm, program_invocation_name, 0, 0);
|
||||
vm_vcpu_add_default(vm, vcpuid, guest_code);
|
||||
|
||||
return vm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a vCPU with reasonable defaults (i.e. a stack and initial PSW)
|
||||
*
|
||||
* Input Args:
|
||||
* vcpuid - The id of the VCPU to add to the VM.
|
||||
* guest_code - The vCPU's entry point
|
||||
*/
|
||||
void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code)
|
||||
{
|
||||
size_t stack_size = DEFAULT_STACK_PGS * getpagesize();
|
||||
uint64_t stack_vaddr;
|
||||
struct kvm_regs regs;
|
||||
struct kvm_sregs sregs;
|
||||
struct kvm_run *run;
|
||||
|
||||
TEST_ASSERT(vm->page_size == 4096, "Unsupported page size: 0x%x",
|
||||
vm->page_size);
|
||||
|
||||
stack_vaddr = vm_vaddr_alloc(vm, stack_size,
|
||||
DEFAULT_GUEST_STACK_VADDR_MIN, 0, 0);
|
||||
|
||||
vm_vcpu_add(vm, vcpuid);
|
||||
|
||||
/* Setup guest registers */
|
||||
vcpu_regs_get(vm, vcpuid, ®s);
|
||||
regs.gprs[15] = stack_vaddr + (DEFAULT_STACK_PGS * getpagesize()) - 160;
|
||||
vcpu_regs_set(vm, vcpuid, ®s);
|
||||
|
||||
vcpu_sregs_get(vm, vcpuid, &sregs);
|
||||
sregs.crs[0] |= 0x00040000; /* Enable floating point regs */
|
||||
sregs.crs[1] = vm->pgd | 0xf; /* Primary region table */
|
||||
vcpu_sregs_set(vm, vcpuid, &sregs);
|
||||
|
||||
run = vcpu_state(vm, vcpuid);
|
||||
run->psw_mask = 0x0400000180000000ULL; /* DAT enabled + 64 bit mode */
|
||||
run->psw_addr = (uintptr_t)guest_code;
|
||||
}
|
||||
|
||||
void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent)
|
||||
{
|
||||
struct vcpu *vcpu = vm->vcpu_head;
|
||||
|
||||
fprintf(stream, "%*spstate: psw: 0x%.16llx:0x%.16llx\n",
|
||||
indent, "", vcpu->state->psw_mask, vcpu->state->psw_addr);
|
||||
}
|
|
@ -821,7 +821,7 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages,
|
|||
uint64_t extra_pg_pages = extra_mem_pages / 512 * 2;
|
||||
|
||||
/* Create VM */
|
||||
vm = vm_create(VM_MODE_P52V48_4K,
|
||||
vm = vm_create(VM_MODE_DEFAULT,
|
||||
DEFAULT_GUEST_PHY_PAGES + extra_pg_pages,
|
||||
O_RDWR);
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
* Copyright (C) 2018, Google LLC.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* for program_invocation_name */
|
||||
|
||||
#include "test_util.h"
|
||||
#include "kvm_util.h"
|
||||
#include "processor.h"
|
||||
|
|
151
tools/testing/selftests/kvm/s390x/sync_regs_test.c
Normal file
151
tools/testing/selftests/kvm/s390x/sync_regs_test.c
Normal file
|
@ -0,0 +1,151 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Test for s390x KVM_CAP_SYNC_REGS
|
||||
*
|
||||
* Based on the same test for x86:
|
||||
* Copyright (C) 2018, Google LLC.
|
||||
*
|
||||
* Adaptions for s390x:
|
||||
* Copyright (C) 2019, Red Hat, Inc.
|
||||
*
|
||||
* Test expected behavior of the KVM_CAP_SYNC_REGS functionality.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* for program_invocation_short_name */
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "test_util.h"
|
||||
#include "kvm_util.h"
|
||||
|
||||
#define VCPU_ID 5
|
||||
|
||||
static void guest_code(void)
|
||||
{
|
||||
for (;;) {
|
||||
asm volatile ("diag 0,0,0x501");
|
||||
asm volatile ("ahi 11,1");
|
||||
}
|
||||
}
|
||||
|
||||
#define REG_COMPARE(reg) \
|
||||
TEST_ASSERT(left->reg == right->reg, \
|
||||
"Register " #reg \
|
||||
" values did not match: 0x%llx, 0x%llx\n", \
|
||||
left->reg, right->reg)
|
||||
|
||||
static void compare_regs(struct kvm_regs *left, struct kvm_sync_regs *right)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
REG_COMPARE(gprs[i]);
|
||||
}
|
||||
|
||||
static void compare_sregs(struct kvm_sregs *left, struct kvm_sync_regs *right)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
REG_COMPARE(acrs[i]);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
REG_COMPARE(crs[i]);
|
||||
}
|
||||
|
||||
#undef REG_COMPARE
|
||||
|
||||
#define TEST_SYNC_FIELDS (KVM_SYNC_GPRS|KVM_SYNC_ACRS|KVM_SYNC_CRS)
|
||||
#define INVALID_SYNC_FIELD 0x80000000
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct kvm_vm *vm;
|
||||
struct kvm_run *run;
|
||||
struct kvm_regs regs;
|
||||
struct kvm_sregs sregs;
|
||||
int rv, cap;
|
||||
|
||||
/* Tell stdout not to buffer its content */
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
cap = kvm_check_cap(KVM_CAP_SYNC_REGS);
|
||||
if (!cap) {
|
||||
fprintf(stderr, "CAP_SYNC_REGS not supported, skipping test\n");
|
||||
exit(KSFT_SKIP);
|
||||
}
|
||||
|
||||
/* Create VM */
|
||||
vm = vm_create_default(VCPU_ID, 0, guest_code);
|
||||
|
||||
run = vcpu_state(vm, VCPU_ID);
|
||||
|
||||
/* Request and verify all valid register sets. */
|
||||
run->kvm_valid_regs = TEST_SYNC_FIELDS;
|
||||
rv = _vcpu_run(vm, VCPU_ID);
|
||||
TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
|
||||
TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
|
||||
"Unexpected exit reason: %u (%s)\n",
|
||||
run->exit_reason,
|
||||
exit_reason_str(run->exit_reason));
|
||||
TEST_ASSERT(run->s390_sieic.icptcode == 4 &&
|
||||
(run->s390_sieic.ipa >> 8) == 0x83 &&
|
||||
(run->s390_sieic.ipb >> 16) == 0x501,
|
||||
"Unexpected interception code: ic=%u, ipa=0x%x, ipb=0x%x\n",
|
||||
run->s390_sieic.icptcode, run->s390_sieic.ipa,
|
||||
run->s390_sieic.ipb);
|
||||
|
||||
vcpu_regs_get(vm, VCPU_ID, ®s);
|
||||
compare_regs(®s, &run->s.regs);
|
||||
|
||||
vcpu_sregs_get(vm, VCPU_ID, &sregs);
|
||||
compare_sregs(&sregs, &run->s.regs);
|
||||
|
||||
/* Set and verify various register values */
|
||||
run->s.regs.gprs[11] = 0xBAD1DEA;
|
||||
run->s.regs.acrs[0] = 1 << 11;
|
||||
|
||||
run->kvm_valid_regs = TEST_SYNC_FIELDS;
|
||||
run->kvm_dirty_regs = KVM_SYNC_GPRS | KVM_SYNC_ACRS;
|
||||
rv = _vcpu_run(vm, VCPU_ID);
|
||||
TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
|
||||
TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
|
||||
"Unexpected exit reason: %u (%s)\n",
|
||||
run->exit_reason,
|
||||
exit_reason_str(run->exit_reason));
|
||||
TEST_ASSERT(run->s.regs.gprs[11] == 0xBAD1DEA + 1,
|
||||
"r11 sync regs value incorrect 0x%llx.",
|
||||
run->s.regs.gprs[11]);
|
||||
TEST_ASSERT(run->s.regs.acrs[0] == 1 << 11,
|
||||
"acr0 sync regs value incorrect 0x%llx.",
|
||||
run->s.regs.acrs[0]);
|
||||
|
||||
vcpu_regs_get(vm, VCPU_ID, ®s);
|
||||
compare_regs(®s, &run->s.regs);
|
||||
|
||||
vcpu_sregs_get(vm, VCPU_ID, &sregs);
|
||||
compare_sregs(&sregs, &run->s.regs);
|
||||
|
||||
/* Clear kvm_dirty_regs bits, verify new s.regs values are
|
||||
* overwritten with existing guest values.
|
||||
*/
|
||||
run->kvm_valid_regs = TEST_SYNC_FIELDS;
|
||||
run->kvm_dirty_regs = 0;
|
||||
run->s.regs.gprs[11] = 0xDEADBEEF;
|
||||
rv = _vcpu_run(vm, VCPU_ID);
|
||||
TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
|
||||
TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
|
||||
"Unexpected exit reason: %u (%s)\n",
|
||||
run->exit_reason,
|
||||
exit_reason_str(run->exit_reason));
|
||||
TEST_ASSERT(run->s.regs.gprs[11] != 0xDEADBEEF,
|
||||
"r11 sync regs value incorrect 0x%llx.",
|
||||
run->s.regs.gprs[11]);
|
||||
|
||||
kvm_vm_free(vm);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -314,6 +314,7 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
|
|||
kvm_vcpu_set_in_spin_loop(vcpu, false);
|
||||
kvm_vcpu_set_dy_eligible(vcpu, false);
|
||||
vcpu->preempted = false;
|
||||
vcpu->ready = false;
|
||||
|
||||
r = kvm_arch_vcpu_init(vcpu);
|
||||
if (r < 0)
|
||||
|
@ -2387,6 +2388,7 @@ bool kvm_vcpu_wake_up(struct kvm_vcpu *vcpu)
|
|||
wqp = kvm_arch_vcpu_wq(vcpu);
|
||||
if (swq_has_sleeper(wqp)) {
|
||||
swake_up_one(wqp);
|
||||
WRITE_ONCE(vcpu->ready, true);
|
||||
++vcpu->stat.halt_wakeup;
|
||||
return true;
|
||||
}
|
||||
|
@ -2500,7 +2502,7 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me, bool yield_to_kernel_mode)
|
|||
continue;
|
||||
} else if (pass && i > last_boosted_vcpu)
|
||||
break;
|
||||
if (!READ_ONCE(vcpu->preempted))
|
||||
if (!READ_ONCE(vcpu->ready))
|
||||
continue;
|
||||
if (vcpu == me)
|
||||
continue;
|
||||
|
@ -4203,8 +4205,8 @@ static void kvm_sched_in(struct preempt_notifier *pn, int cpu)
|
|||
{
|
||||
struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
|
||||
|
||||
if (vcpu->preempted)
|
||||
vcpu->preempted = false;
|
||||
vcpu->preempted = false;
|
||||
WRITE_ONCE(vcpu->ready, false);
|
||||
|
||||
kvm_arch_sched_in(vcpu, cpu);
|
||||
|
||||
|
@ -4216,8 +4218,10 @@ static void kvm_sched_out(struct preempt_notifier *pn,
|
|||
{
|
||||
struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
|
||||
|
||||
if (current->state == TASK_RUNNING)
|
||||
if (current->state == TASK_RUNNING) {
|
||||
vcpu->preempted = true;
|
||||
WRITE_ONCE(vcpu->ready, true);
|
||||
}
|
||||
kvm_arch_vcpu_put(vcpu);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue