forked from gtcasl/qsim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfastforwarder.cpp
135 lines (113 loc) · 4.02 KB
/
fastforwarder.cpp
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
/*****************************************************************************\
* Qemu Simulation Framework (qsim) *
* Qsim is a modified version of the Qemu emulator (www.qemu.org), coupled *
* a C++ API, for the use of computer architecture researchers. *
* *
* This work is licensed under the terms of the GNU GPL, version 2. See the *
* COPYING file in the top-level directory. *
\*****************************************************************************/
// The fast-forwarder: runs until it sees an application start marker and then
// saves the state of the CPUs so it can be reloaded later.
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include "statesaver.h"
// The following two defines can be used to create instruction traces. DEBUG
// enables tracing and LOAD reconfigures the fastforwarder to load a state
// file and trace this. Doing this allows comparison of the trace of the
// loaded state to the trace of the fastforwarder after loading a state.
//#define LOAD
//#define DEBUG
struct Magic_cb_s {
Magic_cb_s(Qsim::OSDomain &osd): osd(osd), app_started(false) {}
Qsim::OSDomain &osd;
int magic_cb_f(int cpu_id, uint64_t rax) {
if (rax == 0xaaaaaaaa) {
app_started = true;
return 1;
}
return 0;
}
bool app_started;
void inst_cb_f(int i, uint64_t p, uint64_t v, uint8_t l, const uint8_t *b,
enum inst_type t)
{
std::cerr << '\n' << std::dec << i << ' ' << std::hex << p << '/' << v;
}
void reg_cb_f(int i, int r, uint8_t s, int w) {
if (!w && s) {
std::cerr << ' ' << x86_regs_str[r] << '(' << osd.get_reg(i, r) << ')';
} else if (!w) {
std::cerr << " f" << std::setw(2) << std::setfill('0') << r
<< '(' << std::setw(2) << osd.get_reg(i, QSIM_ARM_CPSR) << ')';
}
}
};
int main(int argc, char** argv) {
if (argc < 5) {
std::cout << "Usage:\n " << argv[0]
<< " <bzImage> <# CPUs> <ram size (MB)> <output state file> <{x86/a64}>\n";
return 1;
}
std::string arch("x86");
if (argc == 6)
arch = argv[5];
int cpus(atoi(argv[2])), ram_mb(atoi(argv[3]));
if (cpus <= 0) {
std::cerr << "# CPUs " << cpus << " out of range.\n"; return 1;
}
if (ram_mb < 64) {
std::cerr << "Ram size " << ram_mb << " out of range.\n"; return 1;
}
#ifdef LOAD
Qsim::OSDomain osd("state.debug");
#else
Qsim::OSDomain osd(cpus, argv[1], arch, QSIM_HEADLESS, ram_mb);
#endif
Magic_cb_s magic_cb_s(osd);
osd.connect_console(std::cout);
#ifndef LOAD
osd.set_magic_cb(&magic_cb_s, &Magic_cb_s::magic_cb_f);
std::cout << "Fast forwarding...\n";
// The thread will be "idle" during initialization. The "slow cycles"
// mechanism is a dirty hack that keeps timer interrupts from happening
// before the core is fully booted.
std::vector<int> slow_cycles(osd.get_n(), 10);
slow_cycles[0] = 70000;
do {
for (unsigned i = 0; i < 100 && !magic_cb_s.app_started; i++) {
for (int j = 0; j < cpus && !magic_cb_s.app_started; j++) {
if (osd.runnable(j)) {
if (osd.idle(j) && !slow_cycles[j]) {
osd.run(100);
} else {
if (osd.idle(j)) --slow_cycles[j];
osd.run(10000);
}
}
// So we don't immediately run the app start callback on load
if (magic_cb_s.app_started) osd.run(j, 1);
}
}
if (!magic_cb_s.app_started) osd.timer_interrupt();
} while (!magic_cb_s.app_started);
#endif
#ifdef DEBUG
osd.set_inst_cb(&magic_cb_s, &Magic_cb_s::inst_cb_f);
osd.set_reg_cb(&magic_cb_s, &Magic_cb_s::reg_cb_f);
#endif
#ifndef LOAD
std::cout << "Saving state...\n";
Qsim::save_state(osd, argv[4]);
#endif
#ifdef DEBUG
std::cout << "Tracing 1M instructions.\n";
#endif
int runfor = 10000, ran = runfor;
while (ran == runfor) {
ran = osd.run(runfor);
}
std::cout << "Finished.\n";
return 0;
}