Path: blob/master/tools/testing/selftests/kvm/lib/x86/memstress.c
50618 views
// SPDX-License-Identifier: GPL-2.01/*2* x86-specific extensions to memstress.c.3*4* Copyright (C) 2022, Google, Inc.5*/6#include <stdio.h>7#include <stdlib.h>8#include <linux/bitmap.h>9#include <linux/bitops.h>1011#include "test_util.h"12#include "kvm_util.h"13#include "memstress.h"14#include "processor.h"15#include "vmx.h"1617void memstress_l2_guest_code(uint64_t vcpu_id)18{19memstress_guest_code(vcpu_id);20vmcall();21}2223extern char memstress_l2_guest_entry[];24__asm__(25"memstress_l2_guest_entry:"26" mov (%rsp), %rdi;"27" call memstress_l2_guest_code;"28" ud2;"29);3031static void memstress_l1_guest_code(struct vmx_pages *vmx, uint64_t vcpu_id)32{33#define L2_GUEST_STACK_SIZE 6434unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];35unsigned long *rsp;3637GUEST_ASSERT(vmx->vmcs_gpa);38GUEST_ASSERT(prepare_for_vmx_operation(vmx));39GUEST_ASSERT(load_vmcs(vmx));40GUEST_ASSERT(ept_1g_pages_supported());4142rsp = &l2_guest_stack[L2_GUEST_STACK_SIZE - 1];43*rsp = vcpu_id;44prepare_vmcs(vmx, memstress_l2_guest_entry, rsp);4546GUEST_ASSERT(!vmlaunch());47GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);48GUEST_DONE();49}5051uint64_t memstress_nested_pages(int nr_vcpus)52{53/*54* 513 page tables is enough to identity-map 256 TiB of L2 with 1G55* pages and 4-level paging, plus a few pages per-vCPU for data56* structures such as the VMCS.57*/58return 513 + 10 * nr_vcpus;59}6061void memstress_setup_ept(struct vmx_pages *vmx, struct kvm_vm *vm)62{63uint64_t start, end;6465prepare_eptp(vmx, vm);6667/*68* Identity map the first 4G and the test region with 1G pages so that69* KVM can shadow the EPT12 with the maximum huge page size supported70* by the backing source.71*/72nested_identity_map_1g(vmx, vm, 0, 0x100000000ULL);7374start = align_down(memstress_args.gpa, PG_SIZE_1G);75end = align_up(memstress_args.gpa + memstress_args.size, PG_SIZE_1G);76nested_identity_map_1g(vmx, vm, start, end - start);77}7879void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vcpus[])80{81struct vmx_pages *vmx, *vmx0 = NULL;82struct kvm_regs regs;83vm_vaddr_t vmx_gva;84int vcpu_id;8586TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));87TEST_REQUIRE(kvm_cpu_has_ept());8889for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) {90vmx = vcpu_alloc_vmx(vm, &vmx_gva);9192if (vcpu_id == 0) {93memstress_setup_ept(vmx, vm);94vmx0 = vmx;95} else {96/* Share the same EPT table across all vCPUs. */97vmx->eptp = vmx0->eptp;98vmx->eptp_hva = vmx0->eptp_hva;99vmx->eptp_gpa = vmx0->eptp_gpa;100}101102/*103* Override the vCPU to run memstress_l1_guest_code() which will104* bounce it into L2 before calling memstress_guest_code().105*/106vcpu_regs_get(vcpus[vcpu_id], ®s);107regs.rip = (unsigned long) memstress_l1_guest_code;108vcpu_regs_set(vcpus[vcpu_id], ®s);109vcpu_args_set(vcpus[vcpu_id], 2, vmx_gva, vcpu_id);110}111}112113114