-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathProcessTrace.cpp
More file actions
380 lines (334 loc) · 13.2 KB
/
ProcessTrace.cpp
File metadata and controls
380 lines (334 loc) · 13.2 KB
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
/*
* ProcessTrace implementation
*/
/*
* File: ProcessTrace.cpp
* Author: Mike Goss <mikegoss@cs.du.edu>
*
*/
#include "ProcessTrace.h"
#include <algorithm>
#include <cctype>
#include <iomanip>
#include <iostream>
#include <sstream>
using namespace mem;
using std::cin;
using std::cout;
using std::cerr;
using std::getline;
using std::istringstream;
using std::string;
using std::vector;
ProcessTrace::ProcessTrace(std::string file_name_, MMU &memory_, PageFrameAllocator &allocator_)
: file_name(file_name_), line_number(0) {
// Open the trace file. Abort program if can't open.
trace.open(file_name, std::ios_base::in);
if (!trace.is_open()) {
cerr << "ERROR: failed to open trace file: " << file_name << "\n";
exit(2);
}
memory = &memory_;
allocator = &allocator_;
//Build an empty page-directory
PageTable page_directory;
memory->set_PMCB(physical_pmcb);
Addr directory_physical = allocator->get_free_list_head() * mem::kPageSize;
allocator->Allocate(1);
memory->put_bytes(directory_physical, kPageTableSizeBytes, //Write page directory to memory
reinterpret_cast<uint8_t*> (&page_directory));
// load to start virtual mode
const PMCB virtual_pmcb(true, directory_physical);
memory->set_PMCB(virtual_pmcb);
}
ProcessTrace::~ProcessTrace() {
trace.close();
}
void ProcessTrace::Execute(void) {
// Read and process commands
string line; // text line read
string cmd; // command from line
vector<uint32_t> cmdArgs; // arguments from line
// Select the command to execute
while (ParseCommand(line, cmd, cmdArgs)) {
if (cmd == "alloc") {
CmdAlloc(line, cmd, cmdArgs); // allocate memory
} else if (cmd == "compare") {
CmdCompare(line, cmd, cmdArgs); // get and compare multiple bytes
} else if (cmd == "put") {
CmdPut(line, cmd, cmdArgs); // put bytes
} else if (cmd == "fill") {
CmdFill(line, cmd, cmdArgs); // fill bytes with value
} else if (cmd == "copy") {
CmdCopy(line, cmd, cmdArgs); // copy bytes to dest from source
} else if (cmd == "dump") {
CmdDump(line, cmd, cmdArgs); // dump byte values to output
} else if (cmd == "writable") {
CmdWritable(line, cmd, cmdArgs);
} else if (cmd == "#") {
CmdComment(line);
} else {
cerr << "ERROR: invalid command at line " << line_number << ":\n"
<< line << "\n";
exit(2);
}
}
}
bool ProcessTrace::ParseCommand(
string &line, string &cmd, vector<uint32_t> &cmdArgs) {
cmdArgs.clear();
line.clear();
// Read next line
if (std::getline(trace, line)) {
++line_number;
cout << std::dec << line_number << ":";
// Make a string stream from command line
istringstream lineStream(line);
// Get command
lineStream >> cmd;
// Get arguments
if (cmd != "#") {//remainder of line is not a comment
cout << line << std::endl; //print remainder of command line
uint32_t arg;
while (lineStream >> std::hex >> arg) {
cmdArgs.push_back(arg);
}
}
return true;
} else if (trace.eof()) {
return false;
} else {
cerr << "ERROR: getline failed on trace file: " << file_name
<< "at line " << line_number << "\n";
exit(2);
}
}
/*
* Must build and modify page tables for the process
* On initialization of ProcessTrace, build an empty page-directory
* The alloc command will add or modify second-level page tables
*
* Allocate virtual memory for size bytes, starting at virtual address vaddr.
* The starting address, vaddr, and the byte count, size, must be exact multiple of the page size
* (0x1000). The first line of the file must be an alloc command
* Subsequent alloc commands add additional blocks of allocated virtual memory
* they do not remove earlier allocations. All pages should be marked Writable in the
* 1st and 2nd level page tables when initially allocated. All newly-allocated
* memory must be initialized to 0
*/
void ProcessTrace::CmdAlloc(const string &line,
const string &cmd,
const vector<uint32_t> &cmdArgs) {
Addr vaddr = cmdArgs.at(0);
Addr num_bytes = cmdArgs.at(1);
if(num_bytes % 0x1000 != 0){
cerr << "Allocation not a multiple of page frame size" << std::endl;
exit(3);
}
/* Switch to physical mode */
PMCB temp_pmcb;
memory->get_PMCB(temp_pmcb);
memory->set_PMCB(physical_pmcb);
uint32_t numFrames = num_bytes / 0x1000;
uint32_t numPTs = 0;
uint32_t count = 0;
/* Verify that we have enough free page frames to accommodate the entire
* alloc command */
PageTable dir;
Addr dir_base = physical_pmcb.page_table_base;// Get our page directory (1st level page table)
/* Now read the page directory */
try {
memory->get_bytes(reinterpret_cast<uint8_t*> (&dir), dir_base, kPageTableSizeBytes);
} catch (PageFaultException e) {
cout << "Page fault exception while reading page directory.\n";
}
/* Count how many page tables we will need to allocate (if any)
* It's possible that we have to both allocate a page table and then
* the page in that page table, requiring us to allocate extra frames */
uint32_t tempVAddr = vaddr;
while(count++ < numFrames) {
Addr dir_index = ((tempVAddr >> (kPageSizeBits + kPageTableSizeBits)) & kPageTableIndexMask);
bool pageTable_exists = dir[dir_index] & kPTE_PresentMask;
if(pageTable_exists){
numPTs++;
}
tempVAddr += count*kPageSize;
}
count = 0;
numFrames += numPTs;
if(allocator->get_page_frames_free() >= numFrames){
/* While we have page frames to allocate */
while(count++ < numFrames){
Addr frame_pAddr = allocator->get_free_list_head() * kPageSize;
Addr dir_index = ((vaddr >> (kPageSizeBits + kPageTableSizeBits)) & kPageTableIndexMask);
Addr l2_offset = (vaddr >> kPageSizeBits) & kPageTableIndexMask;
/* Find if a page table at this vaddr already exists by checking
* its present bit */
bool pageTable_exists = dir[dir_index] & kPTE_PresentMask;
/* If we have room to allocate */
if(allocator->Allocate(1)){
//allocator->Allocate(1);
/* Compute some offsets */
PageTable l2_temp;
/* If we don't already have a page table at this addr, allocate
* another frame. */
if(!pageTable_exists){
Addr ptAddr = allocator->get_free_list_head() *kPageSize;
/* Check that we can allocate another frame */
if(allocator->Allocate(1)){
dir[dir_index] = ptAddr | kPTE_PresentMask | kPTE_WritableMask;
memory->put_bytes(dir_base, kPageTableSizeBytes,
reinterpret_cast<uint8_t*>(&dir));
}
memory->put_bytes(ptAddr, kPageTableSizeBytes,
reinterpret_cast<uint8_t*>(&l2_temp));
}
/* Specific (L3) page inside of our L2 page table */
Addr l2_pAddr = (dir[dir_index] & 0xFFFFF000);
try {
/* If we DO have a page table, read that page table
* into l2_temp */
memory->get_bytes(reinterpret_cast<uint8_t*> (&l2_temp),
l2_pAddr, kPageTableSizeBytes);
} catch (PageFaultException e) {
cout << "Page fault exception while reading L2 PT.\n";
}
/* Determine if page in L2 table maps to something */
bool pageEntry_exists = l2_temp[l2_offset] & kPTE_PresentMask;
if(!pageEntry_exists){
l2_temp[l2_offset] = frame_pAddr | kPTE_PresentMask | kPTE_WritableMask;
memory->put_bytes(l2_pAddr, kPageTableSizeBytes,
reinterpret_cast<uint8_t*>(&l2_temp));
}
}
/* Move to the next vaddr */
vaddr += count*kPageSize;
}
}
/* Switch back to virtual mode */
memory->set_PMCB(temp_pmcb);
}
void ProcessTrace::CmdCompare(const string &line,
const string &cmd,
const vector<uint32_t> &cmdArgs) {
uint32_t addr = cmdArgs.at(0);
// Compare specified byte values
size_t num_bytes = cmdArgs.size() - 1;
uint8_t buffer[num_bytes];
memory->get_bytes(buffer, addr, num_bytes);
for (int i = 1; i < cmdArgs.size(); ++i) {
if (buffer[i - 1] != cmdArgs.at(i)) {
cout << "compare error at address " << std::hex << addr
<< ", expected " << static_cast<uint32_t> (cmdArgs.at(i))
<< ", actual is " << static_cast<uint32_t> (buffer[i - 1]) << "\n";
}
++addr;
}
}
void ProcessTrace::CmdPut(const string &line,
const string &cmd,
const vector<uint32_t> &cmdArgs) {
// Put multiple bytes starting at specified address
uint32_t addr = cmdArgs.at(0);
size_t num_bytes = cmdArgs.size() - 1;
uint8_t buffer[num_bytes];
for (int i = 1; i < cmdArgs.size(); ++i) {
buffer[i - 1] = cmdArgs.at(i);
}
memory->put_bytes(addr, num_bytes, buffer);
}
void ProcessTrace::CmdCopy(const string &line,
const string &cmd,
const vector<uint32_t> &cmdArgs) {
// Copy specified number of bytes to destination from source
Addr dst = cmdArgs.at(0);
Addr src = cmdArgs.at(1);
Addr num_bytes = cmdArgs.at(2);
uint8_t buffer[num_bytes];
memory->get_bytes(buffer, src, num_bytes);
memory->put_bytes(dst, num_bytes, buffer);
}
void ProcessTrace::CmdFill(const string &line,
const string &cmd,
const vector<uint32_t> &cmdArgs) {
// Fill a sequence of bytes with the specified value
Addr addr = cmdArgs.at(0);
Addr num_bytes = cmdArgs.at(1);
uint8_t val = cmdArgs.at(2);
for (int i = 0; i < num_bytes; ++i) {
memory->put_byte(addr++, &val);
}
}
void ProcessTrace::CmdDump(const string &line,
const string &cmd,
const vector<uint32_t> &cmdArgs) {
uint32_t addr = cmdArgs.at(0);
uint32_t count = cmdArgs.at(1);
// Output the address
cout << std::hex << addr;
// Output the specified number of bytes starting at the address
for (int i = 0; i < count; ++i) {
if ((i % 16) == 0) { // line break every 16 bytes
cout << "\n";
}
uint8_t byte_val;
memory->get_byte(&byte_val, addr++);
cout << " " << std::setfill('0') << std::setw(2)
<< static_cast<uint32_t> (byte_val);
}
cout << "\n";
}
void ProcessTrace::CmdWritable(const std::string& line,
const std::string& cmd,
const std::vector<uint32_t>& cmdArgs) {
//Command Format:
//writable vaddr size status
uint32_t vaddr = cmdArgs.at(0);
uint32_t count = cmdArgs.at(1);
bool status = cmdArgs.at(2);
/* Set to physical -- we're modifying physical page table entries */
PMCB temp_pmcb;
memory->get_PMCB(temp_pmcb);
memory->set_PMCB(physical_pmcb);
PageTable dir;
Addr dir_base = physical_pmcb.page_table_base;// Get our page directory (1st level page table)
/* Now read the page directory */
try {
memory->get_bytes(reinterpret_cast<uint8_t*> (&dir), dir_base, kPageTableSizeBytes);
} catch (PageFaultException e) {
cout << "Page fault exception while reading page directory.\n";
}
Addr l2_offset;
Addr dir_index = ((vaddr >> (kPageSizeBits + kPageTableSizeBits)) & kPageTableIndexMask);
PageTable l2_temp;
Addr l2_pAddr = (dir[dir_index] & 0xFFFFF000);
try {
/* If we DO have a page table, read that page table
* into l2_temp */
memory->get_bytes(reinterpret_cast<uint8_t*> (&l2_temp),
l2_pAddr, kPageTableSizeBytes);
} catch (PageFaultException e) {
cout << "Page fault exception while reading L2 PT.\n";
}
uint32_t num_frames = count/kPageSize;
uint32_t i = 0;
while(i++ < num_frames){
l2_offset = (vaddr >> kPageSizeBits) & kPageTableIndexMask;
/* Determine if page in L2 table maps to something */
bool pageEntry_exists = l2_temp[l2_offset] & kPTE_PresentMask;
if (pageEntry_exists) {
if(!status){
l2_temp[l2_offset] &= ~(kPTE_WritableMask);
} else if (status){
l2_temp[l2_offset] |= kPTE_WritableMask;
}
memory->put_bytes(l2_pAddr, kPageTableSizeBytes,
reinterpret_cast<uint8_t*> (&l2_temp));
}
vaddr += (i*kPageSize);
}
memory->set_PMCB(temp_pmcb);
}
void ProcessTrace::CmdComment(const std::string& line) {
cout << line << std::endl;
}