mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 20:51:03 +02:00
Merge branch 'kvm-5.16-fixes' into kvm-master
* Fixes for Xen emulation * Kill kvm_map_gfn() / kvm_unmap_gfn() and broken gfn_to_pfn_cache * Fixes for migration of 32-bit nested guests on 64-bit hypervisor * Compilation fixes * More SEV cleanups
This commit is contained in:
@@ -363,6 +363,7 @@ union kvm_mmu_extended_role {
|
|||||||
unsigned int cr4_smap:1;
|
unsigned int cr4_smap:1;
|
||||||
unsigned int cr4_smep:1;
|
unsigned int cr4_smep:1;
|
||||||
unsigned int cr4_la57:1;
|
unsigned int cr4_la57:1;
|
||||||
|
unsigned int efer_lma:1;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -125,7 +125,7 @@ static void kvm_update_kvm_cpuid_base(struct kvm_vcpu *vcpu)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct kvm_cpuid_entry2 *kvm_find_kvm_cpuid_features(struct kvm_vcpu *vcpu)
|
static struct kvm_cpuid_entry2 *kvm_find_kvm_cpuid_features(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
u32 base = vcpu->arch.kvm_cpuid_base;
|
u32 base = vcpu->arch.kvm_cpuid_base;
|
||||||
|
|
||||||
|
@@ -4682,6 +4682,7 @@ static union kvm_mmu_extended_role kvm_calc_mmu_role_ext(struct kvm_vcpu *vcpu,
|
|||||||
/* PKEY and LA57 are active iff long mode is active. */
|
/* PKEY and LA57 are active iff long mode is active. */
|
||||||
ext.cr4_pke = ____is_efer_lma(regs) && ____is_cr4_pke(regs);
|
ext.cr4_pke = ____is_efer_lma(regs) && ____is_cr4_pke(regs);
|
||||||
ext.cr4_la57 = ____is_efer_lma(regs) && ____is_cr4_la57(regs);
|
ext.cr4_la57 = ____is_efer_lma(regs) && ____is_cr4_la57(regs);
|
||||||
|
ext.efer_lma = ____is_efer_lma(regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.valid = 1;
|
ext.valid = 1;
|
||||||
|
@@ -237,7 +237,6 @@ static void sev_unbind_asid(struct kvm *kvm, unsigned int handle)
|
|||||||
static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
|
static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
|
||||||
{
|
{
|
||||||
struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
|
struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
|
||||||
bool es_active = argp->id == KVM_SEV_ES_INIT;
|
|
||||||
int asid, ret;
|
int asid, ret;
|
||||||
|
|
||||||
if (kvm->created_vcpus)
|
if (kvm->created_vcpus)
|
||||||
@@ -247,7 +246,8 @@ static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
|
|||||||
if (unlikely(sev->active))
|
if (unlikely(sev->active))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
sev->es_active = es_active;
|
sev->active = true;
|
||||||
|
sev->es_active = argp->id == KVM_SEV_ES_INIT;
|
||||||
asid = sev_asid_new(sev);
|
asid = sev_asid_new(sev);
|
||||||
if (asid < 0)
|
if (asid < 0)
|
||||||
goto e_no_asid;
|
goto e_no_asid;
|
||||||
@@ -257,8 +257,6 @@ static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto e_free;
|
goto e_free;
|
||||||
|
|
||||||
sev->active = true;
|
|
||||||
sev->asid = asid;
|
|
||||||
INIT_LIST_HEAD(&sev->regions_list);
|
INIT_LIST_HEAD(&sev->regions_list);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -268,6 +266,7 @@ e_free:
|
|||||||
sev->asid = 0;
|
sev->asid = 0;
|
||||||
e_no_asid:
|
e_no_asid:
|
||||||
sev->es_active = false;
|
sev->es_active = false;
|
||||||
|
sev->active = false;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1530,7 +1529,7 @@ static int sev_receive_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
|
|||||||
return sev_issue_cmd(kvm, SEV_CMD_RECEIVE_FINISH, &data, &argp->error);
|
return sev_issue_cmd(kvm, SEV_CMD_RECEIVE_FINISH, &data, &argp->error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cmd_allowed_from_miror(u32 cmd_id)
|
static bool is_cmd_allowed_from_mirror(u32 cmd_id)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Allow mirrors VM to call KVM_SEV_LAUNCH_UPDATE_VMSA to enable SEV-ES
|
* Allow mirrors VM to call KVM_SEV_LAUNCH_UPDATE_VMSA to enable SEV-ES
|
||||||
@@ -1757,7 +1756,7 @@ int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
|
|||||||
|
|
||||||
/* Only the enc_context_owner handles some memory enc operations. */
|
/* Only the enc_context_owner handles some memory enc operations. */
|
||||||
if (is_mirroring_enc_context(kvm) &&
|
if (is_mirroring_enc_context(kvm) &&
|
||||||
!cmd_allowed_from_miror(sev_cmd.id)) {
|
!is_cmd_allowed_from_mirror(sev_cmd.id)) {
|
||||||
r = -EINVAL;
|
r = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -1990,7 +1989,12 @@ int svm_vm_copy_asid_from(struct kvm *kvm, unsigned int source_fd)
|
|||||||
mutex_unlock(&source_kvm->lock);
|
mutex_unlock(&source_kvm->lock);
|
||||||
mutex_lock(&kvm->lock);
|
mutex_lock(&kvm->lock);
|
||||||
|
|
||||||
if (sev_guest(kvm)) {
|
/*
|
||||||
|
* Disallow out-of-band SEV/SEV-ES init if the target is already an
|
||||||
|
* SEV guest, or if vCPUs have been created. KVM relies on vCPUs being
|
||||||
|
* created after SEV/SEV-ES initialization, e.g. to init intercepts.
|
||||||
|
*/
|
||||||
|
if (sev_guest(kvm) || kvm->created_vcpus) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto e_mirror_unlock;
|
goto e_mirror_unlock;
|
||||||
}
|
}
|
||||||
|
@@ -247,7 +247,7 @@ static __always_inline bool sev_es_guest(struct kvm *kvm)
|
|||||||
#ifdef CONFIG_KVM_AMD_SEV
|
#ifdef CONFIG_KVM_AMD_SEV
|
||||||
struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
|
struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
|
||||||
|
|
||||||
return sev_guest(kvm) && sev->es_active;
|
return sev->es_active && !WARN_ON_ONCE(!sev->active);
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
@@ -670,33 +670,39 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
|
|||||||
static void nested_cache_shadow_vmcs12(struct kvm_vcpu *vcpu,
|
static void nested_cache_shadow_vmcs12(struct kvm_vcpu *vcpu,
|
||||||
struct vmcs12 *vmcs12)
|
struct vmcs12 *vmcs12)
|
||||||
{
|
{
|
||||||
struct kvm_host_map map;
|
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||||
struct vmcs12 *shadow;
|
struct gfn_to_hva_cache *ghc = &vmx->nested.shadow_vmcs12_cache;
|
||||||
|
|
||||||
if (!nested_cpu_has_shadow_vmcs(vmcs12) ||
|
if (!nested_cpu_has_shadow_vmcs(vmcs12) ||
|
||||||
vmcs12->vmcs_link_pointer == INVALID_GPA)
|
vmcs12->vmcs_link_pointer == INVALID_GPA)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
shadow = get_shadow_vmcs12(vcpu);
|
if (ghc->gpa != vmcs12->vmcs_link_pointer &&
|
||||||
|
kvm_gfn_to_hva_cache_init(vcpu->kvm, ghc,
|
||||||
if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->vmcs_link_pointer), &map))
|
vmcs12->vmcs_link_pointer, VMCS12_SIZE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memcpy(shadow, map.hva, VMCS12_SIZE);
|
kvm_read_guest_cached(vmx->vcpu.kvm, ghc, get_shadow_vmcs12(vcpu),
|
||||||
kvm_vcpu_unmap(vcpu, &map, false);
|
VMCS12_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nested_flush_cached_shadow_vmcs12(struct kvm_vcpu *vcpu,
|
static void nested_flush_cached_shadow_vmcs12(struct kvm_vcpu *vcpu,
|
||||||
struct vmcs12 *vmcs12)
|
struct vmcs12 *vmcs12)
|
||||||
{
|
{
|
||||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||||
|
struct gfn_to_hva_cache *ghc = &vmx->nested.shadow_vmcs12_cache;
|
||||||
|
|
||||||
if (!nested_cpu_has_shadow_vmcs(vmcs12) ||
|
if (!nested_cpu_has_shadow_vmcs(vmcs12) ||
|
||||||
vmcs12->vmcs_link_pointer == INVALID_GPA)
|
vmcs12->vmcs_link_pointer == INVALID_GPA)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
kvm_write_guest(vmx->vcpu.kvm, vmcs12->vmcs_link_pointer,
|
if (ghc->gpa != vmcs12->vmcs_link_pointer &&
|
||||||
get_shadow_vmcs12(vcpu), VMCS12_SIZE);
|
kvm_gfn_to_hva_cache_init(vcpu->kvm, ghc,
|
||||||
|
vmcs12->vmcs_link_pointer, VMCS12_SIZE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
kvm_write_guest_cached(vmx->vcpu.kvm, ghc, get_shadow_vmcs12(vcpu),
|
||||||
|
VMCS12_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2830,6 +2836,17 @@ static int nested_vmx_check_controls(struct kvm_vcpu *vcpu,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nested_vmx_check_address_space_size(struct kvm_vcpu *vcpu,
|
||||||
|
struct vmcs12 *vmcs12)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
if (CC(!!(vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE) !=
|
||||||
|
!!(vcpu->arch.efer & EFER_LMA)))
|
||||||
|
return -EINVAL;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
|
static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
|
||||||
struct vmcs12 *vmcs12)
|
struct vmcs12 *vmcs12)
|
||||||
{
|
{
|
||||||
@@ -2854,18 +2871,16 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
ia32e = !!(vcpu->arch.efer & EFER_LMA);
|
ia32e = !!(vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE);
|
||||||
#else
|
#else
|
||||||
ia32e = false;
|
ia32e = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ia32e) {
|
if (ia32e) {
|
||||||
if (CC(!(vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE)) ||
|
if (CC(!(vmcs12->host_cr4 & X86_CR4_PAE)))
|
||||||
CC(!(vmcs12->host_cr4 & X86_CR4_PAE)))
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
} else {
|
} else {
|
||||||
if (CC(vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE) ||
|
if (CC(vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) ||
|
||||||
CC(vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) ||
|
|
||||||
CC(vmcs12->host_cr4 & X86_CR4_PCIDE) ||
|
CC(vmcs12->host_cr4 & X86_CR4_PCIDE) ||
|
||||||
CC((vmcs12->host_rip) >> 32))
|
CC((vmcs12->host_rip) >> 32))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -2910,9 +2925,9 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
|
|||||||
static int nested_vmx_check_vmcs_link_ptr(struct kvm_vcpu *vcpu,
|
static int nested_vmx_check_vmcs_link_ptr(struct kvm_vcpu *vcpu,
|
||||||
struct vmcs12 *vmcs12)
|
struct vmcs12 *vmcs12)
|
||||||
{
|
{
|
||||||
int r = 0;
|
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||||
struct vmcs12 *shadow;
|
struct gfn_to_hva_cache *ghc = &vmx->nested.shadow_vmcs12_cache;
|
||||||
struct kvm_host_map map;
|
struct vmcs_hdr hdr;
|
||||||
|
|
||||||
if (vmcs12->vmcs_link_pointer == INVALID_GPA)
|
if (vmcs12->vmcs_link_pointer == INVALID_GPA)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2920,17 +2935,21 @@ static int nested_vmx_check_vmcs_link_ptr(struct kvm_vcpu *vcpu,
|
|||||||
if (CC(!page_address_valid(vcpu, vmcs12->vmcs_link_pointer)))
|
if (CC(!page_address_valid(vcpu, vmcs12->vmcs_link_pointer)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (CC(kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->vmcs_link_pointer), &map)))
|
if (ghc->gpa != vmcs12->vmcs_link_pointer &&
|
||||||
|
CC(kvm_gfn_to_hva_cache_init(vcpu->kvm, ghc,
|
||||||
|
vmcs12->vmcs_link_pointer, VMCS12_SIZE)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (CC(kvm_read_guest_offset_cached(vcpu->kvm, ghc, &hdr,
|
||||||
|
offsetof(struct vmcs12, hdr),
|
||||||
|
sizeof(hdr))))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
shadow = map.hva;
|
if (CC(hdr.revision_id != VMCS12_REVISION) ||
|
||||||
|
CC(hdr.shadow_vmcs != nested_cpu_has_shadow_vmcs(vmcs12)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (CC(shadow->hdr.revision_id != VMCS12_REVISION) ||
|
return 0;
|
||||||
CC(shadow->hdr.shadow_vmcs != nested_cpu_has_shadow_vmcs(vmcs12)))
|
|
||||||
r = -EINVAL;
|
|
||||||
|
|
||||||
kvm_vcpu_unmap(vcpu, &map, false);
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3535,6 +3554,9 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
|
|||||||
if (nested_vmx_check_controls(vcpu, vmcs12))
|
if (nested_vmx_check_controls(vcpu, vmcs12))
|
||||||
return nested_vmx_fail(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
|
return nested_vmx_fail(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
|
||||||
|
|
||||||
|
if (nested_vmx_check_address_space_size(vcpu, vmcs12))
|
||||||
|
return nested_vmx_fail(vcpu, VMXERR_ENTRY_INVALID_HOST_STATE_FIELD);
|
||||||
|
|
||||||
if (nested_vmx_check_host_state(vcpu, vmcs12))
|
if (nested_vmx_check_host_state(vcpu, vmcs12))
|
||||||
return nested_vmx_fail(vcpu, VMXERR_ENTRY_INVALID_HOST_STATE_FIELD);
|
return nested_vmx_fail(vcpu, VMXERR_ENTRY_INVALID_HOST_STATE_FIELD);
|
||||||
|
|
||||||
@@ -5264,10 +5286,11 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (vmx->nested.current_vmptr != vmptr) {
|
if (vmx->nested.current_vmptr != vmptr) {
|
||||||
struct kvm_host_map map;
|
struct gfn_to_hva_cache *ghc = &vmx->nested.vmcs12_cache;
|
||||||
struct vmcs12 *new_vmcs12;
|
struct vmcs_hdr hdr;
|
||||||
|
|
||||||
if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmptr), &map)) {
|
if (ghc->gpa != vmptr &&
|
||||||
|
kvm_gfn_to_hva_cache_init(vcpu->kvm, ghc, vmptr, VMCS12_SIZE)) {
|
||||||
/*
|
/*
|
||||||
* Reads from an unbacked page return all 1s,
|
* Reads from an unbacked page return all 1s,
|
||||||
* which means that the 32 bits located at the
|
* which means that the 32 bits located at the
|
||||||
@@ -5278,12 +5301,16 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
|
|||||||
VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID);
|
VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
new_vmcs12 = map.hva;
|
if (kvm_read_guest_offset_cached(vcpu->kvm, ghc, &hdr,
|
||||||
|
offsetof(struct vmcs12, hdr),
|
||||||
|
sizeof(hdr))) {
|
||||||
|
return nested_vmx_fail(vcpu,
|
||||||
|
VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID);
|
||||||
|
}
|
||||||
|
|
||||||
if (new_vmcs12->hdr.revision_id != VMCS12_REVISION ||
|
if (hdr.revision_id != VMCS12_REVISION ||
|
||||||
(new_vmcs12->hdr.shadow_vmcs &&
|
(hdr.shadow_vmcs &&
|
||||||
!nested_cpu_has_vmx_shadow_vmcs(vcpu))) {
|
!nested_cpu_has_vmx_shadow_vmcs(vcpu))) {
|
||||||
kvm_vcpu_unmap(vcpu, &map, false);
|
|
||||||
return nested_vmx_fail(vcpu,
|
return nested_vmx_fail(vcpu,
|
||||||
VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID);
|
VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID);
|
||||||
}
|
}
|
||||||
@@ -5294,8 +5321,11 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
|
|||||||
* Load VMCS12 from guest memory since it is not already
|
* Load VMCS12 from guest memory since it is not already
|
||||||
* cached.
|
* cached.
|
||||||
*/
|
*/
|
||||||
memcpy(vmx->nested.cached_vmcs12, new_vmcs12, VMCS12_SIZE);
|
if (kvm_read_guest_cached(vcpu->kvm, ghc, vmx->nested.cached_vmcs12,
|
||||||
kvm_vcpu_unmap(vcpu, &map, false);
|
VMCS12_SIZE)) {
|
||||||
|
return nested_vmx_fail(vcpu,
|
||||||
|
VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID);
|
||||||
|
}
|
||||||
|
|
||||||
set_current_vmptr(vmx, vmptr);
|
set_current_vmptr(vmx, vmptr);
|
||||||
}
|
}
|
||||||
|
@@ -141,6 +141,16 @@ struct nested_vmx {
|
|||||||
*/
|
*/
|
||||||
struct vmcs12 *cached_shadow_vmcs12;
|
struct vmcs12 *cached_shadow_vmcs12;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPA to HVA cache for accessing vmcs12->vmcs_link_pointer
|
||||||
|
*/
|
||||||
|
struct gfn_to_hva_cache shadow_vmcs12_cache;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPA to HVA cache for VMCS12
|
||||||
|
*/
|
||||||
|
struct gfn_to_hva_cache vmcs12_cache;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Indicates if the shadow vmcs or enlightened vmcs must be updated
|
* Indicates if the shadow vmcs or enlightened vmcs must be updated
|
||||||
* with the data held by struct vmcs12.
|
* with the data held by struct vmcs12.
|
||||||
|
@@ -3307,9 +3307,9 @@ static void record_steal_time(struct kvm_vcpu *vcpu)
|
|||||||
"xor %1, %1\n"
|
"xor %1, %1\n"
|
||||||
"2:\n"
|
"2:\n"
|
||||||
_ASM_EXTABLE_UA(1b, 2b)
|
_ASM_EXTABLE_UA(1b, 2b)
|
||||||
: "+r" (st_preempted),
|
: "+q" (st_preempted),
|
||||||
"+&r" (err)
|
"+&r" (err),
|
||||||
: "m" (st->preempted));
|
"+m" (st->preempted));
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -9547,12 +9547,16 @@ static void vcpu_load_eoi_exitmap(struct kvm_vcpu *vcpu)
|
|||||||
if (!kvm_apic_hw_enabled(vcpu->arch.apic))
|
if (!kvm_apic_hw_enabled(vcpu->arch.apic))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (to_hv_vcpu(vcpu))
|
if (to_hv_vcpu(vcpu)) {
|
||||||
bitmap_or((ulong *)eoi_exit_bitmap,
|
bitmap_or((ulong *)eoi_exit_bitmap,
|
||||||
vcpu->arch.ioapic_handled_vectors,
|
vcpu->arch.ioapic_handled_vectors,
|
||||||
to_hv_synic(vcpu)->vec_bitmap, 256);
|
to_hv_synic(vcpu)->vec_bitmap, 256);
|
||||||
|
static_call(kvm_x86_load_eoi_exitmap)(vcpu, eoi_exit_bitmap);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static_call(kvm_x86_load_eoi_exitmap)(vcpu, eoi_exit_bitmap);
|
static_call(kvm_x86_load_eoi_exitmap)(
|
||||||
|
vcpu, (u64 *)vcpu->arch.ioapic_handled_vectors);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
|
void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
|
||||||
|
@@ -127,9 +127,9 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, int state)
|
|||||||
state_entry_time = vx->runstate_entry_time;
|
state_entry_time = vx->runstate_entry_time;
|
||||||
state_entry_time |= XEN_RUNSTATE_UPDATE;
|
state_entry_time |= XEN_RUNSTATE_UPDATE;
|
||||||
|
|
||||||
BUILD_BUG_ON(sizeof(((struct vcpu_runstate_info *)0)->state_entry_time) !=
|
BUILD_BUG_ON(sizeof_field(struct vcpu_runstate_info, state_entry_time) !=
|
||||||
sizeof(state_entry_time));
|
sizeof(state_entry_time));
|
||||||
BUILD_BUG_ON(sizeof(((struct compat_vcpu_runstate_info *)0)->state_entry_time) !=
|
BUILD_BUG_ON(sizeof_field(struct compat_vcpu_runstate_info, state_entry_time) !=
|
||||||
sizeof(state_entry_time));
|
sizeof(state_entry_time));
|
||||||
|
|
||||||
if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
|
if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
|
||||||
@@ -144,9 +144,9 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, int state)
|
|||||||
*/
|
*/
|
||||||
BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, state) !=
|
BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, state) !=
|
||||||
offsetof(struct compat_vcpu_runstate_info, state));
|
offsetof(struct compat_vcpu_runstate_info, state));
|
||||||
BUILD_BUG_ON(sizeof(((struct vcpu_runstate_info *)0)->state) !=
|
BUILD_BUG_ON(sizeof_field(struct vcpu_runstate_info, state) !=
|
||||||
sizeof(vx->current_runstate));
|
sizeof(vx->current_runstate));
|
||||||
BUILD_BUG_ON(sizeof(((struct compat_vcpu_runstate_info *)0)->state) !=
|
BUILD_BUG_ON(sizeof_field(struct compat_vcpu_runstate_info, state) !=
|
||||||
sizeof(vx->current_runstate));
|
sizeof(vx->current_runstate));
|
||||||
|
|
||||||
if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
|
if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
|
||||||
@@ -163,9 +163,9 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, int state)
|
|||||||
offsetof(struct vcpu_runstate_info, time) - sizeof(u64));
|
offsetof(struct vcpu_runstate_info, time) - sizeof(u64));
|
||||||
BUILD_BUG_ON(offsetof(struct compat_vcpu_runstate_info, state_entry_time) !=
|
BUILD_BUG_ON(offsetof(struct compat_vcpu_runstate_info, state_entry_time) !=
|
||||||
offsetof(struct compat_vcpu_runstate_info, time) - sizeof(u64));
|
offsetof(struct compat_vcpu_runstate_info, time) - sizeof(u64));
|
||||||
BUILD_BUG_ON(sizeof(((struct vcpu_runstate_info *)0)->time) !=
|
BUILD_BUG_ON(sizeof_field(struct vcpu_runstate_info, time) !=
|
||||||
sizeof(((struct compat_vcpu_runstate_info *)0)->time));
|
sizeof_field(struct compat_vcpu_runstate_info, time));
|
||||||
BUILD_BUG_ON(sizeof(((struct vcpu_runstate_info *)0)->time) !=
|
BUILD_BUG_ON(sizeof_field(struct vcpu_runstate_info, time) !=
|
||||||
sizeof(vx->runstate_times));
|
sizeof(vx->runstate_times));
|
||||||
|
|
||||||
if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
|
if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
|
||||||
@@ -205,9 +205,9 @@ int __kvm_xen_has_interrupt(struct kvm_vcpu *v)
|
|||||||
BUILD_BUG_ON(offsetof(struct vcpu_info, evtchn_upcall_pending) !=
|
BUILD_BUG_ON(offsetof(struct vcpu_info, evtchn_upcall_pending) !=
|
||||||
offsetof(struct compat_vcpu_info, evtchn_upcall_pending));
|
offsetof(struct compat_vcpu_info, evtchn_upcall_pending));
|
||||||
BUILD_BUG_ON(sizeof(rc) !=
|
BUILD_BUG_ON(sizeof(rc) !=
|
||||||
sizeof(((struct vcpu_info *)0)->evtchn_upcall_pending));
|
sizeof_field(struct vcpu_info, evtchn_upcall_pending));
|
||||||
BUILD_BUG_ON(sizeof(rc) !=
|
BUILD_BUG_ON(sizeof(rc) !=
|
||||||
sizeof(((struct compat_vcpu_info *)0)->evtchn_upcall_pending));
|
sizeof_field(struct compat_vcpu_info, evtchn_upcall_pending));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For efficiency, this mirrors the checks for using the valid
|
* For efficiency, this mirrors the checks for using the valid
|
||||||
@@ -299,7 +299,7 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case KVM_XEN_ATTR_TYPE_SHARED_INFO:
|
case KVM_XEN_ATTR_TYPE_SHARED_INFO:
|
||||||
data->u.shared_info.gfn = gpa_to_gfn(kvm->arch.xen.shinfo_gfn);
|
data->u.shared_info.gfn = kvm->arch.xen.shinfo_gfn;
|
||||||
r = 0;
|
r = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@@ -874,7 +874,7 @@ void kvm_release_pfn_dirty(kvm_pfn_t pfn);
|
|||||||
void kvm_set_pfn_dirty(kvm_pfn_t pfn);
|
void kvm_set_pfn_dirty(kvm_pfn_t pfn);
|
||||||
void kvm_set_pfn_accessed(kvm_pfn_t pfn);
|
void kvm_set_pfn_accessed(kvm_pfn_t pfn);
|
||||||
|
|
||||||
void kvm_release_pfn(kvm_pfn_t pfn, bool dirty, struct gfn_to_pfn_cache *cache);
|
void kvm_release_pfn(kvm_pfn_t pfn, bool dirty);
|
||||||
int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset,
|
int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset,
|
||||||
int len);
|
int len);
|
||||||
int kvm_read_guest(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len);
|
int kvm_read_guest(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len);
|
||||||
@@ -950,12 +950,8 @@ struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn
|
|||||||
kvm_pfn_t kvm_vcpu_gfn_to_pfn_atomic(struct kvm_vcpu *vcpu, gfn_t gfn);
|
kvm_pfn_t kvm_vcpu_gfn_to_pfn_atomic(struct kvm_vcpu *vcpu, gfn_t gfn);
|
||||||
kvm_pfn_t kvm_vcpu_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
|
kvm_pfn_t kvm_vcpu_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
|
||||||
int kvm_vcpu_map(struct kvm_vcpu *vcpu, gpa_t gpa, struct kvm_host_map *map);
|
int kvm_vcpu_map(struct kvm_vcpu *vcpu, gpa_t gpa, struct kvm_host_map *map);
|
||||||
int kvm_map_gfn(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map,
|
|
||||||
struct gfn_to_pfn_cache *cache, bool atomic);
|
|
||||||
struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn);
|
struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn);
|
||||||
void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map, bool dirty);
|
void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map, bool dirty);
|
||||||
int kvm_unmap_gfn(struct kvm_vcpu *vcpu, struct kvm_host_map *map,
|
|
||||||
struct gfn_to_pfn_cache *cache, bool dirty, bool atomic);
|
|
||||||
unsigned long kvm_vcpu_gfn_to_hva(struct kvm_vcpu *vcpu, gfn_t gfn);
|
unsigned long kvm_vcpu_gfn_to_hva(struct kvm_vcpu *vcpu, gfn_t gfn);
|
||||||
unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *writable);
|
unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *writable);
|
||||||
int kvm_vcpu_read_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, void *data, int offset,
|
int kvm_vcpu_read_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, void *data, int offset,
|
||||||
|
@@ -53,13 +53,6 @@ struct gfn_to_hva_cache {
|
|||||||
struct kvm_memory_slot *memslot;
|
struct kvm_memory_slot *memslot;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gfn_to_pfn_cache {
|
|
||||||
u64 generation;
|
|
||||||
gfn_t gfn;
|
|
||||||
kvm_pfn_t pfn;
|
|
||||||
bool dirty;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE
|
#ifdef KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE
|
||||||
/*
|
/*
|
||||||
* Memory caches are used to preallocate memory ahead of various MMU flows,
|
* Memory caches are used to preallocate memory ahead of various MMU flows,
|
||||||
|
@@ -2548,72 +2548,36 @@ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gfn_to_page);
|
EXPORT_SYMBOL_GPL(gfn_to_page);
|
||||||
|
|
||||||
void kvm_release_pfn(kvm_pfn_t pfn, bool dirty, struct gfn_to_pfn_cache *cache)
|
void kvm_release_pfn(kvm_pfn_t pfn, bool dirty)
|
||||||
{
|
{
|
||||||
if (pfn == 0)
|
if (pfn == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (cache)
|
|
||||||
cache->pfn = cache->gfn = 0;
|
|
||||||
|
|
||||||
if (dirty)
|
if (dirty)
|
||||||
kvm_release_pfn_dirty(pfn);
|
kvm_release_pfn_dirty(pfn);
|
||||||
else
|
else
|
||||||
kvm_release_pfn_clean(pfn);
|
kvm_release_pfn_clean(pfn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_cache_gfn_to_pfn(struct kvm_memory_slot *slot, gfn_t gfn,
|
int kvm_vcpu_map(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map)
|
||||||
struct gfn_to_pfn_cache *cache, u64 gen)
|
|
||||||
{
|
|
||||||
kvm_release_pfn(cache->pfn, cache->dirty, cache);
|
|
||||||
|
|
||||||
cache->pfn = gfn_to_pfn_memslot(slot, gfn);
|
|
||||||
cache->gfn = gfn;
|
|
||||||
cache->dirty = false;
|
|
||||||
cache->generation = gen;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __kvm_map_gfn(struct kvm_memslots *slots, gfn_t gfn,
|
|
||||||
struct kvm_host_map *map,
|
|
||||||
struct gfn_to_pfn_cache *cache,
|
|
||||||
bool atomic)
|
|
||||||
{
|
{
|
||||||
kvm_pfn_t pfn;
|
kvm_pfn_t pfn;
|
||||||
void *hva = NULL;
|
void *hva = NULL;
|
||||||
struct page *page = KVM_UNMAPPED_PAGE;
|
struct page *page = KVM_UNMAPPED_PAGE;
|
||||||
struct kvm_memory_slot *slot = __gfn_to_memslot(slots, gfn);
|
|
||||||
u64 gen = slots->generation;
|
|
||||||
|
|
||||||
if (!map)
|
if (!map)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (cache) {
|
pfn = gfn_to_pfn(vcpu->kvm, gfn);
|
||||||
if (!cache->pfn || cache->gfn != gfn ||
|
|
||||||
cache->generation != gen) {
|
|
||||||
if (atomic)
|
|
||||||
return -EAGAIN;
|
|
||||||
kvm_cache_gfn_to_pfn(slot, gfn, cache, gen);
|
|
||||||
}
|
|
||||||
pfn = cache->pfn;
|
|
||||||
} else {
|
|
||||||
if (atomic)
|
|
||||||
return -EAGAIN;
|
|
||||||
pfn = gfn_to_pfn_memslot(slot, gfn);
|
|
||||||
}
|
|
||||||
if (is_error_noslot_pfn(pfn))
|
if (is_error_noslot_pfn(pfn))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (pfn_valid(pfn)) {
|
if (pfn_valid(pfn)) {
|
||||||
page = pfn_to_page(pfn);
|
page = pfn_to_page(pfn);
|
||||||
if (atomic)
|
hva = kmap(page);
|
||||||
hva = kmap_atomic(page);
|
|
||||||
else
|
|
||||||
hva = kmap(page);
|
|
||||||
#ifdef CONFIG_HAS_IOMEM
|
#ifdef CONFIG_HAS_IOMEM
|
||||||
} else if (!atomic) {
|
|
||||||
hva = memremap(pfn_to_hpa(pfn), PAGE_SIZE, MEMREMAP_WB);
|
|
||||||
} else {
|
} else {
|
||||||
return -EINVAL;
|
hva = memremap(pfn_to_hpa(pfn), PAGE_SIZE, MEMREMAP_WB);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2627,27 +2591,9 @@ static int __kvm_map_gfn(struct kvm_memslots *slots, gfn_t gfn,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_map_gfn(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map,
|
|
||||||
struct gfn_to_pfn_cache *cache, bool atomic)
|
|
||||||
{
|
|
||||||
return __kvm_map_gfn(kvm_memslots(vcpu->kvm), gfn, map,
|
|
||||||
cache, atomic);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(kvm_map_gfn);
|
|
||||||
|
|
||||||
int kvm_vcpu_map(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map)
|
|
||||||
{
|
|
||||||
return __kvm_map_gfn(kvm_vcpu_memslots(vcpu), gfn, map,
|
|
||||||
NULL, false);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(kvm_vcpu_map);
|
EXPORT_SYMBOL_GPL(kvm_vcpu_map);
|
||||||
|
|
||||||
static void __kvm_unmap_gfn(struct kvm *kvm,
|
void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map, bool dirty)
|
||||||
struct kvm_memory_slot *memslot,
|
|
||||||
struct kvm_host_map *map,
|
|
||||||
struct gfn_to_pfn_cache *cache,
|
|
||||||
bool dirty, bool atomic)
|
|
||||||
{
|
{
|
||||||
if (!map)
|
if (!map)
|
||||||
return;
|
return;
|
||||||
@@ -2655,45 +2601,21 @@ static void __kvm_unmap_gfn(struct kvm *kvm,
|
|||||||
if (!map->hva)
|
if (!map->hva)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (map->page != KVM_UNMAPPED_PAGE) {
|
if (map->page != KVM_UNMAPPED_PAGE)
|
||||||
if (atomic)
|
kunmap(map->page);
|
||||||
kunmap_atomic(map->hva);
|
|
||||||
else
|
|
||||||
kunmap(map->page);
|
|
||||||
}
|
|
||||||
#ifdef CONFIG_HAS_IOMEM
|
#ifdef CONFIG_HAS_IOMEM
|
||||||
else if (!atomic)
|
|
||||||
memunmap(map->hva);
|
|
||||||
else
|
else
|
||||||
WARN_ONCE(1, "Unexpected unmapping in atomic context");
|
memunmap(map->hva);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (dirty)
|
if (dirty)
|
||||||
mark_page_dirty_in_slot(kvm, memslot, map->gfn);
|
kvm_vcpu_mark_page_dirty(vcpu, map->gfn);
|
||||||
|
|
||||||
if (cache)
|
kvm_release_pfn(map->pfn, dirty);
|
||||||
cache->dirty |= dirty;
|
|
||||||
else
|
|
||||||
kvm_release_pfn(map->pfn, dirty, NULL);
|
|
||||||
|
|
||||||
map->hva = NULL;
|
map->hva = NULL;
|
||||||
map->page = NULL;
|
map->page = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_unmap_gfn(struct kvm_vcpu *vcpu, struct kvm_host_map *map,
|
|
||||||
struct gfn_to_pfn_cache *cache, bool dirty, bool atomic)
|
|
||||||
{
|
|
||||||
__kvm_unmap_gfn(vcpu->kvm, gfn_to_memslot(vcpu->kvm, map->gfn), map,
|
|
||||||
cache, dirty, atomic);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(kvm_unmap_gfn);
|
|
||||||
|
|
||||||
void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map, bool dirty)
|
|
||||||
{
|
|
||||||
__kvm_unmap_gfn(vcpu->kvm, kvm_vcpu_gfn_to_memslot(vcpu, map->gfn),
|
|
||||||
map, NULL, dirty, false);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(kvm_vcpu_unmap);
|
EXPORT_SYMBOL_GPL(kvm_vcpu_unmap);
|
||||||
|
|
||||||
struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn)
|
struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn)
|
||||||
|
Reference in New Issue
Block a user