mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 17:57:38 -04:00
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull kvm fixes from Paolo Bonzini:
"s390:
- Fix S390_USER_OPEREXEC so it can now be enabled regardless of other
unrelated capabilities
- Fix handling of the _PAGE_UNUSED pte bit that could lead to guest
memory corruption in some scenarios
- A bunch of misc gmap fixes (locking, behaviour under memory
pressure)
- Fix CMMA dirty tracking
x86:
- Tidy up some WARN_ON() and BUG_ON(), replacing them with
WARN_ON_ONCE() or KVM_BUG_ON(). All of these have obviously never
triggered, or somebody would have been annoyed earlier, but still...
- Fix missing interrupt due to stale CR8 intercept
- Add a statistic that can come in handy to debug leaks as well as
the vulnerability to a class of recently-discovered issues
- Do not ask arch/x86/kernel to export
default_cpu_present_to_apicid() just for KVM"
* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (22 commits)
x86/apic: KVM: Use cpu_physical_id() to get APIC ID of running vCPU for AVIC
KVM: x86/mmu: Expose number of shadow MMU shadow pages as a stat
KVM: x86: Unconditionally recompute CR8 intercept on PPR update
KVM: VMX: Grab vmcs12 on CR8 interception update iff vCPU is in guest mode
KVM: x86: WARN (once) if RTC pending EOI tracking goes off the rails
KVM: x86: WARN and fail kvm_set_irq() if a PIC or I/O APIC vector is invalid
KVM: x86: Bug the VM, not the kernel, if the ISR count {under,over}flows
KVM: x86/mmu: Bug the VM, not the host kernel, if KVM write-protects upper SPTEs
KVM: x86: Replace BUG_ON() with WARN_ON_ONCE() on "bad" nested GPA translation
KVM: Replace guest-triggerable BUG_ON() in ioeventfd datamatch with get_unaligned()
KVM: s390: Return failure in case of failure in kvm_s390_set_cmma_bits()
KVM: s390: selftests: Fix cmma selftest
KVM: s390: Fix cmma dirty tracking
KVM: s390: Fix locking in kvm_s390_set_mem_control()
KVM: s390: Fix handle_{sske,pfmf} under memory pressure
KVM: s390: Fix code typo in gmap_protect_asce_top_level()
KVM: s390: Do not set special large pages dirty
KVM: s390: Fix dat_peek_cmma() overflow
s390/mm: Fix handling of _PAGE_UNUSED pte bit
KVM: s390: Fix typo in UCONTROL documentation
...
This commit is contained in:
@@ -6840,7 +6840,7 @@ s390 specific.
|
|||||||
} s390_ucontrol;
|
} s390_ucontrol;
|
||||||
|
|
||||||
s390 specific. A page fault has occurred for a user controlled virtual
|
s390 specific. A page fault has occurred for a user controlled virtual
|
||||||
machine (KVM_VM_S390_UNCONTROL) on its host page table that cannot be
|
machine (KVM_VM_S390_UCONTROL) on its host page table that cannot be
|
||||||
resolved by the kernel.
|
resolved by the kernel.
|
||||||
The program code and the translation exception code that were placed
|
The program code and the translation exception code that were placed
|
||||||
in the cpu's lowcore are presented here as defined by the z Architecture
|
in the cpu's lowcore are presented here as defined by the z Architecture
|
||||||
|
|||||||
@@ -980,6 +980,8 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
|
|||||||
|
|
||||||
static inline void set_pte(pte_t *ptep, pte_t pte)
|
static inline void set_pte(pte_t *ptep, pte_t pte)
|
||||||
{
|
{
|
||||||
|
if (pte_present(pte))
|
||||||
|
pte = clear_pte_bit(pte, __pgprot(_PAGE_UNUSED));
|
||||||
WRITE_ONCE(*ptep, pte);
|
WRITE_ONCE(*ptep, pte);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1359,8 +1361,6 @@ pgprot_t pgprot_writecombine(pgprot_t prot);
|
|||||||
static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
|
static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
|
||||||
pte_t *ptep, pte_t entry, unsigned int nr)
|
pte_t *ptep, pte_t entry, unsigned int nr)
|
||||||
{
|
{
|
||||||
if (pte_present(entry))
|
|
||||||
entry = clear_pte_bit(entry, __pgprot(_PAGE_UNUSED));
|
|
||||||
page_table_check_ptes_set(mm, addr, ptep, entry, nr);
|
page_table_check_ptes_set(mm, addr, ptep, entry, nr);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
set_pte(ptep, entry);
|
set_pte(ptep, entry);
|
||||||
|
|||||||
@@ -1209,7 +1209,7 @@ int dat_peek_cmma(gfn_t start, union asce asce, unsigned int *count, u8 *values)
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = _dat_walk_gfn_range(start, start + *count, asce, &ops, DAT_WALK_DEFAULT, &state);
|
rc = _dat_walk_gfn_range(start, start + *count, asce, &ops, DAT_WALK_DEFAULT, &state);
|
||||||
*count = state.end - start;
|
*count = state.end >= start ? state.end - start : 0;
|
||||||
/* Return success if at least one value was saved, otherwise an error. */
|
/* Return success if at least one value was saved, otherwise an error. */
|
||||||
return (rc == -EFAULT && *count > 0) ? 0 : rc;
|
return (rc == -EFAULT && *count > 0) ? 0 : rc;
|
||||||
}
|
}
|
||||||
@@ -1253,6 +1253,9 @@ int dat_get_cmma(union asce asce, gfn_t *start, unsigned int *count, u8 *values,
|
|||||||
};
|
};
|
||||||
|
|
||||||
_dat_walk_gfn_range(*start, asce_end(asce), asce, &ops, DAT_WALK_IGN_HOLES, &state);
|
_dat_walk_gfn_range(*start, asce_end(asce), asce, &ops, DAT_WALK_IGN_HOLES, &state);
|
||||||
|
/* If no dirty pages were found, wrap around and continue searching */
|
||||||
|
if (*start && state.start == -1)
|
||||||
|
_dat_walk_gfn_range(0, *start, asce, &ops, DAT_WALK_IGN_HOLES, &state);
|
||||||
|
|
||||||
if (state.start == -1) {
|
if (state.start == -1) {
|
||||||
*count = 0;
|
*count = 0;
|
||||||
|
|||||||
@@ -332,7 +332,7 @@ static long gmap_clear_young_crste(union crste *crstep, gfn_t gfn, gfn_t end, st
|
|||||||
new.h.i = 1;
|
new.h.i = 1;
|
||||||
new.s.fc1.y = 0;
|
new.s.fc1.y = 0;
|
||||||
new.s.fc1.prefix_notif = 0;
|
new.s.fc1.prefix_notif = 0;
|
||||||
if (new.s.fc1.d || !new.h.p)
|
if ((new.s.fc1.d || !new.h.p) && !new.s.fc1.s)
|
||||||
folio_set_dirty(phys_to_folio(crste_origin_large(crste)));
|
folio_set_dirty(phys_to_folio(crste_origin_large(crste)));
|
||||||
new.s.fc1.d = 0;
|
new.s.fc1.d = 0;
|
||||||
new.h.p = 1;
|
new.h.p = 1;
|
||||||
@@ -1098,23 +1098,46 @@ int gmap_protect_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gf
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long __set_cmma_dirty_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
static long __set_cmma_clean_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
||||||
{
|
{
|
||||||
__atomic64_or(PGSTE_CMMA_D_BIT, &pgste_of(ptep)->val);
|
union pgste pgste;
|
||||||
|
|
||||||
|
pgste = pgste_get_lock(ptep);
|
||||||
|
pgste.cmma_d = 0;
|
||||||
|
pgste_set_unlock(ptep, pgste);
|
||||||
|
|
||||||
if (need_resched())
|
if (need_resched())
|
||||||
return next;
|
return next;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gmap_set_cmma_all_dirty(struct gmap *gmap)
|
static long __set_cmma_dirty_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
||||||
{
|
{
|
||||||
const struct dat_walk_ops ops = { .pte_entry = __set_cmma_dirty_pte, };
|
union pgste pgste;
|
||||||
|
|
||||||
|
pgste = pgste_get_lock(ptep);
|
||||||
|
if (!pgste.cmma_d)
|
||||||
|
atomic64_inc(walk->priv);
|
||||||
|
pgste.cmma_d = 1;
|
||||||
|
pgste_set_unlock(ptep, pgste);
|
||||||
|
|
||||||
|
if (need_resched())
|
||||||
|
return next;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _gmap_set_cmma_all(struct gmap *gmap, bool dirty)
|
||||||
|
{
|
||||||
|
const struct dat_walk_ops ops = {
|
||||||
|
.pte_entry = dirty ? __set_cmma_dirty_pte : __set_cmma_clean_pte,
|
||||||
|
};
|
||||||
gfn_t gfn = 0;
|
gfn_t gfn = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
scoped_guard(read_lock, &gmap->kvm->mmu_lock)
|
scoped_guard(read_lock, &gmap->kvm->mmu_lock)
|
||||||
gfn = _dat_walk_gfn_range(gfn, asce_end(gmap->asce), gmap->asce, &ops,
|
gfn = _dat_walk_gfn_range(gfn, asce_end(gmap->asce), gmap->asce, &ops,
|
||||||
DAT_WALK_IGN_HOLES, NULL);
|
DAT_WALK_IGN_HOLES,
|
||||||
|
&gmap->kvm->arch.cmma_dirty_pages);
|
||||||
cond_resched();
|
cond_resched();
|
||||||
} while (gfn);
|
} while (gfn);
|
||||||
}
|
}
|
||||||
@@ -1287,7 +1310,7 @@ static int gmap_protect_asce_top_level(struct kvm_s390_mmu_cache *mc, struct gma
|
|||||||
/* Pairs with the smp_wmb() in kvm_mmu_invalidate_end(). */
|
/* Pairs with the smp_wmb() in kvm_mmu_invalidate_end(). */
|
||||||
smp_rmb();
|
smp_rmb();
|
||||||
|
|
||||||
rc = kvm_s390_get_guest_pages(sg->kvm, context.f, asce.rsto, asce.dt + 1, false);
|
rc = kvm_s390_get_guest_pages(sg->kvm, context.f, asce.rsto, asce.tl + 1, false);
|
||||||
if (rc > 0)
|
if (rc > 0)
|
||||||
rc = -EFAULT;
|
rc = -EFAULT;
|
||||||
if (!rc)
|
if (!rc)
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ int gmap_insert_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gfn
|
|||||||
gfn_t r_gfn, int level);
|
gfn_t r_gfn, int level);
|
||||||
int gmap_protect_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gfn, gfn_t r_gfn,
|
int gmap_protect_rmap(struct kvm_s390_mmu_cache *mc, struct gmap *sg, gfn_t p_gfn, gfn_t r_gfn,
|
||||||
kvm_pfn_t pfn, int level, bool wr);
|
kvm_pfn_t pfn, int level, bool wr);
|
||||||
void gmap_set_cmma_all_dirty(struct gmap *gmap);
|
void _gmap_set_cmma_all(struct gmap *gmap, bool dirty);
|
||||||
void _gmap_handle_vsie_unshadow_event(struct gmap *parent, gfn_t gfn);
|
void _gmap_handle_vsie_unshadow_event(struct gmap *parent, gfn_t gfn);
|
||||||
struct gmap *gmap_create_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *gmap,
|
struct gmap *gmap_create_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *gmap,
|
||||||
union asce asce, int edat_level);
|
union asce asce, int edat_level);
|
||||||
@@ -198,6 +198,16 @@ static inline bool pte_needs_unshadow(union pte oldpte, union pte newpte, union
|
|||||||
return !newpte.h.p || !newpte.s.pr;
|
return !newpte.h.p || !newpte.s.pr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void gmap_set_cmma_all_dirty(struct gmap *gmap)
|
||||||
|
{
|
||||||
|
_gmap_set_cmma_all(gmap, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void gmap_set_cmma_all_clean(struct gmap *gmap)
|
||||||
|
{
|
||||||
|
_gmap_set_cmma_all(gmap, false);
|
||||||
|
}
|
||||||
|
|
||||||
static inline union pgste _gmap_ptep_xchg(struct gmap *gmap, union pte *ptep, union pte newpte,
|
static inline union pgste _gmap_ptep_xchg(struct gmap *gmap, union pte *ptep, union pte newpte,
|
||||||
union pgste pgste, gfn_t gfn, bool needs_lock)
|
union pgste pgste, gfn_t gfn, bool needs_lock)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1022,9 +1022,11 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
|
|||||||
if (!kvm->arch.use_cmma)
|
if (!kvm->arch.use_cmma)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
guard(mutex)(&kvm->lock);
|
||||||
VM_EVENT(kvm, 3, "%s", "RESET: CMMA states");
|
VM_EVENT(kvm, 3, "%s", "RESET: CMMA states");
|
||||||
do {
|
do {
|
||||||
start_gfn = dat_reset_cmma(kvm->arch.gmap->asce, start_gfn);
|
scoped_guard(read_lock, &kvm->mmu_lock)
|
||||||
|
start_gfn = dat_reset_cmma(kvm->arch.gmap->asce, start_gfn);
|
||||||
cond_resched();
|
cond_resched();
|
||||||
} while (start_gfn);
|
} while (start_gfn);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@@ -1217,13 +1219,13 @@ static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Must be called with kvm->srcu held to avoid races on memslots, and with
|
* Must be called with kvm->srcu held to avoid races on memslots, and with
|
||||||
* kvm->slots_lock to avoid races with ourselves and kvm_s390_vm_stop_migration.
|
* kvm->slots_lock to avoid races with ourselves, kvm_s390_vm_stop_migration(),
|
||||||
|
* and kvm_s390_get_cmma_bits().
|
||||||
*/
|
*/
|
||||||
static int kvm_s390_vm_start_migration(struct kvm *kvm)
|
static int kvm_s390_vm_start_migration(struct kvm *kvm)
|
||||||
{
|
{
|
||||||
struct kvm_memory_slot *ms;
|
struct kvm_memory_slot *ms;
|
||||||
struct kvm_memslots *slots;
|
struct kvm_memslots *slots;
|
||||||
unsigned long ram_pages = 0;
|
|
||||||
int bkt;
|
int bkt;
|
||||||
|
|
||||||
/* migration mode already enabled */
|
/* migration mode already enabled */
|
||||||
@@ -1240,28 +1242,54 @@ static int kvm_s390_vm_start_migration(struct kvm *kvm)
|
|||||||
kvm_for_each_memslot(ms, bkt, slots) {
|
kvm_for_each_memslot(ms, bkt, slots) {
|
||||||
if (!ms->dirty_bitmap)
|
if (!ms->dirty_bitmap)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
ram_pages += ms->npages;
|
|
||||||
}
|
}
|
||||||
/* mark all the pages as dirty */
|
/*
|
||||||
gmap_set_cmma_all_dirty(kvm->arch.gmap);
|
* Set the flag and let KVM handle ESSA manually, potentially setting
|
||||||
atomic64_set(&kvm->arch.cmma_dirty_pages, ram_pages);
|
* the cmma_d bit in some PGSTEs and increasing cmma_dirty_pages.
|
||||||
kvm->arch.migration_mode = 1;
|
* At this point cmma_dirty_pages is still 0, and all existing PGSTEs
|
||||||
|
* have their cmma_d bit set to 0.
|
||||||
|
* Any newly allocated page table has its entries marked as cmma-clean,
|
||||||
|
* which is fine because the CMMA values are not dirty.
|
||||||
|
*/
|
||||||
|
WRITE_ONCE(kvm->arch.migration_mode, 1);
|
||||||
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_START_MIGRATION);
|
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_START_MIGRATION);
|
||||||
|
/*
|
||||||
|
* Mark all PGSTEs as cmma-dirty, increasing cmma_dirty_pages as needed,
|
||||||
|
* but without double-counting pages that have become dirty on their own
|
||||||
|
* in the meantime.
|
||||||
|
* At this point some pages might have become dirty on their own already
|
||||||
|
* and cmma_dirty_pages might therefore be non-zero.
|
||||||
|
*/
|
||||||
|
gmap_set_cmma_all_dirty(kvm->arch.gmap);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Must be called with kvm->slots_lock to avoid races with ourselves and
|
* Must be called with kvm->slots_lock to avoid races with ourselves,
|
||||||
* kvm_s390_vm_start_migration.
|
* kvm_s390_vm_start_migration() and kvm_s390_get_cmma_bits().
|
||||||
*/
|
*/
|
||||||
static int kvm_s390_vm_stop_migration(struct kvm *kvm)
|
static int kvm_s390_vm_stop_migration(struct kvm *kvm)
|
||||||
{
|
{
|
||||||
/* migration mode already disabled */
|
/* migration mode already disabled */
|
||||||
if (!kvm->arch.migration_mode)
|
if (!kvm->arch.migration_mode)
|
||||||
return 0;
|
return 0;
|
||||||
kvm->arch.migration_mode = 0;
|
/*
|
||||||
|
* Unset the flag and propagate to all vCPUs. From now on the cmma_d
|
||||||
|
* bit will not be touched on any PGSTE.
|
||||||
|
* At this point cmma_dirty_pages is possibly non-zero, and thus some
|
||||||
|
* PGSTEs might have cmma_d set.
|
||||||
|
*/
|
||||||
|
WRITE_ONCE(kvm->arch.migration_mode, 0);
|
||||||
if (kvm->arch.use_cmma)
|
if (kvm->arch.use_cmma)
|
||||||
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_STOP_MIGRATION);
|
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_STOP_MIGRATION);
|
||||||
|
/* Clear cmma_d on all existing PGSTEs and set cmma_dirty_pages to 0. */
|
||||||
|
gmap_set_cmma_all_clean(kvm->arch.gmap);
|
||||||
|
atomic64_set(&kvm->arch.cmma_dirty_pages, 0);
|
||||||
|
/*
|
||||||
|
* At this point the system has the expected state: migration_mode is 0,
|
||||||
|
* cmma_dirty_pages is 0, and all existing PGSTEs have their cmma_d bit
|
||||||
|
* set to 0.
|
||||||
|
*/
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2317,8 +2345,8 @@ static int kvm_s390_get_cmma_bits(struct kvm *kvm,
|
|||||||
static int kvm_s390_set_cmma_bits(struct kvm *kvm,
|
static int kvm_s390_set_cmma_bits(struct kvm *kvm,
|
||||||
const struct kvm_s390_cmma_log *args)
|
const struct kvm_s390_cmma_log *args)
|
||||||
{
|
{
|
||||||
struct kvm_s390_mmu_cache *mc;
|
struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
|
||||||
u8 *bits = NULL;
|
u8 *bits __free(kvfree) = NULL;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
if (!kvm->arch.use_cmma)
|
if (!kvm->arch.use_cmma)
|
||||||
@@ -2338,18 +2366,16 @@ static int kvm_s390_set_cmma_bits(struct kvm *kvm,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
bits = vmalloc(array_size(sizeof(*bits), args->count));
|
bits = vmalloc(array_size(sizeof(*bits), args->count));
|
||||||
if (!bits)
|
if (!bits)
|
||||||
goto out;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = copy_from_user(bits, (void __user *)args->values, args->count);
|
r = copy_from_user(bits, (void __user *)args->values, args->count);
|
||||||
if (r) {
|
if (r)
|
||||||
r = -EFAULT;
|
return -EFAULT;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
r = kvm_s390_mmu_cache_topup(mc);
|
r = kvm_s390_mmu_cache_topup(mc);
|
||||||
if (r)
|
if (r)
|
||||||
break;
|
return r;
|
||||||
scoped_guard(read_lock, &kvm->mmu_lock) {
|
scoped_guard(read_lock, &kvm->mmu_lock) {
|
||||||
r = dat_set_cmma_bits(mc, kvm->arch.gmap->asce, args->start_gfn,
|
r = dat_set_cmma_bits(mc, kvm->arch.gmap->asce, args->start_gfn,
|
||||||
args->count, args->mask, bits);
|
args->count, args->mask, bits);
|
||||||
@@ -2357,9 +2383,7 @@ static int kvm_s390_set_cmma_bits(struct kvm *kvm,
|
|||||||
} while (r == -ENOMEM);
|
} while (r == -ENOMEM);
|
||||||
|
|
||||||
set_bit(GMAP_FLAG_USES_CMM, &kvm->arch.gmap->flags);
|
set_bit(GMAP_FLAG_USES_CMM, &kvm->arch.gmap->flags);
|
||||||
out:
|
|
||||||
kvm_s390_free_mmu_cache(mc);
|
|
||||||
vfree(bits);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3584,7 +3608,8 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
|
|||||||
vcpu->arch.gmap = vcpu->kvm->arch.gmap;
|
vcpu->arch.gmap = vcpu->kvm->arch.gmap;
|
||||||
sca_add_vcpu(vcpu);
|
sca_add_vcpu(vcpu);
|
||||||
}
|
}
|
||||||
if (test_kvm_facility(vcpu->kvm, 74) || vcpu->kvm->arch.user_instr0)
|
if (test_kvm_facility(vcpu->kvm, 74) || vcpu->kvm->arch.user_instr0 ||
|
||||||
|
vcpu->kvm->arch.user_operexec)
|
||||||
vcpu->arch.sie_block->ictl |= ICTL_OPEREXC;
|
vcpu->arch.sie_block->ictl |= ICTL_OPEREXC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -366,7 +366,9 @@ static int handle_sske(struct kvm_vcpu *vcpu)
|
|||||||
if (rc > 1)
|
if (rc > 1)
|
||||||
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
|
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
|
||||||
if (rc == -ENOMEM) {
|
if (rc == -ENOMEM) {
|
||||||
kvm_s390_mmu_cache_topup(vcpu->arch.mc);
|
rc = kvm_s390_mmu_cache_topup(vcpu->arch.mc);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
@@ -1122,7 +1124,9 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
|
|||||||
if (rc > 1)
|
if (rc > 1)
|
||||||
return kvm_s390_inject_program_int(vcpu, rc);
|
return kvm_s390_inject_program_int(vcpu, rc);
|
||||||
if (rc == -ENOMEM) {
|
if (rc == -ENOMEM) {
|
||||||
kvm_s390_mmu_cache_topup(vcpu->arch.mc);
|
rc = kvm_s390_mmu_cache_topup(vcpu->arch.mc);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
@@ -1232,7 +1236,7 @@ static int handle_essa(struct kvm_vcpu *vcpu)
|
|||||||
: ESSA_SET_STABLE_IF_RESIDENT))
|
: ESSA_SET_STABLE_IF_RESIDENT))
|
||||||
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
|
||||||
|
|
||||||
if (!vcpu->kvm->arch.migration_mode) {
|
if (!READ_ONCE(vcpu->kvm->arch.migration_mode)) {
|
||||||
/*
|
/*
|
||||||
* CMMA is enabled in the KVM settings, but is disabled in
|
* CMMA is enabled in the KVM settings, but is disabled in
|
||||||
* the SIE block and in the mm_context, and we are not doing
|
* the SIE block and in the mm_context, and we are not doing
|
||||||
|
|||||||
@@ -181,7 +181,8 @@ void gmap_helper_try_set_pte_unused(struct mm_struct *mm, unsigned long vmaddr)
|
|||||||
if (IS_ERR_OR_NULL(ptep))
|
if (IS_ERR_OR_NULL(ptep))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
__atomic64_or(_PAGE_UNUSED, (long *)ptep);
|
if (pte_present(*ptep))
|
||||||
|
__atomic64_or(_PAGE_UNUSED, (long *)ptep);
|
||||||
pte_unmap_unlock(ptep, ptl);
|
pte_unmap_unlock(ptep, ptl);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gmap_helper_try_set_pte_unused);
|
EXPORT_SYMBOL_GPL(gmap_helper_try_set_pte_unused);
|
||||||
|
|||||||
@@ -1434,7 +1434,6 @@ enum kvm_mmu_type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct kvm_arch {
|
struct kvm_arch {
|
||||||
unsigned long n_used_mmu_pages;
|
|
||||||
unsigned long n_requested_mmu_pages;
|
unsigned long n_requested_mmu_pages;
|
||||||
unsigned long n_max_mmu_pages;
|
unsigned long n_max_mmu_pages;
|
||||||
unsigned int indirect_shadow_pages;
|
unsigned int indirect_shadow_pages;
|
||||||
@@ -1700,6 +1699,7 @@ struct kvm_vm_stat {
|
|||||||
u64 mmu_recycled;
|
u64 mmu_recycled;
|
||||||
u64 mmu_cache_miss;
|
u64 mmu_cache_miss;
|
||||||
u64 mmu_unsync;
|
u64 mmu_unsync;
|
||||||
|
u64 mmu_shadow_pages;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
atomic64_t pages_4k;
|
atomic64_t pages_4k;
|
||||||
@@ -2525,16 +2525,6 @@ static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu)
|
|||||||
kvm_x86_call(vcpu_unblocking)(vcpu);
|
kvm_x86_call(vcpu_unblocking)(vcpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int kvm_cpu_get_apicid(int mps_cpu)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_X86_LOCAL_APIC
|
|
||||||
return default_cpu_present_to_apicid(mps_cpu);
|
|
||||||
#else
|
|
||||||
WARN_ON_ONCE(1);
|
|
||||||
return BAD_APICID;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages);
|
int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages);
|
||||||
|
|
||||||
#define KVM_CLOCK_VALID_FLAGS \
|
#define KVM_CLOCK_VALID_FLAGS \
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ u32 default_cpu_present_to_apicid(int mps_cpu)
|
|||||||
else
|
else
|
||||||
return BAD_APICID;
|
return BAD_APICID;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_FOR_KVM(default_cpu_present_to_apicid);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up the logical destination ID when the APIC operates in logical
|
* Set up the logical destination ID when the APIC operates in logical
|
||||||
|
|||||||
@@ -194,7 +194,8 @@ int kvm_pic_set_irq(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,
|
|||||||
int irq = e->irqchip.pin;
|
int irq = e->irqchip.pin;
|
||||||
int ret, irq_level;
|
int ret, irq_level;
|
||||||
|
|
||||||
BUG_ON(irq < 0 || irq >= PIC_NUM_PINS);
|
if (WARN_ON_ONCE(irq < 0 || irq >= PIC_NUM_PINS))
|
||||||
|
return -1;
|
||||||
|
|
||||||
pic_lock(s);
|
pic_lock(s);
|
||||||
irq_level = __kvm_irq_line_state(&s->irq_states[irq],
|
irq_level = __kvm_irq_line_state(&s->irq_states[irq],
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic);
|
|||||||
|
|
||||||
static void rtc_status_pending_eoi_check_valid(struct kvm_ioapic *ioapic)
|
static void rtc_status_pending_eoi_check_valid(struct kvm_ioapic *ioapic)
|
||||||
{
|
{
|
||||||
if (WARN_ON(ioapic->rtc_status.pending_eoi < 0))
|
if (WARN_ON_ONCE(ioapic->rtc_status.pending_eoi < 0))
|
||||||
kvm_rtc_eoi_tracking_restore_all(ioapic);
|
kvm_rtc_eoi_tracking_restore_all(ioapic);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,7 +484,7 @@ static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
|
|||||||
* ensures that it is only called if it is >= zero, namely
|
* ensures that it is only called if it is >= zero, namely
|
||||||
* if rtc_irq_check_coalesced returns false).
|
* if rtc_irq_check_coalesced returns false).
|
||||||
*/
|
*/
|
||||||
BUG_ON(ioapic->rtc_status.pending_eoi != 0);
|
WARN_ON_ONCE(ioapic->rtc_status.pending_eoi);
|
||||||
ret = __kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe,
|
ret = __kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe,
|
||||||
&ioapic->rtc_status);
|
&ioapic->rtc_status);
|
||||||
ioapic->rtc_status.pending_eoi = (ret < 0 ? 0 : ret);
|
ioapic->rtc_status.pending_eoi = (ret < 0 ? 0 : ret);
|
||||||
@@ -504,7 +504,8 @@ int kvm_ioapic_set_irq(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,
|
|||||||
int irq = e->irqchip.pin;
|
int irq = e->irqchip.pin;
|
||||||
int ret, irq_level;
|
int ret, irq_level;
|
||||||
|
|
||||||
BUG_ON(irq < 0 || irq >= IOAPIC_NUM_PINS);
|
if (WARN_ON_ONCE(irq < 0 || irq >= IOAPIC_NUM_PINS))
|
||||||
|
return -1;
|
||||||
|
|
||||||
spin_lock(&ioapic->lock);
|
spin_lock(&ioapic->lock);
|
||||||
irq_level = __kvm_irq_line_state(&ioapic->irq_states[irq],
|
irq_level = __kvm_irq_line_state(&ioapic->irq_states[irq],
|
||||||
|
|||||||
@@ -767,7 +767,7 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
|
|||||||
kvm_x86_call(hwapic_isr_update)(apic->vcpu, vec);
|
kvm_x86_call(hwapic_isr_update)(apic->vcpu, vec);
|
||||||
else {
|
else {
|
||||||
++apic->isr_count;
|
++apic->isr_count;
|
||||||
BUG_ON(apic->isr_count > MAX_APIC_VECTOR);
|
KVM_BUG_ON(apic->isr_count > MAX_APIC_VECTOR, apic->vcpu->kvm);
|
||||||
/*
|
/*
|
||||||
* ISR (in service register) bit is set when injecting an interrupt.
|
* ISR (in service register) bit is set when injecting an interrupt.
|
||||||
* The highest vector is injected. Thus the latest bit set matches
|
* The highest vector is injected. Thus the latest bit set matches
|
||||||
@@ -808,7 +808,7 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
|
|||||||
kvm_x86_call(hwapic_isr_update)(apic->vcpu, apic_find_highest_isr(apic));
|
kvm_x86_call(hwapic_isr_update)(apic->vcpu, apic_find_highest_isr(apic));
|
||||||
else {
|
else {
|
||||||
--apic->isr_count;
|
--apic->isr_count;
|
||||||
BUG_ON(apic->isr_count < 0);
|
KVM_BUG_ON(apic->isr_count < 0, apic->vcpu->kvm);
|
||||||
apic->highest_isr_cache = -1;
|
apic->highest_isr_cache = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -980,6 +980,8 @@ static void apic_update_ppr(struct kvm_lapic *apic)
|
|||||||
if (__apic_update_ppr(apic, &ppr) &&
|
if (__apic_update_ppr(apic, &ppr) &&
|
||||||
apic_has_interrupt_for_ppr(apic, ppr) != -1)
|
apic_has_interrupt_for_ppr(apic, ppr) != -1)
|
||||||
kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
|
kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
|
||||||
|
else
|
||||||
|
kvm_lapic_update_cr8_intercept(apic->vcpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvm_apic_update_ppr(struct kvm_vcpu *vcpu)
|
void kvm_apic_update_ppr(struct kvm_vcpu *vcpu)
|
||||||
|
|||||||
@@ -1802,13 +1802,13 @@ static void kvm_mmu_check_sptes_at_free(struct kvm_mmu_page *sp)
|
|||||||
|
|
||||||
static void kvm_account_mmu_page(struct kvm *kvm, struct kvm_mmu_page *sp)
|
static void kvm_account_mmu_page(struct kvm *kvm, struct kvm_mmu_page *sp)
|
||||||
{
|
{
|
||||||
kvm->arch.n_used_mmu_pages++;
|
kvm->stat.mmu_shadow_pages++;
|
||||||
kvm_account_pgtable_pages((void *)sp->spt, +1);
|
kvm_account_pgtable_pages((void *)sp->spt, +1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_unaccount_mmu_page(struct kvm *kvm, struct kvm_mmu_page *sp)
|
static void kvm_unaccount_mmu_page(struct kvm *kvm, struct kvm_mmu_page *sp)
|
||||||
{
|
{
|
||||||
kvm->arch.n_used_mmu_pages--;
|
kvm->stat.mmu_shadow_pages--;
|
||||||
kvm_account_pgtable_pages((void *)sp->spt, -1);
|
kvm_account_pgtable_pages((void *)sp->spt, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2836,9 +2836,9 @@ static unsigned long kvm_mmu_zap_oldest_mmu_pages(struct kvm *kvm,
|
|||||||
|
|
||||||
static inline unsigned long kvm_mmu_available_pages(struct kvm *kvm)
|
static inline unsigned long kvm_mmu_available_pages(struct kvm *kvm)
|
||||||
{
|
{
|
||||||
if (kvm->arch.n_max_mmu_pages > kvm->arch.n_used_mmu_pages)
|
if (kvm->arch.n_max_mmu_pages > kvm->stat.mmu_shadow_pages)
|
||||||
return kvm->arch.n_max_mmu_pages -
|
return kvm->arch.n_max_mmu_pages -
|
||||||
kvm->arch.n_used_mmu_pages;
|
kvm->stat.mmu_shadow_pages;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2874,11 +2874,11 @@ void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned long goal_nr_mmu_pages)
|
|||||||
{
|
{
|
||||||
write_lock(&kvm->mmu_lock);
|
write_lock(&kvm->mmu_lock);
|
||||||
|
|
||||||
if (kvm->arch.n_used_mmu_pages > goal_nr_mmu_pages) {
|
if (kvm->stat.mmu_shadow_pages > goal_nr_mmu_pages) {
|
||||||
kvm_mmu_zap_oldest_mmu_pages(kvm, kvm->arch.n_used_mmu_pages -
|
kvm_mmu_zap_oldest_mmu_pages(kvm, kvm->stat.mmu_shadow_pages -
|
||||||
goal_nr_mmu_pages);
|
goal_nr_mmu_pages);
|
||||||
|
|
||||||
goal_nr_mmu_pages = kvm->arch.n_used_mmu_pages;
|
goal_nr_mmu_pages = kvm->stat.mmu_shadow_pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
kvm->arch.n_max_mmu_pages = goal_nr_mmu_pages;
|
kvm->arch.n_max_mmu_pages = goal_nr_mmu_pages;
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ TRACE_EVENT(
|
|||||||
|
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
__entry->mmu_valid_gen = kvm->arch.mmu_valid_gen;
|
__entry->mmu_valid_gen = kvm->arch.mmu_valid_gen;
|
||||||
__entry->mmu_used_pages = kvm->arch.n_used_mmu_pages;
|
__entry->mmu_used_pages = kvm->stat.mmu_shadow_pages;
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk("kvm-mmu-valid-gen %u used_pages %x",
|
TP_printk("kvm-mmu-valid-gen %u used_pages %x",
|
||||||
|
|||||||
@@ -1410,9 +1410,10 @@ static bool wrprot_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root,
|
|||||||
u64 new_spte;
|
u64 new_spte;
|
||||||
bool spte_set = false;
|
bool spte_set = false;
|
||||||
|
|
||||||
rcu_read_lock();
|
if (KVM_BUG_ON(min_level > KVM_MAX_HUGEPAGE_LEVEL, kvm))
|
||||||
|
return false;
|
||||||
|
|
||||||
BUG_ON(min_level > KVM_MAX_HUGEPAGE_LEVEL);
|
rcu_read_lock();
|
||||||
|
|
||||||
for_each_tdp_pte_min_level(iter, kvm, root, min_level, start, end) {
|
for_each_tdp_pte_min_level(iter, kvm, root, min_level, start, end) {
|
||||||
retry:
|
retry:
|
||||||
@@ -1844,7 +1845,8 @@ static bool write_protect_gfn(struct kvm *kvm, struct kvm_mmu_page *root,
|
|||||||
u64 new_spte;
|
u64 new_spte;
|
||||||
bool spte_set = false;
|
bool spte_set = false;
|
||||||
|
|
||||||
BUG_ON(min_level > KVM_MAX_HUGEPAGE_LEVEL);
|
if (KVM_BUG_ON(min_level > KVM_MAX_HUGEPAGE_LEVEL, kvm))
|
||||||
|
return false;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
||||||
|
|||||||
@@ -460,8 +460,8 @@ void avic_ring_doorbell(struct kvm_vcpu *vcpu)
|
|||||||
int cpu = READ_ONCE(vcpu->cpu);
|
int cpu = READ_ONCE(vcpu->cpu);
|
||||||
|
|
||||||
if (cpu != get_cpu()) {
|
if (cpu != get_cpu()) {
|
||||||
wrmsrq(MSR_AMD64_SVM_AVIC_DOORBELL, kvm_cpu_get_apicid(cpu));
|
wrmsrq(MSR_AMD64_SVM_AVIC_DOORBELL, cpu_physical_id(cpu));
|
||||||
trace_kvm_avic_doorbell(vcpu->vcpu_id, kvm_cpu_get_apicid(cpu));
|
trace_kvm_avic_doorbell(vcpu->vcpu_id, cpu_physical_id(cpu));
|
||||||
}
|
}
|
||||||
put_cpu();
|
put_cpu();
|
||||||
}
|
}
|
||||||
@@ -1013,7 +1013,7 @@ static void __avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu,
|
|||||||
enum avic_vcpu_action action)
|
enum avic_vcpu_action action)
|
||||||
{
|
{
|
||||||
struct kvm_svm *kvm_svm = to_kvm_svm(vcpu->kvm);
|
struct kvm_svm *kvm_svm = to_kvm_svm(vcpu->kvm);
|
||||||
int h_physical_id = kvm_cpu_get_apicid(cpu);
|
int h_physical_id = cpu_physical_id(cpu);
|
||||||
struct vcpu_svm *svm = to_svm(vcpu);
|
struct vcpu_svm *svm = to_svm(vcpu);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u64 entry;
|
u64 entry;
|
||||||
|
|||||||
@@ -2152,7 +2152,8 @@ static gpa_t svm_translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa,
|
|||||||
struct vcpu_svm *svm = to_svm(vcpu);
|
struct vcpu_svm *svm = to_svm(vcpu);
|
||||||
struct kvm_mmu *mmu = vcpu->arch.mmu;
|
struct kvm_mmu *mmu = vcpu->arch.mmu;
|
||||||
|
|
||||||
BUG_ON(!mmu_is_nested(vcpu));
|
if (WARN_ON_ONCE(!mmu_is_nested(vcpu)))
|
||||||
|
return gpa;
|
||||||
|
|
||||||
/* Non-GMET walks are always user-walks */
|
/* Non-GMET walks are always user-walks */
|
||||||
if (!(svm->nested.ctl.misc_ctl & SVM_MISC_ENABLE_GMET))
|
if (!(svm->nested.ctl.misc_ctl & SVM_MISC_ENABLE_GMET))
|
||||||
|
|||||||
@@ -7470,7 +7470,8 @@ static gpa_t vmx_translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa,
|
|||||||
{
|
{
|
||||||
struct kvm_mmu *mmu = vcpu->arch.mmu;
|
struct kvm_mmu *mmu = vcpu->arch.mmu;
|
||||||
|
|
||||||
BUG_ON(!mmu_is_nested(vcpu));
|
if (WARN_ON_ONCE(!mmu_is_nested(vcpu)))
|
||||||
|
return gpa;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MBEC differentiates based on the effective U/S bit of
|
* MBEC differentiates based on the effective U/S bit of
|
||||||
|
|||||||
@@ -6873,11 +6873,10 @@ int vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
|
|||||||
|
|
||||||
void vmx_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
|
void vmx_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
|
||||||
{
|
{
|
||||||
struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
|
|
||||||
int tpr_threshold;
|
int tpr_threshold;
|
||||||
|
|
||||||
if (is_guest_mode(vcpu) &&
|
if (is_guest_mode(vcpu) &&
|
||||||
nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW))
|
nested_cpu_has(get_vmcs12(vcpu), CPU_BASED_TPR_SHADOW))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
guard(vmx_vmcs01)(vcpu);
|
guard(vmx_vmcs01)(vcpu);
|
||||||
|
|||||||
@@ -244,6 +244,7 @@ const struct kvm_stats_desc kvm_vm_stats_desc[] = {
|
|||||||
STATS_DESC_COUNTER(VM, mmu_recycled),
|
STATS_DESC_COUNTER(VM, mmu_recycled),
|
||||||
STATS_DESC_COUNTER(VM, mmu_cache_miss),
|
STATS_DESC_COUNTER(VM, mmu_cache_miss),
|
||||||
STATS_DESC_ICOUNTER(VM, mmu_unsync),
|
STATS_DESC_ICOUNTER(VM, mmu_unsync),
|
||||||
|
STATS_DESC_ICOUNTER(VM, mmu_shadow_pages),
|
||||||
STATS_DESC_ICOUNTER(VM, pages_4k),
|
STATS_DESC_ICOUNTER(VM, pages_4k),
|
||||||
STATS_DESC_ICOUNTER(VM, pages_2m),
|
STATS_DESC_ICOUNTER(VM, pages_2m),
|
||||||
STATS_DESC_ICOUNTER(VM, pages_1g),
|
STATS_DESC_ICOUNTER(VM, pages_1g),
|
||||||
@@ -5317,7 +5318,6 @@ static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
|
|||||||
r = kvm_apic_set_state(vcpu, s);
|
r = kvm_apic_set_state(vcpu, s);
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
kvm_lapic_update_cr8_intercept(vcpu);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -12418,8 +12418,6 @@ static int __set_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs,
|
|||||||
kvm_register_mark_dirty(vcpu, VCPU_REG_CR3);
|
kvm_register_mark_dirty(vcpu, VCPU_REG_CR3);
|
||||||
kvm_x86_call(post_set_cr3)(vcpu, sregs->cr3);
|
kvm_x86_call(post_set_cr3)(vcpu, sregs->cr3);
|
||||||
|
|
||||||
kvm_set_cr8(vcpu, sregs->cr8);
|
|
||||||
|
|
||||||
*mmu_reset_needed |= vcpu->arch.efer != sregs->efer;
|
*mmu_reset_needed |= vcpu->arch.efer != sregs->efer;
|
||||||
kvm_x86_call(set_efer)(vcpu, sregs->efer);
|
kvm_x86_call(set_efer)(vcpu, sregs->efer);
|
||||||
|
|
||||||
@@ -12448,7 +12446,7 @@ static int __set_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs,
|
|||||||
kvm_set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
|
kvm_set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
|
||||||
kvm_set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
|
kvm_set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
|
||||||
|
|
||||||
kvm_lapic_update_cr8_intercept(vcpu);
|
kvm_set_cr8(vcpu, sregs->cr8);
|
||||||
|
|
||||||
/* Older userspace won't unhalt the vcpu on reset. */
|
/* Older userspace won't unhalt the vcpu on reset. */
|
||||||
if (kvm_vcpu_is_bsp(vcpu) && kvm_rip_read(vcpu) == 0xfff0 &&
|
if (kvm_vcpu_is_bsp(vcpu) && kvm_rip_read(vcpu) == 0xfff0 &&
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#ifndef SELFTEST_KVM_FACILITY_H
|
#ifndef SELFTEST_KVM_FACILITY_H
|
||||||
#define SELFTEST_KVM_FACILITY_H
|
#define SELFTEST_KVM_FACILITY_H
|
||||||
|
|
||||||
|
#include <linux/atomic.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
|
|
||||||
/* alt_stfle_fac_list[16] + stfle_fac_list[16] */
|
/* alt_stfle_fac_list[16] + stfle_fac_list[16] */
|
||||||
@@ -19,6 +20,11 @@
|
|||||||
extern u64 stfl_doublewords[NB_STFL_DOUBLEWORDS];
|
extern u64 stfl_doublewords[NB_STFL_DOUBLEWORDS];
|
||||||
extern bool stfle_flag;
|
extern bool stfle_flag;
|
||||||
|
|
||||||
|
static inline bool clear_bit_inv(unsigned long nr, unsigned long *ptr)
|
||||||
|
{
|
||||||
|
return clear_bit(nr ^ (BITS_PER_LONG - 1), ptr);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool test_bit_inv(unsigned long nr, const unsigned long *ptr)
|
static inline bool test_bit_inv(unsigned long nr, const unsigned long *ptr)
|
||||||
{
|
{
|
||||||
return test_bit(nr ^ (BITS_PER_LONG - 1), ptr);
|
return test_bit(nr ^ (BITS_PER_LONG - 1), ptr);
|
||||||
|
|||||||
@@ -34,16 +34,22 @@ static char cmma_value_buf[MAIN_PAGE_COUNT + TEST_DATA_PAGE_COUNT];
|
|||||||
/**
|
/**
|
||||||
* Dirty CMMA attributes of exactly one page in the TEST_DATA memslot,
|
* Dirty CMMA attributes of exactly one page in the TEST_DATA memslot,
|
||||||
* so use_cmma goes on and the CMMA related ioctls do something.
|
* so use_cmma goes on and the CMMA related ioctls do something.
|
||||||
|
* Touch the page at offset 1M inside TEST_DATA to make sure its page
|
||||||
|
* tables are allocated in the host.
|
||||||
*/
|
*/
|
||||||
static void guest_do_one_essa(void)
|
static void guest_do_one_essa(void)
|
||||||
{
|
{
|
||||||
asm volatile(
|
asm volatile(
|
||||||
/* load TEST_DATA_START_GFN into r1 */
|
/* load TEST_DATA_START_GFN into r1 */
|
||||||
|
" xgr 1,1\n"
|
||||||
" llilf 1,%[start_gfn]\n"
|
" llilf 1,%[start_gfn]\n"
|
||||||
/* calculate the address from the gfn */
|
/* calculate the address from the gfn */
|
||||||
" sllg 1,1,12(0)\n"
|
" sllg 1,1,12(0)\n"
|
||||||
/* set the first page in TEST_DATA memslot to STABLE */
|
/* set the first page in TEST_DATA memslot to STABLE */
|
||||||
" .insn rrf,0xb9ab0000,2,1,1,0\n"
|
" .insn rrf,0xb9ab0000,2,1,1,0\n"
|
||||||
|
" agfi 1,0x100000\n"
|
||||||
|
/* also touch the first page of the second MB of TEST_DATA */
|
||||||
|
" .insn rrf,0xb9ab0000,2,1,1,0\n"
|
||||||
/* hypercall */
|
/* hypercall */
|
||||||
" diag 0,0,0x501\n"
|
" diag 0,0,0x501\n"
|
||||||
"0: j 0b"
|
"0: j 0b"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
* Authors:
|
* Authors:
|
||||||
* Janosch Frank <frankja@linux.ibm.com>
|
* Janosch Frank <frankja@linux.ibm.com>
|
||||||
*/
|
*/
|
||||||
|
#include "facility.h"
|
||||||
#include "kselftest.h"
|
#include "kselftest.h"
|
||||||
#include "kvm_util.h"
|
#include "kvm_util.h"
|
||||||
#include "test_util.h"
|
#include "test_util.h"
|
||||||
@@ -109,6 +110,111 @@ static void test_user_operexec_combined(void)
|
|||||||
kvm_vm_free(vm);
|
kvm_vm_free(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct kvm_vm *create_vm_without_sthyi(void)
|
||||||
|
{
|
||||||
|
struct kvm_s390_vm_cpu_processor info;
|
||||||
|
struct kvm_vm *vm;
|
||||||
|
|
||||||
|
vm = vm_create(1);
|
||||||
|
|
||||||
|
kvm_device_attr_get(vm->fd, KVM_S390_VM_CPU_MODEL,
|
||||||
|
KVM_S390_VM_CPU_PROCESSOR, &info);
|
||||||
|
|
||||||
|
clear_bit_inv(74, (unsigned long *)&info.fac_list);
|
||||||
|
kvm_device_attr_set(vm->fd, KVM_S390_VM_CPU_MODEL,
|
||||||
|
KVM_S390_VM_CPU_PROCESSOR, &info);
|
||||||
|
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_user_instr0_no_stfle_74(void)
|
||||||
|
{
|
||||||
|
struct kvm_vcpu *vcpu;
|
||||||
|
struct kvm_vm *vm;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
vm = create_vm_without_sthyi();
|
||||||
|
|
||||||
|
rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_INSTR0, 0);
|
||||||
|
TEST_ASSERT_EQ(0, rc);
|
||||||
|
|
||||||
|
vcpu = vm_vcpu_add(vm, 0, guest_code_instr0);
|
||||||
|
|
||||||
|
vcpu_run(vcpu);
|
||||||
|
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
|
||||||
|
TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC);
|
||||||
|
TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0000);
|
||||||
|
|
||||||
|
kvm_vm_free(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_user_operexec_no_stfle_74(void)
|
||||||
|
{
|
||||||
|
struct kvm_vcpu *vcpu;
|
||||||
|
struct kvm_vm *vm;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
vm = create_vm_without_sthyi();
|
||||||
|
|
||||||
|
rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0);
|
||||||
|
TEST_ASSERT_EQ(0, rc);
|
||||||
|
|
||||||
|
vcpu = vm_vcpu_add(vm, 0, guest_code_user_operexec);
|
||||||
|
|
||||||
|
vcpu_run(vcpu);
|
||||||
|
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
|
||||||
|
TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC);
|
||||||
|
TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0807);
|
||||||
|
|
||||||
|
kvm_vm_free(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_instr0_combined_no_stfle_74(void)
|
||||||
|
{
|
||||||
|
struct kvm_vcpu *vcpu;
|
||||||
|
struct kvm_vm *vm;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
vm = create_vm_without_sthyi();
|
||||||
|
|
||||||
|
rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_INSTR0, 0);
|
||||||
|
TEST_ASSERT_EQ(0, rc);
|
||||||
|
rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0);
|
||||||
|
TEST_ASSERT_EQ(0, rc);
|
||||||
|
|
||||||
|
vcpu = vm_vcpu_add(vm, 0, guest_code_instr0);
|
||||||
|
|
||||||
|
vcpu_run(vcpu);
|
||||||
|
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
|
||||||
|
TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC);
|
||||||
|
TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0000);
|
||||||
|
|
||||||
|
kvm_vm_free(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_operexec_combined_no_stfle_74(void)
|
||||||
|
{
|
||||||
|
struct kvm_vcpu *vcpu;
|
||||||
|
struct kvm_vm *vm;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
vm = create_vm_without_sthyi();
|
||||||
|
|
||||||
|
rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_INSTR0, 0);
|
||||||
|
TEST_ASSERT_EQ(0, rc);
|
||||||
|
rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0);
|
||||||
|
TEST_ASSERT_EQ(0, rc);
|
||||||
|
|
||||||
|
vcpu = vm_vcpu_add(vm, 0, guest_code_user_operexec);
|
||||||
|
|
||||||
|
vcpu_run(vcpu);
|
||||||
|
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
|
||||||
|
TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC);
|
||||||
|
TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0807);
|
||||||
|
|
||||||
|
kvm_vm_free(vm);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run all tests above.
|
* Run all tests above.
|
||||||
*
|
*
|
||||||
@@ -122,6 +228,10 @@ static struct testdef {
|
|||||||
{ "instr0", test_user_instr0 },
|
{ "instr0", test_user_instr0 },
|
||||||
{ "operexec", test_user_operexec },
|
{ "operexec", test_user_operexec },
|
||||||
{ "operexec_combined", test_user_operexec_combined},
|
{ "operexec_combined", test_user_operexec_combined},
|
||||||
|
{ "instr0_no_stfle_74", test_user_instr0_no_stfle_74 },
|
||||||
|
{ "instr0_combined_no_stfle_74", test_instr0_combined_no_stfle_74 },
|
||||||
|
{ "operexec_combined_no_stfle_74", test_operexec_combined_no_stfle_74 },
|
||||||
|
{ "operexec_no_stfle_74", test_user_operexec_no_stfle_74 },
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/seqlock.h>
|
#include <linux/seqlock.h>
|
||||||
#include <linux/irqbypass.h>
|
#include <linux/irqbypass.h>
|
||||||
|
#include <linux/unaligned.h>
|
||||||
#include <trace/events/kvm.h>
|
#include <trace/events/kvm.h>
|
||||||
|
|
||||||
#include <kvm/iodev.h>
|
#include <kvm/iodev.h>
|
||||||
@@ -779,21 +780,18 @@ ioeventfd_in_range(struct _ioeventfd *p, gpa_t addr, int len, const void *val)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* otherwise, we have to actually compare the data */
|
/* otherwise, we have to actually compare the data */
|
||||||
|
|
||||||
BUG_ON(!IS_ALIGNED((unsigned long)val, len));
|
|
||||||
|
|
||||||
switch (len) {
|
switch (len) {
|
||||||
case 1:
|
case 1:
|
||||||
_val = *(u8 *)val;
|
_val = get_unaligned((u8 *)val);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
_val = *(u16 *)val;
|
_val = get_unaligned((u16 *)val);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
_val = *(u32 *)val;
|
_val = get_unaligned((u32 *)val);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
_val = *(u64 *)val;
|
_val = get_unaligned((u64 *)val);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user