about summary refs log tree commit diff stats
path: root/src/os
diff options
context:
space:
mode:
Diffstat (limited to 'src/os')
-rw-r--r--src/os/hostext_common.c64
-rw-r--r--src/os/hostext_linux.c227
-rw-r--r--src/os/hostext_wine.c20
3 files changed, 311 insertions, 0 deletions
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;
+}