/*------------------------------------------------------------------------- * free_frm - free a frame *------------------------------------------------------------------------- */ SYSCALL free_frm(int i, int pid) { STATWORD ps; disable(ps); int k = NFRAMES; if (frm_tab[i].fr_refcnt <= 0) { if (frm_tab[i].fr_type == FR_PAGE) { reset_page_tab(frm_tab[i].fr_vpno[pid]); init_frm(i); } else if (frm_tab[i].fr_type == FR_TBL) { pd_t *ptr = (pd_t*) (proctab[pid].pdbr); while (k > 0) { if (ptr->pd_base == (i + FRAME0)) { init_page_dir(ptr); ptr->pd_pres = 0; break; } ptr++; k--; } init_frm(i); } } else { if (frm_tab[i].fr_type == FR_PAGE) { reset_page_tab(frm_tab[i].fr_vpno[pid]); frm_tab[i].fr_vpno[pid] = 0; } } restore(ps); return OK; }
/*------------------------------------------------------------------------- * get_frm - get a free frame according page replacement policy *------------------------------------------------------------------------- */ SYSCALL get_frm(int* avail) { int i, j; STATWORD ps; disable(ps); for (i = 0; i < NFRAMES; i++) { if (frm_tab[i].fr_status == FRM_UNMAPPED) { init_frm(i); *avail = i; frm_tab[i].fr_status = FRM_MAPPED; //kprintf("get_frm returned %d\n",*avail); break; } } if (i == NFRAMES) { // kprintf("Ran out of free frames\n"); //indicates that we ran out of free frames. Implement page replacement policy and return a new frame as per the page replacement policy if (page_replace_policy == LRU) { *avail = next_frame(); //kprintf("get_frm returned %d\n",*avail); } else { *avail = getframe_fifoqueue(); } if (check_update_bs(*avail, frm_tab[*avail].fr_curr_bs, currpid) == OK) { frm_tab[*avail].fr_refcnt--; for (j = NPROC - 1; j > 0; j--) { if (frm_tab[*avail].fr_vpno[j] > 0 && frm_tab[*avail].fr_type == FR_PAGE) { //kprintf("fr_vpno[%d] = 0x%x\n",j,frm_tab[*avail].fr_vpno[j]); free_frm(*avail, j); } } //kprintf("ran out of free frames\n"); } frm_tab[*avail].fr_status = FRM_MAPPED; } //kprintf("get_frm returned %d\n",*avail); frm_tab[*avail].fr_pid = currpid; restore(ps); //kprintf("To be implemented!\n"); return OK; }
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)); } }
/*------------------------------------------------------------------------ * sysinit -- initialize all Xinu data structeres and devices *------------------------------------------------------------------------ */ LOCAL sysinit() { static long currsp; int i,j; struct pentry *pptr; struct sentry *sptr; struct mblock *mptr; SYSCALL pfintr(); numproc = 0; /* initialize system variables */ nextproc = NPROC-1; nextsem = NSEM-1; nextqueue = NPROC; /* q[0..NPROC-1] are processes */ /* initialize free memory list */ /* PC version has to pre-allocate 640K-1024K "hole" */ if (maxaddr+1 > HOLESTART) { memlist.mnext = mptr = (struct mblock *) roundmb(&end); mptr->mnext = (struct mblock *)HOLEEND; mptr->mlen = (int) truncew(((unsigned) HOLESTART - (unsigned)&end)); mptr->mlen -= 4; mptr = (struct mblock *) HOLEEND; mptr->mnext = 0; mptr->mlen = (int) truncew((unsigned)maxaddr - HOLEEND - NULLSTK); /* mptr->mlen = (int) truncew((unsigned)maxaddr - (4096 - 1024 ) * 4096 - HOLEEND - NULLSTK); */ } else { /* initialize free memory list */ memlist.mnext = mptr = (struct mblock *) roundmb(&end); mptr->mnext = 0; mptr->mlen = (int) truncew((unsigned)maxaddr - (int)&end - NULLSTK); } for (i=0 ; i<NPROC ; i++) /* initialize process table */ proctab[i].pstate = PRFREE; #ifdef MEMMARK _mkinit(); /* initialize memory marking */ #endif #ifdef RTCLOCK clkinit(); /* initialize r.t.clock */ #endif mon_init(); /* init monitor */ #ifdef NDEVS for (i=0 ; i<NDEVS ; i++ ) { init_dev(i); } #endif pptr = &proctab[NULLPROC]; /* initialize null process entry */ pptr->pstate = PRCURR; for (j=0; j<7; j++) pptr->pname[j] = "prnull"[j]; pptr->plimit = (WORD)(maxaddr + 1) - NULLSTK; pptr->pbase = (WORD) maxaddr - 3; /* pptr->plimit = (WORD)(maxaddr + 1) - NULLSTK - (4096 - 1024 )*4096; pptr->pbase = (WORD) maxaddr - 3 - (4096-1024)*4096; */ pptr->pesp = pptr->pbase-4; /* for stkchk; rewritten before used */ *( (int *)pptr->pbase ) = MAGIC; pptr->paddr = (WORD) nulluser; pptr->pargs = 0; pptr->pprio = 0; currpid = NULLPROC; for (i=0 ; i<NSEM ; i++) { /* initialize semaphores */ (sptr = &semaph[i])->sstate = SFREE; sptr->sqtail = 1 + (sptr->sqhead = newqueue()); } rdytail = 1 + (rdyhead=newqueue());/* initialize ready list */ //OS proj 3 modify //OS proj 3 modify init_bsm(); //initialize 16 Backing stores init_frm(); //initialize 1024 frames set_evec(14,pfintr); return(OK); }
/*------------------------------------------------------------------------ * nulluser -- initialize system and become the null process (id==0) *------------------------------------------------------------------------ */ nulluser() /* babysit CPU when no one is home */ { int userpid; unsigned long temp; console_dev = SERIAL0; /* set console to COM0 */ initevec(); kprintf("system running up!\n"); sysinit(); enable(); /* enable interrupts */ sprintf(vers, "PC Xinu %s", VERSION); kprintf("\n\n%s\n", vers); if (reboot++ < 1) kprintf("\n"); else kprintf(" (reboot %d)\n", reboot); kprintf("%d bytes real mem\n", (unsigned long) maxaddr+1); #ifdef DETAIL kprintf(" %d", (unsigned long) 0); kprintf(" to %d\n", (unsigned long) (maxaddr) ); #endif kprintf("%d bytes Xinu code\n", (unsigned long) ((unsigned long) &end - (unsigned long) start)); #ifdef DETAIL kprintf(" %d", (unsigned long) start); kprintf(" to %d\n", (unsigned long) &end ); #endif #ifdef DETAIL kprintf("%d bytes user stack/heap space\n", (unsigned long) ((unsigned long) maxaddr - (unsigned long) &end)); kprintf(" %d", (unsigned long) &end); kprintf(" to %d\n", (unsigned long) maxaddr); #endif kprintf("clock %sabled\n", clkruns == 1?"en":"dis"); /* initialize_pagedirectory(); initialize_pagetable(); get_frame(1,FR_DIR,0); get_frame(1,FR_TBL,0); get_frame(1,FR_TBL,0); get_frame(1,FR_TBL,0); get_frame(1,FR_TBL,0); */ init_frm(); init_bsm(); temp = create_ps() ; write_cr3(0x400000); set_evec(14,pfintr); proctab[currpid].pdbr = temp; // pageq.next= &pageq; //Always points to head myheadq = NULL; //actual pointer used by page replacement policyi currq = NULL; pcurrq = NULL; /* create a process to execute the user's main program */ userpid = create(main,INITSTK,INITPRIO,INITNAME,INITARGS); enable_paging(); resume(userpid); while (TRUE) /* empty */; }