about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/arm64/arm64_emitter.h2
-rw-r--r--src/dynarec/arm64/dynarec_arm64_0f.c6
-rw-r--r--src/emu/x64emu.c36
-rw-r--r--src/include/debug.h1
-rw-r--r--src/include/x64emu.h1
-rw-r--r--src/main.c26
-rw-r--r--src/tools/my_cpuid.c29
-rw-r--r--src/tools/rcfile.c18
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) {