about summary refs log tree commit diff stats
path: root/src/dynarec/arm64/updateflags_arm64.c
blob: 2e2af8e91f1c58b109d074ee76fa589ba34ebe01 (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
127
128
129
130
131
132
133
134
135
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>

#include "os.h"
#include "debug.h"
#include "box64context.h"
#include "custommem.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynablock.h"
#include "../dynablock_private.h"

#include "dynarec_native.h"
#include "../dynarec_arch.h"

void updateflags_pass0(dynarec_arm_t* dyn, uint64_t jmp_df[]);
void updateflags_pass1(dynarec_arm_t* dyn, uint64_t jmp_df[]);
void updateflags_pass2(dynarec_arm_t* dyn, uint64_t jmp_df[]);
void updateflags_pass3(dynarec_arm_t* dyn, uint64_t jmp_df[]);

static dynablock_t* updaflags_arm64 = NULL;

static uint8_t dummy_code[] = {0x90, 0xc3}; // some dummy code so update_flags dynablock point to something

void* create_updateflags()
{
    if(updaflags_arm64)
        return updaflags_arm64->block;
    uint64_t jmp_df[d_unknown+1] = {0};
    dynarec_arm_t helper = {0};
    instruction_arm64_t insts[1] = {0};
    helper.insts = insts;
    helper.need_dump = BOX64ENV(dynarec_dump);
    helper.cap = 1;
    helper.f.dfnone = 1;
    helper.f.pending = SF_NODF;
    helper.insts[0].x64.gen_flags = X_ALL;
    // pass 0
    updateflags_pass0(&helper, jmp_df);
    // check if all flags are handled
    int ok = 1;
    for(int i=d_none; i<d_unknown; ++i)
        if(!jmp_df[i]) {
            printf_log(LOG_NONE, "Error, UpdateFlags case %d is not handled, will crash later\n", i);
            ok = 0;
        }
    // pass 1
    updateflags_pass1(&helper, jmp_df);
    // pass 2
    helper.native_size = 0;
    updateflags_pass2(&helper, jmp_df);
    // alloc memory for pass3
    size_t native_size = (helper.native_size+7)&~7;   // round the size...
    size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) +  0  +  0  +  0  + sizeof(dynablock_t) + 0;
    //           dynablock_t*     block (arm insts)            table64               jmpnext code instsize arch callrets     dynablock      relocs
    void* actual_p = (void*)AllocDynarecMap((uintptr_t)&dummy_code, sz, 1);   // arbitrary address
    void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
    void* tablestart = p + native_size;
    void* next = tablestart + helper.table64size*sizeof(uint64_t);
    void* instsize = next + 4*sizeof(void*);
    void* arch = instsize + 0;
    void* callrets = arch + 0;
    if(actual_p==NULL) {
        dynarec_log(LOG_INFO, "AllocDynarecMap(%zu) failed, canceling UpdateBlock\n", sz);
        return NULL;
    }
    helper.block = p;
    dynablock_t* block = (dynablock_t*)(callrets+0);
    memset(block, 0, sizeof(dynablock_t));
    void* relocs = helper.need_reloc?(block+1):NULL;
    // fill the block
    block->x64_addr = &dummy_code;
    block->isize = 0;
    block->actual_block = actual_p;
    helper.relocs = relocs;
    block->relocs = relocs;
    block->table64size = helper.table64size;
    helper.native_start = (uintptr_t)p;
    helper.tablestart = (uintptr_t)tablestart;
    helper.jmp_next = (uintptr_t)next+sizeof(void*);
    helper.instsize = (instsize_t*)instsize;
    *(dynablock_t**)actual_p = block;
    helper.table64cap = helper.table64size;
    helper.table64 = (uint64_t*)helper.tablestart;
    helper.callrets = (callret_t*)callrets;
    block->table64 = helper.table64;
    helper.callret_size = 0;
    // pass 3, emit (log emit native opcode)
    if(helper.need_dump) {
        dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for UpdateFlags", (helper.need_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size);
        PrintFunctionAddr(helper.start, " => ");
        dynarec_log_prefix(0, LOG_NONE, "%s\n", (helper.need_dump>1)?"\e[m":"");
    }
    helper.native_size = 0;
    updateflags_pass3(&helper, jmp_df);
    helper.jmp_sz = helper.jmp_cap = 0;
    helper.jmps = NULL;
    // keep size of instructions for signal handling
    block->instsize = instsize;
    helper.table64 = NULL;
    helper.instsize = NULL;
    helper.predecessor = NULL;
    block->size = sz;
    block->isize = helper.size;
    block->block = p;
    block->jmpnext = next+sizeof(void*);
    block->always_test = helper.always_test;
    block->dirty = block->always_test;
    block->is32bits = 0;
    block->relocsize = helper.reloc_size*sizeof(uint32_t);
    block->arch = NULL;
    block->arch_size = 0;
    block->callret_size = helper.callret_size;
    block->callrets = helper.callrets;
    block->native_size = native_size;
    *(dynablock_t**)next = block;
    *(void**)(next+3*sizeof(void*)) = NULL;
    CreateJmpNext(block->jmpnext, next+3*sizeof(void*));
    ClearCache(block->jmpnext, 4*sizeof(void*));
    block->x64_size = 0;
    // all done...
    ClearCache(actual_p+sizeof(void*), native_size);   // need to clear the cache before execution...

    updaflags_arm64 = block;
    return block->block;
}