about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt3
-rw-r--r--src/core.c174
-rw-r--r--src/dynarec/la64/la64_lock.h2
-rw-r--r--src/include/core_arch.h50
-rw-r--r--src/include/debug.h2
-rw-r--r--src/include/hostext.h52
-rw-r--r--src/os/hostext_common.c64
-rw-r--r--src/os/hostext_linux.c227
-rw-r--r--src/os/hostext_wine.c20
-rw-r--r--src/rv64detect.c126
-rw-r--r--wine/common/wrt.c5
-rw-r--r--wine/include/wine/compiler.h1
-rw-r--r--wine/wow64/CMakeLists.txt2
-rw-r--r--wine/wow64/wowbox64.c11
14 files changed, 391 insertions, 348 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4036a282..32b59734 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -364,6 +364,8 @@ set_source_files_properties(
 set(OS_LINUX_SRC
     "${BOX64_ROOT}/src/os/backtrace.c"
     "${BOX64_ROOT}/src/os/emit_signals_linux.c"
+    "${BOX64_ROOT}/src/os/hostext_common.c"
+    "${BOX64_ROOT}/src/os/hostext_linux.c"
     "${BOX64_ROOT}/src/os/freq_linux.c"
     "${BOX64_ROOT}/src/os/os_linux.c"
     "${BOX64_ROOT}/src/os/perfmap.c"
@@ -1003,7 +1005,6 @@ if(RV64_DYNAREC)
         "${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_arch.c"
         "${BOX64_ROOT}/src/dynarec/rv64/rv64_printer.c"
         "${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_jmpnext.c"
-        "${BOX64_ROOT}/src/rv64detect.c"
         )
     set(DYNAREC_ASM
         ${DYNAREC_ASM}
diff --git a/src/core.c b/src/core.c
index 059003b3..dae932a6 100644
--- a/src/core.c
+++ b/src/core.c
@@ -16,10 +16,6 @@
 #include <stdarg.h>
 #include <ctype.h>
 #ifdef DYNAREC
-#ifdef ARM64
-#include <linux/auxvec.h>
-#include <asm/hwcap.h>
-#endif
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -49,7 +45,7 @@
 #include "env.h"
 #include "cleanup.h"
 #include "freq.h"
-#include "core_arch.h"
+#include "hostext.h"
 
 box64context_t *my_context = NULL;
 extern box64env_t box64env;
@@ -186,166 +182,6 @@ void my_child_fork()
 const char* getCpuName();
 int getNCpuUnmasked();
 
-#ifdef DYNAREC
-void GatherDynarecExtensions()
-{
-#ifdef ARM64
-    unsigned long hwcap = real_getauxval(AT_HWCAP);
-    if(!hwcap)
-        hwcap = HWCAP_ASIMD;
-    // first, check all needed extensions, lif half, edsp and fastmult
-    if((hwcap&HWCAP_ASIMD) == 0) {
-        printf_log(LOG_INFO, "Missing ASMID cpu support, disabling Dynarec\n");
-        SET_BOX64ENV(dynarec, 0);
-        return;
-    }
-    if(hwcap&HWCAP_CRC32)
-        cpuext.crc32 = 1;
-    if(hwcap&HWCAP_PMULL)
-        cpuext.pmull = 1;
-    if(hwcap&HWCAP_AES)
-        cpuext.aes = 1;
-    if(hwcap&HWCAP_ATOMICS)
-        cpuext.atomics = 1;
-    #ifdef HWCAP_SHA1
-    if(hwcap&HWCAP_SHA1)
-        cpuext.sha1 = 1;
-    #endif
-    #ifdef HWCAP_SHA2
-    if(hwcap&HWCAP_SHA2)
-        cpuext.sha2 = 1;
-    #endif
-    #ifdef HWCAP_USCAT
-    if(hwcap&HWCAP_USCAT)
-        cpuext.uscat = 1;
-    #endif
-    #ifdef HWCAP_FLAGM
-    if(hwcap&HWCAP_FLAGM)
-        cpuext.flagm = 1;
-    #endif
-    unsigned long hwcap2 = real_getauxval(AT_HWCAP2);
-    #ifdef HWCAP2_FLAGM2
-    if(hwcap2&HWCAP2_FLAGM2)
-        cpuext.flagm2 = 1;
-    #endif
-    #ifdef HWCAP2_FRINT
-    if(hwcap2&HWCAP2_FRINT)
-        cpuext.frintts = 1;
-    #endif
-    #ifdef HWCAP2_AFP
-    if(hwcap2&HWCAP2_AFP)
-        cpuext.afp = 1;
-    #endif
-    #ifdef HWCAP2_RNG
-    if(hwcap2&HWCAP2_RNG)
-        cpuext.rndr = 1;
-    #endif
-    printf_log(LOG_INFO, "Dynarec for ARM64, with extension: ASIMD");
-    if(cpuext.aes)
-        printf_log_prefix(0, LOG_INFO, " AES");
-    if(cpuext.crc32)
-        printf_log_prefix(0, LOG_INFO, " CRC32");
-    if(cpuext.pmull)
-        printf_log_prefix(0, LOG_INFO, " PMULL");
-    if(cpuext.atomics)
-        printf_log_prefix(0, LOG_INFO, " ATOMICS");
-    if(cpuext.sha1)
-        printf_log_prefix(0, LOG_INFO, " SHA1");
-    if(cpuext.sha2)
-        printf_log_prefix(0, LOG_INFO, " SHA2");
-    if(cpuext.uscat)
-        printf_log_prefix(0, LOG_INFO, " USCAT");
-    if(cpuext.flagm)
-        printf_log_prefix(0, LOG_INFO, " FLAGM");
-    if(cpuext.flagm2)
-        printf_log_prefix(0, LOG_INFO, " FLAGM2");
-    if(cpuext.frintts)
-        printf_log_prefix(0, LOG_INFO, " FRINT");
-    if(cpuext.afp)
-        printf_log_prefix(0, LOG_INFO, " AFP");
-    if(cpuext.rndr)
-        printf_log_prefix(0, LOG_INFO, " RNDR");
-    printf_log_prefix(0, LOG_INFO, "\n");
-#elif defined(LA64)
-    printf_log(LOG_INFO, "Dynarec for LoongArch ");
-    char* p = getenv("BOX64_DYNAREC_LA64NOEXT");
-    if(p == NULL || p[0] == '0') {
-        uint32_t cpucfg2 = 0, idx = 2;
-        asm volatile("cpucfg %0, %1" : "=r"(cpucfg2) : "r"(idx));
-        if (((cpucfg2 >> 6) & 0b11) == 3) {
-            printf_log_prefix(0, LOG_INFO, "with extension LSX LASX");
-        } else {
-            printf_log(LOG_INFO, "\nMissing LSX and/or LASX extension support, disabling Dynarec\n");
-            SET_BOX64ENV(dynarec, 0);
-            return;
-        }
-
-        if (cpuext.lbt = ((cpucfg2 >> 18) & 0b1))
-            printf_log_prefix(0, LOG_INFO, " LBT_X86");
-        if ((cpuext.lam_bh = (cpucfg2 >> 27) & 0b1))
-            printf_log_prefix(0, LOG_INFO, " LAM_BH");
-        if ((cpuext.lamcas = (cpucfg2 >> 28) & 0b1))
-            printf_log_prefix(0, LOG_INFO, " LAMCAS");
-        if ((cpuext.scq = (cpucfg2 >> 30) & 0b1))
-            printf_log_prefix(0, LOG_INFO, " SCQ");
-    }
-    printf_log_prefix(0, LOG_INFO, "\n");
-#elif defined(RV64)
-    void RV64_Detect_Function();
-    // private env. variable for the developer ;)
-    char *p = getenv("BOX64_DYNAREC_RV64NOEXT");
-    if(p == NULL || strcasecmp(p, "1")) {
-        RV64_Detect_Function();
-        if (p) {
-            p = strtok(p, ",");
-            while (p) {
-                if (!strcasecmp(p, "zba")) cpuext.zba = 0;
-                if (!strcasecmp(p, "zbb")) cpuext.zbb = 0;
-                if (!strcasecmp(p, "zbc")) cpuext.zbc = 0;
-                if (!strcasecmp(p, "zbs")) cpuext.zbs = 0;
-                if (!strcasecmp(p, "vector")) {
-                    cpuext.vector = 0;
-                    cpuext.xtheadvector = 0;
-                }
-                if (!strcasecmp(p, "xtheadba")) cpuext.xtheadba = 0;
-                if (!strcasecmp(p, "xtheadbb")) cpuext.xtheadbb = 0;
-                if (!strcasecmp(p, "xtheadbs")) cpuext.xtheadbs = 0;
-                if (!strcasecmp(p, "xtheadmemidx")) cpuext.xtheadmemidx = 0;
-                // if (!strcasecmp(p, "xtheadfmemidx")) cpuext.xtheadfmemidx = 0;
-                // if (!strcasecmp(p, "xtheadmac")) cpuext.xtheadmac = 0;
-                // if (!strcasecmp(p, "xtheadfmv")) cpuext.xtheadfmv = 0;
-                if (!strcasecmp(p, "xtheadmempair")) cpuext.xtheadmempair = 0;
-                if (!strcasecmp(p, "xtheadcondmov")) cpuext.xtheadcondmov = 0;
-                p = strtok(NULL, ",");
-            }
-        }
-    }
-
-    printf_log(LOG_INFO, "Dynarec for rv64g");
-    if (cpuext.vector && !cpuext.xtheadvector) printf_log_prefix(0, LOG_INFO, "v");
-    if (cpuext.zba) printf_log_prefix(0, LOG_INFO, "_zba");
-    if (cpuext.zbb) printf_log_prefix(0, LOG_INFO, "_zbb");
-    if (cpuext.zbc) printf_log_prefix(0, LOG_INFO, "_zbc");
-    if (cpuext.zbs) printf_log_prefix(0, LOG_INFO, "_zbs");
-    if (cpuext.vector && !cpuext.xtheadvector) printf_log_prefix(0, LOG_INFO, "_zvl%d", cpuext.vlen*8);
-    if (cpuext.xtheadba) printf_log_prefix(0, LOG_INFO, "_xtheadba");
-    if (cpuext.xtheadbb) printf_log_prefix(0, LOG_INFO, "_xtheadbb");
-    if (cpuext.xtheadbs) printf_log_prefix(0, LOG_INFO, "_xtheadbs");
-    if (cpuext.xtheadmempair) printf_log_prefix(0, LOG_INFO, "_xtheadmempair");
-    if (cpuext.xtheadcondmov) printf_log_prefix(0, LOG_INFO, "_xtheadcondmov");
-    if (cpuext.xtheadmemidx) printf_log_prefix(0, LOG_INFO, "_xtheadmemidx");
-    // Disable the display since these are only detected but never used.
-    // if(cpuext.xtheadfmemidx) printf_log_prefix(0, LOG_INFO, " xtheadfmemidx");
-    // if(cpuext.xtheadmac) printf_log_prefix(0, LOG_INFO, " xtheadmac");
-    // if(cpuext.xtheadfmv) printf_log_prefix(0, LOG_INFO, " xtheadfmv");
-    if (cpuext.xtheadvector) printf_log_prefix(0, LOG_INFO, "_xthvector");
-    printf_log_prefix(0, LOG_INFO, "\n");
-#else
-#error Unsupported architecture
-#endif
-}
-#endif
-
 void computeRDTSC()
 {
     int hardware  = 0;
@@ -405,8 +241,12 @@ static void displayMiscInfo()
         box64_pagesize = 4096;
 
 #ifdef DYNAREC
-    // grab cpu extensions for dynarec usage
-    GatherDynarecExtensions();
+    if (DetectHostCpuFeatures())
+        PrintHostCpuFeatures();
+    else {
+        printf_log(LOG_INFO, "Minimum CPU requirements not met, disabling DynaRec\n");
+        SET_BOX64ENV(dynarec, 0);
+    }
 #endif
 
     // grab ncpu and cpu name
diff --git a/src/dynarec/la64/la64_lock.h b/src/dynarec/la64/la64_lock.h
index c5175c2e..e51267fe 100644
--- a/src/dynarec/la64/la64_lock.h
+++ b/src/dynarec/la64/la64_lock.h
@@ -1,7 +1,7 @@
 #ifndef __LA64_LOCK__H__
 #define __LA64_LOCK__H__
 #include <stdint.h>
-#include "core_arch.h"
+#include "hostext.h"
 
 extern cpu_ext_t cpuext;
 
diff --git a/src/include/core_arch.h b/src/include/core_arch.h
deleted file mode 100644
index f297bcb8..00000000
--- a/src/include/core_arch.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef __CORE_ARCH_H__
-#define __CORE_ARCH_H__
-#include <stdint.h>
-
-#ifdef DYNAREC
-typedef union cpu_ext_s {
-    struct {
-#ifdef ARM64
- uint64_t atomics:1;    // it's important this is the 1st bit
- uint64_t asimd:1;
- uint64_t aes:1;
- uint64_t pmull:1;
- uint64_t crc32:1;
- uint64_t sha1:1;
- uint64_t sha2:1;
- uint64_t uscat:1;
- uint64_t flagm:1;
- uint64_t flagm2:1;
- uint64_t frintts:1;
- uint64_t afp:1;
- uint64_t rndr:1;
-#elif defined(RV64)
-uint64_t vlen:8;  // Not *8, 8bits should be enugh? that's 2048 vector
- uint64_t zba:1;
- uint64_t zbb:1;
- uint64_t zbc:1;
- uint64_t zbs:1;
- uint64_t vector:1; // rvv 1.0 or xtheadvector
- uint64_t xtheadvector:1;
- uint64_t xtheadba:1;
- uint64_t xtheadbb:1;
- uint64_t xtheadbs:1;
- uint64_t xtheadcondmov:1;
- uint64_t xtheadmemidx:1;
- uint64_t xtheadmempair:1;
- uint64_t xtheadfmemidx:1;
- uint64_t xtheadmac:1;
- uint64_t xtheadfmv:1;
-#elif defined(LA64)
- uint64_t lbt:1;    // it's important it's stay the 1st bit
- uint64_t lam_bh:1;
- uint64_t lamcas:1;
- uint64_t scq:1;
-#endif
-    };
-    uint64_t x;
-} cpu_ext_t;
-#endif
-
-#endif //__CORE_ARCH_H__
\ No newline at end of file
diff --git a/src/include/debug.h b/src/include/debug.h
index 57520cbd..a4b2ee53 100644
--- a/src/include/debug.h
+++ b/src/include/debug.h
@@ -4,7 +4,7 @@
 #include <env.h>
 
 #include "os.h"
-#include "core_arch.h"
+#include "hostext.h"
 
 typedef struct box64context_s box64context_t;
 extern box64env_t box64env;
diff --git a/src/include/hostext.h b/src/include/hostext.h
new file mode 100644
index 00000000..579e76ac
--- /dev/null
+++ b/src/include/hostext.h
@@ -0,0 +1,52 @@
+#ifndef __HOSTEXT_H__
+#define __HOSTEXT_H__
+
+#include <stdint.h>
+
+typedef union cpu_ext_s {
+    struct {
+#ifdef ARM64
+        uint64_t atomics : 1; // it's important this is the 1st bit
+        uint64_t asimd : 1;
+        uint64_t aes : 1;
+        uint64_t pmull : 1;
+        uint64_t crc32 : 1;
+        uint64_t sha1 : 1;
+        uint64_t sha2 : 1;
+        uint64_t uscat : 1;
+        uint64_t flagm : 1;
+        uint64_t flagm2 : 1;
+        uint64_t frintts : 1;
+        uint64_t afp : 1;
+        uint64_t rndr : 1;
+#elif defined(RV64)
+        uint64_t vlen : 8; // Not *8, 8bits should be enugh? that's 2048 vector
+        uint64_t zba : 1;
+        uint64_t zbb : 1;
+        uint64_t zbc : 1;
+        uint64_t zbs : 1;
+        uint64_t vector : 1; // rvv 1.0 or xtheadvector
+        uint64_t xtheadvector : 1;
+        uint64_t xtheadba : 1;
+        uint64_t xtheadbb : 1;
+        uint64_t xtheadbs : 1;
+        uint64_t xtheadcondmov : 1;
+        uint64_t xtheadmemidx : 1;
+        uint64_t xtheadmempair : 1;
+        uint64_t xtheadfmemidx : 1;
+        uint64_t xtheadmac : 1;
+        uint64_t xtheadfmv : 1;
+#elif defined(LA64)
+        uint64_t lbt : 1; // it's important it's stay the 1st bit
+        uint64_t lam_bh : 1;
+        uint64_t lamcas : 1;
+        uint64_t scq : 1;
+#endif
+    };
+    uint64_t x;
+} cpu_ext_t;
+
+int DetectHostCpuFeatures(void);
+void PrintHostCpuFeatures(void);
+
+#endif //__HOSTEXT_H__
\ No newline at end of file
diff --git a/src/os/hostext_common.c b/src/os/hostext_common.c
new file mode 100644
index 00000000..258e1af4
--- /dev/null
+++ b/src/os/hostext_common.c
@@ -0,0 +1,64 @@
+#include "debug.h"
+
+void PrintHostCpuFeatures(void)
+{
+#ifdef ARM64
+    printf_log(LOG_INFO, "Dynarec for ARM64, with extension: ASIMD");
+    if(cpuext.aes)
+        printf_log_prefix(0, LOG_INFO, " AES");
+    if(cpuext.crc32)
+        printf_log_prefix(0, LOG_INFO, " CRC32");
+    if(cpuext.pmull)
+        printf_log_prefix(0, LOG_INFO, " PMULL");
+    if(cpuext.atomics)
+        printf_log_prefix(0, LOG_INFO, " ATOMICS");
+    if(cpuext.sha1)
+        printf_log_prefix(0, LOG_INFO, " SHA1");
+    if(cpuext.sha2)
+        printf_log_prefix(0, LOG_INFO, " SHA2");
+    if(cpuext.uscat)
+        printf_log_prefix(0, LOG_INFO, " USCAT");
+    if(cpuext.flagm)
+        printf_log_prefix(0, LOG_INFO, " FLAGM");
+    if(cpuext.flagm2)
+        printf_log_prefix(0, LOG_INFO, " FLAGM2");
+    if(cpuext.frintts)
+        printf_log_prefix(0, LOG_INFO, " FRINT");
+    if(cpuext.afp)
+        printf_log_prefix(0, LOG_INFO, " AFP");
+    if(cpuext.rndr)
+        printf_log_prefix(0, LOG_INFO, " RNDR");
+    printf_log_prefix(0, LOG_INFO, "\n");
+#elif defined(LA64)
+    printf_log(LOG_INFO, "Dynarec for LoongArch with extension LSX LASX");
+    if (cpuext.lbt)
+        printf_log_prefix(0, LOG_INFO, " LBT_X86");
+    if (cpuext.lam_bh)
+        printf_log_prefix(0, LOG_INFO, " LAM_BH");
+    if (cpuext.lamcas)
+        printf_log_prefix(0, LOG_INFO, " LAMCAS");
+    if (cpuext.scq)
+        printf_log_prefix(0, LOG_INFO, " SCQ");
+    printf_log_prefix(0, LOG_INFO, "\n");
+#elif defined(RV64)
+    printf_log(LOG_INFO, "Dynarec for rv64g");
+    if (cpuext.vector && !cpuext.xtheadvector) printf_log_prefix(0, LOG_INFO, "v");
+    if (cpuext.zba) printf_log_prefix(0, LOG_INFO, "_zba");
+    if (cpuext.zbb) printf_log_prefix(0, LOG_INFO, "_zbb");
+    if (cpuext.zbc) printf_log_prefix(0, LOG_INFO, "_zbc");
+    if (cpuext.zbs) printf_log_prefix(0, LOG_INFO, "_zbs");
+    if (cpuext.vector && !cpuext.xtheadvector) printf_log_prefix(0, LOG_INFO, "_zvl%d", cpuext.vlen * 8);
+    if (cpuext.xtheadba) printf_log_prefix(0, LOG_INFO, "_xtheadba");
+    if (cpuext.xtheadbb) printf_log_prefix(0, LOG_INFO, "_xtheadbb");
+    if (cpuext.xtheadbs) printf_log_prefix(0, LOG_INFO, "_xtheadbs");
+    if (cpuext.xtheadmempair) printf_log_prefix(0, LOG_INFO, "_xtheadmempair");
+    if (cpuext.xtheadcondmov) printf_log_prefix(0, LOG_INFO, "_xtheadcondmov");
+    if (cpuext.xtheadmemidx) printf_log_prefix(0, LOG_INFO, "_xtheadmemidx");
+    // Disable the display since these are only detected but never used.
+    // if(cpuext.xtheadfmemidx) printf_log_prefix(0, LOG_INFO, " xtheadfmemidx");
+    // if(cpuext.xtheadmac) printf_log_prefix(0, LOG_INFO, " xtheadmac");
+    // if(cpuext.xtheadfmv) printf_log_prefix(0, LOG_INFO, " xtheadfmv");
+    if (cpuext.xtheadvector) printf_log_prefix(0, LOG_INFO, "_xthvector");
+    printf_log_prefix(0, LOG_INFO, "\n");
+#endif
+}
\ No newline at end of file
diff --git a/src/os/hostext_linux.c b/src/os/hostext_linux.c
new file mode 100644
index 00000000..60c6a21f
--- /dev/null
+++ b/src/os/hostext_linux.c
@@ -0,0 +1,227 @@
+#include "auxval.h"
+#include "debug.h"
+
+
+#ifdef ARM64
+#include <linux/auxvec.h>
+#include <asm/hwcap.h>
+#endif
+
+#ifdef RV64
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include "dynarec/rv64/rv64_emitter.h"
+
+
+// Detect RV64 extensions, by executing on of the opcode with a SIGILL signal handler
+
+static sigjmp_buf sigbuf = {0};
+typedef int (*iFiip_t)(int, int, void*);
+static void detect_sigill(int sig)
+{
+    siglongjmp(sigbuf, 1);
+}
+
+static int Check(void* block)
+{
+    static uint64_t buf[2] = {0};
+    // Clear instruction cache
+    __clear_cache(block, block+box64_pagesize);
+    // Setup SIGILL signal handler
+    __sighandler_t old = signal(SIGILL, detect_sigill);
+    if(sigsetjmp(sigbuf, 1)) {
+        // didn't work, extension not present
+        signal(SIGILL, old);
+        return 0;
+    }
+    int result = ((iFiip_t)block)(0, 1, buf);
+    if (result != 42) {
+        // wrong result, extension not present
+        signal(SIGILL, old);
+        return 0;
+    }
+    // done...
+    signal(SIGILL, old);
+    return 1;
+}
+
+void rv64Detect(void)
+{
+    // Alloc memory to execute stuffs
+    void* my_block = mmap(NULL, box64_pagesize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+    if(my_block==(void*)-1) {
+        return;
+    }
+    uint32_t* block;
+    #define EMIT(A) *block = (A); ++block
+
+
+    // THead vendor extensions
+    block = (uint32_t*)my_block;
+    ADDI(A0, xZR, 40);
+    ADDI(A1, xZR, 1);
+    TH_ADDSL(A0, A0, A1, 1);
+    BR(xRA);
+    cpuext.xtheadba
+        = cpuext.xtheadbb
+        = cpuext.xtheadbs
+        = cpuext.xtheadcondmov
+        = cpuext.xtheadmemidx
+        = cpuext.xtheadmempair
+        = cpuext.xtheadfmemidx
+        = cpuext.xtheadmac
+        = cpuext.xtheadfmv = Check(my_block);
+
+    // Official extensions
+
+    if (!cpuext.xtheadba) {
+        // Test Zba with ADDUW
+        block = (uint32_t*)my_block;
+        ADDUW(A0, A0, A1);
+        ADDI(A0, xZR, 42);
+        BR(xRA);
+        cpuext.zba = Check(my_block);
+        // Test Zbb with ANDN
+        block = (uint32_t*)my_block;
+        ANDN(A0, A0, A1);
+        ADDI(A0, xZR, 42);
+        BR(xRA);
+        cpuext.zbb = Check(my_block);
+        // Test Zbc with CLMUL
+        block = (uint32_t*)my_block;
+        CLMUL(A0, A0, A1);
+        ADDI(A0, xZR, 42);
+        BR(xRA);
+        cpuext.zbc = Check(my_block);
+        // Test Zbs with BCLR
+        block = (uint32_t*)my_block;
+        BCLR(A0, A0, A1);
+        ADDI(A0, xZR, 42);
+        BR(xRA);
+        cpuext.zbs = Check(my_block);
+    }
+
+    block = (uint32_t*)my_block;
+    CSRRS(xZR, xZR, 0xc22 /* vlenb */);
+    ADDI(A0, xZR, 42);
+    BR(xRA);
+    cpuext.vector = Check(my_block);
+
+    if (cpuext.vector) {
+        block = (uint32_t*)my_block;
+        CSRRS(xZR, xZR, 0x00f /* vcsr */); // vcsr does not exists in xtheadvector
+        ADDI(A0, xZR, 42);
+        BR(xRA);
+        cpuext.xtheadvector = !Check(my_block);
+    }
+
+    if (cpuext.vector) {
+        int vlenb = 0;
+        asm volatile("csrr %0, 0xc22" : "=r"(vlenb));
+        cpuext.vlen = vlenb;
+        if (vlenb < 16) {
+            // we need vlen >= 128
+            cpuext.vector = 0;
+        }
+    }
+
+    // Finish
+    // Free the memory my_block
+    munmap(my_block, box64_pagesize);
+}
+#endif
+
+int DetectHostCpuFeatures(void)
+{
+#ifdef ARM64
+    unsigned long hwcap = real_getauxval(AT_HWCAP);
+    if(!hwcap)
+        hwcap = HWCAP_ASIMD;
+    // first, check all needed extensions, lif half, edsp and fastmult
+    if ((hwcap & HWCAP_ASIMD) == 0) return 0;
+    if(hwcap&HWCAP_CRC32)
+        cpuext.crc32 = 1;
+    if(hwcap&HWCAP_PMULL)
+        cpuext.pmull = 1;
+    if(hwcap&HWCAP_AES)
+        cpuext.aes = 1;
+    if(hwcap&HWCAP_ATOMICS)
+        cpuext.atomics = 1;
+    #ifdef HWCAP_SHA1
+    if(hwcap&HWCAP_SHA1)
+        cpuext.sha1 = 1;
+    #endif
+    #ifdef HWCAP_SHA2
+    if(hwcap&HWCAP_SHA2)
+        cpuext.sha2 = 1;
+    #endif
+    #ifdef HWCAP_USCAT
+    if(hwcap&HWCAP_USCAT)
+        cpuext.uscat = 1;
+    #endif
+    #ifdef HWCAP_FLAGM
+    if(hwcap&HWCAP_FLAGM)
+        cpuext.flagm = 1;
+    #endif
+    unsigned long hwcap2 = real_getauxval(AT_HWCAP2);
+    #ifdef HWCAP2_FLAGM2
+    if(hwcap2&HWCAP2_FLAGM2)
+        cpuext.flagm2 = 1;
+    #endif
+    #ifdef HWCAP2_FRINT
+    if(hwcap2&HWCAP2_FRINT)
+        cpuext.frintts = 1;
+    #endif
+    #ifdef HWCAP2_AFP
+    if(hwcap2&HWCAP2_AFP)
+        cpuext.afp = 1;
+    #endif
+    #ifdef HWCAP2_RNG
+    if(hwcap2&HWCAP2_RNG)
+        cpuext.rndr = 1;
+    #endif
+#elif defined(LA64)
+    char* p = getenv("BOX64_DYNAREC_LA64NOEXT");
+    if(p == NULL || p[0] == '0') {
+        uint32_t cpucfg2 = 0, idx = 2;
+        asm volatile("cpucfg %0, %1" : "=r"(cpucfg2) : "r"(idx));
+        if (((cpucfg2 >> 6) & 0b11) != 3) return 0; // LSX/LASX must present
+
+        cpuext.lbt = (cpucfg2 >> 18) & 0b1;
+        cpuext.lam_bh = (cpucfg2 >> 27) & 0b1;
+        cpuext.lamcas = (cpucfg2 >> 28) & 0b1;
+        cpuext.scq = (cpucfg2 >> 30) & 0b1;
+    }
+#elif defined(RV64)
+    // private env. variable for the developer ;)
+    char *p = getenv("BOX64_DYNAREC_RV64NOEXT");
+    if(p == NULL || strcasecmp(p, "1")) {
+        rv64Detect();
+        if (p) {
+            p = strtok(p, ",");
+            while (p) {
+                if (!strcasecmp(p, "zba")) cpuext.zba = 0;
+                if (!strcasecmp(p, "zbb")) cpuext.zbb = 0;
+                if (!strcasecmp(p, "zbc")) cpuext.zbc = 0;
+                if (!strcasecmp(p, "zbs")) cpuext.zbs = 0;
+                if (!strcasecmp(p, "vector")) {
+                    cpuext.vector = 0;
+                    cpuext.xtheadvector = 0;
+                }
+                if (!strcasecmp(p, "xtheadba")) cpuext.xtheadba = 0;
+                if (!strcasecmp(p, "xtheadbb")) cpuext.xtheadbb = 0;
+                if (!strcasecmp(p, "xtheadbs")) cpuext.xtheadbs = 0;
+                if (!strcasecmp(p, "xtheadmemidx")) cpuext.xtheadmemidx = 0;
+                // if (!strcasecmp(p, "xtheadfmemidx")) cpuext.xtheadfmemidx = 0;
+                // if (!strcasecmp(p, "xtheadmac")) cpuext.xtheadmac = 0;
+                // if (!strcasecmp(p, "xtheadfmv")) cpuext.xtheadfmv = 0;
+                if (!strcasecmp(p, "xtheadmempair")) cpuext.xtheadmempair = 0;
+                if (!strcasecmp(p, "xtheadcondmov")) cpuext.xtheadcondmov = 0;
+                p = strtok(NULL, ",");
+            }
+        }
+    }
+#endif
+    return 1;
+}
\ No newline at end of file
diff --git a/src/os/hostext_wine.c b/src/os/hostext_wine.c
new file mode 100644
index 00000000..3b6d5663
--- /dev/null
+++ b/src/os/hostext_wine.c
@@ -0,0 +1,20 @@
+#include <winternl.h>
+
+#include "debug.h"
+#include "wine/compiler.h"
+#include "wine/debug.h"
+
+int DetectHostCpuFeatures(void)
+{
+    cpuext.asimd = 1;
+    if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE))
+        cpuext.aes = cpuext.sha1 = cpuext.sha2 = cpuext.pmull = 1;
+    if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE))
+        cpuext.crc32 = 1;
+    if (IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE))
+        cpuext.atomics = 1;
+
+    // TODO
+    cpuext.uscat = cpuext.flagm = cpuext.flagm2 = cpuext.frintts = cpuext.afp = cpuext.rndr = 0;
+    return 1;
+}
diff --git a/src/rv64detect.c b/src/rv64detect.c
deleted file mode 100644
index 3cce199e..00000000
--- a/src/rv64detect.c
+++ /dev/null
@@ -1,126 +0,0 @@
-#include <string.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <signal.h>
-#include <sys/mman.h>
-#include <setjmp.h>
-
-#include "debug.h"
-#include "dynarec/rv64/rv64_emitter.h"
-
-// Detect RV64 extensions, by executing on of the opcode with a SIGILL signal handler
-
-static sigjmp_buf sigbuf = {0};
-typedef int (*iFiip_t)(int, int, void*);
-static void detect_sigill(int sig)
-{
-    siglongjmp(sigbuf, 1);
-}
-
-static int Check(void* block)
-{
-    static uint64_t buf[2] = {0};
-    // Clear instruction cache
-    __clear_cache(block, block+box64_pagesize);
-    // Setup SIGILL signal handler
-    __sighandler_t old = signal(SIGILL, detect_sigill);
-    if(sigsetjmp(sigbuf, 1)) {
-        // didn't work, extension not present
-        signal(SIGILL, old);
-        return 0;
-    }
-    int result = ((iFiip_t)block)(0, 1, buf);
-    if (result != 42) {
-        // wrong result, extension not present
-        signal(SIGILL, old);
-        return 0;
-    }
-    // done...
-    signal(SIGILL, old);
-    return 1;
-}
-
-void RV64_Detect_Function()
-{
-    // Alloc memory to execute stuffs
-    void* my_block = mmap(NULL, box64_pagesize, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-    if(my_block==(void*)-1) {
-        return;
-    }
-    uint32_t* block;
-    #define EMIT(A) *block = (A); ++block
-
-
-    // THead vendor extensions
-    block = (uint32_t*)my_block;
-    ADDI(A0, xZR, 40);
-    ADDI(A1, xZR, 1);
-    TH_ADDSL(A0, A0, A1, 1);
-    BR(xRA);
-    cpuext.xtheadba
-        = cpuext.xtheadbb
-        = cpuext.xtheadbs
-        = cpuext.xtheadcondmov
-        = cpuext.xtheadmemidx
-        = cpuext.xtheadmempair
-        = cpuext.xtheadfmemidx
-        = cpuext.xtheadmac
-        = cpuext.xtheadfmv = Check(my_block);
-
-    // Official extensions
-
-    if (!cpuext.xtheadba) {
-        // Test Zba with ADDUW
-        block = (uint32_t*)my_block;
-        ADDUW(A0, A0, A1);
-        ADDI(A0, xZR, 42);
-        BR(xRA);
-        cpuext.zba = Check(my_block);
-        // Test Zbb with ANDN
-        block = (uint32_t*)my_block;
-        ANDN(A0, A0, A1);
-        ADDI(A0, xZR, 42);
-        BR(xRA);
-        cpuext.zbb = Check(my_block);
-        // Test Zbc with CLMUL
-        block = (uint32_t*)my_block;
-        CLMUL(A0, A0, A1);
-        ADDI(A0, xZR, 42);
-        BR(xRA);
-        cpuext.zbc = Check(my_block);
-        // Test Zbs with BCLR
-        block = (uint32_t*)my_block;
-        BCLR(A0, A0, A1);
-        ADDI(A0, xZR, 42);
-        BR(xRA);
-        cpuext.zbs = Check(my_block);
-    }
-
-    block = (uint32_t*)my_block;
-    CSRRS(xZR, xZR, 0xc22 /* vlenb */);
-    ADDI(A0, xZR, 42);
-    BR(xRA);
-    cpuext.vector = Check(my_block);
-
-    if (cpuext.vector) {
-        block = (uint32_t*)my_block;
-        CSRRS(xZR, xZR, 0x00f /* vcsr */); // vcsr does not exists in xtheadvector
-        ADDI(A0, xZR, 42);
-        BR(xRA);
-        cpuext.xtheadvector = !Check(my_block);
-    }
-
-    if (cpuext.vector) {
-        int vlenb = 0;
-        asm volatile("csrr %0, 0xc22" : "=r"(vlenb));
-        cpuext.vlen = vlenb;
-        if (vlenb < 16) {
-            // we need vlen >= 128
-            cpuext.vector = 0;
-        }
-    }
-
-    // Finish
-    // Free the memory my_block
-    munmap(my_block, box64_pagesize);
-}
diff --git a/wine/common/wrt.c b/wine/common/wrt.c
index d9725e4b..82477c1f 100644
--- a/wine/common/wrt.c
+++ b/wine/common/wrt.c
@@ -234,3 +234,8 @@ void WINAPI GetSystemInfo(SYSTEM_INFO* si)
 
     fillSystemInfo(si, &basic_info, &cpu_info);
 }
