diff options
Diffstat (limited to 'src/os')
| -rw-r--r-- | src/os/hostext_common.c | 64 | ||||
| -rw-r--r-- | src/os/hostext_linux.c | 227 | ||||
| -rw-r--r-- | src/os/hostext_wine.c | 20 |
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; +} |