File Index
Files and directories
Sign in
FILE

memstress.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/kvm/lib/x86/memstress.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * x86-specific extensions to memstress.c.
  4 *
  5 * Copyright (C) 2022, Google, Inc.
  6 */
  7#include <stdio.h>
  8#include <stdlib.h>
  9#include <linux/bitmap.h>
 10#include <linux/bitops.h>
 11
 12#include "test_util.h"
 13#include "kvm_util.h"
 14#include "memstress.h"
 15#include "processor.h"
 16#include "vmx.h"
 17
 18void memstress_l2_guest_code(uint64_t vcpu_id)
 19{
 20	memstress_guest_code(vcpu_id);
 21	vmcall();
 22}
 23
 24extern char memstress_l2_guest_entry[];
 25__asm__(
 26"memstress_l2_guest_entry:"
 27"	mov (%rsp), %rdi;"
 28"	call memstress_l2_guest_code;"
 29"	ud2;"
 30);
 31
 32static void memstress_l1_guest_code(struct vmx_pages *vmx, uint64_t vcpu_id)
 33{
 34#define L2_GUEST_STACK_SIZE 64
 35	unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
 36	unsigned long *rsp;
 37
 38	GUEST_ASSERT(vmx->vmcs_gpa);
 39	GUEST_ASSERT(prepare_for_vmx_operation(vmx));
 40	GUEST_ASSERT(load_vmcs(vmx));
 41	GUEST_ASSERT(ept_1g_pages_supported());
 42
 43	rsp = &l2_guest_stack[L2_GUEST_STACK_SIZE - 1];
 44	*rsp = vcpu_id;
 45	prepare_vmcs(vmx, memstress_l2_guest_entry, rsp);
 46
 47	GUEST_ASSERT(!vmlaunch());
 48	GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);
 49	GUEST_DONE();
 50}
 51
 52uint64_t memstress_nested_pages(int nr_vcpus)
 53{
 54	/*
 55	 * 513 page tables is enough to identity-map 256 TiB of L2 with 1G
 56	 * pages and 4-level paging, plus a few pages per-vCPU for data
 57	 * structures such as the VMCS.
 58	 */
 59	return 513 + 10 * nr_vcpus;
 60}
 61
 62void memstress_setup_ept(struct vmx_pages *vmx, struct kvm_vm *vm)
 63{
 64	uint64_t start, end;
 65
 66	prepare_eptp(vmx, vm);
 67
 68	/*
 69	 * Identity map the first 4G and the test region with 1G pages so that
 70	 * KVM can shadow the EPT12 with the maximum huge page size supported
 71	 * by the backing source.
 72	 */
 73	nested_identity_map_1g(vmx, vm, 0, 0x100000000ULL);
 74
 75	start = align_down(memstress_args.gpa, PG_SIZE_1G);
 76	end = align_up(memstress_args.gpa + memstress_args.size, PG_SIZE_1G);
 77	nested_identity_map_1g(vmx, vm, start, end - start);
 78}
 79
 80void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vcpus[])
 81{
 82	struct vmx_pages *vmx, *vmx0 = NULL;
 83	struct kvm_regs regs;
 84	vm_vaddr_t vmx_gva;
 85	int vcpu_id;
 86
 87	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
 88	TEST_REQUIRE(kvm_cpu_has_ept());
 89
 90	for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) {
 91		vmx = vcpu_alloc_vmx(vm, &vmx_gva);
 92
 93		if (vcpu_id == 0) {
 94			memstress_setup_ept(vmx, vm);
 95			vmx0 = vmx;
 96		} else {
 97			/* Share the same EPT table across all vCPUs. */
 98			vmx->eptp = vmx0->eptp;
 99			vmx->eptp_hva = vmx0->eptp_hva;
100			vmx->eptp_gpa = vmx0->eptp_gpa;
101		}
102
103		/*
104		 * Override the vCPU to run memstress_l1_guest_code() which will
105		 * bounce it into L2 before calling memstress_guest_code().
106		 */
107		vcpu_regs_get(vcpus[vcpu_id], &regs);
108		regs.rip = (unsigned long) memstress_l1_guest_code;
109		vcpu_regs_set(vcpus[vcpu_id], &regs);
110		vcpu_args_set(vcpus[vcpu_id], 2, vmx_gva, vcpu_id);
111	}
112}
~/ Read-only file preview.