Changeset 74529 in vbox
- Timestamp:
- Sep 28, 2018 5:44:49 PM (6 years ago)
- Location:
- trunk/src/VBox/VMM/testcase
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/testcase/Makefile.kmk
r74524 r74529 411 411 # Special NEM host testcase. 412 412 # 413 if1of ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH), win.amd64)413 if1of ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH), $(if-expr "$(USERNAME)" == "bird",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 419 $(KBUILD_DEVTOOLS)/win.x86/sdk/v10.0.17134.0/include/10.0.17134.0/um \ -
trunk/src/VBox/VMM/testcase/NemRawBench-1.cpp
r74524 r74529 7 7 # include <WinHvPlatform.h> 8 8 typedef unsigned long long uint64_t; 9 10 #elif defined(RT_OS_LINUX) 11 # include <linux/kvm.h> 12 # include <errno.h> 13 # include <stdint.h> 14 # include <sys/fcntl.h> 15 # include <sys/ioctl.h> 16 # include <sys/mman.h> 17 # include <unistd.h> 18 # include <time.h> 19 9 20 #else 10 21 # error "port me" 11 22 #endif 23 24 #include <stdarg.h> 12 25 #include <stdio.h> 13 #include <stdarg.h> 26 #include <stdlib.h> 27 #include <string.h> 14 28 15 29 … … 54 68 /** @} */ 55 69 static uint64_t (WINAPI *g_pfnRtlGetSystemTimePrecise)(void); 70 71 #elif defined(RT_OS_LINUX) 72 /** The VM handle. */ 73 static int g_fdVm; 74 /** The VCPU handle. */ 75 static int g_fdVCpu; 76 /** The kvm_run structure for the VCpu. */ 77 static struct kvm_run *g_pVCpuRun; 78 /** The size of the g_pVCpuRun mapping. */ 79 static ssize_t g_cbVCpuRun; 56 80 #endif 57 81 … … 72 96 #ifdef RT_OS_WINDOWS 73 97 return g_pfnRtlGetSystemTimePrecise() * 100; 98 #elif defined(RT_OS_LINUX) 99 struct timespec ts; 100 clock_gettime(CLOCK_MONOTONIC, &ts); 101 return (uint64_t)ts.tv_sec * UINT64_C(1000000000) + ts.tv_nsec; 74 102 #else 75 103 # error "port me" … … 79 107 80 108 #ifdef RT_OS_WINDOWS 109 110 /* 111 * Windows - Hyper-V Platform API. 112 */ 81 113 82 114 static int createVM(void) … … 227 259 return 1; 228 260 } 229 230 261 231 262 … … 374 405 } 375 406 407 408 376 409 #elif defined(RT_OS_LINUX) 377 # error "port me" 410 411 /* 412 * GNU/linux - KVM 413 */ 414 415 static int createVM(void) 416 { 417 int fd = open("/dev/kvm", O_RDWR); 418 if (fd < 0) 419 return error("Error opening /dev/kvm: %d\n", errno); 420 421 g_fdVm = ioctl(fd, KVM_CREATE_VM, (uintptr_t)0); 422 if (g_fdVm < 0) 423 return error("KVM_CREATE_VM failed: %d\n", errno); 424 425 /* Create the VCpu. */ 426 g_cbVCpuRun = ioctl(fd, KVM_GET_VCPU_MMAP_SIZE, (uintptr_t)0); 427 if (g_cbVCpuRun <= 0x1000 || (g_cbVCpuRun & 0xfff)) 428 return error("Failed to get KVM_GET_VCPU_MMAP_SIZE: %#xz errno=%d\n", g_cbVCpuRun, errno); 429 430 g_fdVCpu = ioctl(g_fdVm, KVM_CREATE_VCPU, (uintptr_t)0); 431 if (g_fdVCpu < 0) 432 return error("KVM_CREATE_VCPU failed: %d\n", errno); 433 434 g_pVCpuRun = (struct kvm_run *)mmap(NULL, g_cbVCpuRun, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fdVCpu, 0); 435 if ((void *)g_pVCpuRun == MAP_FAILED) 436 return error("mmap kvm_run failed: %d\n", errno); 437 438 /* Memory. */ 439 g_pbMem = (unsigned char *)mmap(NULL, g_cbMem, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 440 if ((void *)g_pbMem == MAP_FAILED) 441 return error("mmap RAM failed: %d\n", errno); 442 443 struct kvm_userspace_memory_region MemReg; 444 MemReg.slot = 0; 445 MemReg.flags = 0; 446 MemReg.guest_phys_addr = MY_MEM_BASE; 447 MemReg.memory_size = g_cbMem; 448 MemReg.userspace_addr = (uintptr_t)g_pbMem; 449 int rc = ioctl(g_fdVm, KVM_SET_USER_MEMORY_REGION, &MemReg); 450 if (rc != 0) 451 return error("KVM_SET_USER_MEMORY_REGION failed: %d (%d)\n", errno, rc); 452 453 close(fd); 454 return 0; 455 } 456 457 458 static void printSReg(const char *pszName, struct kvm_segment const *pSReg) 459 { 460 fprintf(stderr, " %5s=%04x base=%016llx limit=%08x type=%#x p=%d dpl=%d db=%d s=%d l=%d g=%d avl=%d un=%d\n", 461 pszName, pSReg->selector, pSReg->base, pSReg->limit, pSReg->type, pSReg->present, pSReg->dpl, 462 pSReg->db, pSReg->s, pSReg->l, pSReg->g, pSReg->avl, pSReg->unusable); 463 } 464 465 466 static int runtimeError(const char *pszFormat, ...) 467 { 468 fprintf(stderr, "runtime error: "); 469 va_list va; 470 va_start(va, pszFormat); 471 vfprintf(stderr, pszFormat, va); 472 va_end(va); 473 474 fprintf(stderr, " exit_reason=%#010x\n", g_pVCpuRun->exit_reason); 475 fprintf(stderr, "ready_for_interrupt_injection=%#x\n", g_pVCpuRun->ready_for_interrupt_injection); 476 fprintf(stderr, " if_flag=%#x\n", g_pVCpuRun->if_flag); 477 fprintf(stderr, " flags=%#x\n", g_pVCpuRun->flags); 478 fprintf(stderr, " kvm_valid_regs=%#018llx\n", g_pVCpuRun->kvm_valid_regs); 479 fprintf(stderr, " kvm_dirty_regs=%#018llx\n", g_pVCpuRun->kvm_dirty_regs); 480 481 struct kvm_regs Regs; 482 memset(&Regs, 0, sizeof(Regs)); 483 struct kvm_sregs SRegs; 484 memset(&SRegs, 0, sizeof(SRegs)); 485 if ( ioctl(g_fdVCpu, KVM_GET_REGS, &Regs) != -1 486 && ioctl(g_fdVCpu, KVM_GET_SREGS, &SRegs) != -1) 487 { 488 fprintf(stderr, " rip=%016llx\n", Regs.rip); 489 printSReg("cs", &SRegs.cs); 490 fprintf(stderr, " rflags=%08llx\n", Regs.rflags); 491 fprintf(stderr, " rax=%016llx\n", Regs.rax); 492 fprintf(stderr, " rbx=%016llx\n", Regs.rcx); 493 fprintf(stderr, " rdx=%016llx\n", Regs.rdx); 494 fprintf(stderr, " rcx=%016llx\n", Regs.rbx); 495 fprintf(stderr, " rsp=%016llx\n", Regs.rsp); 496 fprintf(stderr, " rbp=%016llx\n", Regs.rbp); 497 fprintf(stderr, " rsi=%016llx\n", Regs.rsi); 498 fprintf(stderr, " rdi=%016llx\n", Regs.rdi); 499 printSReg("ss", &SRegs.ss); 500 printSReg("ds", &SRegs.ds); 501 printSReg("es", &SRegs.es); 502 printSReg("fs", &SRegs.fs); 503 printSReg("gs", &SRegs.gs); 504 printSReg("tr", &SRegs.tr); 505 printSReg("ldtr", &SRegs.ldt); 506 507 uint64_t const offMem = Regs.rip + SRegs.cs.base - MY_MEM_BASE; 508 if (offMem < g_cbMem - 10) 509 fprintf(stderr, " bytes at PC (%#zx): %02x %02x %02x %02x %02x %02x %02x %02x\n", (size_t)(offMem + MY_MEM_BASE), 510 g_pbMem[offMem ], g_pbMem[offMem + 1], g_pbMem[offMem + 2], g_pbMem[offMem + 3], 511 g_pbMem[offMem + 4], g_pbMem[offMem + 5], g_pbMem[offMem + 6], g_pbMem[offMem + 7]); 512 } 513 514 return 1; 515 } 516 517 static int runRealModeTest(unsigned cInstructions, const char *pszInstruction, 518 unsigned uEax, unsigned uEcx, unsigned uEdx, unsigned uEbx, 519 unsigned uEsp, unsigned uEbp, unsigned uEsi, unsigned uEdi) 520 { 521 /* 522 * Setup real mode context. 523 */ 524 #define SET_SEG(a_SReg, a_Base, a_Limit, a_Sel, a_fCode) \ 525 do { \ 526 a_SReg.base = (a_Base); \ 527 a_SReg.limit = (a_Limit); \ 528 a_SReg.selector = (a_Sel); \ 529 a_SReg.type = (a_fCode) ? 10 : 3; \ 530 a_SReg.present = 1; \ 531 a_SReg.dpl = 0; \ 532 a_SReg.db = 0; \ 533 a_SReg.s = 1; \ 534 a_SReg.l = 0; \ 535 a_SReg.g = 0; \ 536 a_SReg.avl = 0; \ 537 a_SReg.unusable = 0; \ 538 a_SReg.padding = 0; \ 539 } while (0) 540 struct kvm_regs Regs; 541 memset(&Regs, 0, sizeof(Regs)); 542 Regs.rax = uEax; 543 Regs.rcx = uEcx; 544 Regs.rdx = uEdx; 545 Regs.rbx = uEbx; 546 Regs.rsp = uEsp; 547 Regs.rbp = uEbp; 548 Regs.rsi = uEsi; 549 Regs.rdi = uEdi; 550 Regs.rip = MY_TEST_RIP; 551 Regs.rflags = 1; 552 int rc = ioctl(g_fdVCpu, KVM_SET_REGS, &Regs); 553 if (rc != 0) 554 return error("KVM_SET_REGS failed: %d (rc=%d)\n", errno, rc); 555 556 struct kvm_sregs SRegs; 557 memset(&SRegs, 0, sizeof(SRegs)); 558 rc = ioctl(g_fdVCpu, KVM_GET_SREGS, &SRegs); 559 if (rc != 0) 560 return error("KVM_GET_SREGS failed: %d (rc=%d)\n", errno, rc); 561 SET_SEG(SRegs.es, 0x00000, 0xffff, 0x0000, 0); 562 SET_SEG(SRegs.cs, 0x00000, 0xffff, 0x0000, 1); 563 SET_SEG(SRegs.ss, 0x00000, 0xffff, 0x0000, 0); 564 SET_SEG(SRegs.ds, 0x00000, 0xffff, 0x0000, 0); 565 SET_SEG(SRegs.fs, 0x00000, 0xffff, 0x0000, 0); 566 SET_SEG(SRegs.gs, 0x00000, 0xffff, 0x0000, 0); 567 //SRegs.cr0 = 0x10010 /*WP+ET*/; 568 SRegs.cr2 = 0; 569 //SRegs.cr3 = 0; 570 //SRegs.cr4 = 0; 571 rc = ioctl(g_fdVCpu, KVM_SET_SREGS, &SRegs); 572 if (rc != 0) 573 return error("KVM_SET_SREGS failed: %d (rc=%d)\n", errno, rc); 574 575 /* 576 * Run the test. 577 */ 578 uint64_t const nsStart = getNanoTS(); 579 for (;;) 580 { 581 rc = ioctl(g_fdVCpu, KVM_RUN, (uintptr_t)0); 582 if (rc == 0) 583 { 584 if (g_pVCpuRun->exit_reason == KVM_EXIT_IO) 585 { 586 if (g_pVCpuRun->io.port == MY_NOP_PORT) 587 { /* likely: nop instruction */ } 588 else if (g_pVCpuRun->io.port == MY_TERM_PORT) 589 break; 590 else 591 return runtimeError("Unexpected I/O port access (for %s): %#x\n", pszInstruction, g_pVCpuRun->io.port); 592 } 593 else if (g_pVCpuRun->exit_reason == KVM_EXIT_MMIO) 594 { 595 if (g_pVCpuRun->mmio.phys_addr == MY_NOP_MMIO) 596 { /* likely: nop address */ } 597 else 598 return runtimeError("Unexpected memory access (for %s): %#llx\n", pszInstruction, g_pVCpuRun->mmio.phys_addr); 599 } 600 else 601 return runtimeError("Unexpected exit (for %s): %d\n", pszInstruction, g_pVCpuRun->exit_reason); 602 } 603 else 604 return runtimeError("KVM_RUN failed (for %s): %#x (ret %d)\n", pszInstruction, errno, rc); 605 } 606 uint64_t const nsElapsed = getNanoTS() - nsStart; 607 608 /* Report the results. */ 609 uint64_t const cInstrPerSec = nsElapsed ? (uint64_t)cInstructions * 1000000000 / nsElapsed : 0; 610 printf("%10u %s instructions per second\n", (unsigned)cInstrPerSec, pszInstruction); 611 return 0; 612 } 613 614 378 615 #elif defined(RT_OS_DARWIN) 379 616 # error "port me" … … 383 620 384 621 385 staticint ioportTest(unsigned cFactor)622 int ioportTest(unsigned cFactor) 386 623 { 387 624 /* … … 398 635 /* JNZ MY_TEST_RIP */ 399 636 *pb++ = 0x75; 400 *pb++ = (signed char)(pbStart - pb + 1); 637 *pb = (signed char)(pbStart - pb + 1); 638 pb++; 401 639 /* OUT 1, AL - Temination port call. */ 402 640 *pb++ = 0xe6; … … 411 649 412 650 413 staticint cpuidTest(unsigned cFactor)651 int cpuidTest(unsigned cFactor) 414 652 { 415 653 /* … … 421 659 { 422 660 /* XOR EAX,EAX */ 661 #ifndef RT_OS_LINUX /* Broken on 4.18.0, probably wrong rip advance (2 instead of 3 bytes). */ 423 662 *pb++ = 0x66; 663 #endif 424 664 *pb++ = 0x33; 425 665 *pb++ = 0xc0; … … 434 674 /* JNZ MY_TEST_RIP */ 435 675 *pb++ = 0x75; 436 *pb++ = (signed char)(pbStart - pb + 1); 676 *pb = (signed char)(pbStart - pb + 1); 677 pb++; 437 678 /* OUT 1, AL - Temination port call. */ 438 679 *pb++ = 0xe6; … … 447 688 448 689 449 staticint mmioTest(unsigned cFactor)690 int mmioTest(unsigned cFactor) 450 691 { 451 692 /* … … 465 706 /* JNZ MY_TEST_RIP */ 466 707 *pb++ = 0x75; 467 *pb++ = (signed char)(pbStart - pb + 1); 708 *pb = (signed char)(pbStart - pb + 1); 709 pb++; 468 710 /* OUT 1, AL - Temination port call. */ 469 711 *pb++ = 0xe6; … … 541 783 */ 542 784 ioportTest(cFactor); 785 #ifndef RT_OS_LINUX 543 786 cpuidTest(cFactor); 787 #endif 544 788 mmioTest(cFactor); 545 789 … … 548 792 return rcExit; 549 793 } 794 795 /* 796 * Results: 797 * 798 * - Linux 4.18.0-1-amd64 (debian); AMD Threadripper: 799 * 545108 OUT instructions per second 800 * 373159 MMIO/r1 instructions per second 801 * 802 * 803 */
Note:
See TracChangeset
for help on using the changeset viewer.