Changeset 74533 in vbox
- Timestamp:
- Sep 30, 2018 2:50:51 PM (6 years ago)
- Location:
- trunk/src/VBox/VMM/testcase
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/testcase/Makefile.kmk
r74529 r74533 411 411 # Special NEM host testcase. 412 412 # 413 if1of ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH), $(if-expr "$(USERNAME)" == "bird", linux.amd64,) win.amd64)413 if1of ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH), $(if-expr "$(USERNAME)" == "bird",darwin.amd64 linux.amd64,) win.amd64) 414 414 PROGRAMS += NemRawBench-1 415 415 NemRawBench-1_TEMPLATE = VBoxR3Static 416 416 NemRawBench-1_SOURCES = NemRawBench-1.cpp 417 #NemRawBench-1_BLD_TYPE = release417 NemRawBench-1_BLD_TYPE = release 418 418 NemRawBench-1_INCS.win = \ 419 $(KBUILD_DEVTOOLS)/win.x86/sdk/v10.0.17134.0/include/10.0.17134.0/um \ 420 $(KBUILD_DEVTOOLS)/win.x86/sdk/v10.0.17134.0/include/10.0.17134.0/shared 419 $(KBUILD_DEVTOOLS)/win.x86/sdk/v10.0.17134.0/include/10.0.17134.0/um \ 420 $(KBUILD_DEVTOOLS)/win.x86/sdk/v10.0.17134.0/include/10.0.17134.0/shared 421 NemRawBench-1_CXXFLAGS.darwin = \ 422 -F/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform//Developer/SDKs/MacOSX10.13.sdk/System/Library/Frameworks 423 #NemRawBench-1_LDFLAGS.darwin = \ 424 # -F/System/Library/Frameworks \ 425 # -framework Hypervisor 426 NemRawBench-1_LDFLAGS.darwin = \ 427 /System/Library/Frameworks/Hypervisor.framework/Hypervisor 421 428 endif 422 429 -
trunk/src/VBox/VMM/testcase/NemRawBench-1.cpp
r74531 r74533 1 /* $Id$ */ 2 /** @file 3 * NEM Benchmark. 4 */ 5 6 /* 7 * Copyright (C) 2018 Oracle Corporation 8 * 9 * This file is part of VirtualBox Open Source Edition (OSE), as 10 * available from http://www.virtualbox.org. This file is free software; 11 * you can redistribute it and/or modify it under the terms of the GNU 12 * General Public License (GPL) as published by the Free Software 13 * Foundation, in version 2 as it comes in the "COPYING" file of the 14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the 15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 16 */ 17 1 18 2 19 /********************************************************************************************************************************* … … 11 28 # include <linux/kvm.h> 12 29 # include <errno.h> 13 # include <stdint.h>14 30 # include <sys/fcntl.h> 15 31 # include <sys/ioctl.h> … … 18 34 # include <time.h> 19 35 36 #elif defined(RT_OS_DARWIN) 37 # include <Availability.h> 38 # if 1 /* header mix hack */ 39 # undef __OSX_AVAILABLE_STARTING 40 # define __OSX_AVAILABLE_STARTING(_osx, _ios) 41 # endif 42 # include <Hypervisor/hv.h> 43 # include <Hypervisor/hv_arch_x86.h> 44 # include <Hypervisor/hv_arch_vmx.h> 45 # include <Hypervisor/hv_vmx.h> 46 # include <mach/mach_time.h> 47 # include <mach/kern_return.h> 48 # include <sys/time.h> 49 # include <time.h> 50 # include <sys/mman.h> 51 # include <errno.h> 52 20 53 #else 21 54 # error "port me" … … 23 56 24 57 #include <stdarg.h> 58 #include <stdint.h> 25 59 #include <stdio.h> 26 60 #include <stdlib.h> … … 42 76 /** The no-op test port number. */ 43 77 #define MY_NOP_PORT 0x7f 78 79 #define MY_TEST_F_NOP_IO (1U<<0) 80 #define MY_TEST_F_CPUID (1U<<1) 81 #define MY_TEST_F_NOP_MMIO (1U<<2) 44 82 45 83 … … 78 116 /** The size of the g_pVCpuRun mapping. */ 79 117 static ssize_t g_cbVCpuRun; 118 119 #elif defined(RT_OS_DARWIN) 120 /** The VCpu ID. */ 121 static hv_vcpuid_t g_idVCpu; 80 122 #endif 81 123 … … 96 138 #ifdef RT_OS_WINDOWS 97 139 return g_pfnRtlGetSystemTimePrecise() * 100; 140 98 141 #elif defined(RT_OS_LINUX) 99 142 struct timespec ts; 100 143 clock_gettime(CLOCK_MONOTONIC, &ts); 101 144 return (uint64_t)ts.tv_sec * UINT64_C(1000000000) + ts.tv_nsec; 145 146 #elif defined(RT_OS_DARWIN) 147 static struct mach_timebase_info s_Info = { 0, 0 }; 148 static double s_rdFactor = 0.0; 149 /* Lazy init. */ 150 if (s_Info.denom != 0) 151 { /* likely */ } 152 else if (mach_timebase_info(&s_Info) == KERN_SUCCESS) 153 s_rdFactor = (double)s_Info.numer / (double)s_Info.denom; 154 else 155 { 156 error("mach_timebase_info(&Info) failed\n"); 157 exit(1); 158 } 159 if (s_Info.denom == 1 && s_Info.numer == 1) /* special case: absolute time is in nanoseconds */ 160 return mach_absolute_time(); 161 return mach_absolute_time() * s_rdFactor; 102 162 #else 103 # error "port me" 163 struct timeval tv; 164 gettimeofday(&tv, NULL); 165 return (uint64_t)tv.tv_sec * UINT64_C(1000000000) 166 + (tv.tv_usec * UINT32_C(1000)); 104 167 #endif 168 } 169 170 171 char *formatNum(uint64_t uNum, int cchWidth, char *pszDst, size_t cbDst) 172 { 173 char szTmp[64 + 22]; 174 #ifdef _MSC_VER 175 size_t cchTmp = snprintf(szTmp, sizeof(szTmp) - 22, "%I64u", uNum); 176 #else 177 size_t cchTmp = snprintf(szTmp, sizeof(szTmp) - 22, "%llu", uNum); 178 #endif 179 size_t cSeps = (cchTmp - 1) / 3; 180 if (cSeps) 181 { 182 szTmp[cchTmp + cSeps] = '\0'; 183 for (size_t iSrc = cchTmp, iDst = cchTmp + cSeps; cSeps > 0; cSeps--) 184 { 185 szTmp[--iDst] = szTmp[--iSrc]; 186 szTmp[--iDst] = szTmp[--iSrc]; 187 szTmp[--iDst] = szTmp[--iSrc]; 188 szTmp[--iDst] = ' '; 189 } 190 } 191 snprintf(pszDst, cbDst, "%*s", cchWidth, szTmp); 192 return pszDst; 105 193 } 106 194 … … 236 324 { "cr3", WHvX64RegisterCr3, 64 }, 237 325 { "cr4", WHvX64RegisterCr4, 64 }, 238 };326 }; 239 327 for (unsigned i = 0; i < sizeof(s_aRegs) / sizeof(s_aRegs[0]); i++) 240 328 { … … 261 349 262 350 263 static int runRealModeTest(unsigned cInstructions, const char *pszInstruction, 351 static int runRealModeTest(unsigned cInstructions, const char *pszInstruction, unsigned fTest, 264 352 unsigned uEax, unsigned uEcx, unsigned uEdx, unsigned uEbx, 265 353 unsigned uEsp, unsigned uEbp, unsigned uEsi, unsigned uEdi) 266 354 { 355 (void)fTest; 356 267 357 /* 268 358 * Initialize the real mode context. … … 295 385 ADD_REG64(WHvX64RegisterRdi, uEdi); 296 386 ADD_REG64(WHvX64RegisterRip, MY_TEST_RIP); 297 ADD_REG64(WHvX64RegisterRflags, 1);387 ADD_REG64(WHvX64RegisterRflags, 2); 298 388 ADD_SEG(WHvX64RegisterEs, 0x00000, 0xffff, 0x0000, 0); 299 389 ADD_SEG(WHvX64RegisterCs, 0x00000, 0xffff, 0x0000, 1); … … 515 605 } 516 606 517 static int runRealModeTest(unsigned cInstructions, const char *pszInstruction, 607 static int runRealModeTest(unsigned cInstructions, const char *pszInstruction, unsigned fTest, 518 608 unsigned uEax, unsigned uEcx, unsigned uEdx, unsigned uEbx, 519 609 unsigned uEsp, unsigned uEbp, unsigned uEsi, unsigned uEdi) 520 610 { 611 (void)fTest; 612 521 613 /* 522 614 * Setup real mode context. … … 549 641 Regs.rdi = uEdi; 550 642 Regs.rip = MY_TEST_RIP; 551 Regs.rflags = 1;643 Regs.rflags = 2; 552 644 int rc = ioctl(g_fdVCpu, KVM_SET_REGS, &Regs); 553 645 if (rc != 0) … … 614 706 615 707 #elif defined(RT_OS_DARWIN) 616 # error "port me" 708 709 /* 710 * Mac OS X - Hypervisor API. 711 */ 712 713 static int createVM(void) 714 { 715 /* VM and VCpu */ 716 hv_return_t rcHv = hv_vm_create(HV_VM_DEFAULT); 717 if (rcHv != HV_SUCCESS) 718 return error("hv_vm_create failed: %#x\n", rcHv); 719 720 g_idVCpu = -1; 721 rcHv = hv_vcpu_create(&g_idVCpu, HV_VCPU_DEFAULT); 722 if (rcHv != HV_SUCCESS) 723 return error("hv_vcpu_create failed: %#x\n", rcHv); 724 725 /* Memory. */ 726 g_pbMem = (unsigned char *)mmap(NULL, g_cbMem, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); 727 if ((void *)g_pbMem == MAP_FAILED) 728 return error("mmap RAM failed: %d\n", errno); 729 memset(g_pbMem, 0xf4, g_cbMem); 730 731 rcHv = hv_vm_map(g_pbMem, MY_MEM_BASE, g_cbMem, HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC); 732 if (rcHv != HV_SUCCESS) 733 return error("hv_vm_map failed: %#x\n", rcHv); 734 735 rcHv = hv_vm_protect(0x2000, 0x1000, HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC); 736 if (rcHv != HV_SUCCESS) 737 return error("hv_vm_protect failed: %#x\n", rcHv); 738 return 0; 739 } 740 741 742 static int runtimeError(const char *pszFormat, ...) 743 { 744 fprintf(stderr, "runtime error: "); 745 va_list va; 746 va_start(va, pszFormat); 747 vfprintf(stderr, pszFormat, va); 748 va_end(va); 749 750 static struct { const char *pszName; uint32_t uField; uint32_t uFmt : 31; uint32_t fIsReg : 1; } const s_aFields[] = 751 { 752 { "VMCS_RO_EXIT_REASON", VMCS_RO_EXIT_REASON, 64, 0 }, 753 { "VMCS_RO_EXIT_QUALIFIC", VMCS_RO_EXIT_QUALIFIC, 64, 0 }, 754 { "VMCS_RO_INSTR_ERROR", VMCS_RO_INSTR_ERROR, 64, 0 }, 755 { "VMCS_RO_VMEXIT_IRQ_INFO", VMCS_RO_VMEXIT_IRQ_INFO, 64, 0 }, 756 { "VMCS_RO_VMEXIT_IRQ_ERROR", VMCS_RO_VMEXIT_IRQ_ERROR, 64, 0 }, 757 { "VMCS_RO_VMEXIT_INSTR_LEN", VMCS_RO_VMEXIT_INSTR_LEN, 64, 0 }, 758 { "VMCS_RO_VMX_INSTR_INFO", VMCS_RO_VMX_INSTR_INFO, 64, 0 }, 759 { "VMCS_RO_GUEST_LIN_ADDR", VMCS_RO_GUEST_LIN_ADDR, 64, 0 }, 760 { "VMCS_GUEST_PHYSICAL_ADDRESS",VMCS_GUEST_PHYSICAL_ADDRESS,64, 0 }, 761 { "VMCS_RO_IO_RCX", VMCS_RO_IO_RCX, 64, 0 }, 762 { "VMCS_RO_IO_RSI", VMCS_RO_IO_RSI, 64, 0 }, 763 { "VMCS_RO_IO_RDI", VMCS_RO_IO_RDI, 64, 0 }, 764 { "VMCS_RO_IO_RIP", VMCS_RO_IO_RIP, 64, 0 }, 765 { "rip", HV_X86_RIP, 64, 1 }, 766 { "rip (vmcs)", VMCS_GUEST_RIP, 64, 0 }, 767 { "cs", HV_X86_CS, 16, 1 }, 768 { "cs (vmcs)", VMCS_GUEST_CS, 16, 0 }, 769 { "cs.base", VMCS_GUEST_CS_BASE, 64, 0 }, 770 { "cs.limit", VMCS_GUEST_CS_LIMIT, 32, 0 }, 771 { "cs.attr", VMCS_GUEST_CS_AR, 32, 0 }, 772 { "rflags", HV_X86_RFLAGS, 32, 1 }, 773 { "rax", HV_X86_RAX, 64, 1 }, 774 { "rcx", HV_X86_RCX, 64, 1 }, 775 { "rdx", HV_X86_RDX, 64, 1 }, 776 { "rbx", HV_X86_RBX, 64, 1 }, 777 { "rsp", HV_X86_RSP, 64, 1 }, 778 { "rsp (vmcs)", VMCS_GUEST_RSP, 64, 0 }, 779 { "ss", HV_X86_SS, 16, 1 }, 780 { "ss (vmcs)", VMCS_GUEST_SS, 16, 0 }, 781 { "ss.base", VMCS_GUEST_SS_BASE, 64, 0 }, 782 { "ss.limit", VMCS_GUEST_SS_LIMIT, 32, 0 }, 783 { "ss.attr", VMCS_GUEST_SS_AR, 32, 0 }, 784 { "rbp", HV_X86_RBP, 64, 1 }, 785 { "rsi", HV_X86_RSI, 64, 1 }, 786 { "rdi", HV_X86_RDI, 64, 1 }, 787 { "ds", HV_X86_DS, 16, 1 }, 788 { "ds (vmcs)", VMCS_GUEST_DS, 16, 0 }, 789 { "ds.base", VMCS_GUEST_DS_BASE, 64, 0 }, 790 { "ds.limit", VMCS_GUEST_DS_LIMIT, 32, 0 }, 791 { "ds.attr", VMCS_GUEST_DS_AR, 32, 0 }, 792 { "es", HV_X86_ES, 16, 1 }, 793 { "es (vmcs)", VMCS_GUEST_ES, 16, 0 }, 794 { "es.base", VMCS_GUEST_ES_BASE, 64, 0 }, 795 { "es.limit", VMCS_GUEST_ES_LIMIT, 32, 0 }, 796 { "es.attr", VMCS_GUEST_ES_AR, 32, 0 }, 797 { "fs", HV_X86_FS, 16, 1 }, 798 { "fs (vmcs)", VMCS_GUEST_FS, 16, 0 }, 799 { "fs.base", VMCS_GUEST_FS_BASE, 64, 0 }, 800 { "fs.limit", VMCS_GUEST_FS_LIMIT, 32, 0 }, 801 { "fs.attr", VMCS_GUEST_FS_AR, 32, 0 }, 802 { "gs", HV_X86_GS, 16, 1 }, 803 { "gs (vmcs)", VMCS_GUEST_GS, 16, 0 }, 804 { "gs.base", VMCS_GUEST_GS_BASE, 64, 0 }, 805 { "gs.limit", VMCS_GUEST_GS_LIMIT, 32, 0 }, 806 { "gs.attr", VMCS_GUEST_GS_AR, 32, 0 }, 807 { "cr0", HV_X86_CR0, 64, 1 }, 808 { "cr0 (vmcs)", VMCS_GUEST_CR0, 64, 0 }, 809 { "cr2", HV_X86_CR2, 64, 1 }, 810 { "cr3", HV_X86_CR3, 64, 1 }, 811 { "cr3 (vmcs)", VMCS_GUEST_CR3, 64, 0 }, 812 { "cr4", HV_X86_CR4, 64, 1 }, 813 { "cr4 (vmcs)", VMCS_GUEST_CR4, 64, 0 }, 814 { "idtr.base", VMCS_GUEST_IDTR_BASE, 64, 0 }, 815 { "idtr.limit", VMCS_GUEST_IDTR_LIMIT, 32, 0 }, 816 { "gdtr.base", VMCS_GUEST_GDTR_BASE, 64, 0 }, 817 { "gdtr.limit", VMCS_GUEST_GDTR_LIMIT, 32, 0 }, 818 819 { "VMCS_CTRL_PIN_BASED", VMCS_CTRL_PIN_BASED, 64, 0 }, 820 { "VMCS_CTRL_CPU_BASED", VMCS_CTRL_CPU_BASED, 64, 0 }, 821 { "VMCS_CTRL_CPU_BASED2", VMCS_CTRL_CPU_BASED2, 64, 0 }, 822 { "VMCS_CTRL_VMENTRY_CONTROLS", VMCS_CTRL_VMENTRY_CONTROLS, 64, 0 }, 823 { "VMCS_CTRL_VMEXIT_CONTROLS", VMCS_CTRL_VMEXIT_CONTROLS, 64, 0 }, 824 { "VMCS_CTRL_EXC_BITMAP", VMCS_CTRL_EXC_BITMAP, 64, 0 }, 825 { "VMCS_CTRL_CR0_MASK", VMCS_CTRL_CR0_MASK, 64, 0 }, 826 { "VMCS_CTRL_CR0_SHADOW", VMCS_CTRL_CR0_SHADOW, 64, 0 }, 827 { "VMCS_CTRL_CR4_MASK", VMCS_CTRL_CR4_MASK, 64, 0 }, 828 { "VMCS_CTRL_CR4_SHADOW", VMCS_CTRL_CR4_SHADOW, 64, 0 }, 829 }; 830 for (unsigned i = 0; i < sizeof(s_aFields) / sizeof(s_aFields[0]); i++) 831 { 832 uint64_t uValue = UINT64_MAX; 833 hv_return_t rcHv; 834 if (s_aFields[i].fIsReg) 835 rcHv = hv_vcpu_read_register(g_idVCpu, (hv_x86_reg_t)s_aFields[i].uField, &uValue); 836 else 837 rcHv = hv_vmx_vcpu_read_vmcs(g_idVCpu, s_aFields[i].uField, &uValue); 838 if (rcHv == HV_SUCCESS) 839 { 840 if (s_aFields[i].uFmt == 16) 841 fprintf(stderr, "%28s=%04llx\n", s_aFields[i].pszName, uValue); 842 else if (s_aFields[i].uFmt == 32) 843 fprintf(stderr, "%28s=%08llx\n", s_aFields[i].pszName, uValue); 844 else 845 fprintf(stderr, "%28s=%08x'%08x\n", s_aFields[i].pszName, (uint32_t)(uValue >> 32), (uint32_t)uValue); 846 } 847 else 848 fprintf(stderr, "%28s=<%s failed %#x>\n", s_aFields[i].pszName, 849 s_aFields[i].fIsReg ? "hv_vcpu_read_register" : "hv_vmx_vcpu_read_vmcs", rcHv); 850 } 851 return 1; 852 } 853 854 855 static int runRealModeTest(unsigned cInstructions, const char *pszInstruction, unsigned fTest, 856 unsigned uEax, unsigned uEcx, unsigned uEdx, unsigned uEbx, 857 unsigned uEsp, unsigned uEbp, unsigned uEsi, unsigned uEdi) 858 { 859 /* 860 * Setup real mode context. 861 */ 862 #define WRITE_REG_RET(a_enmReg, a_uValue) \ 863 do { \ 864 hv_return_t rcHvX = hv_vcpu_write_register(g_idVCpu, a_enmReg, a_uValue); \ 865 if (rcHvX == HV_SUCCESS) { /* likely */ } \ 866 else return error("hv_vcpu_write_register(%#x, %s, %#llx) -> %#x\n", g_idVCpu, #a_enmReg, (uint64_t)(a_uValue), rcHvX); \ 867 } while (0) 868 #define READ_REG_RET(a_enmReg, a_puValue) \ 869 do { \ 870 hv_return_t rcHvX = hv_vcpu_read_register(g_idVCpu, a_enmReg, a_puValue); \ 871 if (rcHvX == HV_SUCCESS) { /* likely */ } \ 872 else return error("hv_vcpu_read_register(%#x, %s,) -> %#x\n", g_idVCpu, #a_enmReg, rcHvX); \ 873 } while (0) 874 #define WRITE_VMCS_RET(a_enmField, a_uValue) \ 875 do { \ 876 hv_return_t rcHvX = hv_vmx_vcpu_write_vmcs(g_idVCpu, a_enmField, a_uValue); \ 877 if (rcHvX == HV_SUCCESS) { /* likely */ } \ 878 else return error("hv_vmx_vcpu_write_vmcs(%#x, %s, %#llx) -> %#x\n", g_idVCpu, #a_enmField, (uint64_t)(a_uValue), rcHvX); \ 879 } while (0) 880 #define READ_VMCS_RET(a_enmField, a_puValue) \ 881 do { \ 882 hv_return_t rcHvX = hv_vmx_vcpu_read_vmcs(g_idVCpu, a_enmField, a_puValue); \ 883 if (rcHvX == HV_SUCCESS) { /* likely */ } \ 884 else return error("hv_vmx_vcpu_read_vmcs(%#x, %s,) -> %#x\n", g_idVCpu, #a_enmField, rcHvX); \ 885 } while (0) 886 #define READ_CAP_RET(a_enmCap, a_puValue) \ 887 do { \ 888 hv_return_t rcHvX = hv_vmx_read_capability(a_enmCap, a_puValue); \ 889 if (rcHvX == HV_SUCCESS) { /* likely */ } \ 890 else return error("hv_vmx_read_capability(%s) -> %#x\n", #a_enmCap); \ 891 } while (0) 892 #define CAP_2_CTRL(a_uCap, a_fWanted) ( ((a_fWanted) | (uint32_t)(a_uCap)) & (uint32_t)((a_uCap) >> 32) ) 893 #if 1 894 uint64_t uCap; 895 READ_CAP_RET(HV_VMX_CAP_PINBASED, &uCap); 896 WRITE_VMCS_RET(VMCS_CTRL_PIN_BASED, CAP_2_CTRL(uCap, PIN_BASED_INTR | PIN_BASED_NMI | PIN_BASED_VIRTUAL_NMI)); 897 READ_CAP_RET(HV_VMX_CAP_PROCBASED, &uCap); 898 WRITE_VMCS_RET(VMCS_CTRL_CPU_BASED, CAP_2_CTRL(uCap, CPU_BASED_HLT 899 | CPU_BASED_INVLPG 900 | CPU_BASED_MWAIT 901 | CPU_BASED_RDPMC 902 | CPU_BASED_RDTSC 903 | CPU_BASED_CR3_LOAD 904 | CPU_BASED_CR3_STORE 905 | CPU_BASED_CR8_LOAD 906 | CPU_BASED_CR8_STORE 907 | CPU_BASED_MOV_DR 908 | CPU_BASED_UNCOND_IO 909 | CPU_BASED_MONITOR 910 | CPU_BASED_PAUSE 911 )); 912 READ_CAP_RET(HV_VMX_CAP_PROCBASED2, &uCap); 913 WRITE_VMCS_RET(VMCS_CTRL_CPU_BASED2, CAP_2_CTRL(uCap, 0)); 914 READ_CAP_RET(HV_VMX_CAP_ENTRY, &uCap); 915 WRITE_VMCS_RET(VMCS_CTRL_VMENTRY_CONTROLS, CAP_2_CTRL(uCap, 0)); 916 #endif 917 WRITE_VMCS_RET(VMCS_CTRL_EXC_BITMAP, UINT32_MAX); 918 WRITE_VMCS_RET(VMCS_CTRL_CR0_MASK, 0x60000000); 919 WRITE_VMCS_RET(VMCS_CTRL_CR0_SHADOW, 0x00000000); 920 WRITE_VMCS_RET(VMCS_CTRL_CR4_MASK, 0x00000000); 921 WRITE_VMCS_RET(VMCS_CTRL_CR4_SHADOW, 0x00000000); 922 923 WRITE_REG_RET(HV_X86_RAX, uEax); 924 WRITE_REG_RET(HV_X86_RCX, uEcx); 925 WRITE_REG_RET(HV_X86_RDX, uEdx); 926 WRITE_REG_RET(HV_X86_RBX, uEbx); 927 WRITE_REG_RET(HV_X86_RSP, uEsp); 928 WRITE_REG_RET(HV_X86_RBP, uEbp); 929 WRITE_REG_RET(HV_X86_RSI, uEsi); 930 WRITE_REG_RET(HV_X86_RDI, uEdi); 931 WRITE_REG_RET(HV_X86_RIP, MY_TEST_RIP); 932 WRITE_REG_RET(HV_X86_RFLAGS, 2); 933 WRITE_REG_RET(HV_X86_ES, 0x0000); 934 WRITE_VMCS_RET(VMCS_GUEST_ES_BASE, 0x0000000); 935 WRITE_VMCS_RET(VMCS_GUEST_ES_LIMIT, 0xffff); 936 WRITE_VMCS_RET(VMCS_GUEST_ES_AR, 0x93); 937 WRITE_REG_RET(HV_X86_CS, 0x0000); 938 WRITE_VMCS_RET(VMCS_GUEST_CS_BASE, 0x0000000); 939 WRITE_VMCS_RET(VMCS_GUEST_CS_LIMIT, 0xffff); 940 WRITE_VMCS_RET(VMCS_GUEST_CS_AR, 0x9b); 941 WRITE_REG_RET(HV_X86_SS, 0x0000); 942 WRITE_VMCS_RET(VMCS_GUEST_SS_BASE, 0x0000000); 943 WRITE_VMCS_RET(VMCS_GUEST_SS_LIMIT, 0xffff); 944 WRITE_VMCS_RET(VMCS_GUEST_SS_AR, 0x93); 945 WRITE_REG_RET(HV_X86_DS, 0x0000); 946 WRITE_VMCS_RET(VMCS_GUEST_DS_BASE, 0x0000000); 947 WRITE_VMCS_RET(VMCS_GUEST_DS_LIMIT, 0xffff); 948 WRITE_VMCS_RET(VMCS_GUEST_DS_AR, 0x93); 949 WRITE_REG_RET(HV_X86_FS, 0x0000); 950 WRITE_VMCS_RET(VMCS_GUEST_FS_BASE, 0x0000000); 951 WRITE_VMCS_RET(VMCS_GUEST_FS_LIMIT, 0xffff); 952 WRITE_VMCS_RET(VMCS_GUEST_FS_AR, 0x93); 953 WRITE_REG_RET(HV_X86_GS, 0x0000); 954 WRITE_VMCS_RET(VMCS_GUEST_GS_BASE, 0x0000000); 955 WRITE_VMCS_RET(VMCS_GUEST_GS_LIMIT, 0xffff); 956 WRITE_VMCS_RET(VMCS_GUEST_GS_AR, 0x93); 957 //WRITE_REG_RET(HV_X86_CR0, 0x10030 /*WP+NE+ET*/); 958 WRITE_VMCS_RET(VMCS_GUEST_CR0, 0x10030 /*WP+NE+ET*/); 959 //WRITE_REG_RET(HV_X86_CR2, 0); 960 //WRITE_REG_RET(HV_X86_CR3, 0); 961 WRITE_VMCS_RET(VMCS_GUEST_CR3, 0); 962 //WRITE_REG_RET(HV_X86_CR4, 0x2000); 963 WRITE_VMCS_RET(VMCS_GUEST_CR4, 0x2000); 964 WRITE_VMCS_RET(VMCS_GUEST_LDTR, 0x0000); 965 WRITE_VMCS_RET(VMCS_GUEST_LDTR_BASE, 0x00000000); 966 WRITE_VMCS_RET(VMCS_GUEST_LDTR_LIMIT, 0x0000); 967 WRITE_VMCS_RET(VMCS_GUEST_LDTR_AR, 0x10000); 968 WRITE_VMCS_RET(VMCS_GUEST_TR, 0x0000); 969 WRITE_VMCS_RET(VMCS_GUEST_TR_BASE, 0x00000000); 970 WRITE_VMCS_RET(VMCS_GUEST_TR_LIMIT, 0x0000); 971 WRITE_VMCS_RET(VMCS_GUEST_TR_AR, 0x00083); 972 hv_vcpu_flush(g_idVCpu); 973 hv_vcpu_invalidate_tlb(g_idVCpu); 974 975 /* 976 * Run the test. 977 */ 978 uint32_t cExits = 0; 979 uint64_t const nsStart = getNanoTS(); 980 for (;; cExits++) 981 { 982 hv_return_t rcHv = hv_vcpu_run(g_idVCpu); 983 if (rcHv == HV_SUCCESS) 984 { 985 uint64_t uExitReason = UINT64_MAX; 986 READ_VMCS_RET(VMCS_RO_EXIT_REASON, &uExitReason); 987 if (!(uExitReason & UINT64_C(0x80000000))) 988 { 989 if (uExitReason == VMX_REASON_IO) 990 { 991 uint64_t uIoQual = UINT64_MAX; 992 READ_VMCS_RET(VMCS_RO_EXIT_QUALIFIC, &uIoQual); 993 if ((uint16_t)(uIoQual >> 16) == MY_NOP_PORT && (fTest & MY_TEST_F_NOP_IO)) 994 { /* likely: nop instruction */ } 995 else if ((uint16_t)(uIoQual >> 16) == MY_TERM_PORT) 996 break; 997 else 998 return runtimeError("Unexpected I/O port access (for %s): %#x\n", pszInstruction, (uint16_t)(uIoQual >> 16)); 999 1000 /* Advance RIP. */ 1001 uint64_t cbInstr = UINT64_MAX; 1002 READ_VMCS_RET(VMCS_RO_VMEXIT_INSTR_LEN, &cbInstr); 1003 if (cbInstr < 1 || cbInstr > 15) 1004 return runtimeError("Bad instr len: %#llx\n", cbInstr); 1005 uint64_t uRip = UINT64_MAX; 1006 READ_REG_RET(HV_X86_RIP, &uRip); 1007 WRITE_REG_RET(HV_X86_RIP, uRip + cbInstr); 1008 } 1009 else if (uExitReason == VMX_REASON_CPUID && (fTest & MY_TEST_F_CPUID)) 1010 { 1011 /* Set registers and advance RIP. */ 1012 WRITE_REG_RET(HV_X86_RAX, 0x42424242); 1013 WRITE_REG_RET(HV_X86_RCX, 0x04242424); 1014 WRITE_REG_RET(HV_X86_RDX, 0x00424242); 1015 WRITE_REG_RET(HV_X86_RBX, 0x00024242); 1016 1017 uint64_t cbInstr = UINT64_MAX; 1018 READ_VMCS_RET(VMCS_RO_VMEXIT_INSTR_LEN, &cbInstr); 1019 if (cbInstr < 1 || cbInstr > 15) 1020 return runtimeError("Bad instr len: %#llx\n", cbInstr); 1021 uint64_t uRip = UINT64_MAX; 1022 READ_REG_RET(HV_X86_RIP, &uRip); 1023 WRITE_REG_RET(HV_X86_RIP, uRip + cbInstr); 1024 } 1025 else if (uExitReason == VMX_REASON_EPT_VIOLATION) 1026 { 1027 uint64_t uEptQual = UINT64_MAX; 1028 READ_VMCS_RET(VMCS_RO_EXIT_QUALIFIC, &uEptQual); 1029 uint64_t GCPhys = UINT64_MAX; 1030 READ_VMCS_RET(VMCS_GUEST_PHYSICAL_ADDRESS, &GCPhys); 1031 if (GCPhys == MY_NOP_MMIO && (fTest & MY_TEST_F_NOP_MMIO)) 1032 { /* likely */ } 1033 else if (GCPhys == MY_TEST_RIP) 1034 continue; /* dunno why we get this, but restarting it works */ 1035 else 1036 return runtimeError("Unexpected EPT viotaion at %#llx\n", GCPhys); 1037 1038 /* Set RAX and advance RIP. */ 1039 WRITE_REG_RET(HV_X86_RAX, 42); 1040 1041 uint64_t cbInstr = UINT64_MAX; 1042 READ_VMCS_RET(VMCS_RO_VMEXIT_INSTR_LEN, &cbInstr); 1043 if (cbInstr < 1 || cbInstr > 15) 1044 return runtimeError("Bad instr len: %#llx\n", cbInstr); 1045 uint64_t uRip = UINT64_MAX; 1046 READ_REG_RET(HV_X86_RIP, &uRip); 1047 WRITE_REG_RET(HV_X86_RIP, uRip + cbInstr); 1048 } 1049 else if (uExitReason == VMX_REASON_IRQ) 1050 { /* ignore */ } 1051 else 1052 return runtimeError("Unexpected exit reason: %#x\n", uExitReason); 1053 } 1054 else 1055 return runtimeError("VM entry failure: %#x\n", uExitReason); 1056 } 1057 else 1058 return runtimeError("hv_vcpu_run failed (for %s): %#x\n", pszInstruction, rcHv); 1059 } 1060 uint64_t const nsElapsed = getNanoTS() - nsStart; 1061 1062 /* Report the results. */ 1063 char szTmp1[64], szTmp2[64], szTmp3[64]; 1064 uint64_t const cInstrPerSec = nsElapsed ? (uint64_t)cInstructions * 1000000000 / nsElapsed : 0; 1065 printf("%s %7s instructions per second (%s exits in %s ns)\n", 1066 formatNum(cInstrPerSec, 10, szTmp1, sizeof(szTmp1)), pszInstruction, 1067 formatNum(cExits, 0, szTmp2, sizeof(szTmp2)), 1068 formatNum(nsElapsed, 0, szTmp3, sizeof(szTmp3))); 1069 return 0; 1070 } 1071 617 1072 #else 618 1073 # error "port me" 619 1074 #endif 1075 1076 void dumpCode(uint8_t const *pb, uint8_t *pbEnd) 1077 { 1078 printf("testing:"); 1079 for (; pb != pbEnd; pb++) 1080 printf(" %02x", *pb); 1081 printf("\n"); 1082 } 620 1083 621 1084 … … 635 1098 /* JNZ MY_TEST_RIP */ 636 1099 *pb++ = 0x75; 637 *pb = (signed char)(pbStart - pb +1);1100 *pb = (signed char)(pbStart - pb - 1); 638 1101 pb++; 639 1102 /* OUT 1, AL - Temination port call. */ … … 643 1106 *pb++ = 0xeb; 644 1107 *pb++ = 0xfc; 645 646 return runRealModeTest(100000 * cFactor, "OUT", 42 /*eax*/, 10000 * cFactor /*ecx*/, MY_NOP_PORT /*edx*/, 0 /*ebx*/, 1108 dumpCode(pbStart, pb); 1109 1110 return runRealModeTest(100000 * cFactor, "OUT", MY_TEST_F_NOP_IO, 1111 42 /*eax*/, 10000 * cFactor /*ecx*/, MY_NOP_PORT /*edx*/, 0 /*ebx*/, 647 1112 0 /*esp*/, 0 /*ebp*/, 0 /*esi*/, 0 /*uEdi*/); 648 1113 } … … 659 1124 { 660 1125 /* XOR EAX,EAX */ 661 #ifndef RT_OS_LINUX /* Broken on 4.18.0, probably wrong rip advance (2 instead of 3 bytes). */662 1126 *pb++ = 0x66; 663 #endif664 1127 *pb++ = 0x33; 665 1128 *pb++ = 0xc0; … … 674 1137 /* JNZ MY_TEST_RIP */ 675 1138 *pb++ = 0x75; 676 *pb = (signed char)(pbStart - pb +1);1139 *pb = (signed char)(pbStart - pb - 1); 677 1140 pb++; 678 1141 /* OUT 1, AL - Temination port call. */ … … 682 1145 *pb++ = 0xeb; 683 1146 *pb++ = 0xfc; 684 685 return runRealModeTest(100000 * cFactor, "CPUID", 0 /*eax*/, 0 /*ecx*/, 0 /*edx*/, 0 /*ebx*/, 1147 dumpCode(pbStart, pb); 1148 1149 return runRealModeTest(100000 * cFactor, "CPUID", MY_TEST_F_CPUID, 1150 0 /*eax*/, 0 /*ecx*/, 0 /*edx*/, 0 /*ebx*/, 686 1151 0 /*esp*/, 0 /*ebp*/, 10000 * cFactor /*esi*/, 0 /*uEdi*/); 687 1152 } … … 706 1171 /* JNZ MY_TEST_RIP */ 707 1172 *pb++ = 0x75; 708 *pb = (signed char)(pbStart - pb +1);1173 *pb = (signed char)(pbStart - pb - 1); 709 1174 pb++; 710 1175 /* OUT 1, AL - Temination port call. */ … … 714 1179 *pb++ = 0xeb; 715 1180 *pb++ = 0xfc; 716 717 return runRealModeTest(100000 * cFactor, "MMIO/r1" , 0 /*eax*/, 0 /*ecx*/, 0 /*edx*/, MY_NOP_MMIO /*ebx*/, 1181 dumpCode(pbStart, pb); 1182 1183 return runRealModeTest(100000 * cFactor, "MMIO/r1", MY_TEST_F_NOP_MMIO, 1184 0 /*eax*/, 0 /*ecx*/, 0 /*edx*/, MY_NOP_MMIO /*ebx*/, 718 1185 0 /*esp*/, 0 /*ebp*/, 10000 * cFactor /*esi*/, 0 /*uEdi*/); 719 1186 } … … 728 1195 #ifdef RT_OS_WINDOWS 729 1196 unsigned const cFactorDefault = 4; 1197 #elif RT_OS_DARWIN 1198 unsigned const cFactorDefault = 32; 730 1199 #else 731 unsigned const cFactorDefault = 10;1200 unsigned const cFactorDefault = 24; 732 1201 #endif 733 1202 unsigned cFactor = cFactorDefault; … … 788 1257 mmioTest(cFactor); 789 1258 1259 790 1260 printf("tstNemMini-1: done\n"); 791 1261 } … … 805 1275 * 39088 MMIO/r1 instructions per second 806 1276 * 1277 * - Darwin/xnu 10.12.6/16.7.0; 3.1GHz Core i7-7920HQ (Kaby Lake): 1278 * 925 845 OUT instructions per second (3 200 307 exits in 3 456 301 621 ns) 1279 * 949 278 CPUID instructions per second (3 200 222 exits in 3 370 980 173 ns) 1280 * 871 499 MMIO/r1 instructions per second (3 200 223 exits in 3 671 834 221 ns) 807 1281 */
Note:
See TracChangeset
for help on using the changeset viewer.