/******************************************************************************* * Name: new_pgd * * Desc: Allocates and intializes a new page directory. Usually called during * process creation. * * Params: None. * * Returns: Pointer to the newly allocated pgd. NULL on error. ******************************************************************************/ pd_t * new_pgd(void) { int pd_id = 0; pd_t *new_pd = NULL; frm_map_t *new_frame = NULL; STATWORD ps; disable(ps); DTRACE_START; new_frame = get_frm(FR_PDIR); if (NULL == new_frame) { DTRACE("DBG$ %d %s> get_frm() failed\n", currpid, __func__); goto RESTORE_AND_RETURN_NULL; } new_frame->fr_type = FR_PDIR; /* The PD would start at the PA of the frame that we just got. */ new_pd = (pd_t *) FR_ID_TO_PA(new_frame->fr_id); /* Same as page tables, each pd entry is 4 bytes long. Thus, a frame which * is 4 KB, can hold (NBPG / 4 = 1024) entries. Intially all the fields * are set to zero. Also, every process will share the global page tables. */ bzero(new_pd, sizeof(pd_t)); for (pd_id = 0; pd_id < PT_NGPT; ++pd_id) { new_pd[pd_id].pd_pres = 1; new_pd[pd_id].pd_write = 1; new_pd[pd_id].pd_avail = 1; /* The base should contain vpage of the frame containing the global * page tables. */ new_pd[pd_id].pd_base = VADDR_TO_VPAGE((unsigned) g_pt[pd_id]); } DTRACE("DBG$ %d %s> pgd at 0x%08x is being returned\n", \ currpid, __func__, new_pd); DTRACE_END; restore(ps); return new_pd; RESTORE_AND_RETURN_NULL: DTRACE_END; restore(ps); return NULL; }
/******************************************************************************* * Name: new_pgt * * Desc: Allocates and intializes a new page table. * * Params: None. * * Returns: Pointer to the newly allocated pgt. NULL on error. ******************************************************************************/ pt_t * new_pgt(void) { pt_t *new_pt = NULL; frm_map_t *new_frame = NULL; STATWORD ps; disable(ps); DTRACE_START; new_frame = get_frm(FR_PTBL); if (NULL == new_frame) { DTRACE("DBG$ %d %s> get-frm() failed\n", currpid, __func__); kprintf("\n\n"); kprintf("FATAL ERROR: Ran out of free frames for page tables!\n"); kprintf("Process '%s' with PID '%d' will be terminated.\n", \ P_GET_PNAME(currpid), currpid); kprintf("\n\n"); sleep(9); DTRACE_END; restore(ps); kill(getpid()); goto RESTORE_AND_RETURN_NULL; } new_frame->fr_type = FR_PTBL; /* The PT would start at the PA of the frame that we just got. Since, it's * coniguous, we can fill-in the values in a looped manner. */ new_pt = (pt_t *) FR_ID_TO_PA(new_frame->fr_id); init_pgt(new_pt); DTRACE("DBG$ %d %s> returning new pgt at 0x%08x\n", \ currpid, __func__, new_pt); DTRACE_END; restore(ps); return new_pt; RESTORE_AND_RETURN_NULL: DTRACE("DBG$ %d %s> returning NULL\n", currpid, __func__); DTRACE_END; restore(ps); return NULL; }
/*------------------------------------------------------------------------- * pfint - paging fault ISR *------------------------------------------------------------------------- */ SYSCALL pfint() { STATWORD ps; disable(ps); int vp, p, q; int i; unsigned long fault_addr; int store, pageth; int new_frame, m_frame = -1; pt_t *ptr_pt; fault_addr = read_cr2(); vp = (fault_addr & ~(NBPG - 1)) >> 12; //If process tries to access bs that it has not got using getbs. if (bsm_lookup(currpid, fault_addr, &store, &pageth) == SYSERR) { kill(currpid); } pd_t *ptr_pd = (pd_t *) (proctab[currpid].pdbr); p = (fault_addr & 0xFFC00000) >> 22; q = (fault_addr & 0x003FF000) >> 12; ptr_pd = ptr_pd + p; if (ptr_pd->pd_pres == 0) { get_frm(&new_frame); frm_tab[new_frame].fr_pid = currpid; frm_tab[new_frame].fr_type = FR_TBL; new_frame = new_frame + FRAME0; add_page_dir(ptr_pd, new_frame, ((proctab[currpid].pdbr & ~(NBPG - 1)) >> 12) - FRAME0); } else
/*------------------------------------------------------------------------- * pfint - paging fault ISR *------------------------------------------------------------------------- */ SYSCALL pfint() { STATWORD ps; disable(ps); unsigned long int eip = read_cr2(); unsigned long int pd_offset = eip >> 22; unsigned long int pt_offset = eip >>12; pt_offset = pt_offset & 1023; unsigned long offset = eip; offset = offset & 4095; eip = eip >> 12; //vpno int i = 0, flag = 0; int backing_store_page, bs_id; for(i = 0 ; i < NBS; i++) { if(proctab[currpid].map[i].bs_pid == currpid) { if(proctab[currpid].map[i].next == NULL) { if(proctab[currpid].map[i].bs_vpno == eip) //we found the exact page { backing_store_page = proctab[currpid].map[i].starting_page; flag = 1; } else if(proctab[currpid].map[i].bs_vpno < eip && (proctab[currpid].map[i].bs_vpno+proctab[currpid].map[i].bs_npages) >= eip) { backing_store_page = proctab[currpid].map[i].starting_page + eip - proctab[currpid].map[i].bs_vpno; flag = 1; } } else { bs_map_t *move = &(proctab[currpid].map[i]); while(move != NULL) { if(move->bs_vpno == eip) //we found the exact page { backing_store_page = move->starting_page; flag = 1; break; } else if(move->bs_vpno < eip && (move->bs_npages+move->bs_vpno) >= eip) { backing_store_page = move->starting_page + eip - move->bs_vpno; flag = 1; break; } move = move->next; } } } if(flag==1) { bs_id = i; break; } } unsigned long *bs_addr = (unsigned long *)(backing_store_page*NBPG); //populate page table //checking if page dir is empty pd_t *ptr1 = (pd_t *)(proctab[currpid].pdbr); ptr1 += pd_offset; pt_t *ptr; if(ptr1->pd_pres == 1) //page table exists hence add entry to that { ptr = (pt_t *)((ptr1->pd_base)*NBPG); frm_tab[(ptr1->pd_base)-FRAME0].refcnt++; frm_map[(ptr1->pd_base)-FRAME0].fr_refcnt++; } else //we need to create a page table, add our free_frame entry to it and add the page table entry to the directory { //kprintf("\nin else %d\n",ptr1); int pt_frame = get_frm(); frm_tab[pt_frame-FRAME0].status = FRM_PGT; frm_tab[pt_frame-FRAME0].refcnt++; frm_map[pt_frame-FRAME0].fr_status = FRM_MAPPED; frm_map[pt_frame-FRAME0].fr_pid = currpid; frm_map[pt_frame-FRAME0].fr_refcnt++; frm_map[pt_frame-FRAME0].fr_type = FR_TBL; ptr = (pt_t*)(pt_frame*NBPG); //add the above table to page directory ptr1->pd_pres = 1; ptr1->pd_write = 1; ptr1->pd_user = 0; ptr1->pd_pwt = 0; ptr1->pd_pcd = 0; ptr1->pd_acc = 0; ptr1->pd_mbz = 0; ptr1->pd_fmb = 0; ptr1->pd_global = 0; ptr1->pd_avail = 0; ptr1->pd_base = pt_frame; } //add entry to page table ptr += pt_offset; ptr->pt_pres = 1; ptr->pt_write = 1; ptr->pt_user = 0; ptr->pt_pwt = 0; ptr->pt_pcd = 0; ptr->pt_acc = 0; ptr->pt_dirty = 0; ptr->pt_mbz = 0; ptr->pt_global = 0; ptr->pt_avail = 0; //getting a free frame an setting the frame mappings int free_frame; if(page_table[backing_store_page-total_bs_available] != -1) { free_frame = page_table[backing_store_page-total_bs_available]; frm_map[free_frame-FRAME0].fr_refcnt++; frm_tab[free_frame-FRAME0].refcnt++; fr_map_t *map = (fr_map_t *)getmem(sizeof(fr_map_t)); map->fr_pid = currpid; map->fr_vpno = eip; map->shared = NULL; fr_map_t *next = (fr_map_t *)getmem(sizeof(fr_map_t)); next = &(frm_map[free_frame-FRAME0]); while(next->shared != NULL) next = next->shared; next->shared = map; } else { //obtain free frame free_frame = get_frm(); frm_tab[free_frame-FRAME0].status = FRM_BS; frm_tab[free_frame-FRAME0].refcnt++; frm_tab[free_frame-FRAME0].bs = bs_id; frm_tab[free_frame-FRAME0].bs_page = backing_store_page; frm_tab[free_frame-FRAME0].bs_next = NULL; frm_tab[free_frame-FRAME0].fifo = NULL; frm_tab[free_frame-FRAME0].age = 128; frm_map[free_frame-FRAME0].fr_status = FRM_MAPPED; frm_map[free_frame-FRAME0].fr_pid = currpid; frm_map[free_frame-FRAME0].fr_vpno = eip; frm_map[free_frame-FRAME0].fr_refcnt++; frm_map[free_frame-FRAME0].fr_type = FR_PAGE; frm_map[free_frame-FRAME0].bs_page_num = backing_store_page; page_table[backing_store_page-total_bs_available] = free_frame; //set bs mappings if(bs_tab[bs_id].frm == NULL) bs_tab[bs_id].frm = &frm_tab[free_frame-FRAME0]; else { frame_t *move = (frame_t *)getmem(sizeof(frame_t)); move = bs_tab[bs_id].frm; while(move->bs_next != NULL) { move = move->bs_next; } move->bs_next = &frm_tab[free_frame-FRAME0]; } //adding this frame to the fifo queue if(fifo_head == NULL) { //queue is empty fifo_head = &frm_tab[free_frame-FRAME0]; fifo_tail = fifo_head; } else { fifo_tail->fifo = &frm_tab[free_frame-FRAME0]; fifo_tail = &frm_tab[free_frame-FRAME0]; } } unsigned long *dest_addr = (unsigned long *)(free_frame*NBPG); //copy page from bs to phy for(i = 0; i < NBPG/sizeof(unsigned long); i++) { *dest_addr = *bs_addr; dest_addr++; bs_addr++; } ptr->pt_base = free_frame; restore(ps); return OK; }
/******************************************************************************* * Name: pf_handler * * Desc: High level page fault handling code. The low level page fault * interrupt handler is written in assembly. It'll setup the required * registers (faulted address in CR2) and the stack frame with the * error code. This routine is responsible for the following: * 1. Read the faulted address and lookup BS to find if this address is * mapped. If so, get the BS id and the offset within the BS. If * not, this is an illegal access - kill the process and move on. * 2. Actual paging starts here. Lookup the proctab to find the pid's * pdir base. From the faulted address, we can get the pdir offset. * Using these two, check if a page table exist for the faulted * address. If not create one. * 3. If the page table is presnet, get the ptbl offset from the * faulted vaddr. This points to the location of the page table * entry. Now, check if the frame assoicated with this page is * already present in the memory (shared pages). If so, update the * page table's 'pres' bit to reflect this and increment the * frame's refcount. If not, allocate a new frame and update the * page table entry to reflect that the frame is present. * 4. Processor caches the paging entries (TLB) maintained by software * and uses them whenever possible. When a pgt entry's 'pres' bit * is cleared, we need to flush the entry from the processor * cache so that the proceessor would use the updated software * data. This is described in detail in section 4.8 of Intel IA32 * software developer manual (vol 3). There are many ways to force * the processor to use the software tables, than hardware cache. * One such way is to reload teh CR0 register. So, if any of the * 'pres' bits are modified, we reload the CR0 register. * * Params: None. * * Returns: SYSCALL * OK - on success * SYSERR - on error ******************************************************************************/ SYSCALL pf_handler(void) { int bs_id = EMPTY; int bs_offset = EMPTY; int fr_id = EMPTY; uint32_t pdir_offset = 0; uint32_t ptbl_offset = 0; uint32_t page_offset = 0; uint32_t fault_addr = 0; pd_t *pdir = NULL; pt_t *ptbl = NULL; frm_map_t *frptr = NULL; frm_map_t *pt_frptr = NULL; virt_addr_t *fault_vaddr = NULL; STATWORD ps; disable(ps); DTRACE_START; DTRACE("DBG$ %d %s> inside high-level page fault handler\n", \ currpid, __func__); /* vaddr : pdir_offset : ptbl_offset : page_offset * 32 bits : 10 bits : 10 bits : 12 bits */ fault_addr = read_cr2(); /* The virtual address is 32-bits. So, we directly read the required set of * bits by assigining it to a strcutre with appropriate bit-fields. */ fault_vaddr = (virt_addr_t *) (&fault_addr); pdir_offset = (uint32_t) fault_vaddr->pd_offset; ptbl_offset = (uint32_t) fault_vaddr->pt_offset; page_offset = (uint32_t) fault_vaddr->pg_offset; DTRACE("DBG$ %d %s> faulted vaddr 0x%08x, vpage %d\n", \ currpid, __func__, fault_addr, VADDR_TO_VPAGE(fault_addr)); DTRACE("DBG$ %d %s> pd %d, pt %d, pg %d\n", \ currpid, __func__, pdir_offset, ptbl_offset, page_offset); /* Check the BS for a mapping for the faulted vaddr and the pid. If present, * record the BS id and the offset within the BS. If not present, it's * illeagal memory access. Kill the process and return. */ if (SYSERR == bsm_lookup(currpid, fault_addr, &bs_id, &bs_offset, NULL, NULL)) { DTRACE("DBG$ %d %s> bsm_lookup() failed\n", currpid, __func__); DTRACE("DBG$ %d %s> pid %d will be killed\n", \ currpid, __func__, currpid); kprintf("\n\n"); kprintf("FATAL ERROR: Process '%s' with pid '%d' is trying to access " \ "virtual memory out of its range! \nThe process will be " \ "terminated.\n", P_GET_PNAME(currpid), currpid); kprintf("\n\n"); sleep(9); DTRACE_END; restore(ps); kill(currpid); goto RESTORE_AND_RETURN_ERROR; } /* Get the currpid's page directory and index to the appropriate pgt. If pgt * isn't present, create one. */ pdir = P_GET_PDIR(currpid); if (FALSE == PD_GET_PRES(pdir, pdir_offset)) { DTRACE("DBG$ %d %s> pgt not present for pid %d, pd offset %d, " \ "pt offset %d, pg offset %d, vaddr 0x%08x\n", currpid, \ __func__, currpid, pdir_offset, ptbl_offset, page_offset, \ fault_addr); ptbl = new_pgt(); if (NULL == ptbl) { DTRACE("DBG$ %d %s> new_pgt() failed\n", currpid, __func__); goto RESTORE_AND_RETURN_ERROR; } /* Fill-in few meta-data for the pgt frame just created. */ pt_frptr = FR_GET_FPTR(FR_PA_TO_ID(ptbl)); pt_frptr->fr_pid = currpid; /* Set the 'pres' and 'write' bits alone. Rest would've been zeroed * out by new_pgt(). Also, set the base of the new page table. */ pdir[pdir_offset].pd_pres = 1; pdir[pdir_offset].pd_write = 1; pdir[pdir_offset].pd_base = VADDR_TO_VPAGE((unsigned) ptbl); } else { DTRACE("DBG$ %d %s> ptbl already present at 0x%08x, fr id %d\n", \ currpid, __func__, VPAGE_TO_VADDR(PD_GET_BASE(pdir, pdir_offset)),\ FR_PA_TO_ID(VPAGE_TO_VADDR(PD_GET_BASE(pdir, pdir_offset)))); } ptbl = (pt_t *) VPAGE_TO_VADDR(PD_GET_BASE(pdir, pdir_offset)); DTRACE("DBG$ %d %s> ptbl present at 0x%08x, fr id %d\n", \ currpid, __func__, ptbl, FR_PA_TO_ID(ptbl)); /* Find if a frame representing the same BS id and offset is present in the * memory (shared pages). If so, just update the page table entry and * increment teh refcount. */ if (EMPTY == (fr_id = is_frm_present(bs_id, bs_offset))) { DTRACE("DBG$ %d %s> frame not present.. creating a new frame\n", \ currpid, __func__); frptr = get_frm(FR_PAGE); if (NULL == frptr) { DTRACE("DBG$ %d %s> get_frm() failed\n", currpid, __func__); goto RESTORE_AND_RETURN_ERROR; } fr_id = frptr->fr_id; frm_pidmap_oper(fr_id, getpid(), FR_OP_PMAP_SET); frm_record_details(fr_id, getpid(), VADDR_TO_VPAGE(fault_addr)); /* Read the appropriate page from BS onto the new frame. */ if (SYSERR == read_bs((char *) FR_ID_TO_PA(fr_id), bs_id, bs_offset)) { DTRACE("DBG$ %d %s> read_bs() failed for fr id %d, bs %d, " \ "offset %d\n", currpid, __func__, fr_id, bs_id, bs_offset); goto RESTORE_AND_RETURN_ERROR; } else { DTRACE("DBG$ %d %s> reading for fr id %d, bs %d, offset %d\n", \ currpid, __func__, fr_id, bs_id, bs_offset); } /* Fill-in the new BS details in the frame. */ frptr->fr_type = FR_PAGE; frptr->fr_bs = bs_id; frptr->fr_bsoffset = bs_offset; inc_frm_refcount(fr_id); #ifdef DBG_ON print_frm_id(fr_id); #endif } else { /* A frame representing the same BS and offset is already present in the * memory. So, just increment the refcount of the frame. */ frm_pidmap_oper(fr_id, getpid(), FR_OP_PMAP_SET); frm_record_details(fr_id, getpid(), VADDR_TO_VPAGE(fault_addr)); inc_frm_refcount(fr_id); } /* In both cases (frame present and frame not present), we need to update * the page table entry as at this point, the frame is loaded onto the * memory. Do the following w.r.t. the pgt frame: * 1. Set the 'pres' bit in the page table entry corresponding to the * newly loaded page to reflect that the page is present in the * memory. * 2. Set the 'write' bit (as given in PA3 description). * 3. Update the 'base' of the page entry corresponding to the newly * created page to point to the frame. * 4. Increment the refcount of the pgt frame. Unlike data frames, where * refocunt denotes the # of processes that map to the actual * physical frame, pgt frame's refcount reflects the # of pages * (that are part of this pgt) that are present in the memory. * This will be decremented when a frame is paged out and the * pgt frame will be freed when the refcount reaches zero. */ ptbl[ptbl_offset].pt_pres = 1; ptbl[ptbl_offset].pt_write = 1; ptbl[ptbl_offset].pt_base = FR_ID_TO_VPAGE(fr_id); inc_frm_refcount(FR_PA_TO_ID(ptbl)); /* Reload the CR0 register would force the processor to flush the tables * that the processor maintains in hardware cache and to use the updated * software tables. */ enable_paging(); DTRACE("DBG$ %d %s> returning OK\n", currpid, __func__); DTRACE_END; restore(ps); return OK; RESTORE_AND_RETURN_ERROR: DTRACE("DBG$ %d %s> returning SYSERR\n", currpid, __func__); DTRACE_END; restore(ps); return SYSERR; }
/*------------------------------------------------------------------------ * nulluser -- initialize system and become the null process (id==0) *------------------------------------------------------------------------ */ nulluser() /* babysit CPU when no one is home */ { int userpid; //OS proj 3 modify int i; unsigned long nullproc_PDBR, main_PDBR; //int free_fr1,free_fr2,free_fr3,free_fr4; 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 //OS proj 3 modify /*Create new page table for null process: - create page directory (outer page table) - initialize 1:1 mapping for the first 4096 pages - allocate 4 page tables (4x1024 pages) - assign each page table entry to the address starting from page number 0 to 1023 - this page tables should be shared between processes*/ nullproc_PDBR = init_pagedir(currpid); //func in frame.c write_cr3(nullproc_PDBR); proctab[currpid].pdbr = nullproc_PDBR; //create global frames to map 4096 /*All memory below page 4096 will be "global". That is, it is usable and visible by all processes and accessible by simply using its actual physical addresses. As a result, the first four page tables for every process will be the same, and thus should be shared.*/ for(i = 0; i < 4; ++i) { global_pagetable_fr[i] = get_frm(); global_pagetable_addr[i] = 0x00400000 + (unsigned long) global_pagetable_fr[i] * NBPG; map_frame_to_proc_virtpage(global_pagetable_fr[i], currpid, global_pagetable_addr[i] >> 12, FR_TBL); /* frm_tab[global_pagetable_fr[i]].fr_status = FRM_MAPPED; frm_tab[global_pagetable_fr[i]].fr_type = FR_TBL; frm_tab[global_pagetable_fr[i]].fr_dirty = 1; frm_tab[global_pagetable_fr[i]].fr_loadtime = ctr1000; */ } share_global_tables(nullproc_PDBR); //implement get_frm() enable_paging(); kprintf("clock %sabled\n", clkruns == 1?"en":"dis"); /* create a process to execute the user's main program */ userpid = create(main,INITSTK,INITPRIO,INITNAME,INITARGS); //OS proj 3 modify main_PDBR = init_pagedir(userpid); proctab[userpid].pdbr = main_PDBR; share_global_tables(main_PDBR); resume(userpid); while (TRUE) /* empty */; }
/*------------------------------------------------------------------------- * pfint - paging fault ISR *------------------------------------------------------------------------- */ SYSCALL pfint() { STATWORD ps; disable(ps); unsigned long int eip = read_cr2(); //kprintf("\n\n#PF in %s, cr2:%x",proctab[currpid].pname, eip); unsigned long int pd_offset = eip >> 22; unsigned long int pt_offset = eip >>12; pt_offset = pt_offset & 1023; unsigned long offset = eip; offset = offset & 4095; //kprintf("\nEIP read is %lu\n",eip); eip = eip >> 12; //vpno //kprintf("\nEIP shifted is %lu\n",eip); int i = 0, flag = 0; int backing_store_page, bs_id; for(i = 0 ; i < NBS; i++) { if(proctab[currpid].map[i].pid == currpid) { //kprintf("\nif\n"); if(proctab[currpid].map[i].next == NULL) { //kprintf("\nif if\n"); if(proctab[currpid].map[i].vpno == eip) //we found the exact page { backing_store_page = proctab[currpid].map[i].base_page; flag = 1; //kprintf("\nif if if\n"); } else if(proctab[currpid].map[i].vpno < eip && (proctab[currpid].map[i].vpno+proctab[currpid].map[i].npages) >= eip) //we found the page in the range of base_page - npages { backing_store_page = proctab[currpid].map[i].base_page + eip - proctab[currpid].map[i].vpno; flag = 1; //kprintf("\nif if else if\n"); } } else { //kprintf("\nelse\n"); bs_map_t *jump = &(proctab[currpid].map[i]); while(jump != NULL) { //kprintf("\nwhile\n"); if(jump->vpno == eip) //we found the exact page { backing_store_page = jump->base_page; flag = 1; //kprintf("\nif else if\n"); break; } else if(jump->vpno < eip && (jump->npages+jump->vpno) >= eip) //we found the page in the range of base_page - npages { backing_store_page = jump->base_page + eip - jump->vpno; flag = 1; //kprintf("\nif else else if\n"); break; } jump = jump->next; } } } if(flag) { bs_id = i; break; } } //kprintf("\nin pfint bs %d, bs_page %d",bs_id,backing_store_page); unsigned long *bs_addr = (unsigned long *)(backing_store_page*NBPG); //populate page table //checking if page dir is empty pd_t *ptr1 = (pd_t *)(proctab[currpid].pdbr); //kprintf("\nbefore %d, %lu\n",ptr1,pd_offset); ptr1 += pd_offset; pt_t *ptr; if(ptr1->pd_pres == 1) //page table exists hence add entry to that { ptr = (pt_t *)((ptr1->pd_base)*NBPG); frm_tab[(ptr1->pd_base)-FRAME0].refcnt++; frm_map[(ptr1->pd_base)-FRAME0].fr_refcnt++; } else //we need to create a page table, add our free_frm entry to it and add the page table entry to the directory { //kprintf("\nin else %d\n",ptr1); int pt_frame = get_frm(); frm_tab[pt_frame-FRAME0].status = FRM_PGT; frm_tab[pt_frame-FRAME0].refcnt++; frm_map[pt_frame-FRAME0].fr_status = FRM_MAPPED; frm_map[pt_frame-FRAME0].fr_pid = currpid; frm_map[pt_frame-FRAME0].fr_refcnt++; frm_map[pt_frame-FRAME0].fr_type = FR_TBL; ptr = (pt_t*)(pt_frame*NBPG); //add the above table to page directory ptr1->pd_pres = 1; ptr1->pd_write = 1; ptr1->pd_user = 0; ptr1->pd_pwt = 0; ptr1->pd_pcd = 0; ptr1->pd_acc = 0; ptr1->pd_mbz = 0; ptr1->pd_fmb = 0; ptr1->pd_global = 0; ptr1->pd_avail = 0; ptr1->pd_base = pt_frame; //kprintf("\nget_frm return frame %d. To be page table for process %s",pt_frame, proctab[currpid].pname); } //add entry to page table ptr += pt_offset; ptr->pt_pres = 1; ptr->pt_write = 1; ptr->pt_user = 0; ptr->pt_pwt = 0; ptr->pt_pcd = 0; ptr->pt_acc = 0; ptr->pt_dirty = 0; ptr->pt_mbz = 0; ptr->pt_global = 0; ptr->pt_avail = 0; //getting a free frame an setting the frame mappings int free_frm; if(ni_page_table[backing_store_page-total_bs_left] != -1) // if backing store is already mapped then we share the frame { free_frm = ni_page_table[backing_store_page-total_bs_left]; //kprintf("\nIN NI frm = %d, ni = %d\n",free_frm, ni_page_table[backing_store_page-total_bs_left]); frm_map[free_frm-FRAME0].fr_refcnt++; frm_tab[free_frm-FRAME0].refcnt++; //adding this vpno and pid to the shared frame map list fr_map_t *map = (fr_map_t *)getmem(sizeof(fr_map_t)); map->fr_pid = currpid; map->fr_vpno = eip; map->shared = NULL; fr_map_t *next = (fr_map_t *)getmem(sizeof(fr_map_t)); next = &(frm_map[free_frm-FRAME0]); while(next->shared != NULL) next = next->shared; next->shared = map; //printing the list /*kprintf("\nSHARED VPNO: "); next = &(frm_map[free_frm-FRAME0]); while(next != NULL) { kprintf("%d -> ",next->fr_vpno); next = next->shared; }*/ } else { free_frm = get_frm(); frm_tab[free_frm-FRAME0].status = FRM_BS; frm_tab[free_frm-FRAME0].refcnt++; frm_tab[free_frm-FRAME0].bs = bs_id; frm_tab[free_frm-FRAME0].bs_page = backing_store_page; frm_tab[free_frm-FRAME0].bs_next = NULL; frm_tab[free_frm-FRAME0].fifo = NULL; frm_tab[free_frm-FRAME0].age = 128; frm_map[free_frm-FRAME0].fr_status = FRM_MAPPED; frm_map[free_frm-FRAME0].fr_pid = currpid; frm_map[free_frm-FRAME0].fr_vpno = eip; frm_map[free_frm-FRAME0].fr_refcnt++; frm_map[free_frm-FRAME0].fr_type = FR_PAGE; frm_map[free_frm-FRAME0].bs_page_num = backing_store_page; ni_page_table[backing_store_page-total_bs_left] = free_frm; //set bs mappings if(bs_tab[bs_id].frm == NULL) bs_tab[bs_id].frm = &frm_tab[free_frm-FRAME0]; else { //frame_t *jump = &frm_tab[free_frm-FRAME0]; frame_t *jump = (frame_t *)getmem(sizeof(frame_t)); jump = bs_tab[bs_id].frm; while(jump->bs_next != NULL) { jump = jump->bs_next; //kprintf("\njumping\n"); } jump->bs_next = &frm_tab[free_frm-FRAME0]; } //adding this frame to the fifo queue if(fifo_head == NULL) { //queue is empty fifo_head = &frm_tab[free_frm-FRAME0]; fifo_tail = fifo_head; } else { fifo_tail->fifo = &frm_tab[free_frm-FRAME0]; fifo_tail = &frm_tab[free_frm-FRAME0]; } } //kprintf("\nget_frm return frame %d.", free_frm); unsigned long *dst_addr = (unsigned long *)(free_frm*NBPG); //kprintf("\n\n Virtual page %d mapped to bs page %d, bs id %d, mapped to frame %d, %lu",eip, backing_store_page, bs_id, free_frm,dst_addr); /*frame_t *next = fifo_head; kprintf("\nFIFO : "); while(next != NULL) { kprintf("%d-> ",next->frame_num); next = next->fifo; } kprintf("\n");*/ //copy page from bs to phy for(i = 0; i < NBPG/sizeof(unsigned long); i++) { *dst_addr = *bs_addr; dst_addr++; bs_addr++; } ptr->pt_base = free_frm; restore(ps); //kprintf("\nmap bs%d/page: %d to frame %d",bs_id, (backing_store_page-proctab[currpid].map[bs_id].base_page), free_frm); 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)); } }