-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtrap.c
583 lines (509 loc) · 17.8 KB
/
trap.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
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
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
#include <inc/mmu.h>
#include <inc/x86.h>
#include <inc/assert.h>
#include <kern/memory_manager.h>
#include <kern/trap.h>
#include <kern/console.h>
#include <kern/command_prompt.h>
#include <kern/user_environment.h>
#include <kern/file_manager.h>
#include <kern/syscall.h>
#include <kern/sched.h>
#include <kern/kclock.h>
#include <kern/trap.h>
extern void __static_cpt(uint32 *ptr_page_directory, const uint32 virtual_address, uint32 **ptr_page_table);
void __page_fault_handler_with_buffering(struct Env * curenv, uint32 fault_va);
void page_fault_handler(struct Env * curenv, uint32 fault_va);
void table_fault_handler(struct Env * curenv, uint32 fault_va);
static struct Taskstate ts;
//2014 Test Free(): Set it to bypass the PAGE FAULT on an instruction with this length and continue executing the next one
// 0 means don't bypass the PAGE FAULT
uint8 bypassInstrLength = 0;
/// Interrupt descriptor table. (Must be built at run time because
/// shifted function addresses can't be represented in relocation records.)
///
struct Gatedesc idt[256] = { { 0 } };
struct Pseudodesc idt_pd = {
sizeof(idt) - 1, (uint32) idt
};
extern void (*PAGE_FAULT)();
extern void (*SYSCALL_HANDLER)();
extern void (*DBL_FAULT)();
extern void (*ALL_FAULTS0)();
extern void (*ALL_FAULTS1)();
extern void (*ALL_FAULTS2)();
extern void (*ALL_FAULTS3)();
extern void (*ALL_FAULTS4)();
extern void (*ALL_FAULTS5)();
extern void (*ALL_FAULTS6)();
extern void (*ALL_FAULTS7)();
//extern void (*ALL_FAULTS8)();
//extern void (*ALL_FAULTS9)();
extern void (*ALL_FAULTS10)();
extern void (*ALL_FAULTS11)();
extern void (*ALL_FAULTS12)();
extern void (*ALL_FAULTS13)();
//extern void (*ALL_FAULTS14)();
//extern void (*ALL_FAULTS15)();
extern void (*ALL_FAULTS16)();
extern void (*ALL_FAULTS17)();
extern void (*ALL_FAULTS18)();
extern void (*ALL_FAULTS19)();
extern void (*ALL_FAULTS32)();
extern void (*ALL_FAULTS33)();
extern void (*ALL_FAULTS34)();
extern void (*ALL_FAULTS35)();
extern void (*ALL_FAULTS36)();
extern void (*ALL_FAULTS37)();
extern void (*ALL_FAULTS38)();
extern void (*ALL_FAULTS39)();
extern void (*ALL_FAULTS40)();
extern void (*ALL_FAULTS41)();
extern void (*ALL_FAULTS42)();
extern void (*ALL_FAULTS43)();
extern void (*ALL_FAULTS44)();
extern void (*ALL_FAULTS45)();
extern void (*ALL_FAULTS46)();
extern void (*ALL_FAULTS47)();
static const char *trapname(int trapno)
{
static const char * const excnames[] = {
"Divide error",
"Debug",
"Non-Maskable Interrupt",
"Breakpoint",
"Overflow",
"BOUND Range Exceeded",
"Invalid Opcode",
"Device Not Available",
"Double Fault",
"Coprocessor Segment Overrun",
"Invalid TSS",
"Segment Not Present",
"Stack Fault",
"General Protection",
"Page Fault",
"(unknown trap)",
"x87 FPU Floating-Point Error",
"Alignment Check",
"Machine-Check",
"SIMD Floating-Point Exception"
};
if (trapno < sizeof(excnames)/sizeof(excnames[0]))
return excnames[trapno];
if (trapno == T_SYSCALL)
return "System call";
return "(unknown trap)";
}
void
idt_init(void)
{
extern struct Segdesc gdt[];
// LAB 3: Your code here.
//initialize idt
SETGATE(idt[T_PGFLT], 0, GD_KT , &PAGE_FAULT, 0) ;
SETGATE(idt[T_SYSCALL], 0, GD_KT , &SYSCALL_HANDLER, 3) ;
SETGATE(idt[T_DBLFLT], 0, GD_KT , &DBL_FAULT, 0) ;
SETGATE(idt[T_DIVIDE ], 0, GD_KT , &ALL_FAULTS0, 3) ;
SETGATE(idt[T_DEBUG ], 1, GD_KT , &ALL_FAULTS1, 3) ;
SETGATE(idt[T_NMI ], 0, GD_KT , &ALL_FAULTS2, 3) ;
SETGATE(idt[T_BRKPT ], 1, GD_KT , &ALL_FAULTS3, 3) ;
SETGATE(idt[T_OFLOW ], 1, GD_KT , &ALL_FAULTS4, 3) ;
SETGATE(idt[T_BOUND ], 0, GD_KT , &ALL_FAULTS5, 3) ;
SETGATE(idt[T_ILLOP ], 0, GD_KT , &ALL_FAULTS6, 3) ;
SETGATE(idt[T_DEVICE ], 0, GD_KT , &ALL_FAULTS7, 3) ;
//SETGATE(idt[T_DBLFLT ], 0, GD_KT , &ALL_FAULTS, 3) ;
//SETGATE(idt[], 0, GD_KT , &ALL_FAULTS, 3) ;
SETGATE(idt[T_TSS ], 0, GD_KT , &ALL_FAULTS10, 3) ;
SETGATE(idt[T_SEGNP ], 0, GD_KT , &ALL_FAULTS11, 3) ;
SETGATE(idt[T_STACK ], 0, GD_KT , &ALL_FAULTS12, 3) ;
SETGATE(idt[T_GPFLT ], 0, GD_KT , &ALL_FAULTS13, 3) ;
//SETGATE(idt[T_PGFLT ], 0, GD_KT , &ALL_FAULTS, 3) ;
//SETGATE(idt[ne T_RES ], 0, GD_KT , &ALL_FAULTS, 3) ;
SETGATE(idt[T_FPERR ], 0, GD_KT , &ALL_FAULTS16, 3) ;
SETGATE(idt[T_ALIGN ], 0, GD_KT , &ALL_FAULTS17, 3) ;
SETGATE(idt[T_MCHK ], 0, GD_KT , &ALL_FAULTS18, 3) ;
SETGATE(idt[T_SIMDERR ], 0, GD_KT , &ALL_FAULTS19, 3) ;
SETGATE(idt[IRQ0_Clock], 0, GD_KT , &ALL_FAULTS32, 3) ;
SETGATE(idt[33], 0, GD_KT , &ALL_FAULTS33, 3) ;
SETGATE(idt[34], 0, GD_KT , &ALL_FAULTS34, 3) ;
SETGATE(idt[35], 0, GD_KT , &ALL_FAULTS35, 3) ;
SETGATE(idt[36], 0, GD_KT , &ALL_FAULTS36, 3) ;
SETGATE(idt[37], 0, GD_KT , &ALL_FAULTS37, 3) ;
SETGATE(idt[38], 0, GD_KT , &ALL_FAULTS38, 3) ;
SETGATE(idt[39], 0, GD_KT , &ALL_FAULTS39, 3) ;
SETGATE(idt[40], 0, GD_KT , &ALL_FAULTS40, 3) ;
SETGATE(idt[41], 0, GD_KT , &ALL_FAULTS41, 3) ;
SETGATE(idt[42], 0, GD_KT , &ALL_FAULTS42, 3) ;
SETGATE(idt[43], 0, GD_KT , &ALL_FAULTS43, 3) ;
SETGATE(idt[44], 0, GD_KT , &ALL_FAULTS44, 3) ;
SETGATE(idt[45], 0, GD_KT , &ALL_FAULTS45, 3) ;
SETGATE(idt[46], 0, GD_KT , &ALL_FAULTS46, 3) ;
SETGATE(idt[47], 0, GD_KT , &ALL_FAULTS47, 3) ;
// Setup a TSS so that we get the right stack
// when we trap to the kernel.
ts.ts_esp0 = KERNEL_STACK_TOP;
ts.ts_ss0 = GD_KD;
// Initialize the TSS field of the gdt.
gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32) (&ts),
sizeof(struct Taskstate), 0);
gdt[GD_TSS >> 3].sd_s = 0;
// Load the TSS
ltr(GD_TSS);
// Load the IDT
asm volatile("lidt idt_pd");
}
void print_trapframe(struct Trapframe *tf)
{
cprintf("TRAP frame at %p\n", tf);
print_regs(&tf->tf_regs);
cprintf(" es 0x----%04x\n", tf->tf_es);
cprintf(" ds 0x----%04x\n", tf->tf_ds);
cprintf(" trap 0x%08x %s - %d\n", tf->tf_trapno, trapname(tf->tf_trapno), tf->tf_trapno);
cprintf(" err 0x%08x\n", tf->tf_err);
cprintf(" eip 0x%08x\n", tf->tf_eip);
cprintf(" cs 0x----%04x\n", tf->tf_cs);
cprintf(" flag 0x%08x\n", tf->tf_eflags);
cprintf(" esp 0x%08x\n", tf->tf_esp);
cprintf(" ss 0x----%04x\n", tf->tf_ss);
}
void print_regs(struct PushRegs *regs)
{
cprintf(" edi 0x%08x\n", regs->reg_edi);
cprintf(" esi 0x%08x\n", regs->reg_esi);
cprintf(" ebp 0x%08x\n", regs->reg_ebp);
cprintf(" oesp 0x%08x\n", regs->reg_oesp);
cprintf(" ebx 0x%08x\n", regs->reg_ebx);
cprintf(" edx 0x%08x\n", regs->reg_edx);
cprintf(" ecx 0x%08x\n", regs->reg_ecx);
cprintf(" eax 0x%08x\n", regs->reg_eax);
}
static void trap_dispatch(struct Trapframe *tf)
{
// Handle processor exceptions.
// LAB 3: Your code here.
if(tf->tf_trapno == T_PGFLT)
{
//print_trapframe(tf);
if(isPageReplacmentAlgorithmLRU())
{
//cprintf("===========Table WS before updating time stamp========\n");
//env_table_ws_print(curenv) ;
update_WS_time_stamps();
}
fault_handler(tf);
}
else if (tf->tf_trapno == T_SYSCALL)
{
uint32 ret = syscall(tf->tf_regs.reg_eax
,tf->tf_regs.reg_edx
,tf->tf_regs.reg_ecx
,tf->tf_regs.reg_ebx
,tf->tf_regs.reg_edi
,tf->tf_regs.reg_esi);
tf->tf_regs.reg_eax = ret;
}
else if(tf->tf_trapno == T_DBLFLT)
{
panic("double fault!!");
}
else if (tf->tf_trapno == IRQ0_Clock)
{
clock_interrupt_handler() ;
}
else
{
// Unexpected trap: The user process or the kernel has a bug.
//print_trapframe(tf);
if (tf->tf_cs == GD_KT)
{
panic("unhandled trap in kernel");
}
else {
//env_destroy(curenv);
return;
}
}
return;
}
void trap(struct Trapframe *tf)
{
kclock_stop();
int userTrap = 0;
if ((tf->tf_cs & 3) == 3) {
assert(curenv);
curenv->env_tf = *tf;
tf = &(curenv->env_tf);
userTrap = 1;
}
if(tf->tf_trapno == IRQ0_Clock)
{
if (userTrap)
{
assert(curenv);
curenv->nClocks++ ;
}
}
else if (tf->tf_trapno == T_PGFLT){
//2016: Bypass the faulted instruction
if (bypassInstrLength != 0){
if (userTrap){
curenv->env_tf.tf_eip = (uint32*)((uint32)(curenv->env_tf.tf_eip)
+ bypassInstrLength);
env_run(curenv);
}
else{
tf->tf_eip = (uint32*)((uint32)(tf->tf_eip) + bypassInstrLength);
kclock_resume();
env_pop_tf(tf);
}
}
}
trap_dispatch(tf);
if (userTrap)
{
assert(curenv && curenv->env_status == ENV_RUNNABLE);
env_run(curenv);
}
/* 2019
* If trap from kernel, then return to the called kernel function using the passed
param "tf" not the user one that's stored in curenv
*/
else
{
env_pop_tf((tf));
}
}
void setPageReplacmentAlgorithmLRU(){_PageRepAlgoType = PG_REP_LRU;}
void setPageReplacmentAlgorithmCLOCK(){_PageRepAlgoType = PG_REP_CLOCK;}
void setPageReplacmentAlgorithmFIFO(){_PageRepAlgoType = PG_REP_FIFO;}
void setPageReplacmentAlgorithmModifiedCLOCK(){_PageRepAlgoType = PG_REP_MODIFIEDCLOCK;}
uint32 isPageReplacmentAlgorithmLRU(){if(_PageRepAlgoType == PG_REP_LRU) return 1; return 0;}
uint32 isPageReplacmentAlgorithmCLOCK(){if(_PageRepAlgoType == PG_REP_CLOCK) return 1; return 0;}
uint32 isPageReplacmentAlgorithmFIFO(){if(_PageRepAlgoType == PG_REP_FIFO) return 1; return 0;}
uint32 isPageReplacmentAlgorithmModifiedCLOCK(){if(_PageRepAlgoType == PG_REP_MODIFIEDCLOCK) return 1; return 0;}
void enableModifiedBuffer(uint32 enableIt){_EnableModifiedBuffer = enableIt;}
uint32 isModifiedBufferEnabled(){ return _EnableModifiedBuffer ; }
void enableBuffering(uint32 enableIt){_EnableBuffering = enableIt;}
uint32 isBufferingEnabled(){ return _EnableBuffering ; }
void setModifiedBufferLength(uint32 length) { _ModifiedBufferLength = length;}
uint32 getModifiedBufferLength() { return _ModifiedBufferLength;}
void detect_modified_loop()
{
struct Frame_Info * slowPtr = LIST_FIRST(&modified_frame_list);
struct Frame_Info * fastPtr = LIST_FIRST(&modified_frame_list);
while (slowPtr && fastPtr) {
fastPtr = LIST_NEXT(fastPtr); // advance the fast pointer
if (fastPtr == slowPtr) // and check if its equal to the slow pointer
{
cprintf("loop detected in modiflist\n");
break;
}
if (fastPtr == NULL) {
break; // since fastPtr is NULL we reached the tail
}
fastPtr = LIST_NEXT(fastPtr); //advance and check again
if (fastPtr == slowPtr) {
cprintf("loop detected in modiflist\n");
break;
}
slowPtr = LIST_NEXT(slowPtr); // advance the slow pointer only once
}
cprintf("finished modi loop detection\n");
}
void fault_handler(struct Trapframe *tf)
{
int userTrap = 0;
if ((tf->tf_cs & 3) == 3) {
userTrap = 1;
}
//print_trapframe(tf);
uint32 fault_va;
// Read processor's CR2 register to find the faulting address
fault_va = rcr2();
//2017: Check stack overflow for Kernel
if (!userTrap)
{
if (fault_va < KERNEL_STACK_TOP - KERNEL_STACK_SIZE && fault_va >= USER_LIMIT)
panic("Kernel: stack overflow exception!");
}
//2017: Check stack underflow for User
else
{
if (fault_va >= USTACKTOP)
panic("User: stack underflow exception!");
}
//get a pointer to the environment that caused the fault at runtime
struct Env* faulted_env = curenv;
//check the faulted address, is it a table or not ?
//If the directory entry of the faulted address is NOT PRESENT then
if ( (curenv->env_page_directory[PDX(fault_va)] & PERM_PRESENT) != PERM_PRESENT)
{
// we have a table fault =============================================================
// cprintf("[%s] user TABLE fault va %08x\n", curenv->prog_name, fault_va);
faulted_env->tableFaultsCounter ++ ;
table_fault_handler(faulted_env, fault_va);
}
else
{
// we have normal page fault =============================================================
faulted_env->pageFaultsCounter ++ ;
// cprintf("[%08s] user PAGE fault va %08x\n", curenv->prog_name, fault_va);
// cprintf("\nPage working set BEFORE fault handler...\n");
// env_page_ws_print(curenv);
if(isBufferingEnabled())
{
__page_fault_handler_with_buffering(faulted_env, fault_va);
}
else
{
page_fault_handler(faulted_env, fault_va);
}
// cprintf("\nPage working set AFTER fault handler...\n");
// env_page_ws_print(curenv);
}
/*************************************************************/
//Refresh the TLB cache
tlbflush();
/*************************************************************/
}
//Handle the table fault
void table_fault_handler(struct Env * curenv, uint32 fault_va)
{
//Check if it's a stack page
uint32* ptr_table;
if(USE_KHEAP)
{
ptr_table = create_page_table(curenv->env_page_directory, (uint32)fault_va);
}
else
{
__static_cpt(curenv->env_page_directory, (uint32)fault_va, &ptr_table);
}
}
//Handle the page fault
void page_fault_handler(struct Env * curenv, uint32 fault_va)
{
__page_fault_handler_with_buffering(curenv, fault_va);
}
void __page_fault_handler_with_buffering(struct Env * curenv, uint32 fault_va)
{
//TODO: [PROJECT 2019 - MS1 - [3] Page Fault Handler: PLACEMENT & REPLACEMENT CASES]
// Write your code here, remove the panic and write your code
//cprintf("%d\n", fault_va);
if(env_page_ws_get_size(curenv) < curenv->page_WS_max_size) //no replacement needed, just add the page to the working set
PFH_placement(curenv, fault_va);
else if (isPageReplacmentAlgorithmModifiedCLOCK())
PFH_replacement_MC(curenv, fault_va);
//TODO: [PROJECT 2019 - BONUS6] Change WS Size according to “Program Priority”
}
void PFH_placement(struct Env *curenv, uint32 fault_va){
int fault_resolved = 0; //boolean used to update working set at the end of the function
uint32 page_permissions = pt_get_page_permissions(curenv, fault_va);
if(page_permissions & PERM_BUFFERED){ //page is buffered
pt_set_page_permissions(curenv, fault_va, PERM_PRESENT, PERM_BUFFERED); //set present bit, clear buffered bit
//getting frame info and clearing the isBuffered flag
uint32 *ptr_page_table;
struct Frame_Info *ptr_frame_info = get_frame_info(curenv->env_page_directory, (void *)fault_va, &ptr_page_table);
ptr_frame_info->isBuffered = 0;
if(page_permissions & PERM_MODIFIED)
bufferlist_remove_page(&modified_frame_list, ptr_frame_info);
else
bufferlist_remove_page(&free_frame_list, ptr_frame_info);
fault_resolved = 1;
}
else{ //page is not buffered
uint32 *ptr_page_table;
struct Frame_Info *ptr_frame_info = get_frame_info(curenv->env_page_directory, (void *)fault_va, &ptr_page_table);
allocate_frame(&ptr_frame_info);
map_frame(curenv->env_page_directory, ptr_frame_info, (void *)fault_va, PERM_PRESENT|PERM_USER|PERM_WRITEABLE);
int read_from_page_file = pf_read_env_page(curenv, (void *)fault_va);
if(read_from_page_file == E_PAGE_NOT_EXIST_IN_PF){ //page doesn't exist in page file
if(fault_va >= USTACKBOTTOM && fault_va < USTACKTOP){ //stack page
int add_to_page_file = pf_add_empty_env_page(curenv, fault_va, 1);
if(add_to_page_file != E_NO_PAGE_FILE_SPACE)
fault_resolved = 1;
}
}
else //page exists in page file
fault_resolved = 1;
}
if(fault_resolved){ //update working set
int index = curenv->page_last_WS_index;
for(int i = 0; i < curenv->page_WS_max_size; i++){
uint32 cur_VA = curenv->ptr_pageWorkingSet[index].virtual_address;
if(curenv->ptr_pageWorkingSet[index].empty || !(pt_get_page_permissions(curenv, cur_VA) & PERM_PRESENT)){ //found an empty slot in working set
env_page_ws_set_entry(curenv, index, fault_va);
curenv->page_last_WS_index = (index + 1)%curenv->page_WS_max_size;
break;
}
index = (index + 1)%curenv->page_WS_max_size;
}
}
else
panic("Illegal memory access!\n");
}
void PFH_replacement_MC(struct Env *curenv, uint32 fault_va){
uint32 victim_VA = MC_getVictimVA(curenv);
uint32 *ptr_page_table;
struct Frame_Info *ptr_frame_info = get_frame_info(curenv->env_page_directory, (void *)victim_VA, &ptr_page_table);
ptr_frame_info->isBuffered = 1;
ptr_frame_info->environment = curenv;
ptr_frame_info->va = victim_VA;
pt_set_page_permissions(curenv, victim_VA, PERM_BUFFERED, PERM_PRESENT); //set buffered bit, clear present bit
uint32 permissions = pt_get_page_permissions(curenv, victim_VA);
if(!(permissions & PERM_MODIFIED))
bufferList_add_page(&free_frame_list, ptr_frame_info);
else{ //victim page is modified
bufferList_add_page(&modified_frame_list, ptr_frame_info);
uint32 modifiedList_size = LIST_SIZE(&modified_frame_list);
if(modifiedList_size == getModifiedBufferLength()){ //modified list is full, write all pages to page file
struct Frame_Info *ptr_modified_frame_info;
LIST_FOREACH(ptr_modified_frame_info, &modified_frame_list){
uint32 cur_VA = ptr_modified_frame_info->va;
pf_update_env_page(curenv, (void *)cur_VA, ptr_modified_frame_info);
pt_set_page_permissions(curenv, cur_VA, 0, PERM_MODIFIED);
bufferlist_remove_page(&modified_frame_list, ptr_modified_frame_info);
bufferList_add_page(&free_frame_list, ptr_modified_frame_info);
}
cprintf("Updating done, current ML size = %d\n", LIST_SIZE(&modified_frame_list));
}
}
PFH_placement(curenv, fault_va);
}
uint32 MC_getVictimVA(struct Env *curenv){
uint32 victim_VA = -1;
int index = curenv->page_last_WS_index;
int try = 1;
while(victim_VA == -1){
if(try == 1){
for(int i = 0; i < curenv->page_WS_max_size; i++){
uint32 cur_VA = curenv->ptr_pageWorkingSet[index].virtual_address;
uint32 cur_permissions = pt_get_page_permissions(curenv, cur_VA);
if(!(cur_permissions & PERM_MODIFIED) && !(cur_permissions & PERM_USED)){ //found a victim (not modified, not used)
victim_VA = cur_VA;
curenv->page_last_WS_index = index;
break;
}
index = (index + 1)%curenv->page_WS_max_size;
}
try = 2;
continue;
}
if(try == 2){
for(int i = 0; i < curenv->page_WS_max_size; i++){
uint32 cur_VA = curenv->ptr_pageWorkingSet[index].virtual_address;
uint32 cur_permissions = pt_get_page_permissions(curenv, cur_VA);
if(!(cur_permissions & PERM_USED)){ //found a victim (not used)
victim_VA = cur_VA;
curenv->page_last_WS_index = index;
break;
}
pt_set_page_permissions(curenv, cur_VA, 0, PERM_USED);
index = (index + 1)%curenv->page_WS_max_size;
}
try = 1;
}
}
return victim_VA;
}