-
Notifications
You must be signed in to change notification settings - Fork 61
/
elfload.js
182 lines (161 loc) · 7.22 KB
/
elfload.js
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// Load ELF64 file
// loadElf is passed as the callback function to binary file reader.
// - May assume access to RISCV (the processor).
// - Setup done in run.html
function loadElf(binfile, filename, filesList) {
//binfile = binfile.Content;
globfilename = filename; // global access to filename
//document.getElementById("testresult").innerHTML = "Loading " + filename;
var elf = {};
var magic = ((binfile.charCodeAt(0) & 0xFF) << 24) | ((binfile.charCodeAt(1) & 0xFF) << 16) |
((binfile.charCodeAt(2) & 0xFF) << 8) | (binfile.charCodeAt(3) & 0xFF);
if (magic === 0x7f454c46) {
// everything is fine. proceed
} else {
throw new RISCVError("NOT AN ELF. ERR");
}
// e_ident (16 bytes, ELF identification string)
elf["magic"] = magic; // magic num to identify ELF files
elf["ei_class"] = binfile.charCodeAt(4) & 0xFF; // 1 -> 32 bit, 2 -> 64 bit
elf["ei_data"] = binfile.charCodeAt(5) & 0xFF; // 1 little end, 2 big end
elf["ei_version"] = binfile.charCodeAt(6) & 0xFF; // currently always 1
elf["ei_pad"] = binfile.charCodeAt(7) & 0xFF; // marks beginning of padding
if (elf["ei_data"] === 1) {
var end = "l";
RISCV.endianness = "little";
} else if (elf["ei_data"] === 2) {
var end = "b";
RISCV.endianness = "big";
} else {
throw new RISCVError("ELF has invalid endianness");
}
// type of object file. should be 2 for executable
elf["e_type"] = bytes_to_int(binfile, 16, 2, end);
// architecture
elf["e_machine"] = bytes_to_int(binfile, 18, 2, end);
// elf version (should always be 1)
elf["e_version"] = bytes_to_int(binfile, 20, 4, end);
// virtual address of entry point into program (0x10000)
elf["e_entry"] = bytes_to_long(binfile, 24, 8, end);
// offset for program header
elf["e_phoff"] = bytes_to_long(binfile, 32, 8, end);
// offset for section header
elf["e_shoff"] = bytes_to_long(binfile, 40, 8, end);
// processor flags
elf["e_flags"] = bytes_to_int(binfile, 48, 4, end);
// elf header size
elf["e_ehsize"] = bytes_to_int(binfile, 52, 2, end);
// size of each individual entry in program header table
elf["e_phentsize"] = bytes_to_int(binfile, 54, 2, end);
// number of entries in program header table
elf["e_phnum"] = bytes_to_int(binfile, 56, 2, end);
// size of each individual entry in section header table
elf["e_shentsize"] = bytes_to_int(binfile, 58, 2, end);
// number of entries in section header table
elf["e_shnum"] = bytes_to_int(binfile, 60, 2, end);
// section header string table index
elf["e_shstrndx"] = bytes_to_int(binfile, 62, 2, end);
// show elf header information to the user
//update_elf_proptable(elf, elfproptab);
// step through section headers, build up array
var section_headers = [];
for (var i = 0; i < elf["e_shnum"]; i++) {
var addr = elf["e_shoff"].getLowBits() + i*elf["e_shentsize"];
var section = {};
section["name"] = bytes_to_int(binfile, addr, 4, end);
section["type"] = bytes_to_int(binfile, addr+4, 4, end);
section["flags"] = bytes_to_long(binfile, addr+8, 8, end);
section["addr"] = bytes_to_long(binfile, addr+16, 8, end);
section["offs"] = bytes_to_long(binfile, addr+24, 8, end);
section["size"] = bytes_to_long(binfile, addr+32, 8, end);
section_headers.push(section);
}
// copy necessary data into memory
for (var i = 0; i < section_headers.length; i++) {
// check for allocate flag (bit #1) and type != 8 (aka NOT NOBITS)
if ((((section_headers[i]["flags"].getLowBits() >> 1) & 0x1) == 0x1) && (section_headers[i]["type"] != 8)) {
for (var j = 0; j < section_headers[i]["size"].getLowBits(); j++) {
RISCV.memory[((section_headers[i]["addr"].getLowBits()&0x7FFFFFFF) + j) >> 2] |= (binfile.charCodeAt((section_headers[i]["offs"].getLowBits()|0)+j) & 0xFF) << ((j & 0x3) << 3);
}
} else if ((((section_headers[i]["flags"].getLowBits() >> 1) & 0x1) == 0x1) && (section_headers[i]["type"] == 8)) {
// for .bss, load in zeroes, since it's not actually stored in the elf
for (var j = 0; j < section_headers[i]["size"].getLowBits(); j++) {
RISCV.memory[((section_headers[i]["addr"].getLowBits()&0x7FFFFFFF) + j) >> 2] = 0x0;
}
}
}
// [todo] - Detect when this is the proxy kernel
// FOR NOW, ASSUME THAT THIS IS THE PROXY KERNEL
//RISCV.store_word_to_mem(0, 1) // single core
RISCV.store_word_to_mem(new Long(0x0, 0x0), RISCV.memamount); // amount of memory in MiB
// start running program
RISCV.pc = elf["e_entry"].getLowBits();
// reset clock
RISCV.reset_wall_clock();
// GET breakpoints and make global dict
breakpoints = "";
breakpoints = breakpoints.trim();
breakpoints = breakpoints.replace(/ +(?= )/g, ""); // strip extra spaces
breakpoints = breakpoints.split(" ");
breaks = new Object();
for (var i = 0; i < breakpoints.length; i++) {
breaks[parseInt(breakpoints[i], 16)] = 0x1;
}
// show register contents to user
//update_html_regtable(RISCV, tab);
}
// numbytes must always be 8, keep it as an arg for consistency
function bytes_to_long(input, addr, numbytes, end) {
if (end == "b") {
return new Long(bytes_to_int(input, addr+4, 4, end), bytes_to_int(input, addr, 4, end));
} else if (end == "l") {
return new Long(bytes_to_int(input, addr, 4, end), bytes_to_int(input, addr+4, 4, end));
} else {
throw new RISCVError("invalid endianness in bytes_to_long");
}
}
// load numbytes bytes from input starting at input[addr] using endianness end
// valid values for end: "l": little, "b": big
function bytes_to_int(input, addr, numbytes, end) {
var toArr = [];
for (var x = 0; x < numbytes; x++) {
toArr.push(input.charCodeAt(addr+x) & 0xFF);
}
if (end === "l") {
toArr = toArr.reverse();
}
var output = 0;
for (var x = 0; x < numbytes; x++) {
output = output | (toArr[x] << (8*(numbytes-1-x)));
}
return output;
}
function chainedFileLoader(binFile, filename, filesList) {
// add binFile and filename to global array
RISCV.pname_fd[filename] = RISCV.next_fd;
RISCV.fd_pname[RISCV.next_fd] = filename;
RISCV.binaries[RISCV.next_fd] = binFile;
RISCV.next_fd += 1;
if (filesList.length > 0) {
handle_file_continue(filesList);
} else {
// call elfload with vmlinux kernel to start boot
loadElf(RISCV.binaries[RISCV.pname_fd["vmlinux"]], "vmlinux", filesList);
// if cmdargs is empty and next fd is 5, assume fd 4 is user prog:
var arg = "";
if (arg === "" && RISCV.next_fd == 5) {
if (RISCV.pname_fd["vmlinux"] == 3) {
cmdargs.value = RISCV.fd_pname[4] + "";
} else {
cmdargs.value = RISCV.fd_pname[3] + "";
}
}
cont = true;
// now, run!
while (cont) {
cont = elfRunNextInst();
}
return;
}
//$('#WriteCRun').removeAttr('disabled');
}