+
+BOOL WINAPI IsProcessorFeaturePresent(DWORD feature)
+{
+    return RtlIsProcessorFeaturePresent(feature);
+}
diff --git a/wine/include/wine/compiler.h b/wine/include/wine/compiler.h
index a38f624b..ca7aedf4 100644
--- a/wine/include/wine/compiler.h
+++ b/wine/include/wine/compiler.h
@@ -92,6 +92,7 @@ NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE, PVOID*, SIZE_T*, ULONG, ULONG*);
 NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE, PVOID*, ULONG_PTR, SIZE_T*, ULONG, ULONG);
 PVOID WINAPI RtlReAllocateHeap(HANDLE, ULONG, PVOID, SIZE_T);
 NTSTATUS WINAPI NtFreeVirtualMemory(HANDLE, PVOID*, SIZE_T*, ULONG);
+BOOLEAN WINAPI RtlIsProcessorFeaturePresent(UINT feature);
 
 static inline uintptr_t calculate_fs(void)
 {
diff --git a/wine/wow64/CMakeLists.txt b/wine/wow64/CMakeLists.txt
index a8d996f9..47b28da7 100644
--- a/wine/wow64/CMakeLists.txt
+++ b/wine/wow64/CMakeLists.txt
@@ -87,6 +87,8 @@ set(WOW64_BOX64CPU_SRC
     "${BOX64_ROOT}/src/emu/x87emu_private.c"
     "${BOX64_ROOT}/src/os/backtrace.c"
     "${BOX64_ROOT}/src/os/os_wine.c"
+    "${BOX64_ROOT}/src/os/hostext_common.c"
+    "${BOX64_ROOT}/src/os/hostext_wine.c"
     "${BOX64_ROOT}/src/os/freq_wine.c"
     "${BOX64_ROOT}/src/os/symbolfuncs_wine.c"
     "${BOX64_ROOT}/src/os/emit_signal_wine.c"
diff --git a/wine/wow64/wowbox64.c b/wine/wow64/wowbox64.c
index 02b25c05..770af6bf 100644
--- a/wine/wow64/wowbox64.c
+++ b/wine/wow64/wowbox64.c
@@ -24,7 +24,7 @@
 #include "rbtree.h"
 #include "wine/compiler.h"
 #include "wine/debug.h"
-#include "core_arch.h"
+#include "hostext.h"
 
 uintptr_t box64_pagesize = 4096;
 
@@ -226,6 +226,14 @@ NTSTATUS WINAPI BTCpuProcessInit(void)
     LoadEnvVariables();
     InitializeEnvFiles();
 
+    if (!BOX64ENV(nobanner)) PrintBox64Version(1);
+    if (DetectHostCpuFeatures())
+        PrintHostCpuFeatures();
+    else {
+        printf_log(LOG_INFO, "Minimum CPU requirements not met, disabling DynaRec\n");
+        SET_BOX64ENV(dynarec, 0);
+    }
+
     TCHAR filename[MAX_PATH];
     if (GetModuleFileNameA(NULL, filename, MAX_PATH)) {
         char* shortname = strrchr(filename, '\\');
@@ -235,7 +243,6 @@ NTSTATUS WINAPI BTCpuProcessInit(void)
         }
     }
 
-    if (!BOX64ENV(nobanner)) PrintBox64Version(1);
     PrintEnvVariables(&box64env, LOG_INFO);
 
     memset(bopcode, 0xc3, sizeof(bopcode));