void allocate_frame(int pid, int type, uint32 vpage) { int i; for (i = 0; i < NFRAMES; i++) { if(invertpagetable[page_head].empty == TRUE) { invertpagetable[page_head].pid = pid; invertpagetable[page_head].type = type; invertpagetable[page_head].empty = FALSE; invertpagetable[page_head].vpage = vpage; return; } page_head = (++page_head) % NFRAMES; } kprintf ("Could not find any empty pages. Must evict\n"); if (policy == FIFO) { kprintf("Eviction Policy: FIFO\n"); uint32 evict_page = (page_head + 1) % NFRAMES; while(invertpagetable[page_head].type != FRAME_REG) { evict_page = (page_head + 1) % NFRAMES; if (evict_page == (page_head + 1) % NFRAMES) { kprintf ("All frames filled by directories or tables!\n"); } } page_head = evict_page; int old_pid = invertpagetable[page_head].pid; int old_type = invertpagetable[page_head].type; int old_vpage = invertpagetable[page_head].vpage; int old_bs = bs_page(old_vpage); int old_pd = pd(old_vpage); int old_pt = pt(old_vpage); struct procent *old_prptr = &proctab[old_pid]; pd_t *old_pd_t = old_prptr->prpagedir; pt_t *old_pt_t = (old_pd_t[old_pd].pd_base << 12); old_pt_t[old_pt].pt_pres = 0; char* addr = (char *)frame2addr(page_head); if(open_bs(old_prptr->prbs) == (uint32)-1 || write_bs(addr, old_prptr->prbs, old_bs)|| close_bs(old_prptr->prbs) == (uint32)-1) { kprintf("Backing store error during eviction!"); return; } invertpagetable[page_head].pid = pid; invertpagetable[page_head].type = type; invertpagetable[page_head].empty = FALSE; invertpagetable[page_head].vpage = vpage; } }
/*------------------------------------------------------------------------- * free_frm - free a frame *------------------------------------------------------------------------- */ SYSCALL free_frm(int i) { STATWORD ps; disable(ps); unsigned long v_addr; unsigned int pt_offset; unsigned int pd_offset; unsigned long pdbr; pd_t *pd_entry; pt_t *pt_entry; int bs_store; int page_num; if(frm_tab[i].fr_type == FR_PAGE) { // kprintf("Inside free frame starting \n"); v_addr = frm_tab[i].fr_vpno; pdbr = proctab[frm_tab[i].fr_pid].pdbr; pd_offset = v_addr>>10; pt_offset = v_addr & 0x000003FF; pd_entry = pdbr+(pd_offset*sizeof(pd_t)); pt_entry = (pd_entry->pd_base*NBPG)+(pt_offset*sizeof(pt_t)); bs_store = proctab[frm_tab[i].fr_pid].store; page_num = frm_tab[i].fr_vpno-proctab[frm_tab[i].fr_pid].vhpno; // kprintf("Before write bs bs_store %d and page_num %d\n", bs_store, page_num); write_bs((i+FRAME0)*NBPG, bs_store, page_num); // kprintf("After write bs\n"); pt_entry->pt_pres = 0; pt_entry->pt_write = 0; pt_entry->pt_base = 0; frm_tab[i].cookie = 0; frm_tab[i].fr_dirty = 0; frm_tab[i].fr_loadtime = 0; frm_tab[i].fr_pid = -1; frm_tab[i].fr_refcnt = 0; frm_tab[i].fr_status = FRM_UNMAPPED; frm_tab[i].fr_type = FR_PAGE; frm_tab[i].fr_vpno = BASE_VIRTUAL_PAGE; frm_tab[i].next_frame = -1; frm_tab[pd_entry->pd_base-FRAME0].fr_refcnt--; if(frm_tab[pd_entry->pd_base-FRAME0].fr_refcnt == 0) { frm_tab[pd_entry->pd_base-FRAME0].cookie = 0; frm_tab[pd_entry->pd_base-FRAME0].fr_dirty = 0; frm_tab[pd_entry->pd_base-FRAME0].fr_loadtime = 0; frm_tab[pd_entry->pd_base-FRAME0].fr_pid = -1; frm_tab[pd_entry->pd_base-FRAME0].fr_refcnt = 0; frm_tab[pd_entry->pd_base-FRAME0].fr_status = FRM_UNMAPPED; frm_tab[pd_entry->pd_base-FRAME0].fr_type = FR_PAGE; frm_tab[pd_entry->pd_base-FRAME0].fr_vpno = BASE_VIRTUAL_PAGE; frm_tab[pd_entry->pd_base-FRAME0].next_frame = -1; pd_entry->pd_pres = 0; } }
SYSCALL pfint() { unsigned long cr2,physical_addr; virt_addr_t * vaddr; int vp,s,o,avail,*store,*pageth; unsigned int p,q,pt; pd_t *pd; pt_t *new_pt; STATWORD ps; // Disable interrupts disable(ps); if(GDB) kprintf("\n*************pfint is running!************\n"); // Get the faulted address. The processor loads the CR2 register // with the 32-bit address that generated the exception. /* 1. Get the faulted address. */ cr2 = read_cr2(); vaddr = (virt_addr_t *)(&cr2); if(GDB) kprintf("&cr2=%x, cr2=%x, &vaddr=%x, vaddr=%x\n",&cr2,cr2,&vaddr,vaddr); /* 2. Let 'vp' be the virtual page number of the page containing of the faulted address */ vp = a2pno(cr2); if(GDB) kprintf("vp=%d,\n",vp); /* 3. Let pd point to the current page directory. */ pd = proctab[currpid].pdbr; if(GDB) kprintf("pd=%x,\n",pd); /* 4. Check that a is a legal address (i.e., it has been mapped). If it is not, print an error message and kill the process. */ pageth = getmem( sizeof(int *) ); store = getmem( sizeof(int *) ); if( SYSERR == bsm_lookup(currpid, vp, store, pageth)){ kprintf("ERROR: This virtual address hasn't been mapped!\n"); kill(currpid); } /* 5. Let p be the upper ten bits of a. [p represents page dirctory offset] */ /* 6. Let q be the bits [21:12] of a. [p represents page table offset.] /* 7.1 Let pt point to the pth page table.*/ p = vaddr->pd_offset; q = vaddr->pt_offset; pt = vaddr->pg_offset; if(GDB) kprintf("p=%d,q=%d,pt=%d\n",p,q,pt); /* 7.2 If the pth page table does not exist obtain a frame for it and initialize it. */ if(pd[p].pd_pres != 1){ if(GDB) kprintf("**obtain a frame for the new page table. \n"); avail = get_frm(); //get the id of a new frame from frm_tab[]; if (avail == -1) { if(GDB) kprintf("Could not create page table!\n"); restore(ps); return SYSERR; } //initialize frame[avail], update the process_id and frame_type of this frame. init_frm(avail, currpid, FR_TBL); frm_tab[avail].fr_upper_t = pa2frid((unsigned long) pd); if(GDB) kprintf("upper page table @frame[%d] pd=%x, a2pno(pd)=%d\n",frm_tab[avail].fr_upper_t, pd, a2pno((unsigned long) pd)); new_pt = frid2pa(avail); init_pt(new_pt); //update this page_table_entry in the page_directory. pd[p].pd_pres = 1; pd[p].pd_write = 1; pd[p].pd_user = 0; // not sure about the usage; pd[p].pd_pwt = 0; pd[p].pd_pcd = 0; pd[p].pd_acc = 0; pd[p].pd_mbz = 0; pd[p].pd_fmb = 0; pd[p].pd_global = 0; pd[p].pd_avail = 0; // not in use right now. pd[p].pd_base = a2pno((unsigned long) new_pt); /* location of page table */ if(GDB) kprintf("New page_table(%x)@frame[%d] updated in page_directory[%d]@(frame[%d])\n", new_pt, avail, p, frm_tab[avail].fr_upper_t); if(GDB) kprintf("q=%d, new_pt[q]=%x, new_pt=%x, pd[p].pd_base=%d\n", q, new_pt[q], new_pt, pd[p].pd_base); } //if the page table has already existed, just need to refcnt++; else { int avail = pd[p].pd_base -1024; frm_tab[avail].fr_refcnt++; if(GDB) kprintf("frm_tab[%d].fr_refcnt = %d, frame_type: %d\n",avail, frm_tab[avail].fr_refcnt, frm_tab[avail].fr_type); } /* 8.1 Using the backing store map, find the store s and page offset o which correspond to vp. */ //already saved in 'store' and 'pageth' s = *store; o = *pageth; /* 8.2 In the inverted page table increment the reference count of the frame which holds pt. This indicates that one more of pt's entries is marked "present." */ avail = find_frm(currpid,vp); if (avail == -1) { if(GDB) kprintf("allocating a page for the page fault\n"); avail = get_frm(); if(avail == -1) { if(GDB) kprintf("ATTENTION! Frames full. ###Replacement NEEDED!###\n"); int frame_number = proctab[currpid].nframes-1; int frame_id = proc_frames[currpid][0]; //update_proc_frames(pid,frame_number); int i; for (i = 0; i+1 < frame_number; ++i) { proc_frames[currpid][i] = proc_frames[currpid][i+1]; } proctab[currpid].nframes = frame_number; int pid = frm_tab[frame_id].fr_pid; int upper_id = frm_tab[frame_id].fr_upper_t; vp = frm_tab[frame_id].fr_vpno; if(GDB) kprintf("currpid=%d, frame[%d].pid=%d .vpno=%d, upper_frame[%d].ref=%d\n",currpid,frame_id,pid,vp,upper_id,frm_tab[upper_id].fr_refcnt); p = vp>>10; q = vp &0x003ff; new_pt = vp2pa(pd[p].pd_base); new_pt[q].pt_pres = 0; new_pt[q].pt_write = 1; new_pt[q].pt_base = 0; if(GDB) kprintf("pd_offset=%d, pt_offset=%d, pt_dirty=%d\n",p,q,new_pt[q].pt_dirty); if(new_pt[q].pt_dirty == 1) { //write back and pageth = getmem( sizeof(int *) ); store = getmem( sizeof(int *) ); if( SYSERR == bsm_lookup(currpid, vp, store, pageth)){ kprintf("ERROR: This virtual address hasn't been mapped!\n"); kill(currpid); } if(GDB) kprintf("maping found: {pid: %d, vpno: %d, store: %d, pageth: %d}\n",currpid,vp,*store,*pageth); write_bs((char *)new_pt, *store, *pageth); } init_pt(new_pt); reset_frm(frame_id); frm_tab[upper_id].fr_refcnt -= 2; //it is 2, not 1. if(frm_tab[upper_id].fr_refcnt <= 0){ //mark the appropriate entry in pd as being not present, and free pt. } //invalidate the TLB entry for the page vp using the invlpg instruction if(pid == currpid) { set_PDBR(currpid); } } else { init_frm(avail, currpid, FR_PAGE); frm_tab[avail].fr_upper_t = pd[p].pd_base-FRAME0; if(GDB) kprintf("upper page table @frame[%d]\n",frm_tab[avail].fr_upper_t); frm_tab[avail].fr_vpno = vp; int counter = proctab[currpid].nframes; proc_frames[currpid][counter] = frm_tab[avail].fr_id; proctab[currpid].nframes++; if(GDB) kprintf("proc_frames[%d][%d] = frame[%d]\n",currpid,counter,avail); // Add this frame to head of the frame list within the bs of this process //(frm_tab[avail].bs_next)->fr_vpno //, proctab[currpid].bsmap[s].frames->bs_next if(GDB) kprintf("&frm_tab[avail].bs_next = %x\n",frm_tab[avail].bs_next, &frm_tab[avail].bs_next); if(GDB) kprintf("proctab[%d].bsmap[%d].frames = %x, ->vpno=%d, ->bs_next=%x\n",currpid, s, proctab[currpid].bsmap[s].frames, proctab[currpid].bsmap[s].frames->fr_vpno, proctab[currpid].bsmap[s].frames->bs_next); frm_tab[avail].bs_next = getmem(sizeof(fr_map_t *)); frm_tab[avail].bs_next = proctab[currpid].bsmap[s].frames; proctab[currpid].bsmap[s].frames = &frm_tab[avail]; fr_map_t *frame = proctab[currpid].bsmap[s].frames; int i = frame->fr_vpno; if(GDB) kprintf("i = %d\n",i); if(GDB) kprintf("~~~frame[%d] linked to frame[%d]\n", avail, frame->bs_next==NULL?-1:frame->bs_next->fr_id); if(GDB) kprintf("frame[%d].bs_next = %x, &**=%x\n",avail,frm_tab[avail].bs_next, &frm_tab[avail].bs_next); if(GDB) kprintf("proctab[%d].bsmap[%d].frames = %x, ->vpno=%d, ->bs_next=%x\n",currpid, s, proctab[currpid].bsmap[s].frames, proctab[currpid].bsmap[s].frames->fr_vpno, proctab[currpid].bsmap[s].frames->bs_next); if(GDB) kprintf("Mapping frame[%d](ppno[%d]) to {pid[%d], vpno[%d]} -> {bs[%d],offset:%d}\n", avail,frid2vpno(avail),currpid,vp,s,o); physical_addr = frid2pa(avail); read_bs(physical_addr,s,o); if(GDB) kprintf("copied from bs[%d]:offset[%d] to vp[%d]@(%x)\n",s,o,vp,vp2pa(vp)); } }
int free_frame(frame_t * frame) { intmask mask; mask = disable(); //LOG("Freeing"); //print_frame(frame); if(frame->id <5) { LOG(" WHAT THE F**K %d %d", frame->id, frame->type); restore(mask); return OK; } //kprintf("id %d type %d ", frame->id, frame->type); //print_fifo_list(); //kprintf("\n"); if(frame == NULL) { restore(mask); return SYSERR; } else if(!FRAMEID_IS_VALID(frame->id)) { restore(mask); return SYSERR; } else if(frame->type == FREE) { restore(mask); return OK; } else if(frame->type == PAGE){ //print_fifo_list(); //LOG("Got here 0.5"); //3. Using the inverted page table, get vp, the virtual page number of the page to be replaced. uint32 vp = frame->vp_no; //4. Let a be vp*4096 (the first virtual address on page vp). hook_pswap_out(vp, frame->id + FRAME0); uint32 a = vp*PAGE_SIZE; virtual_addr * virt = (virtual_addr *) &a; //5. Let p be the high 10 bits of a. Let q be bits [21:12] of a. uint32 p = virt->page_directory_offset; uint32 q = virt->page_table_offset; //6. Let pid be the process id of the process owning vp. pid32 pid = frame->pid; //7. Let pd point to the page directory of process pid. struct procent *prptr; /* Ptr to process table entry */ prptr = &proctab[pid]; pd_t * pd = prptr->pagedir; if( pd == NULL) { LOG(" pd doesn't exist "); restore(mask); return SYSERR; } bool8 pt_pres = FALSE; pt_pres = (bool8) pd[p].pd_pres; bool8 pg_pres = FALSE; bool8 dirty = FALSE; if(pt_pres) { //8. Let pt point to the pid's p_th page table. pt_t * pt = (pt_t *) ((pd[p].pd_base) * PAGE_SIZE); pg_pres = (bool8) pt[q].pt_pres; uint32 pg_base = (uint32) pt[q].pt_base; if(pg_pres){ if((uint32)FRAMEID_TO_VPAGE(frame->id) == pg_base) { pg_pres = TRUE; dirty = pt[q].pt_dirty; } else { pg_pres = FALSE; } } } if(pg_pres) { frame_t * pt_frame = &frames[(pd[p].pd_base) - FRAME0]; pt_t * pt = (pt_t *) ((pd[p].pd_base) * PAGE_SIZE); //9. Mark the appropriate entry of pt as not present. pt[q].pt_pres = 0; if(pt_frame->type == VPTBL){ decr_frame_refcount(pt_frame); if(pt_frame->refcount == 0){ pd[p].pd_pres = 0; free_frame(pt_frame); } bzero((char *)&pt[q], sizeof(pt_t)); } else if(pt_frame->type == GPTBL) { // kprintf(" Uh OH"); } // If the reference count has reached zero, you should mark the appropriate entry in pd as "not present." // This conserves frames by keeping only page tables which are necessary. //LOG("Got here 1.5"); //If the dirty bit for page vp was set in its page table, you must do the following: //a) Using the backing store map, find the store and page offset within the store, given pid and a. // If the lookup fails, something is wrong. Print an error message and kill the process with id pid. //b) Write the page back to the backing store. //LOG("Got here 2"); if(dirty){ bsd_t bs_store_id; int bs_store_page_offset; if(SYSERR == bs_map_check(pid, vp, &bs_store_id, &bs_store_page_offset)) { kprintf("FATAL :Can't find the bs_map"); restore(mask); kill(currpid); return SYSERR; } //print_frame(frame); if(BACKSTORE_ID_IS_VALID(frame->backstore) && BACKSTORE_OFFSET_IS_VALID(frame->backstore_offset) && frame->backstore == bs_store_id && frame->backstore_offset == bs_store_page_offset) { //LOG("Frame %d was dirty", frame->id); open_bs(frame->backstore); write_bs(FRAMEID_TO_PHYSICALADDR(frame->id), frame->backstore, frame->backstore_offset); close_bs(frame->backstore); } //else //{ // print_frame(frame); // kprintf("Fatal error: Cannot locate backstore for vpage %d to swap out page for pid %d ", vp, pid); // kill(pid); // initialize_frame(frame); // restore(mask); // return SYSERR; //} } else{ //print_frame(frame); } } //LOG("Got here 1"); //10. If the page being removed belongs to the current process, // invalidate the TLB entry for the page vp, using the invlpg instruction (see Intel Manual, volumes II and III for more details on this instruction). // 11. In the inverted page table, decrement the reference count of the frame occupied by pt. //LOG(" Free frame"); //print_frame(frame); enable_paging(); initialize_frame(frame); // Update page table entries associated with this frame // set the frame to be free } else if(frame->type == VPTBL) { evict_from_fifo_list(frame); hook_ptable_delete(frame->id + FRAME0); enable_paging(); initialize_frame(frame); } else if(frame->type == DIR) { struct procent * prptrNULL = &proctab[NULLPROC]; pd_t * null_pg_dir = prptrNULL->pagedir; struct procent *prptr; /* Ptr to process table entry */ prptr = &proctab[currpid]; if(prptr->pagedir!= null_pg_dir) { evict_from_fifo_list(frame); prptr->pagedir = prptrNULL->pagedir; switch_page_directory(prptr->pagedir); enable_paging(); initialize_frame(frame); } } restore(mask); return OK; }