about summary refs log tree commit diff stats
path: root/src/rv64detect.c
blob: 8ef0ad824bcc2ab2dc840a0b5af17b55ecdb6d2f (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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#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);
    rv64_xtheadba
        = rv64_xtheadbb
        = rv64_xtheadbs
        = rv64_xtheadcondmov
        = rv64_xtheadmemidx
        = rv64_xtheadmempair
        = rv64_xtheadfmemidx
        = rv64_xtheadmac
        = rv64_xtheadfmv = Check(my_block);

    // Official extensions

    if (!rv64_xtheadba) {
        // Test Zba with ADDUW
        block = (uint32_t*)my_block;
        ADDUW(A0, A0, A1);
        ADDI(A0, xZR, 42);
        BR(xRA);
        rv64_zba = Check(my_block);
        // Test Zbb with ANDN
        block = (uint32_t*)my_block;
        ANDN(A0, A0, A1);
        ADDI(A0, xZR, 42);
        BR(xRA);
        rv64_zbb = Check(my_block);
        // Test Zbc with CLMUL
        block = (uint32_t*)my_block;
        CLMUL(A0, A0, A1);
        ADDI(A0, xZR, 42);
        BR(xRA);
        rv64_zbc = Check(my_block);
        // Test Zbs with BCLR
        block = (uint32_t*)my_block;
        BCLR(A0, A0, A1);
        ADDI(A0, xZR, 42);
        BR(xRA);
        rv64_zbs = Check(my_block);
    }

    block = (uint32_t*)my_block;
    CSRRS(xZR, xZR, 0xc22 /* vlenb */);
    ADDI(A0, xZR, 42);
    BR(xRA);
    rv64_vector = Check(my_block);

    if (rv64_vector) {
        block = (uint32_t*)my_block;
        CSRRS(xZR, xZR, 0x00f /* vcsr */); // vcsr does not exists in xtheadvector
        ADDI(A0, xZR, 42);
        BR(xRA);
        rv64_xtheadvector = !Check(my_block);
    }

    if (rv64_vector) {
        int vlenb = 0;
        asm volatile("csrr %0, 0xc22" : "=r"(vlenb));
        rv64_vlen = vlenb * 8;
        if (vlenb < 16) {
            // we need vlen >= 128
            rv64_vector = 0;
        }
    }

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