about summary refs log tree commit diff stats
path: root/src/rv64detect.c
blob: 9976d1d79b446059cd56aae60c4ca9dbd152ed8a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#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 void(*vFii_t)(int, int);
static void detect_sigill(int sig)
{
    siglongjmp(sigbuf, 1);
}

static int Check(void* block)
{
    // 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;
    }
    ((vFii_t)block)(0, 1);
    // 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
    // Test Zba with ADDUW
    block = (uint32_t*)my_block;
    ADDUW(A0, A0, A1);
    BR(xRA);
    rv64_zba = Check(my_block);
    // Test Zbb with ANDN
    block = (uint32_t*)my_block;
    ANDN(A0, A0, A1);
    BR(xRA);
    rv64_zbb = Check(my_block);
    // Test Zbc with CLMUL
    block = (uint32_t*)my_block;
    CLMUL(A0, A0, A1);
    BR(xRA);
    rv64_zbc = Check(my_block);
    // Test Zbs with BCLR
    block = (uint32_t*)my_block;
    BCLR(A0, A0, A1);
    BR(xRA);
    rv64_zbs = Check(my_block);

    // Finish
    // Free the memory my_block
    munmap(my_block, box64_pagesize);
}