Import of kernel-4.18.0-553.147.1.el8_10
This commit is contained in:
parent
716d17b51c
commit
0dc80ff683
@ -12,7 +12,7 @@ RHEL_MINOR = 10
|
||||
#
|
||||
# Use this spot to avoid future merge conflicts.
|
||||
# Do not trim this comment.
|
||||
RHEL_RELEASE = 553.146.1
|
||||
RHEL_RELEASE = 553.147.1
|
||||
|
||||
#
|
||||
# ZSTREAM
|
||||
|
||||
@ -280,10 +280,29 @@ EXPORT_SYMBOL_GPL(fpu_enable_guest_xfd_features);
|
||||
#ifdef CONFIG_X86_64
|
||||
void fpu_update_guest_xfd(struct fpu_guest *guest_fpu, u64 xfd)
|
||||
{
|
||||
struct fpstate *fpstate = guest_fpu->fpstate;
|
||||
|
||||
fpregs_lock();
|
||||
guest_fpu->fpstate->xfd = xfd;
|
||||
if (guest_fpu->fpstate->in_use)
|
||||
xfd_update_state(guest_fpu->fpstate);
|
||||
|
||||
/*
|
||||
* KVM's guest ABI is that setting XFD[i]=1 *can* immediately revert the
|
||||
* save state to its initial configuration. Likewise, KVM_GET_XSAVE does
|
||||
* the same as XSAVE and returns XSTATE_BV[i]=0 whenever XFD[i]=1.
|
||||
*
|
||||
* If the guest's FPU state is in hardware, just update XFD: the XSAVE
|
||||
* in fpu_swap_kvm_fpstate will clear XSTATE_BV[i] whenever XFD[i]=1.
|
||||
*
|
||||
* If however the guest's FPU state is NOT resident in hardware, clear
|
||||
* disabled components in XSTATE_BV now, or a subsequent XRSTOR will
|
||||
* attempt to load disabled components and generate #NM _in the host_.
|
||||
*/
|
||||
if (xfd && test_thread_flag(TIF_NEED_FPU_LOAD))
|
||||
fpstate->regs.xsave.header.xfeatures &= ~xfd;
|
||||
|
||||
fpstate->xfd = xfd;
|
||||
if (fpstate->in_use)
|
||||
xfd_update_state(fpstate);
|
||||
|
||||
fpregs_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fpu_update_guest_xfd);
|
||||
@ -391,6 +410,13 @@ int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf,
|
||||
if (ustate->xsave.header.xfeatures & ~xcr0)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Disabled features must be in their initial state, otherwise XRSTOR
|
||||
* causes an exception.
|
||||
*/
|
||||
if (WARN_ON_ONCE(ustate->xsave.header.xfeatures & kstate->xfd))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Nullify @vpkru to preserve its current value if PKRU's bit isn't set
|
||||
* in the header. KVM's odd ABI is to leave PKRU untouched in this
|
||||
|
||||
@ -5141,12 +5141,11 @@ void init_decode_cache(struct x86_emulate_ctxt *ctxt)
|
||||
ctxt->mem_read.end = 0;
|
||||
}
|
||||
|
||||
int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
|
||||
int x86_emulate_insn(struct x86_emulate_ctxt *ctxt, bool check_intercepts)
|
||||
{
|
||||
const struct x86_emulate_ops *ops = ctxt->ops;
|
||||
int rc = X86EMUL_CONTINUE;
|
||||
int saved_dst_type = ctxt->dst.type;
|
||||
unsigned emul_flags;
|
||||
|
||||
ctxt->mem_read.pos = 0;
|
||||
|
||||
@ -5161,7 +5160,6 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
|
||||
goto done;
|
||||
}
|
||||
|
||||
emul_flags = ctxt->ops->get_hflags(ctxt);
|
||||
if (unlikely(ctxt->d &
|
||||
(No64|Undefined|Sse|Mmx|Intercept|CheckPerm|Priv|Prot|String))) {
|
||||
if ((ctxt->mode == X86EMUL_MODE_PROT64 && (ctxt->d & No64)) ||
|
||||
@ -5195,7 +5193,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
|
||||
fetch_possible_mmx_operand(&ctxt->dst);
|
||||
}
|
||||
|
||||
if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && ctxt->intercept) {
|
||||
if (unlikely(check_intercepts) && ctxt->intercept) {
|
||||
rc = emulator_check_intercept(ctxt, ctxt->intercept,
|
||||
X86_ICPT_PRE_EXCEPT);
|
||||
if (rc != X86EMUL_CONTINUE)
|
||||
@ -5224,7 +5222,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) {
|
||||
if (unlikely(check_intercepts) && (ctxt->d & Intercept)) {
|
||||
rc = emulator_check_intercept(ctxt, ctxt->intercept,
|
||||
X86_ICPT_POST_EXCEPT);
|
||||
if (rc != X86EMUL_CONTINUE)
|
||||
@ -5278,7 +5276,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
|
||||
|
||||
special_insn:
|
||||
|
||||
if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) {
|
||||
if (unlikely(check_intercepts) && (ctxt->d & Intercept)) {
|
||||
rc = emulator_check_intercept(ctxt, ctxt->intercept,
|
||||
X86_ICPT_POST_MEMACCESS);
|
||||
if (rc != X86EMUL_CONTINUE)
|
||||
|
||||
@ -492,7 +492,7 @@ bool x86_page_table_writing_insn(struct x86_emulate_ctxt *ctxt);
|
||||
#define EMULATION_RESTART 1
|
||||
#define EMULATION_INTERCEPTED 2
|
||||
void init_decode_cache(struct x86_emulate_ctxt *ctxt);
|
||||
int x86_emulate_insn(struct x86_emulate_ctxt *ctxt);
|
||||
int x86_emulate_insn(struct x86_emulate_ctxt *ctxt, bool check_intercepts);
|
||||
int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
|
||||
u16 tss_selector, int idt_index, int reason,
|
||||
bool has_error_code, u32 error_code);
|
||||
|
||||
@ -4079,22 +4079,23 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
|
||||
if (handle_abnormal_pfn(vcpu, fault, ACC_ALL, &r))
|
||||
return r;
|
||||
|
||||
r = RET_PF_RETRY;
|
||||
|
||||
if (is_tdp_mmu_fault)
|
||||
read_lock(&vcpu->kvm->mmu_lock);
|
||||
else
|
||||
else {
|
||||
write_lock(&vcpu->kvm->mmu_lock);
|
||||
r = make_mmu_pages_available(vcpu);
|
||||
if (r)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (is_page_fault_stale(vcpu, fault, mmu_seq))
|
||||
if (is_page_fault_stale(vcpu, fault, mmu_seq)) {
|
||||
r = RET_PF_RETRY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (is_tdp_mmu_fault) {
|
||||
r = kvm_tdp_mmu_map(vcpu, fault);
|
||||
} else {
|
||||
r = make_mmu_pages_available(vcpu);
|
||||
if (r)
|
||||
goto out_unlock;
|
||||
r = __direct_map(vcpu, fault);
|
||||
}
|
||||
|
||||
@ -6044,13 +6045,19 @@ restart:
|
||||
pfn = spte_to_pfn(*sptep);
|
||||
|
||||
/*
|
||||
* We cannot do huge page mapping for indirect shadow pages,
|
||||
* which are found on the last rmap (level = 1) when not using
|
||||
* tdp; such shadow pages are synced with the page table in
|
||||
* the guest, and the guest page table is using 4K page size
|
||||
* mapping if the indirect sp has level = 1.
|
||||
* Direct shadow page can be replaced by a hugepage if the host
|
||||
* mapping level allows it and the memslot maps all of the host
|
||||
* hugepage. Note! If the memslot maps only part of the
|
||||
* hugepage, sp->gfn may be below slot->base_gfn, and querying
|
||||
* the max mapping level would cause an out-of-bounds lpage_info
|
||||
* access. So the gfn bounds check *must* be done first.
|
||||
*
|
||||
* Indirect shadow pages are created when the guest page tables
|
||||
* are using 4K pages. Since the host mapping is always
|
||||
* constrained by the page size in the guest, indirect shadow
|
||||
* pages are never collapsible.
|
||||
*/
|
||||
if (sp->role.direct && !kvm_is_reserved_pfn(pfn) &&
|
||||
if (sp->role.direct && !kvm_is_reserved_pfn(pfn) && is_gfn_in_memslot(slot, sp->gfn) &&
|
||||
sp->role.level < kvm_mmu_max_mapping_level(kvm, slot, sp->gfn,
|
||||
pfn, PG_LEVEL_NUM)) {
|
||||
pte_list_remove(kvm, rmap_head, sptep);
|
||||
|
||||
@ -893,15 +893,17 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
|
||||
walker.pte_access &= ~ACC_EXEC_MASK;
|
||||
}
|
||||
|
||||
r = RET_PF_RETRY;
|
||||
write_lock(&vcpu->kvm->mmu_lock);
|
||||
|
||||
if (is_page_fault_stale(vcpu, fault, mmu_seq))
|
||||
goto out_unlock;
|
||||
|
||||
r = make_mmu_pages_available(vcpu);
|
||||
if (r)
|
||||
goto out_unlock;
|
||||
|
||||
if (is_page_fault_stale(vcpu, fault, mmu_seq)) {
|
||||
r = RET_PF_RETRY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
r = FNAME(fetch)(vcpu, fault, &walker);
|
||||
|
||||
out_unlock:
|
||||
|
||||
@ -154,7 +154,7 @@ TRACE_EVENT(kvm_xen_hypercall,
|
||||
|
||||
TRACE_EVENT(kvm_pio,
|
||||
TP_PROTO(unsigned int rw, unsigned int port, unsigned int size,
|
||||
unsigned int count, void *data),
|
||||
unsigned int count, const void *data),
|
||||
TP_ARGS(rw, port, size, count, data),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
|
||||
@ -280,6 +280,21 @@ static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs)
|
||||
vcpu->arch.regs_dirty = 0;
|
||||
}
|
||||
|
||||
static void nested_put_vmcs12_pages(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
|
||||
/*
|
||||
* Unpin physical memory we referred to in the vmcs02. The APIC access
|
||||
* page's backing page (yeah, confusing) shouldn't actually be accessed,
|
||||
* and if it is written, the contents are irrelevant.
|
||||
*/
|
||||
kvm_vcpu_unmap(vcpu, &vmx->nested.apic_access_page_map, false);
|
||||
kvm_vcpu_unmap(vcpu, &vmx->nested.virtual_apic_map, true);
|
||||
kvm_vcpu_unmap(vcpu, &vmx->nested.pi_desc_map, true);
|
||||
vmx->nested.pi_desc = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free whatever needs to be freed from vmx->nested when L1 goes down, or
|
||||
* just stops using VMX.
|
||||
@ -287,6 +302,7 @@ static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs)
|
||||
static void free_nested(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
struct vmcs *shadow_vmcs;
|
||||
|
||||
if (WARN_ON_ONCE(vmx->loaded_vmcs != &vmx->vmcs01))
|
||||
vmx_switch_vmcs(vcpu, &vmx->vmcs01);
|
||||
@ -304,22 +320,22 @@ static void free_nested(struct kvm_vcpu *vcpu)
|
||||
vmx->nested.current_vmptr = INVALID_GPA;
|
||||
if (enable_shadow_vmcs) {
|
||||
vmx_disable_shadow_vmcs(vmx);
|
||||
vmcs_clear(vmx->vmcs01.shadow_vmcs);
|
||||
free_vmcs(vmx->vmcs01.shadow_vmcs);
|
||||
|
||||
/*
|
||||
* Keep the pointer visible until after VMCLEAR, so migration
|
||||
* can clear an active shadow VMCS on the old CPU.
|
||||
*/
|
||||
shadow_vmcs = vmx->vmcs01.shadow_vmcs;
|
||||
vmcs_clear(shadow_vmcs);
|
||||
vmx->vmcs01.shadow_vmcs = NULL;
|
||||
free_vmcs(shadow_vmcs);
|
||||
}
|
||||
kfree(vmx->nested.cached_vmcs12);
|
||||
vmx->nested.cached_vmcs12 = NULL;
|
||||
kfree(vmx->nested.cached_shadow_vmcs12);
|
||||
vmx->nested.cached_shadow_vmcs12 = NULL;
|
||||
/* Unpin physical memory we referred to in the vmcs02 */
|
||||
if (vmx->nested.apic_access_page) {
|
||||
kvm_release_page_clean(vmx->nested.apic_access_page);
|
||||
vmx->nested.apic_access_page = NULL;
|
||||
}
|
||||
kvm_vcpu_unmap(vcpu, &vmx->nested.virtual_apic_map, true);
|
||||
kvm_vcpu_unmap(vcpu, &vmx->nested.pi_desc_map, true);
|
||||
vmx->nested.pi_desc = NULL;
|
||||
|
||||
nested_put_vmcs12_pages(vcpu);
|
||||
|
||||
kvm_mmu_free_roots(vcpu->kvm, &vcpu->arch.guest_mmu, KVM_MMU_ROOTS_ALL);
|
||||
|
||||
@ -3172,8 +3188,6 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
|
||||
struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
struct kvm_host_map *map;
|
||||
struct page *page;
|
||||
u64 hpa;
|
||||
|
||||
if (!vcpu->arch.pdptrs_from_userspace &&
|
||||
!nested_cpu_has_ept(vmcs12) && is_pae_paging(vcpu)) {
|
||||
@ -3188,23 +3202,12 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
|
||||
|
||||
|
||||
if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) {
|
||||
/*
|
||||
* Translate L1 physical address to host physical
|
||||
* address for vmcs02. Keep the page pinned, so this
|
||||
* physical address remains valid. We keep a reference
|
||||
* to it so we can release it later.
|
||||
*/
|
||||
if (vmx->nested.apic_access_page) { /* shouldn't happen */
|
||||
kvm_release_page_clean(vmx->nested.apic_access_page);
|
||||
vmx->nested.apic_access_page = NULL;
|
||||
}
|
||||
page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->apic_access_addr);
|
||||
if (!is_error_page(page)) {
|
||||
vmx->nested.apic_access_page = page;
|
||||
hpa = page_to_phys(vmx->nested.apic_access_page);
|
||||
vmcs_write64(APIC_ACCESS_ADDR, hpa);
|
||||
map = &vmx->nested.apic_access_page_map;
|
||||
|
||||
if (!kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->apic_access_addr), map)) {
|
||||
vmcs_write64(APIC_ACCESS_ADDR, pfn_to_hpa(map->pfn));
|
||||
} else {
|
||||
pr_debug_ratelimited("%s: no backing 'struct page' for APIC-access address in vmcs12\n",
|
||||
pr_debug_ratelimited("%s: no backing for APIC-access address in vmcs12\n",
|
||||
__func__);
|
||||
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
||||
vcpu->run->internal.suberror =
|
||||
@ -3515,6 +3518,8 @@ vmentry_fail_vmexit:
|
||||
if (!from_vmentry)
|
||||
return NVMX_VMENTRY_VMEXIT;
|
||||
|
||||
nested_put_vmcs12_pages(vcpu);
|
||||
|
||||
load_vmcs12_host_state(vcpu, vmcs12);
|
||||
vmcs12->vm_exit_reason = exit_reason.full;
|
||||
if (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
|
||||
@ -4650,14 +4655,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
|
||||
vmx_update_cpu_dirty_logging(vcpu);
|
||||
}
|
||||
|
||||
/* Unpin physical memory we referred to in vmcs02 */
|
||||
if (vmx->nested.apic_access_page) {
|
||||
kvm_release_page_clean(vmx->nested.apic_access_page);
|
||||
vmx->nested.apic_access_page = NULL;
|
||||
}
|
||||
kvm_vcpu_unmap(vcpu, &vmx->nested.virtual_apic_map, true);
|
||||
kvm_vcpu_unmap(vcpu, &vmx->nested.pi_desc_map, true);
|
||||
vmx->nested.pi_desc = NULL;
|
||||
nested_put_vmcs12_pages(vcpu);
|
||||
|
||||
if (vmx->nested.reload_vmcs01_apic_access_page) {
|
||||
vmx->nested.reload_vmcs01_apic_access_page = false;
|
||||
|
||||
@ -205,7 +205,7 @@ struct nested_vmx {
|
||||
* Guest pages referred to in the vmcs02 with host-physical
|
||||
* pointers, so we must keep them pinned while L2 runs.
|
||||
*/
|
||||
struct page *apic_access_page;
|
||||
struct kvm_host_map apic_access_page_map;
|
||||
struct kvm_host_map virtual_apic_map;
|
||||
struct kvm_host_map pi_desc_map;
|
||||
|
||||
|
||||
@ -5126,9 +5126,18 @@ static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
|
||||
static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
|
||||
struct kvm_xsave *guest_xsave)
|
||||
{
|
||||
union fpregs_state *xstate = (union fpregs_state *)guest_xsave->region;
|
||||
|
||||
if (fpstate_is_confidential(&vcpu->arch.guest_fpu))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* For backwards compatibility, do not expect disabled features to be in
|
||||
* their initial state. XSTATE_BV[i] must still be cleared whenever
|
||||
* XFD[i]=1, or XRSTOR would cause a #NM.
|
||||
*/
|
||||
xstate->xsave.header.xfeatures &= ~vcpu->arch.guest_fpu.fpstate->xfd;
|
||||
|
||||
return fpu_copy_uabi_to_guest_fpstate(&vcpu->arch.guest_fpu,
|
||||
guest_xsave->region,
|
||||
supported_xcr0, &vcpu->arch.pkru);
|
||||
@ -7380,36 +7389,47 @@ emul_write:
|
||||
return emulator_write_emulated(ctxt, addr, new, bytes, exception);
|
||||
}
|
||||
|
||||
static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
|
||||
{
|
||||
int r = 0, i;
|
||||
|
||||
for (i = 0; i < vcpu->arch.pio.count; i++) {
|
||||
if (vcpu->arch.pio.in)
|
||||
r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, vcpu->arch.pio.port,
|
||||
vcpu->arch.pio.size, pd);
|
||||
else
|
||||
r = kvm_io_bus_write(vcpu, KVM_PIO_BUS,
|
||||
vcpu->arch.pio.port, vcpu->arch.pio.size,
|
||||
pd);
|
||||
if (r)
|
||||
break;
|
||||
pd += vcpu->arch.pio.size;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int emulator_pio_in_out(struct kvm_vcpu *vcpu, int size,
|
||||
unsigned short port,
|
||||
unsigned short port, void *data,
|
||||
unsigned int count, bool in)
|
||||
{
|
||||
unsigned i;
|
||||
int r;
|
||||
|
||||
WARN_ON_ONCE(vcpu->arch.pio.count);
|
||||
for (i = 0; i < count; i++) {
|
||||
if (in)
|
||||
r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, port, size, data);
|
||||
else
|
||||
r = kvm_io_bus_write(vcpu, KVM_PIO_BUS, port, size, data);
|
||||
|
||||
if (r) {
|
||||
if (i == 0)
|
||||
goto userspace_io;
|
||||
|
||||
/*
|
||||
* Userspace must have unregistered the device while PIO
|
||||
* was running. Drop writes / read as 0.
|
||||
*/
|
||||
if (in)
|
||||
memset(data, 0, size * (count - i));
|
||||
break;
|
||||
}
|
||||
|
||||
data += size;
|
||||
}
|
||||
return 1;
|
||||
|
||||
userspace_io:
|
||||
vcpu->arch.pio.port = port;
|
||||
vcpu->arch.pio.in = in;
|
||||
vcpu->arch.pio.count = count;
|
||||
vcpu->arch.pio.count = count;
|
||||
vcpu->arch.pio.size = size;
|
||||
|
||||
if (!kernel_pio(vcpu, vcpu->arch.pio_data))
|
||||
return 1;
|
||||
if (in)
|
||||
memset(vcpu->arch.pio_data, 0, size * count);
|
||||
else
|
||||
memcpy(vcpu->arch.pio_data, data, size * count);
|
||||
|
||||
vcpu->run->exit_reason = KVM_EXIT_IO;
|
||||
vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
|
||||
@ -7417,22 +7437,23 @@ static int emulator_pio_in_out(struct kvm_vcpu *vcpu, int size,
|
||||
vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
|
||||
vcpu->run->io.count = count;
|
||||
vcpu->run->io.port = port;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __emulator_pio_in(struct kvm_vcpu *vcpu, int size,
|
||||
unsigned short port, unsigned int count)
|
||||
unsigned short port, void *val, unsigned int count)
|
||||
{
|
||||
WARN_ON(vcpu->arch.pio.count);
|
||||
memset(vcpu->arch.pio_data, 0, size * count);
|
||||
return emulator_pio_in_out(vcpu, size, port, count, true);
|
||||
int r = emulator_pio_in_out(vcpu, size, port, val, count, true);
|
||||
if (r)
|
||||
trace_kvm_pio(KVM_PIO_IN, port, size, count, val);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void complete_emulator_pio_in(struct kvm_vcpu *vcpu, void *val)
|
||||
{
|
||||
int size = vcpu->arch.pio.size;
|
||||
unsigned count = vcpu->arch.pio.count;
|
||||
unsigned int count = vcpu->arch.pio.count;
|
||||
memcpy(val, vcpu->arch.pio_data, size * count);
|
||||
trace_kvm_pio(KVM_PIO_IN, vcpu->arch.pio.port, size, count, vcpu->arch.pio_data);
|
||||
vcpu->arch.pio.count = 0;
|
||||
@ -7449,16 +7470,11 @@ static int emulator_pio_in(struct kvm_vcpu *vcpu, int size,
|
||||
* shenanigans as KVM doesn't support modifying the rep count,
|
||||
* and the emulator ensures @count doesn't overflow the buffer.
|
||||
*/
|
||||
} else {
|
||||
int r = __emulator_pio_in(vcpu, size, port, count);
|
||||
if (!r)
|
||||
return r;
|
||||
|
||||
/* Results already available, fall through. */
|
||||
complete_emulator_pio_in(vcpu, val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
complete_emulator_pio_in(vcpu, val);
|
||||
return 1;
|
||||
return __emulator_pio_in(vcpu, size, port, val, count);
|
||||
}
|
||||
|
||||
static int emulator_pio_in_emulated(struct x86_emulate_ctxt *ctxt,
|
||||
@ -7473,15 +7489,8 @@ static int emulator_pio_out(struct kvm_vcpu *vcpu, int size,
|
||||
unsigned short port, const void *val,
|
||||
unsigned int count)
|
||||
{
|
||||
int ret;
|
||||
|
||||
memcpy(vcpu->arch.pio_data, val, size * count);
|
||||
trace_kvm_pio(KVM_PIO_OUT, port, size, count, vcpu->arch.pio_data);
|
||||
ret = emulator_pio_in_out(vcpu, size, port, count, false);
|
||||
if (ret)
|
||||
vcpu->arch.pio.count = 0;
|
||||
|
||||
return ret;
|
||||
trace_kvm_pio(KVM_PIO_OUT, port, size, count, val);
|
||||
return emulator_pio_in_out(vcpu, size, port, (void *)val, count, false);
|
||||
}
|
||||
|
||||
static int emulator_pio_out_emulated(struct x86_emulate_ctxt *ctxt,
|
||||
@ -8474,7 +8483,14 @@ restart:
|
||||
ctxt->exception.address = 0;
|
||||
}
|
||||
|
||||
r = x86_emulate_insn(ctxt);
|
||||
/*
|
||||
* Check L1's instruction intercepts when emulating instructions for
|
||||
* L2, unless KVM is re-emulating a previously decoded instruction,
|
||||
* e.g. to complete userspace I/O, in which case KVM has already
|
||||
* checked the intercepts.
|
||||
*/
|
||||
r = x86_emulate_insn(ctxt, is_guest_mode(vcpu) &&
|
||||
!(emulation_type & EMULTYPE_NO_DECODE));
|
||||
|
||||
if (r == EMULATION_INTERCEPTED)
|
||||
return 1;
|
||||
@ -12754,7 +12770,7 @@ static int kvm_sev_es_outs(struct kvm_vcpu *vcpu, unsigned int size,
|
||||
|
||||
/* memcpy done already by emulator_pio_out. */
|
||||
vcpu->arch.sev_pio_count -= count;
|
||||
vcpu->arch.sev_pio_data += count * vcpu->arch.pio.size;
|
||||
vcpu->arch.sev_pio_data += count * size;
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
@ -12770,20 +12786,20 @@ static int kvm_sev_es_outs(struct kvm_vcpu *vcpu, unsigned int size,
|
||||
static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size,
|
||||
unsigned int port);
|
||||
|
||||
static void advance_sev_es_emulated_ins(struct kvm_vcpu *vcpu)
|
||||
static void advance_sev_es_emulated_ins(struct kvm_vcpu *vcpu, unsigned count, int size)
|
||||
{
|
||||
unsigned count = vcpu->arch.pio.count;
|
||||
complete_emulator_pio_in(vcpu, vcpu->arch.sev_pio_data);
|
||||
vcpu->arch.sev_pio_count -= count;
|
||||
vcpu->arch.sev_pio_data += count * vcpu->arch.pio.size;
|
||||
vcpu->arch.sev_pio_data += count * size;
|
||||
}
|
||||
|
||||
static int complete_sev_es_emulated_ins(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned count = vcpu->arch.pio.count;
|
||||
int size = vcpu->arch.pio.size;
|
||||
int port = vcpu->arch.pio.port;
|
||||
|
||||
advance_sev_es_emulated_ins(vcpu);
|
||||
complete_emulator_pio_in(vcpu, vcpu->arch.sev_pio_data);
|
||||
advance_sev_es_emulated_ins(vcpu, count, size);
|
||||
if (vcpu->arch.sev_pio_count)
|
||||
return kvm_sev_es_ins(vcpu, size, port);
|
||||
return 1;
|
||||
@ -12795,11 +12811,11 @@ static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size,
|
||||
for (;;) {
|
||||
unsigned int count =
|
||||
min_t(unsigned int, PAGE_SIZE / size, vcpu->arch.sev_pio_count);
|
||||
if (!__emulator_pio_in(vcpu, size, port, count))
|
||||
if (!__emulator_pio_in(vcpu, size, port, vcpu->arch.sev_pio_data, count))
|
||||
break;
|
||||
|
||||
/* Emulation done by the kernel. */
|
||||
advance_sev_es_emulated_ins(vcpu);
|
||||
advance_sev_es_emulated_ins(vcpu, count, size);
|
||||
if (!vcpu->arch.sev_pio_count)
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -368,7 +368,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
|
||||
|
||||
struct log_c *lc;
|
||||
uint32_t region_size;
|
||||
unsigned int region_count;
|
||||
sector_t region_count;
|
||||
size_t bitset_size, buf_size;
|
||||
int r;
|
||||
char dummy;
|
||||
@ -397,6 +397,10 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
|
||||
}
|
||||
|
||||
region_count = dm_sector_div_up(ti->len, region_size);
|
||||
if (region_count > UINT_MAX) {
|
||||
DMWARN("region count exceeds limit of %u", UINT_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lc = kmalloc(sizeof(*lc), GFP_KERNEL);
|
||||
if (!lc) {
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/rational.h>
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
#include <linux/dma/hsu.h>
|
||||
#include <linux/8250_pci.h>
|
||||
@ -364,8 +365,16 @@ static const struct mid8250_board dnv_board = {
|
||||
.flags = FL_BASE1,
|
||||
.freq = 133333333,
|
||||
.base_baud = 115200,
|
||||
.setup = dnv_setup,
|
||||
.exit = dnv_exit,
|
||||
/*
|
||||
* Errata:
|
||||
* HSUART May Stop Functioning when DMA is Active.
|
||||
*
|
||||
* - Denverton document #572409, rev 3.4, DNV60
|
||||
* - Ice Lake Xeon D document #714070, ICXD65
|
||||
* - Snowridge document #731931, SNR44
|
||||
*/
|
||||
.setup = PTR_IF(false, dnv_setup),
|
||||
.exit = PTR_IF(false, dnv_exit),
|
||||
};
|
||||
|
||||
#define MID_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board }
|
||||
|
||||
@ -1635,8 +1635,13 @@ static int do_umount(struct mount *mnt, int flags)
|
||||
|
||||
namespace_lock();
|
||||
lock_mount_hash();
|
||||
event++;
|
||||
|
||||
/* Recheck MNT_LOCKED with the locks held */
|
||||
retval = -EINVAL;
|
||||
if (mnt->mnt.mnt_flags & MNT_LOCKED)
|
||||
goto out;
|
||||
|
||||
event++;
|
||||
if (flags & MNT_DETACH) {
|
||||
if (!list_empty(&mnt->mnt_list))
|
||||
umount_tree(mnt, UMOUNT_PROPAGATE);
|
||||
@ -1650,6 +1655,7 @@ static int do_umount(struct mount *mnt, int flags)
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
out:
|
||||
unlock_mount_hash();
|
||||
namespace_unlock();
|
||||
return retval;
|
||||
@ -1740,7 +1746,7 @@ int ksys_umount(char __user *name, int flags)
|
||||
goto dput_and_out;
|
||||
if (!check_mnt(mnt))
|
||||
goto dput_and_out;
|
||||
if (mnt->mnt.mnt_flags & MNT_LOCKED)
|
||||
if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */
|
||||
goto dput_and_out;
|
||||
retval = -EPERM;
|
||||
if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN))
|
||||
@ -1823,8 +1829,14 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
|
||||
for (s = r; s; s = next_mnt(s, r)) {
|
||||
if (!(flag & CL_COPY_UNBINDABLE) &&
|
||||
IS_MNT_UNBINDABLE(s)) {
|
||||
s = skip_mnt_tree(s);
|
||||
continue;
|
||||
if (s->mnt.mnt_flags & MNT_LOCKED) {
|
||||
/* Both unbindable and locked. */
|
||||
q = ERR_PTR(-EPERM);
|
||||
goto out;
|
||||
} else {
|
||||
s = skip_mnt_tree(s);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!(flag & CL_COPY_MNT_NS_FILE) &&
|
||||
is_mnt_ns_file(s->mnt.mnt_root)) {
|
||||
@ -1898,7 +1910,7 @@ void drop_collected_mounts(struct vfsmount *mnt)
|
||||
{
|
||||
namespace_lock();
|
||||
lock_mount_hash();
|
||||
umount_tree(real_mount(mnt), UMOUNT_SYNC);
|
||||
umount_tree(real_mount(mnt), 0);
|
||||
unlock_mount_hash();
|
||||
namespace_unlock();
|
||||
}
|
||||
|
||||
@ -35,17 +35,36 @@
|
||||
#include "xfs_ag.h"
|
||||
|
||||
static DEFINE_MUTEX(xfs_uuid_table_mutex);
|
||||
static int xfs_uuid_table_size;
|
||||
static uuid_t *xfs_uuid_table;
|
||||
static DEFINE_XARRAY_ALLOC(xfs_uuid_table);
|
||||
|
||||
static uuid_t *
|
||||
xfs_uuid_search(
|
||||
uuid_t *new_uuid)
|
||||
{
|
||||
unsigned long index = 0;
|
||||
uuid_t *uuid;
|
||||
|
||||
xa_for_each(&xfs_uuid_table, index, uuid) {
|
||||
if (uuid_equal(uuid, new_uuid))
|
||||
return uuid;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
xfs_uuid_delete(
|
||||
uuid_t *uuid,
|
||||
unsigned int index)
|
||||
{
|
||||
ASSERT(uuid_equal(xa_load(&xfs_uuid_table, index), uuid));
|
||||
xa_erase(&xfs_uuid_table, index);
|
||||
}
|
||||
|
||||
void
|
||||
xfs_uuid_table_free(void)
|
||||
{
|
||||
if (xfs_uuid_table_size == 0)
|
||||
return;
|
||||
kmem_free(xfs_uuid_table);
|
||||
xfs_uuid_table = NULL;
|
||||
xfs_uuid_table_size = 0;
|
||||
ASSERT(xa_empty(&xfs_uuid_table));
|
||||
xa_destroy(&xfs_uuid_table);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -57,7 +76,7 @@ xfs_uuid_mount(
|
||||
struct xfs_mount *mp)
|
||||
{
|
||||
uuid_t *uuid = &mp->m_sb.sb_uuid;
|
||||
int hole, i;
|
||||
int ret;
|
||||
|
||||
/* Publish UUID in struct super_block */
|
||||
uuid_copy(&mp->m_super->s_uuid, uuid);
|
||||
@ -71,30 +90,17 @@ xfs_uuid_mount(
|
||||
}
|
||||
|
||||
mutex_lock(&xfs_uuid_table_mutex);
|
||||
for (i = 0, hole = -1; i < xfs_uuid_table_size; i++) {
|
||||
if (uuid_is_null(&xfs_uuid_table[i])) {
|
||||
hole = i;
|
||||
continue;
|
||||
}
|
||||
if (uuid_equal(uuid, &xfs_uuid_table[i]))
|
||||
goto out_duplicate;
|
||||
if (unlikely(xfs_uuid_search(uuid))) {
|
||||
xfs_warn(mp, "Filesystem has duplicate UUID %pU - can't mount",
|
||||
uuid);
|
||||
mutex_unlock(&xfs_uuid_table_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hole < 0) {
|
||||
xfs_uuid_table = krealloc(xfs_uuid_table,
|
||||
(xfs_uuid_table_size + 1) * sizeof(*xfs_uuid_table),
|
||||
GFP_KERNEL | __GFP_NOFAIL);
|
||||
hole = xfs_uuid_table_size++;
|
||||
}
|
||||
xfs_uuid_table[hole] = *uuid;
|
||||
ret = xa_alloc(&xfs_uuid_table, &mp->m_uuid_table_index, uuid,
|
||||
xa_limit_32b, GFP_KERNEL);
|
||||
mutex_unlock(&xfs_uuid_table_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
out_duplicate:
|
||||
mutex_unlock(&xfs_uuid_table_mutex);
|
||||
xfs_warn(mp, "Filesystem has duplicate UUID %pU - can't mount", uuid);
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC void
|
||||
@ -102,21 +108,12 @@ xfs_uuid_unmount(
|
||||
struct xfs_mount *mp)
|
||||
{
|
||||
uuid_t *uuid = &mp->m_sb.sb_uuid;
|
||||
int i;
|
||||
|
||||
if (mp->m_flags & XFS_MOUNT_NOUUID)
|
||||
return;
|
||||
|
||||
mutex_lock(&xfs_uuid_table_mutex);
|
||||
for (i = 0; i < xfs_uuid_table_size; i++) {
|
||||
if (uuid_is_null(&xfs_uuid_table[i]))
|
||||
continue;
|
||||
if (!uuid_equal(uuid, &xfs_uuid_table[i]))
|
||||
continue;
|
||||
memset(&xfs_uuid_table[i], 0, sizeof(uuid_t));
|
||||
break;
|
||||
}
|
||||
ASSERT(i < xfs_uuid_table_size);
|
||||
xfs_uuid_delete(uuid, mp->m_uuid_table_index);
|
||||
mutex_unlock(&xfs_uuid_table_mutex);
|
||||
}
|
||||
|
||||
|
||||
@ -221,6 +221,9 @@ typedef struct xfs_mount {
|
||||
unsigned int *m_errortag;
|
||||
struct xfs_kobj m_errortag_kobj;
|
||||
#endif
|
||||
|
||||
/* Index of uuid record in the uuid xarray. */
|
||||
unsigned int m_uuid_table_index;
|
||||
} xfs_mount_t;
|
||||
|
||||
#define M_IGEO(mp) (&(mp)->m_ino_geo)
|
||||
|
||||
@ -1454,6 +1454,11 @@ int kvm_request_irq_source_id(struct kvm *kvm);
|
||||
void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id);
|
||||
bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args);
|
||||
|
||||
static inline bool is_gfn_in_memslot(const struct kvm_memory_slot *slot, gfn_t gfn)
|
||||
{
|
||||
return gfn >= slot->base_gfn && gfn < slot->base_gfn + slot->npages;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a pointer to the memslot if it contains gfn.
|
||||
* Otherwise returns NULL.
|
||||
@ -1464,7 +1469,7 @@ try_get_memslot(struct kvm_memory_slot *slot, gfn_t gfn)
|
||||
if (!slot)
|
||||
return NULL;
|
||||
|
||||
if (gfn >= slot->base_gfn && gfn < slot->base_gfn + slot->npages)
|
||||
if (is_gfn_in_memslot(slot, gfn))
|
||||
return slot;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
|
||||
kernel.centos,1,Red Hat,kernel-core,4.18.0-553.146.1.el8.x86_64,mailto:secalert@redhat.com
|
||||
kernel.centos,1,Red Hat,kernel-core,4.18.0-553.147.1.el8.x86_64,mailto:secalert@redhat.com
|
||||
|
||||
@ -453,8 +453,8 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
|
||||
return err;
|
||||
}
|
||||
|
||||
if (ALIGN(tailen, L1_CACHE_BYTES) > PAGE_SIZE ||
|
||||
ALIGN(skb->data_len, L1_CACHE_BYTES) > PAGE_SIZE)
|
||||
if (ALIGN(skb->data_len + tailen, L1_CACHE_BYTES) >
|
||||
PAGE_SIZE)
|
||||
goto cow;
|
||||
|
||||
if (!skb_cloned(skb)) {
|
||||
|
||||
@ -500,8 +500,8 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
|
||||
return err;
|
||||
}
|
||||
|
||||
if (ALIGN(tailen, L1_CACHE_BYTES) > PAGE_SIZE ||
|
||||
ALIGN(skb->data_len, L1_CACHE_BYTES) > PAGE_SIZE)
|
||||
if (ALIGN(skb->data_len + tailen, L1_CACHE_BYTES) >
|
||||
PAGE_SIZE)
|
||||
goto cow;
|
||||
|
||||
if (!skb_cloned(skb)) {
|
||||
|
||||
@ -183,8 +183,20 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
|
||||
|
||||
if (fragid == LAST_FRAGMENT) {
|
||||
TIPC_SKB_CB(head)->validated = 0;
|
||||
if (unlikely(!tipc_msg_validate(&head)))
|
||||
|
||||
/* If the reassembled skb has been freed in
|
||||
* tipc_msg_validate() because of an invalid truesize,
|
||||
* then head will point to a newly allocated reassembled
|
||||
* skb, while *headbuf points to freed reassembled skb.
|
||||
* In such cases, correct *headbuf for freeing the newly
|
||||
* allocated reassembled skb later.
|
||||
*/
|
||||
if (unlikely(!tipc_msg_validate(&head))) {
|
||||
if (head != *headbuf)
|
||||
*headbuf = head;
|
||||
goto err;
|
||||
}
|
||||
|
||||
*buf = head;
|
||||
TIPC_SKB_CB(head)->tail = NULL;
|
||||
*headbuf = NULL;
|
||||
|
||||
@ -405,6 +405,7 @@ static inline unsigned int x86_model(unsigned int eax)
|
||||
return ((eax >> 12) & 0xf0) | ((eax >> 4) & 0x0f);
|
||||
}
|
||||
|
||||
void vcpu_xsave_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_xsave *xstate);
|
||||
struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid);
|
||||
void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid,
|
||||
struct kvm_x86_state *state);
|
||||
|
||||
@ -1179,6 +1179,16 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid)
|
||||
return state;
|
||||
}
|
||||
|
||||
void vcpu_xsave_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_xsave *xstate)
|
||||
{
|
||||
struct vcpu *vcpu = vcpu_find(vm, vcpuid);
|
||||
int r;
|
||||
|
||||
r = ioctl(vcpu->fd, KVM_SET_XSAVE, xstate);
|
||||
TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_XSAVE, r: %i",
|
||||
r);
|
||||
}
|
||||
|
||||
void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *state)
|
||||
{
|
||||
struct vcpu *vcpu = vcpu_find(vm, vcpuid);
|
||||
|
||||
@ -252,6 +252,20 @@ static void init_regs(void)
|
||||
__xsetbv(0x0, xcr0);
|
||||
}
|
||||
|
||||
enum {
|
||||
/* Retrieve TMM0 from guest, stash it for TEST_RESTORE_TILEDATA */
|
||||
TEST_SAVE_TILEDATA = 1,
|
||||
|
||||
/* Check TMM0 against tiledata */
|
||||
TEST_COMPARE_TILEDATA = 2,
|
||||
|
||||
/* Restore TMM0 from earlier save */
|
||||
TEST_RESTORE_TILEDATA = 4,
|
||||
|
||||
/* Full VM save/restore */
|
||||
TEST_SAVE_RESTORE = 8,
|
||||
};
|
||||
|
||||
static void __attribute__((__flatten__)) guest_code(struct tile_config *amx_cfg,
|
||||
struct tile_data *tiledata,
|
||||
struct xsave_data *xsave_data)
|
||||
@ -268,20 +282,29 @@ static void __attribute__((__flatten__)) guest_code(struct tile_config *amx_cfg,
|
||||
GUEST_ASSERT(xtile.bytes_per_tile == 1024);
|
||||
GUEST_ASSERT(xtile.bytes_per_row == 64);
|
||||
GUEST_ASSERT(xtile.max_rows == 16);
|
||||
GUEST_SYNC(1);
|
||||
GUEST_SYNC(TEST_SAVE_RESTORE);
|
||||
|
||||
/* xfd=0, enable amx */
|
||||
wrmsr(MSR_IA32_XFD, 0);
|
||||
GUEST_SYNC(2);
|
||||
GUEST_SYNC(TEST_SAVE_RESTORE);
|
||||
GUEST_ASSERT(rdmsr(MSR_IA32_XFD) == 0);
|
||||
set_tilecfg(amx_cfg);
|
||||
__ldtilecfg(amx_cfg);
|
||||
GUEST_SYNC(3);
|
||||
GUEST_SYNC(TEST_SAVE_RESTORE);
|
||||
/* Check save/restore when trap to userspace */
|
||||
__tileloadd(tiledata);
|
||||
GUEST_SYNC(4);
|
||||
GUEST_SYNC(TEST_SAVE_TILEDATA | TEST_COMPARE_TILEDATA | TEST_SAVE_RESTORE);
|
||||
|
||||
/* xfd=0x40000, disable amx tiledata */
|
||||
wrmsr(MSR_IA32_XFD, XFEATURE_MASK_XTILEDATA);
|
||||
|
||||
/* host tries setting tiledata while guest XFD is set */
|
||||
GUEST_SYNC(TEST_RESTORE_TILEDATA);
|
||||
GUEST_SYNC(TEST_SAVE_RESTORE);
|
||||
|
||||
wrmsr(MSR_IA32_XFD, 0);
|
||||
__tilerelease();
|
||||
GUEST_SYNC(5);
|
||||
GUEST_SYNC(TEST_SAVE_RESTORE);
|
||||
/* bit 18 not in the XCOMP_BV after xsavec() */
|
||||
set_xstatebv(xsave_data, XFEATURE_MASK_XTILEDATA);
|
||||
__xsavec(xsave_data, XFEATURE_MASK_XTILEDATA);
|
||||
@ -289,13 +312,13 @@ static void __attribute__((__flatten__)) guest_code(struct tile_config *amx_cfg,
|
||||
|
||||
/* xfd=0x40000, disable amx tiledata */
|
||||
wrmsr(MSR_IA32_XFD, XFEATURE_MASK_XTILEDATA);
|
||||
GUEST_SYNC(6);
|
||||
GUEST_SYNC(TEST_SAVE_RESTORE);
|
||||
GUEST_ASSERT(rdmsr(MSR_IA32_XFD) == XFEATURE_MASK_XTILEDATA);
|
||||
set_tilecfg(amx_cfg);
|
||||
__ldtilecfg(amx_cfg);
|
||||
/* Trigger #NM exception */
|
||||
__tileloadd(tiledata);
|
||||
GUEST_SYNC(10);
|
||||
GUEST_SYNC(TEST_COMPARE_TILEDATA | TEST_SAVE_RESTORE);
|
||||
|
||||
GUEST_DONE();
|
||||
}
|
||||
@ -303,15 +326,15 @@ static void __attribute__((__flatten__)) guest_code(struct tile_config *amx_cfg,
|
||||
void guest_nm_handler(struct ex_regs *regs)
|
||||
{
|
||||
/* Check if #NM is triggered by XFEATURE_MASK_XTILEDATA */
|
||||
GUEST_SYNC(7);
|
||||
GUEST_SYNC(TEST_SAVE_RESTORE);
|
||||
GUEST_ASSERT(rdmsr(MSR_IA32_XFD_ERR) == XFEATURE_MASK_XTILEDATA);
|
||||
GUEST_SYNC(8);
|
||||
GUEST_SYNC(TEST_SAVE_RESTORE);
|
||||
GUEST_ASSERT(rdmsr(MSR_IA32_XFD_ERR) == XFEATURE_MASK_XTILEDATA);
|
||||
/* Clear xfd_err */
|
||||
wrmsr(MSR_IA32_XFD_ERR, 0);
|
||||
/* xfd=0, enable amx */
|
||||
wrmsr(MSR_IA32_XFD, 0);
|
||||
GUEST_SYNC(9);
|
||||
GUEST_SYNC(TEST_SAVE_RESTORE);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -322,11 +345,11 @@ int main(int argc, char *argv[])
|
||||
struct kvm_vm *vm;
|
||||
struct kvm_run *run;
|
||||
struct kvm_x86_state *state;
|
||||
struct kvm_x86_state *tile_state = NULL;
|
||||
int xsave_restore_size = 0;
|
||||
vm_vaddr_t amx_cfg, tiledata, xsavedata;
|
||||
struct ucall uc;
|
||||
u32 amx_offset;
|
||||
int stage, ret;
|
||||
int ret;
|
||||
|
||||
vm_xsave_req_perm(XSTATE_XTILE_DATA_BIT);
|
||||
|
||||
@ -371,11 +394,12 @@ int main(int argc, char *argv[])
|
||||
memset(addr_gva2hva(vm, xsavedata), 0, 3 * getpagesize());
|
||||
vcpu_args_set(vm, VCPU_ID, 3, amx_cfg, tiledata, xsavedata);
|
||||
|
||||
for (stage = 1; ; stage++) {
|
||||
int iter = 0;
|
||||
for (;;) {
|
||||
_vcpu_run(vm, VCPU_ID);
|
||||
TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
|
||||
"Stage %d: unexpected exit reason: %u (%s),\n",
|
||||
stage, run->exit_reason,
|
||||
iter, run->exit_reason,
|
||||
exit_reason_str(run->exit_reason));
|
||||
|
||||
switch (get_ucall(vm, VCPU_ID, &uc)) {
|
||||
@ -384,37 +408,50 @@ int main(int argc, char *argv[])
|
||||
__FILE__, uc.args[1]);
|
||||
/* NOT REACHED */
|
||||
case UCALL_SYNC:
|
||||
switch (uc.args[1]) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
fprintf(stderr, "GUEST_SYNC(%ld)\n", uc.args[1]);
|
||||
break;
|
||||
case 4:
|
||||
case 10:
|
||||
fprintf(stderr,
|
||||
"GUEST_SYNC(%ld), check save/restore status\n", uc.args[1]);
|
||||
++iter;
|
||||
if (uc.args[1] & TEST_SAVE_TILEDATA) {
|
||||
fprintf(stderr, "GUEST_SYNC #%d, save tiledata\n", iter);
|
||||
tile_state = vcpu_save_state(vm, VCPU_ID);
|
||||
}
|
||||
if (uc.args[1] & TEST_COMPARE_TILEDATA) {
|
||||
fprintf(stderr, "GUEST_SYNC #%d, check TMM0 contents\n", iter);
|
||||
|
||||
/* Compacted mode, get amx offset by xsave area
|
||||
* size subtract 8K amx size.
|
||||
*/
|
||||
amx_offset = xsave_restore_size - NUM_TILES*TILE_SIZE;
|
||||
state = vcpu_save_state(vm, VCPU_ID);
|
||||
void *amx_start = (void *)state->xsave + amx_offset;
|
||||
u32 amx_offset = xsave_restore_size - NUM_TILES*TILE_SIZE;
|
||||
void *amx_start = (void *)tile_state->xsave + amx_offset;
|
||||
void *tiles_data = (void *)addr_gva2hva(vm, tiledata);
|
||||
/* Only check TMM0 register, 1 tile */
|
||||
ret = memcmp(amx_start, tiles_data, TILE_SIZE);
|
||||
TEST_ASSERT(ret == 0, "memcmp failed, ret=%d\n", ret);
|
||||
}
|
||||
if (uc.args[1] & TEST_RESTORE_TILEDATA) {
|
||||
fprintf(stderr, "GUEST_SYNC #%d, before KVM_SET_XSAVE\n", iter);
|
||||
vcpu_xsave_set(vm, VCPU_ID, tile_state->xsave);
|
||||
fprintf(stderr, "GUEST_SYNC #%d, after KVM_SET_XSAVE\n", iter);
|
||||
}
|
||||
if (uc.args[1] & TEST_SAVE_RESTORE) {
|
||||
fprintf(stderr, "GUEST_SYNC #%d, save/restore VM state\n", iter);
|
||||
state = vcpu_save_state(vm, VCPU_ID);
|
||||
memset(®s1, 0, sizeof(regs1));
|
||||
vcpu_regs_get(vm, VCPU_ID, ®s1);
|
||||
|
||||
kvm_vm_release(vm);
|
||||
|
||||
/* Restore state in a new VM. */
|
||||
kvm_vm_restart(vm, O_RDWR);
|
||||
vm_vcpu_add(vm, VCPU_ID);
|
||||
vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
|
||||
vcpu_load_state(vm, VCPU_ID, state);
|
||||
run = vcpu_state(vm, VCPU_ID);
|
||||
kvm_x86_state_cleanup(state);
|
||||
break;
|
||||
case 9:
|
||||
fprintf(stderr,
|
||||
"GUEST_SYNC(%ld), #NM exception and enable amx\n", uc.args[1]);
|
||||
break;
|
||||
|
||||
memset(®s2, 0, sizeof(regs2));
|
||||
vcpu_regs_get(vm, VCPU_ID, ®s2);
|
||||
TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)),
|
||||
"Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx",
|
||||
(ulong) regs2.rdi, (ulong) regs2.rsi);
|
||||
}
|
||||
break;
|
||||
case UCALL_DONE:
|
||||
@ -424,25 +461,6 @@ int main(int argc, char *argv[])
|
||||
TEST_FAIL("Unknown ucall %lu", uc.cmd);
|
||||
}
|
||||
|
||||
state = vcpu_save_state(vm, VCPU_ID);
|
||||
memset(®s1, 0, sizeof(regs1));
|
||||
vcpu_regs_get(vm, VCPU_ID, ®s1);
|
||||
|
||||
kvm_vm_release(vm);
|
||||
|
||||
/* Restore state in a new VM. */
|
||||
kvm_vm_restart(vm, O_RDWR);
|
||||
vm_vcpu_add(vm, VCPU_ID);
|
||||
vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
|
||||
vcpu_load_state(vm, VCPU_ID, state);
|
||||
run = vcpu_state(vm, VCPU_ID);
|
||||
kvm_x86_state_cleanup(state);
|
||||
|
||||
memset(®s2, 0, sizeof(regs2));
|
||||
vcpu_regs_get(vm, VCPU_ID, ®s2);
|
||||
TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)),
|
||||
"Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx",
|
||||
(ulong) regs2.rdi, (ulong) regs2.rsi);
|
||||
}
|
||||
done:
|
||||
kvm_vm_free(vm);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user