diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/arm64/arm64_emitter.h | 2 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_0f.c | 6 | ||||
| -rw-r--r-- | src/emu/x64emu.c | 36 | ||||
| -rw-r--r-- | src/include/debug.h | 1 | ||||
| -rw-r--r-- | src/include/x64emu.h | 1 | ||||
| -rw-r--r-- | src/main.c | 26 | ||||
| -rw-r--r-- | src/tools/my_cpuid.c | 29 | ||||
| -rw-r--r-- | src/tools/rcfile.c | 18 |
8 files changed, 108 insertions, 11 deletions
diff --git a/src/dynarec/arm64/arm64_emitter.h b/src/dynarec/arm64/arm64_emitter.h index d44fa5d9..7450fdd4 100644 --- a/src/dynarec/arm64/arm64_emitter.h +++ b/src/dynarec/arm64/arm64_emitter.h @@ -769,6 +769,8 @@ #define MSR_fpsr(Rt) EMIT(MRS_gen(0, 1, 3, 4, 4, 1, Rt)) // mrs x0, cntvct_el0 op0=0b11 op1=0b011 CRn=0b1110 CRm=0b0000 op2=0b010 #define MRS_cntvct_el0(Rt) EMIT(MRS_gen(1, 1, 0b011, 0b1110, 0b0000, 0b010, Rt)) +// mrs x0, cntpctss_el0 op0=0b11 op1=0b011 CRn=0b1110 CRm=0b0000 op2=0b101 +#define MRS_cntpctss_el0(Rt) EMIT(MRS_gen(1, 1, 0b011, 0b1110, 0b0000, 0b101, Rt)) // NEON Saturation Bit #define FPSR_QC 27 // NEON Input Denormal Cumulative diff --git a/src/dynarec/arm64/dynarec_arm64_0f.c b/src/dynarec/arm64/dynarec_arm64_0f.c index a19961bd..309f9622 100644 --- a/src/dynarec/arm64/dynarec_arm64_0f.c +++ b/src/dynarec/arm64/dynarec_arm64_0f.c @@ -482,7 +482,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin case 0x31: INST_NAME("RDTSC"); NOTEST(x1); - MRS_cntvct_el0(x1); + if(box64_rdtsc) { + CALL_(ReadTSC, x1, x3); + } else { + MRS_cntvct_el0(x1); + } LSRx(xRDX, x1, 32); MOVw_REG(xRAX, x1); // wipe upper part break; diff --git a/src/emu/x64emu.c b/src/emu/x64emu.c index 77626fdc..4d8bf629 100644 --- a/src/emu/x64emu.c +++ b/src/emu/x64emu.c @@ -583,15 +583,16 @@ uint64_t ReadTSC(x64emu_t* emu) { (void)emu; - //TODO: implement hardware counter read? (only available in kernel space?) - // Read the TimeStamp Counter as 64bits. - // this is supposed to be the number of cycle executed since last reset - // fall back to gettime... + // Hardware counter, per architecture #ifdef ARM64 - uint64_t val; - asm volatile("mrs %0, cntvct_el0" : "=r" (val)); - return val; -#elif !defined(NOGETCLOCK) + if(!box64_rdtsc) { + uint64_t val; + asm volatile("mrs %0, cntvct_el0" : "=r" (val)); + return val; + } +#endif + // fall back to gettime... +#if !defined(NOGETCLOCK) struct timespec ts; clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); return (uint64_t)(ts.tv_sec) * 1000000000LL + ts.tv_nsec; @@ -602,6 +603,25 @@ uint64_t ReadTSC(x64emu_t* emu) #endif } +uint64_t ReadTSCFrequency(x64emu_t* emu) +{ + (void)emu; + // Hardware counter, per architecture +#ifdef ARM64 + if(!box64_rdtsc) { + uint64_t val; + asm volatile("mrs %0, cntfrq_el0" : "=r" (val)); + return val; + } +#endif + // fall back to get time +#if !defined(NOGETCLOCK) + return 1000000000LL; +#else + return 1000000; +#endif +} + void ResetSegmentsCache(x64emu_t *emu) { if(!emu) diff --git a/src/include/debug.h b/src/include/debug.h index 468fe5c4..59568021 100644 --- a/src/include/debug.h +++ b/src/include/debug.h @@ -13,6 +13,7 @@ extern int box64_dynarec_test; extern int box64_maxcpu; extern int box64_mmap32; extern int box64_ignoreint3; +extern int box64_rdtsc; #ifdef DYNAREC extern int box64_dynarec_dump; extern int box64_dynarec_trace; diff --git a/src/include/x64emu.h b/src/include/x64emu.h index e0adf686..450f7a63 100644 --- a/src/include/x64emu.h +++ b/src/include/x64emu.h @@ -53,6 +53,7 @@ void CallAllCleanup(x64emu_t *emu); void UnimpOpcode(x64emu_t* emu, int is32bits); uint64_t ReadTSC(x64emu_t* emu); +uint64_t ReadTSCFrequency(x64emu_t* emu); double FromLD(void* ld); // long double (80bits pointer) -> double long double LD2localLD(void* ld); // long double (80bits pointer) -> long double (80 or 128bits) diff --git a/src/main.c b/src/main.c index 000b1c9f..491bde58 100644 --- a/src/main.c +++ b/src/main.c @@ -57,6 +57,7 @@ int box64_mmap32 = 1; int box64_mmap32 = 0; #endif int box64_ignoreint3 = 0; +int box64_rdtsc = 0; #ifdef DYNAREC int box64_dynarec = 1; int box64_dynarec_dump = 0; @@ -999,6 +1000,30 @@ void LoadLogEnv() if(box64_ignoreint3) printf_log(LOG_INFO, "Will silently ignore INT3 in the code\n"); } + p = getenv("BOX64_RDTSC"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='0'+2) + box64_rdtsc = p[0]-'0'; + } + if(box64_rdtsc==2) { + #if defined(ARM64) + box64_rdtsc = 0; // allow hardxare counter + uint64_t freq = ReadTSCFrequency(NULL); + printf_log(LOG_INFO, "Hardware counter measured at %d Mhz, ", freq/1000); + if(freq>1000000000) { + printf_log(LOG_INFO, "keeping it\n"); + } else { + box64_rdtsc = 1; + printf_log(LOG_INFO, "not using it\n"); + } + #else + box64_rdtsc = 1; + printf_log(LOG_INFO, "Will use time-based emulation for rdtsc, even if hardware counter are available\n"); + #endif + } else if(box64_rdtsc) + printf_log(LOG_INFO, "Will use time-based emulation for rdtsc, even if hardware counter are available\n"); + } box64_pagesize = sysconf(_SC_PAGESIZE); if(!box64_pagesize) box64_pagesize = 4096; @@ -1140,6 +1165,7 @@ void PrintFlags() { printf(" BOX64_ENV1='XXX=yyyy' will add XXX=yyyy env. var. and continue with BOX86_ENV2 ... until var doesn't exist\n"); printf(" BOX64_JITGDB with 1 to launch \"gdb\" when a segfault is trapped, attached to the offending process\n"); printf(" BOX64_MMAP32=1 to use 32bits address space mmap in priority for external mmap as soon a 32bits process are detected (default for Snapdragon build)\n"); + printf(" BOX64_RDTSC to use a monotonic timer for rdtsc even if hardware counter are available (or check if precision is >=1Ghz for 2)\n"); } void PrintHelp() { diff --git a/src/tools/my_cpuid.c b/src/tools/my_cpuid.c index 7ee95ff0..bc584851 100644 --- a/src/tools/my_cpuid.c +++ b/src/tools/my_cpuid.c @@ -182,7 +182,7 @@ void my_cpuid(x64emu_t* emu, uint32_t tmp32u) switch(tmp32u) { case 0x0: // emulate a P4. TODO: Emulate a Core2? - R_EAX = 0x0000000F;//0x80000004; + R_EAX = 0x00000015;//0x80000004; // return GenuineIntel R_EBX = 0x756E6547; R_EDX = 0x49656E69; @@ -321,9 +321,22 @@ void my_cpuid(x64emu_t* emu, uint32_t tmp32u) default: R_EAX = 0; } break; + case 0x15: // TSC core frenquency + R_EAX = 1; // denominator + R_EBX = 1; // numerator + { + uint64_t freq = ReadTSCFrequency(emu); + while(freq>100000000) { + freq/=10; + R_EAX *= 10; + } + R_ECX = freq; // nominal frequency in Hz + } + R_EDX = 0; + break; case 0x80000000: // max extended - R_EAX = 0x80000005; + R_EAX = 0x80000007; break; case 0x80000001: //Extended Processor Signature and Feature Bits R_EAX = 0; // reserved @@ -362,6 +375,18 @@ void my_cpuid(x64emu_t* emu, uint32_t tmp32u) R_ECX = 0; R_EDX = 0; break; + case 0x80000006: // L2 cache line size and associativity + R_EAX = 0; + R_EBX = 0; + R_ECX = 0; + R_EDX = 0; + break; + case 0x80000007: // Invariant TSC + R_EAX = 0; + R_EBX = 0; + R_ECX = 0; + R_EDX = 0 | (1<<8); // Invariant TSC + break; default: printf_log(LOG_INFO, "Warning, CPUID command %X unsupported (ECX=%08x)\n", tmp32u, R_ECX); R_EAX = 0; diff --git a/src/tools/rcfile.c b/src/tools/rcfile.c index b628fb6b..9c44336c 100644 --- a/src/tools/rcfile.c +++ b/src/tools/rcfile.c @@ -10,6 +10,7 @@ #include "box64context.h" #include "fileutils.h" #include "pathcoll.h" +#include "x64emu.h" #ifdef HAVE_TRACE #include "x64trace.h" #endif @@ -88,6 +89,7 @@ ENTRYBOOL(BOX64_SHOWSEGV, box64_showsegv) \ ENTRYBOOL(BOX64_SHOWBT, box64_showbt) \ ENTRYBOOL(BOX64_MMAP32, box64_mmap32) \ ENTRYBOOL(BOX64_IGNOREINT3, box64_ignoreint3) \ +ENTRYINT(BOX64_RDTSC, box64_rdtsc, 0, 2, 2) \ ENTRYBOOL(BOX64_X11THREADS, box64_x11threads) \ ENTRYBOOL(BOX64_X11GLX, box64_x11glx) \ ENTRYDSTRING(BOX64_LIBGL, box64_libGL) \ @@ -574,6 +576,22 @@ void ApplyParams(const char* name) my_context->bashpath = strdup(param->bash); printf_log(LOG_INFO, "Applying %s=%s\n", "BOX64_BASH", param->bash); } + if(param->is_box64_rdtsc_present && (box64_rdtsc==2)) { + #if defined(ARM64) + box64_rdtsc = 0; // allow hardxware counter + uint64_t freq = ReadTSCFrequency(NULL); + printf_log(LOG_INFO, "Applying RDTSC: Hardware counter measured at %d Mhz, ", freq/1000); + if(freq>1000000000) { + printf_log(LOG_INFO, "keeping it\n"); + } else { + box64_rdtsc = 1; + printf_log(LOG_INFO, "not using it\n"); + } + #else + box64_rdtsc = 1; + printf_log(LOG_INFO, "Applying RDTSC: Will use time-based emulation for rdtsc, even if hardware counter are available\n"); + #endif + } #ifdef HAVE_TRACE int old_x64trace = my_context->x64trace; if(param->is_trace_present) { |