forked from antmicro/tlib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
helper.c
161 lines (136 loc) · 4.76 KB
/
helper.c
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include "cpu.h"
#include <global_helper.h>
#include "callbacks.h"
#include "debug.h"
#include "atomic.h"
// Dirty addresses handling
#define MAX_DIRTY_ADDRESSES_LIST_COUNT 100
static uint64_t dirty_addresses_list[MAX_DIRTY_ADDRESSES_LIST_COUNT];
static short current_dirty_addresses_list_index = 0;
void flush_dirty_addresses_list()
{
if (current_dirty_addresses_list_index==0) {
// list is empty
return;
}
tlib_mass_broadcast_dirty((void *)&dirty_addresses_list, current_dirty_addresses_list_index);
current_dirty_addresses_list_index = 0;
}
void append_dirty_address(uint64_t address)
{
if (address == dirty_addresses_list[current_dirty_addresses_list_index-1]) {
return;
}
if (current_dirty_addresses_list_index == MAX_DIRTY_ADDRESSES_LIST_COUNT) {
// list is full
flush_dirty_addresses_list();
}
dirty_addresses_list[current_dirty_addresses_list_index++] = address;
}
// broadcast argument allows us to mark elements that we got from other cores without repeating the broadcast
void mark_tbs_containing_pc_as_dirty(target_ulong addr, int access_width, int broadcast)
{
helper_mark_tbs_as_dirty(cpu, addr, access_width, broadcast);
}
void HELPER(invalidate_dirty_addresses_shared)(CPUState *env)
{
if (unlikely(env->tb_broadcast_dirty)) {
uint64_t size = 0;
uint64_t *addresses = tlib_get_dirty_addresses_list(&size);
for (uint64_t i = 0; i < size; ++i) {
uint64_t start = addresses[i] & TARGET_PAGE_MASK;
uint64_t end = start | ~TARGET_PAGE_MASK;
tb_invalidate_phys_page_range_inner(start, end, false, false);
}
}
}
// verify if there are instructions left to execute, update instructions count
// and trim the block and exit to the main loop if necessary
uint32_t HELPER(prepare_block_for_execution)(void *tb)
{
cpu->current_tb = (TranslationBlock *)tb;
if(unlikely(cpu->exception_index >= 0)) {
// Exit the current block if a exception is pending. This will be true if a block interrupt was requested
// at the end of the previous block, but couldn't be handled there. See `interrupt_current_translation_block`
// for reason why that could happen.
return 1;
}
if (cpu->exit_request != 0) {
return cpu->exit_request;
}
uint32_t instructions_left = cpu->instructions_count_limit - cpu->instructions_count_value;
if (instructions_left == 0) {
// setting `tb_restart_request` to 1 will stop executing this block at the end of the header
cpu->tb_restart_request = 1;
} else if (cpu->current_tb->icount > instructions_left) {
// this block is too long, remove it from the jump cache,
// jump back to the main loop and find short enough in phys cache
tb_jmp_cache_remove(cpu->current_tb);
cpu->tb_restart_request = 1;
} else if (cpu->current_tb->dirty_flag) {
// invalidate this block and jump back to the main loop
tb_phys_invalidate(cpu->current_tb, -1);
cpu->tb_restart_request = 1;
}
return cpu->tb_restart_request;
}
uint32_t HELPER(block_begin_event)()
{
uint32_t result = tlib_on_block_begin(cpu->current_tb->pc, cpu->current_tb->icount);
if (result == 0) {
cpu->exit_request = 1;
}
return result;
}
void HELPER(block_finished_event)(target_ulong address, uint32_t executed_instructions)
{
tlib_on_block_finished(address, executed_instructions);
}
void HELPER(abort)(void) {
tlib_abort("aborted by gen_abort!");
}
void HELPER(log)(uint32_t id, uint32_t pc)
{
tlib_printf(LOG_LEVEL_INFO, "Log @ pc=0x%08X (block start: 0x%08X) : '%s'", pc, CPU_PC(
cpu), msgs[id] == NULL ? "unknown??" : msgs[id]);
}
void HELPER(acquire_global_memory_lock)(CPUState * env)
{
acquire_global_memory_lock(env);
}
void HELPER(release_global_memory_lock)(CPUState * env)
{
release_global_memory_lock(env);
}
void HELPER(reserve_address)(CPUState * env, ram_addr_t address, uint32_t manual_free)
{
reserve_address(env, address, (uint8_t)manual_free);
}
target_ulong HELPER(check_address_reservation)(CPUState * env, ram_addr_t address)
{
return check_address_reservation(env, address);
}
void HELPER(cancel_reservation)(CPUState * env)
{
cancel_reservation(env);
}
void HELPER(var_log)(target_ulong v)
{
tlib_printf(LOG_LEVEL_INFO, "Var Log: 0x" TARGET_FMT_lx, v);
}
void HELPER(count_opcode_inner)(uint32_t instruction_id)
{
cpu->opcode_counters[instruction_id].counter++;
}
void HELPER(announce_stack_change)(target_ulong pc, uint32_t state)
{
tlib_announce_stack_change(pc, state);
}
void HELPER(on_interrupt_end_event)(uint64_t exception_index)
{
tlib_on_interrupt_end(exception_index);
}
void HELPER(tlb_flush)(CPUState* env)
{
tlb_flush(env, 1, true);
}