Ejemplo n.º 1
0
/*******************************************************************************
 * 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;
}
Ejemplo n.º 2
0
/*******************************************************************************
 * 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;
}
Ejemplo n.º 3
0
/*-------------------------------------------------------------------------
 * 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
Ejemplo n.º 4
0
/*-------------------------------------------------------------------------
 * 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;
}
Ejemplo n.º 5
0
/*******************************************************************************
 * 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;
}
Ejemplo n.º 6
0
/*------------------------------------------------------------------------
 *  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 */;
}
Ejemplo n.º 7
0
/*-------------------------------------------------------------------------
 * 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;
}
Ejemplo n.º 8
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));
      }
    }