Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * x86_64-specific extensions to perf_test_util.c.
0004  *
0005  * Copyright (C) 2022, Google, Inc.
0006  */
0007 #include <stdio.h>
0008 #include <stdlib.h>
0009 #include <linux/bitmap.h>
0010 #include <linux/bitops.h>
0011 
0012 #include "test_util.h"
0013 #include "kvm_util.h"
0014 #include "perf_test_util.h"
0015 #include "processor.h"
0016 #include "vmx.h"
0017 
0018 void perf_test_l2_guest_code(uint64_t vcpu_id)
0019 {
0020     perf_test_guest_code(vcpu_id);
0021     vmcall();
0022 }
0023 
0024 extern char perf_test_l2_guest_entry[];
0025 __asm__(
0026 "perf_test_l2_guest_entry:"
0027 "   mov (%rsp), %rdi;"
0028 "   call perf_test_l2_guest_code;"
0029 "   ud2;"
0030 );
0031 
0032 static void perf_test_l1_guest_code(struct vmx_pages *vmx, uint64_t vcpu_id)
0033 {
0034 #define L2_GUEST_STACK_SIZE 64
0035     unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
0036     unsigned long *rsp;
0037 
0038     GUEST_ASSERT(vmx->vmcs_gpa);
0039     GUEST_ASSERT(prepare_for_vmx_operation(vmx));
0040     GUEST_ASSERT(load_vmcs(vmx));
0041     GUEST_ASSERT(ept_1g_pages_supported());
0042 
0043     rsp = &l2_guest_stack[L2_GUEST_STACK_SIZE - 1];
0044     *rsp = vcpu_id;
0045     prepare_vmcs(vmx, perf_test_l2_guest_entry, rsp);
0046 
0047     GUEST_ASSERT(!vmlaunch());
0048     GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);
0049     GUEST_DONE();
0050 }
0051 
0052 uint64_t perf_test_nested_pages(int nr_vcpus)
0053 {
0054     /*
0055      * 513 page tables is enough to identity-map 256 TiB of L2 with 1G
0056      * pages and 4-level paging, plus a few pages per-vCPU for data
0057      * structures such as the VMCS.
0058      */
0059     return 513 + 10 * nr_vcpus;
0060 }
0061 
0062 void perf_test_setup_ept(struct vmx_pages *vmx, struct kvm_vm *vm)
0063 {
0064     uint64_t start, end;
0065 
0066     prepare_eptp(vmx, vm, 0);
0067 
0068     /*
0069      * Identity map the first 4G and the test region with 1G pages so that
0070      * KVM can shadow the EPT12 with the maximum huge page size supported
0071      * by the backing source.
0072      */
0073     nested_identity_map_1g(vmx, vm, 0, 0x100000000ULL);
0074 
0075     start = align_down(perf_test_args.gpa, PG_SIZE_1G);
0076     end = align_up(perf_test_args.gpa + perf_test_args.size, PG_SIZE_1G);
0077     nested_identity_map_1g(vmx, vm, start, end - start);
0078 }
0079 
0080 void perf_test_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vcpus[])
0081 {
0082     struct vmx_pages *vmx, *vmx0 = NULL;
0083     struct kvm_regs regs;
0084     vm_vaddr_t vmx_gva;
0085     int vcpu_id;
0086 
0087     TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
0088 
0089     for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) {
0090         vmx = vcpu_alloc_vmx(vm, &vmx_gva);
0091 
0092         if (vcpu_id == 0) {
0093             perf_test_setup_ept(vmx, vm);
0094             vmx0 = vmx;
0095         } else {
0096             /* Share the same EPT table across all vCPUs. */
0097             vmx->eptp = vmx0->eptp;
0098             vmx->eptp_hva = vmx0->eptp_hva;
0099             vmx->eptp_gpa = vmx0->eptp_gpa;
0100         }
0101 
0102         /*
0103          * Override the vCPU to run perf_test_l1_guest_code() which will
0104          * bounce it into L2 before calling perf_test_guest_code().
0105          */
0106         vcpu_regs_get(vcpus[vcpu_id], &regs);
0107         regs.rip = (unsigned long) perf_test_l1_guest_code;
0108         vcpu_regs_set(vcpus[vcpu_id], &regs);
0109         vcpu_args_set(vcpus[vcpu_id], 2, vmx_gva, vcpu_id);
0110     }
0111 }