//pmm_init - setup a pmm to manage physical memory, build PDT&PT to setup paging mechanism // - check the correctness of pmm & paging mechanism, print PDT&PT void pmm_init(void) { init_pmm_manager (); page_init (); #ifndef NOCHECK //check_alloc_page(); #endif boot_pgdir = boot_alloc_page (); memset (boot_pgdir, 0, PGSIZE); boot_pgdir_pa = PADDR (boot_pgdir); current_pgdir_pa = boot_pgdir_pa; #ifndef NOCHECK //check_pgdir (); #endif static_assert(KERNBASE % PTSIZE == 0 && KERNTOP % PTSIZE == 0); boot_pgdir[PDX(VPT)] = PADDR(boot_pgdir) | PTE_P | PTE_SPR_R | PTE_SPR_W | PTE_A | PTE_D; boot_map_segment(boot_pgdir, KERNBASE, RAM_SIZE, 0, PTE_SPR_R | PTE_SPR_W | PTE_A | PTE_D); enable_paging (); #ifndef NOCHECK //check_boot_pgdir (); #endif print_pgdir (kprintf); slab_init (); }
void start_process(volatile process *p) { //////print("~~~~ Process started with id = %d and CR3 is %x ~~~~",p->pid,p->cr3); enable_paging(p->cr3); current_running_process = p; p->state = TASK_RUNNING; //////print("Process started suckaaaaa %d",p->pid); }
static void switch_to_higher_half() { uint32_t i, entries; /* zero out paging structure */ memset((void *) _BSP_PD, 0, sizeof(_BSP_PD)); /* entries count required to map the kernel */ entries = ((uint32_t)(&kernel_end) + KERNEL_HEAP_SIZE + TABLE_MASK) / TABLE_SIZE; uint32_t *_BSP_PT = (uint32_t *) scratch; //init_heap_alloc(entries * PAGE_SIZE, PAGE_SIZE); /* identity map pages */ for (i = 0; i < entries * 1024; ++i) _BSP_PT[i] = (i * PAGE_SIZE) | P | RW; /* map the lower-half */ for (i = 0; i < entries; ++i) _BSP_PD[i] = ((uint32_t) _BSP_PT + i * PAGE_SIZE) | P | RW; /* map the upper-half */ for (i = 0; i < entries; ++i) _BSP_PD[768 + i] = ((uint32_t) _BSP_PT + i * PAGE_SIZE) | P | RW; /* Enable paging using Bootstrap Processor Page Directory */ enable_paging((uint32_t) _BSP_PD); }
/* * init_page_directory * DESCRIPTION: Initializes page_directory entries to not present, then fills first * entry with 4mb of 1024 4kb pages. Then fills next entry with just one * 4mb page for the kernal. * INPUTS: none * OUTPUTS: none * RETURN VALUE: none * SIDE EFFECTS: Enables paging once it sets the page directory/table */ void init_page_directory(uint32_t address){ int i,j=0; // for iterations // calculate index from vidmap address uint16_t page_dir_index = (VIDMAP & PD_INDEX_MASK) >> 22; // initialize page directory to not present for (i=0;i<INDEX_SIZE;i++){ page_directory[i] = NOT_PRESENT_WRITE; // initialize page directory to read/write but not present } // initialize all pages to not present when creating new page table for (i=0;i<INDEX_SIZE;i++){ page_table_vidmap[i] = j | NOT_PRESENT_WRITE; // initialize to supervisor, read/write, not present j = j + SIZE_OF_PAGE; // increment by one 4kb page } // map a 4kb page for the first terminal page_table_vidmap[0] = VIDEO_ADDR | PRESENT_USER; // initialize passed flags // map a 4kb page for the second terminal page_table_vidmap[1] = (VIDMAP + SIZE_OF_PAGE) | PRESENT_USER; // initialize passed flags // map a 4kb page for the third terminal page_table_vidmap[2] = (VIDMAP + 2*SIZE_OF_PAGE) | PRESENT_USER; // initialize passed flags // set constructed page table to correct index of page directory page_directory[page_dir_index] = (uint32_t)page_table_vidmap | PRESENT_USER; // map first 4mb with 1024 4kb pages map_4kb_page(VIDEO_ADDR, PRESENT_WRITE); // map second 4mb with one 4mb page map_4mb_page(FOUR_MEGABYTES, KERNEL_FLAGS); // enable paging by setting the control registers in "paging_control.S" enable_paging(page_directory); return; }
//pmm_init - setup a pmm to manage physical memory, build PDT&PT to setup paging mechanism // - check the correctness of pmm & paging mechanism, print PDT&PT void pmm_init(void) { //We need to alloc/free the physical memory (granularity is 4KB or other size). //So a framework of physical memory manager (struct pmm_manager)is defined in pmm.h //First we should init a physical memory manager(pmm) based on the framework. //Then pmm can alloc/free the physical memory. //Now the first_fit/best_fit/worst_fit/buddy_system pmm are available. init_pmm_manager(); // detect physical memory space, reserve already used memory, // then use pmm->init_memmap to create free page list page_init(); //use pmm->check to verify the correctness of the alloc/free function in a pmm check_alloc_page(); // create boot_pgdir, an initial page directory(Page Directory Table, PDT) boot_pgdir = boot_alloc_page(); memset(boot_pgdir, 0, PGSIZE); boot_cr3 = PADDR(boot_pgdir); check_pgdir(); static_assert(KERNBASE % PTSIZE == 0 && KERNTOP % PTSIZE == 0); // recursively insert boot_pgdir in itself // to form a virtual page table at virtual address VPT // cprintf("haah1\n"); // map all physical memory to linear memory with base linear addr KERNBASE //linear_addr KERNBASE~KERNBASE+KMEMSIZE = phy_addr 0~KMEMSIZE //But shouldn't use this map until enable_paging() & gdt_init() finished. boot_map_segment(boot_pgdir, 0, KMEMSIZE, 0, PTE_TYPE_URWX_SRWX | PTE_R | PTE_V); boot_pgdir[PDX(VPT)] = PADDR(boot_pgdir) | PTE_TYPE_TABLE | PTE_R | PTE_V; // pgdir_alloc_page(boot_pgdir, USTACKTOP-PGSIZE , PTE_TYPE_URW_SRW); //cprintf("haha2\n"); //temporary map: //virtual_addr 3G~3G+4M = linear_addr 0~4M = linear_addr 3G~3G+4M = phy_addr 0~4M //boot_pgdir[0] = boot_pgdir[PDX(KERNBASE)]; //cprintf("OK!\n"); enable_paging(); // cprintf("haah\n"); //reload gdt(third time,the last time) to map all physical memory //virtual_addr 0~4G=liear_addr 0~4G //then set kernel stack(ss:esp) in TSS, setup TSS in gdt, load TSS //gdt_init(); //disable the map of virtual_addr 0~4M //boot_pgdir[0] = 0; //now the basic virtual memory map(see memalyout.h) is established. //check the correctness of the basic virtual memory map. check_boot_pgdir(); print_pgdir(); kmalloc_init(); }
/*------------------------------------------------------------------------ * nulluser -- initialize system and become the null process (id==0) *------------------------------------------------------------------------ */ nulluser() /* babysit CPU when no one is home */ { int userpid; console_dev = SERIAL0; /* set console to COM0 */ initevec(); kprintf("system running up!\n"); sysinit(); /* create a process to execute the user's main program */ /*****************************/ 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"); userpid = create(main, INITSTK, INITPRIO, INITNAME, INITARGS); enable_paging((proctab[NULLPROC].pd->frm_num) * NBPG); enable(); resume(userpid); /* create a process to execute the user's main program */ while (TRUE) /* empty */; }
void setup_pdt_enable_paging() { uint16_t i = 0; while(i < 1024) { PDT[i].address = i * 0x400000; PDT[i].page_size = 1; PDT[i].rw = 1; PDT[i].present = 1; i++; } enable_paging((uint32_t) &PDT); }
static page_frame_t kernel_page_table_install(struct multiboot_info *mb) { // Certain very important things already exist in physical memory. They // need to be marked as present so that the allocator doesn't grab them by // accident. // After they are marked as present they can safely be mapped with // map_page. // Iterate over the multiboot memory map table and mark certain addresses // as unusable. klogf("Marking unusable!\n"); multiboot_memory_map_t *mm_last = (multiboot_memory_map_t*)(mb->mmap_addr + mb->mmap_length); for (multiboot_memory_map_t *mm = (multiboot_memory_map_t*)mb->mmap_addr; mm < mm_last; mm = (multiboot_memory_map_t*)((uintptr_t)mm + mm->size + sizeof(mm->size))) { // If the memory is not available if (mm->type != MULTIBOOT_MEMORY_AVAILABLE) { klogf("Unusable physical address %p of type %p and length %p\n", mm->addr, mm->type, mm->len); for (uint64_t page = PAGE_ALIGN(mm->addr); page < NEXT_PAGE(mm->addr+mm->len); page += PAGE_SIZE) { use_frame(page); } } } klogf("mm_addr table %p\n", mb->mmap_addr); klogf("apm table %p\n", mb->apm_table); klogf("fb table %p\n", mb->framebuffer_addr); klogf("vbe int off %p\n", mb->vbe_interface_off); // Catch NULL pointer dereferences use_frame(0); // Mark all the pages the kernel sits on as used use_range(KERNEL_START, KERNEL_END); // Mark the kernel heap as in use use_frame(KHEAP_PHYS_ROOT); // Mark video memory as in use use_range(VGA_BEGIN, VGA_END); // Mark the paging directory as in use use_frame(PAGE_DIRECTORY); page_frame_t page_dir = bootstrap_kernel_page_table(); enable_paging(page_dir); return page_dir; }
void init_paging() { size_t sz; uint32_t i; uint32_t mem_end_page; DPRINTK("paging...\t\t"); mem_end_page = 0x1000000; nframes = mem_end_page / PAGE_SIZ; sz = INDEX_FROM_BIT(nframes); frames = (uint32_t *)kmalloc(sz); memset(frames, 0, sz); kernel_directory = (struct page_directory *) kmalloc_a(sizeof(struct page_directory)); memset(kernel_directory, 0, sizeof(struct page_directory)); // don't do this... current_directory = kernel_directory; // do this instead... kernel_directory->physical_addr = (uint32_t)kernel_directory->tables_physical; for (i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += PAGE_SIZ) get_page(i, 1, kernel_directory); i = 0; while (i < placement_addr + PAGE_SIZ) { alloc_frame(get_page(i, 1, kernel_directory), 0, 0); i += PAGE_SIZ; } for (i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += PAGE_SIZ) alloc_frame(get_page(i, 1, kernel_directory), 0, 0); // register_interrupt_handler(14, page_fault); switch_page_directory(kernel_directory); enable_paging(); kheap = create_heap(KHEAP_START, KHEAP_START + KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0); current_directory = clone_directory(kernel_directory); switch_page_directory(current_directory); DPRINTK("done!\n"); }
void paging_init(void) { memset(page_directory, 0, sizeof(unsigned long) * 1024); memset(page_table, 0, sizeof(unsigned long) * 1024); int i; for(i=0;i<1024;i++){ page_table[i] = (i*4096) | flagsPTE; page_directory[i] = 0; } page_directory[0] = (unsigned long) page_table | flagsPDE; enable_paging((unsigned long)page_directory); }
void paging_init(void) { memset(kpage_directory, 0, sizeof(unsigned long) * 1024); memset(kpage_tables, 0, sizeof(unsigned long) * 1024 * page_directory_size); int i,j,address = 0; for(j=0;j<page_directory_size;j++){ for(i=0;i<1024;i++){ kpage_tables[j].entry[i] = address | flagsPTE; address = address + 4096; } kpage_directory[j] = (unsigned long) &kpage_tables[j] | flagsPDE; } enable_paging((unsigned long)kpage_directory); }
/* initPaging: initialize system page table. Everything is mapped flat, * and private memory is cached. */ void initPaging() { unsigned long addrMap, mloc; // Zero out the page tables void _asm_bzero(unsigned long base, unsigned long count); _asm_bzero(PTBASE, 1024*1024*4); // Fill in PD entries addrMap = PTBASE; for (mloc = 0; mloc < 1023*4; mloc+=4) { *(unsigned long *)mloc = addrMap | PTE_P | PTE_RW; addrMap += 0x1000; } // Last PD entry points to the PD itself. *(unsigned long *)mloc = PAGEDIRLOC | PTE_P | PTE_RW; #define MAP(virt, phys, vlimit, flags) \ addrMap = (phys); \ for (mloc = (virt)/0x400+PTBASE; mloc < (vlimit)/0x400+PTBASE; mloc+=4) \ { \ *(unsigned long *)mloc = addrMap | (flags); \ addrMap += 0x1000; \ } // Fill in PT entries // Private mem (0x0 -> same; < 0x29000000) MAP(0, 0, 0x29000000, PTE_P | PTE_RW); // SHM (0x80000000 -> same; < 0x84000000) MAP(0x80000000, 0x80000000, 0x84000000, PTE_P | PTE_RW | PTE_CD); // MPB (0xc0000000 -> same; < 0xd9000000) MAP(0xc0000000, 0xc0000000, 0xd9000000, PTE_P | PTE_RW | PTE_PMB); // CRB, FPGA, MCPC TCP/IP IF, and VRC (0xe0000000 -> same; < 0xfc000000) MAP(0xe0000000, 0xe0000000, 0xfc000000, PTE_P | PTE_RW | PTE_CD); // APIC and upper private mem (0xfee00000 -> same; < 0xffc00000) MAP(0xfee00000, 0xfee00000, 0xffc00000, PTE_P | PTE_RW | PTE_CD); enable_paging(PAGEDIRLOC); }
/* To init paging, we identity map the first 4MB of memory to the kernel's * page table. Then we set bit 31 of cr0. */ int init_paging() { uint32 i, j, pdes, error; void* addr = 0; word_t *p; kern_page_dir = (word_t)PD_BASE; /* This division will have MOD of 0. If not, there is an awkward ammount * of memory (not 4K divisable) and we just ignore the leftover. */ pdes = frame_count/PT_ENTRIES; /* Number of required page directory entires to map all physical frames. */ /* Zero out the page table. */ bzero( (void*)kern_page_dir, FRAME_LEN ); /* Map all of physical memory to the kernel page table. */ for( i = 0; i < pdes; i++ ) { p = (word_t*)MEMMAN_ALLOC_KERN_FRAME( &error ); if( error == 1 ) { kprintf( "Error allocating kernel frame for PT.\n" ); return RET_FAILURE; } for( j = 0; j < PT_ENTRIES; j++ ) { p[j] = frame_to_pte_user( (word_t)addr ); addr += FRAME_LEN; } ((word_t*)kern_page_dir)[i] = frame_to_pde_user( (word_t)p ); } /* Load the page directory into cr3. */ __asm__ __volatile( "movl %0, %%eax; \ movl %%eax, %%cr3" : : "r" (kern_page_dir) ); /* Enable paging. */ enable_paging(); return RET_SUCCESS; }
void procB(void) { int rc = EMPTY; int vpage = 8000; int npages = 100; int bs_id = 5; char *x; char temp; rc = get_bs(bs_id, npages); kprintf("get_bs in %s.. %d\n", __func__, rc); rc = xmmap(vpage, bs_id, npages); kprintf("xmmap in %s.. %d\n", rc); x = (char *) (vpage * NBPG); kprintf("%s trying to access vaddr 0x%08x\n", __func__, x); temp = *x; kprintf("value of temp in %s.. %c\n", __func__, temp); sleep(1); enable_paging(); *x = 's'; temp = *x; kprintf("value of temp in %s.. %c\n", __func__, temp); rc = xmunmap(vpage); kprintf("xmunmap in %s.. %d\n", __func__, rc); /* Try to access VM after unmapping it. The process should be killed. */ kprintf("value of temp in %s.. %c\n", __func__, *x); kprintf("This line should never be printed!\n"); rc = release_bs(bs_id); kprintf("release_bs in %s.. %d\n", __func__, rc); return; }
void init() { struct ext_mem_format *ptr_exts; // structure-pointer to structure struct ext_mem_format temp_struc; // temporary structure struct inode ino_kern; struct ext_mem_format ext_mem_strucs[50]; // 386 usable RAM list format usec_t ino_sec; ubyte_t num_servs; // number of servers to read to memory uint_t tot_mem, counter, counter1; // counters byte *ptr_mem=(byte *)ext_mem_strucs; // byte-pointer to structure /* * Get absolute sector for first ivector. * It is stored in a global variable. */ sosfs_ivec_first(); /* read kernel's and server's inode sector */ ino_sec = sosfs_iget("/boot/kernel"); /* if error */ if (ino_sec == -1) { low_putstr("Inode not found\n"); while (1); } /* read kernel's inode */ sosfs_read_raw(ino_sec, &ino_kern); /* zero out the vector */ for (tot_mem=0; tot_mem<512; tot_mem++) buffer[tot_mem]=0; /* * Copy arguments from real-mode to protected-mode. * The monitor program wishes to pass the arguments to the kernel. * This is done by a little hack that uses an interrupt instruction * passing a buffer to copy from real-mode to protected-mode using * BIOS. */ kargs_init(); /* * Get total amount of RAM. * The most reliable way to know the system's memory-mapping * is by using the BIOS; we use int $0x15 function 0xe820. */ low_tot_ram(ext_mem_strucs); /* point to memory-map vector */ ptr_exts=ext_mem_strucs; /* * Traverse the structures until magic number found. * Our interrupt handler set a magic number after the last * entry returned by the BIOS handler. */ kprintf("\n"); kprintf("BIOS-provided physical-memory mappings\n"); kprintf("======================================================\n"); while (ptr_exts->acpi_ext != 0x12345) { /* if we must ignore the entry, so we do */ if (ptr_exts->reg_len == 0) continue; /* print type of memory to terminal */ switch (ptr_exts->reg_type) { case 1: kprintf("Usable RAM at "); if (ptr_exts->base_addr[0] != 0) { zero_mem(ptr_exts); put_list(ptr_exts); } break; case 2: kprintf("Reserved/unusable RAM at "); break; case 3: case 4: case 5: kprintf("ACPI RAM at "); break; } /* * Create a temporary structure and copy the entire structure * to it. * Print the address range. */ temp_struc = *ptr_exts; // copy structure temp_struc.reg_len[0] += temp_struc.base_addr[0]; kprintf("%x-", &temp_struc); kprintf("%x", temp_struc.reg_len); kprintf("\n"); for (tot_mem=0; tot_mem<512; tot_mem++) buffer[tot_mem]=0; ptr_exts++; // advance one structure } kprintf("======================================================\n"); /* * Set up initial memory mappings. * Load user-level servers to predefined physical memory and * identically map them. Map the monitor program and the kernel * also to identical physical addresses. Also map those programs' * heaps. */ load_init(); heap_init(); /* list returned by BIOS might be unsorted */ sort_free_list(); /* machine-dependent format to machine-independent format */ dep_2_indep_list(ptr_list); mmap_init(); enable_paging(); SOS_init(); }
/* * syscall_execve * * Implements the execve system call. This effectively does a "brain transplant" * on a process by arranging for it to run a different program to what it was * previously. This is achieved by loading the new program from the file system, * placing a copy in the process's text segment, and changing the instruction * pointer of the process to point to the first instruction of the loaded * executable file. * * In addition to loading a new program, this call is also responsible for passing * command line arguments to the new program. This is done by using the memory * at the bottom of the stack (actually the highest address, since the stack grows * downwards), in which the array of strings corresponding to argv is placed. The * argv and argc values are placed at the top of the stack, so that the main * function will be able to access them as arguments. */ int syscall_execve(const char *filename, char *const argv[], char *const envp[], regs * r) { process *proc = current_process; /* * Verify that the filename and all of the pointers within argc arg valid * (i.e. completely reside in the process's address space) */ if (!valid_string(filename)) return -EFAULT; unsigned int argno = 0; if (NULL != argv) { while (1) { if (!valid_pointer(argv, (argno + 1) * sizeof(char *))) return -EFAULT; if (NULL == argv[argno]) break; if (!valid_string(argv[argno])) return -EFAULT; argno++; } } /* * Check that the specified executable file actually exists, and find out its * location within the file system */ directory_entry *entry; int res; if (0 > (res = get_directory_entry(filesystem, filename, &entry))) return res; if (TYPE_DIR == entry->type) return -EISDIR; /* * Calculate number of arguments and amount of space needed to store them */ unsigned int argc = 0; unsigned int argslen = 0; for (argc = 0; argv && argv[argc]; argc++) argslen += strlen(argv[argc]) + 1; /* * Allocate a temporary buffer in which to store the argument data. This will * later be copied to the process's stack. The reason we can't do this * in-place is that doing so would risk overwriting some of the data we are * copying from. */ unsigned int argdata_size = argslen + argc * sizeof(char *) + 2 * sizeof(int); char *argdata = kmalloc(argdata_size); char **newargv = (char **)(argdata + 8); /* * Work backwards through the allocated buffer, copying in the strings one- * by-one */ unsigned int pos = argdata_size; for (argno = 0; argno < argc; argno++) { unsigned int nbytes = strlen(argv[argno]) + 1; pos -= nbytes; memmove(&argdata[pos], argv[argno], nbytes); newargv[argno] = (char *)(PROCESS_STACK_BASE - argdata_size + pos); } /* * Set argc and argv as the top two words on the stack. These are the values * that main will see passed in as its parameters. */ *(unsigned int *)(argdata + 0) = argc; *(unsigned int *)(argdata + 4) = PROCESS_STACK_BASE - argdata_size + 8; /* * Unmap the existing text segment */ disable_paging(); unsigned int addr; for (addr = proc->text_start; addr < proc->text_end; addr += PAGE_SIZE) unmap_and_free_page(proc->pdir, addr); for (addr = proc->data_start; addr < proc->data_end; addr += PAGE_SIZE) unmap_and_free_page(proc->pdir, addr); /* * Resize text and data segments to 0 bytes each */ proc->text_start = PROCESS_TEXT_BASE; proc->text_end = PROCESS_TEXT_BASE; proc->data_start = PROCESS_DATA_BASE; proc->data_end = PROCESS_DATA_BASE; /* * Load in the text segment from the executable file */ char *data = filesystem + entry->location; for (pos = 0; pos < entry->size; pos += PAGE_SIZE) { proc->text_end = proc->text_start + pos; void *page = alloc_page(); if (PAGE_SIZE <= entry->size - pos) memmove(page, &data[pos], PAGE_SIZE); else memmove(page, &data[pos], entry->size - pos); map_page(proc->pdir, proc->text_end, (unsigned int)page, PAGE_USER, PAGE_READ_WRITE); } proc->text_end = proc->text_start + pos; enable_paging(current_process->pdir); /* * Copy the command line argument data we set up above to the process's * stack */ memmove((void *)(PROCESS_STACK_BASE - argdata_size), argdata, argdata_size); kfree(argdata); /* * Set up the process's saved register state so that when it resumes * execution, it will start from the beginning of the loaded code. */ init_regs(r, PROCESS_STACK_BASE - argdata_size, (void *)current_process->text_start); return 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; }
/******************************************************************************* * Name: pgt_update_for_pid * * Desc: Called when a frame is freed. This routine: * 1. Goes over all the pgts of the given process and clears the * 'pres' bit of the page table entry as the frame is about to * be freed, eventually. * 2. As it goes over the page tables of the process, it records * the dirty bit value of the page table. This will be * returned to the caller so that caller can write-off the frame * to the BS. * 3. If all the frames of the page table frame are freed, the page * table frame itself can be freed. In this case, we need to * update the 'pres' bit of the corrsponding entry in the page * directory (outer page table) of the process. * 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: * fr_id - frame id of the frame being paged out/removed * pid - pid of the proc whose page table is to be updated (optional) * passing EMPTY would update all pid page tables * * Returns: int * TRUE - if the dirty bit is set for at least one proc * FALSE - if the dirty bit is not set for any of the procs * EMPTY - oops! something went wrong.. ******************************************************************************/ int pgt_update_for_pid(int fr_id, int pid) { int rc = FALSE; frm_map_t *frptr = NULL; STATWORD ps; disable(ps); DTRACE_START; if (FALSE == FR_IS_ID_VALID(fr_id)) { DTRACE("DBG$ %d %s> bad fr id %d\n", currpid, __func__, fr_id); rc = EMPTY; goto RESTORE_AND_RETURN; } /* If the given frame is free, the required pgt's would have been updated * earlier. Just return. */ if (FR_FREE == FR_GET_STATUS(fr_id)) { DTRACE("DBG$ %d %s> fr id %d is free\n", \ currpid, __func__, fr_id, FR_GET_STATUS(fr_id)); rc = FALSE; goto RESTORE_AND_RETURN; } /* This routine is only to update the page tables when a frame is removed * or a proc unmaps the frame. So, we only have to bother about data pages. */ if (FR_PAGE != FR_GET_TYPE(fr_id)) { DTRACE("DBG$ %d %s> fr id %d isn't a data frame.. type %d\n", \ currpid, __func__, fr_id, FR_GET_TYPE(fr_id)); rc = FALSE; goto RESTORE_AND_RETURN; } if (isbadpid(pid)) { DTRACE("DBG$ %d %s> bad pid %d\n", currpid, __func__, pid); rc = EMPTY; goto RESTORE_AND_RETURN; } if (PRFREE == P_GET_PSTATE(pid)) { DTRACE("DBG$ %d %s> pid %d is in free state\n", \ currpid, __func__, pid); rc = EMPTY; goto RESTORE_AND_RETURN; } /* If the pid doesn't use the given frame, return FALSE. */ if (FALSE == frm_pidmap_oper(fr_id, pid, FR_OP_PMAP_CHK)) { DTRACE("DBG$ %d %s> fr id %d is not used by pid %d\n", currpid, __func__, fr_id, pid); rc = FALSE; goto RESTORE_AND_RETURN; } /* If we are here, we are good to go. Update the page table by doing the * following: * 1. Record the dirty bit value. * 2. Clear the 'pres' bit for the page in the page table. * 3. Decrement the refcount of the page table. * 4. If the refcount of the frame containing the page table reaches 0, * free the frame. * 5. If the frame containing the page table is freed, clear the 'pres' * bit of the page directory entry of the process containing the just * freed frame. */ frptr = FR_GET_FPTR(fr_id); rc = pgt_oper(fr_id, pid, frptr->fr_vpage[pid], PT_OP_FREE_FRM); RESTORE_AND_RETURN: /* 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_END; restore(ps); return rc; }
/* * syscall_fork * * Implements the fork system call, which makes a copy of an existing process. * After this call has completed, the two processes will have exactly the same * state, with the exception of their process ids and the return value from the * fork call. The return value that the parent process sees will be the (non-zero) * process id of the child. The child will see a return value of 0. Based on this, * each of the two processes can go their separate ways, with the child process * typically taking completely different code * path, such as a call to exec. * * This call is an alternative to start_process. fork is the standard way to create * processes under UNIX, and in most cases is the *only* way for new processes to * be started, at least from user-space. * * The *full* state of a process must be copied here, including all fields of the * process object, and all of the memory associated with the process in its various * segments (text, data, and stack). */ pid_t syscall_fork(regs * r) { /* * Find a free process identifier */ pid_t child_pid = get_free_pid(); if (0 > child_pid) return -EAGAIN; process *parent = current_process; process *child = &processes[child_pid]; memset(child, 0, sizeof(process)); child->pid = child_pid; child->parent_pid = parent->pid; child->exists = 1; /* * Create a page directory for the new process, and set the segment ranges. * Note that we have to temporarily disable paging here, because we need to * deal with physical memory when allocating a page directory and setting up * the mappings. */ disable_paging(); child->pdir = (page_dir) alloc_page(); child->text_start = parent->text_start; child->text_end = parent->text_end; child->data_start = parent->data_start; child->data_end = parent->data_end; child->stack_start = parent->stack_start; child->stack_end = parent->stack_end; /* * Identity map memory 0-6Mb */ unsigned int addr; for (addr = 0 * MB; addr < 6 * MB; addr += PAGE_SIZE) map_page(child->pdir, addr, addr, PAGE_USER, PAGE_READ_ONLY); /* * Copy parent's text, data, and stack segments to child */ map_and_copy(parent->pdir, child->pdir, child->text_start, child->text_end); map_and_copy(parent->pdir, child->pdir, child->data_start, child->data_end); map_and_copy(parent->pdir, child->pdir, child->stack_start, child->stack_end); enable_paging(current_process->pdir); /* * Copy file handles. The reference count is increased on each of them, so * that we can keep track of how many file descriptors refere to each file * handle. This information is needed so we know when to destroy a file handle * (i.e. when its reference count reaches 0). */ int i; for (i = 0; i < MAX_FDS; i++) { if (NULL != parent->filedesc[i]) { child->filedesc[i] = parent->filedesc[i]; child->filedesc[i]->refcount++; } } /* * Copy the saved CPU registers of the current process, which determines its * execution state (instruction pointer, stack pointer etc.) */ child->saved_regs = *r; child->saved_regs.eax = 0; /* child's return value from fork */ memmove(child->cwd, parent->cwd, PATH_MAX); /* * Place the process on the ready list, so that it can begin execution on a * subsequent context switch */ child->ready = 1; list_add(&ready, child); /* * Return the child's process id... note that this value will only go to the * parent, since we set the child's return value from fork above */ return child_pid; }
/** * Initializes the page structures, * move to the page structure # 0 (kernel). * and turn on the paging. */ void paging_init(unsigned int mbi_addr) { pdir_init_kern(mbi_addr); set_pdir_base(0); enable_paging(); }
void init_paging (u32_t upper_mem_kb, u32_t img_phys_end_addr) { u32_t tmp1 = 0xA000; u32_t tmp2 = PAGE_OFFSET; u32_t phys_end_of_kernel = kernel_phys_end_addr ( upper_mem_kb, img_phys_end_addr); /* Setup the page directory entry for the region 0-4 MB */ insert_pg_dir_entry ( 0, (u32_t *) phys_addr ( (u32_t) kernel_pg_dir), phys_addr ( (u32_t) pg_table2), PRESENT | RW | ACCESSED); /* Identity map the video memory */ while ( tmp1 <= 0xFF000) { insert_pg_table_entry ( tmp1, (u32_t *) phys_addr ( (u32_t) pg_table2), tmp1, PRESENT | RW | CACHE_DISABLE | ACCESSED); tmp1 += PAGE_SIZE_BYTES; } tmp1 = (u32_t) __kernel_load_addr; /* Identity map the kernel */ while ( tmp1 < phys_end_of_kernel) { insert_pg_table_entry ( tmp1, (u32_t *) phys_addr ( (u32_t) pg_table2), tmp1, PRESENT | RW | GLOBAL | ACCESSED); tmp1 += PAGE_SIZE_BYTES; } /* Set the page directory entry for the 4 MB starting at * virtual address 0xC0000000 */ insert_pg_dir_entry (PAGE_OFFSET, (u32_t *) phys_addr ( (u32_t) kernel_pg_dir), phys_addr ( (u32_t) pg_table1), PRESENT | RW | GLOBAL | ACCESSED); tmp1 = (u32_t) __kernel_load_addr; tmp2 = PAGE_OFFSET; /* Map the virtual kernel address space onto the physical * pages */ while ( tmp1 < phys_end_of_kernel) { insert_pg_table_entry ( tmp2, (u32_t *) phys_addr ( (u32_t) pg_table1), tmp1, PRESENT | RW | GLOBAL | ACCESSED); tmp1 += PAGE_SIZE_BYTES; tmp2 += PAGE_SIZE_BYTES; } /* Map the page directory onto itself in the upper 4 MB of the * virual address space. This is needed for mapping physical * pages into the virtual address space */ kernel_pg_dir [1023] = (u32_t) kernel_pg_dir | PRESENT | RW | ACCESSED; /* Let the CPU know where the page directory is */ set_pg_dir ( phys_addr ( (u32_t) kernel_pg_dir)); /* Lets get the show on the road :) */ enable_paging(); }
/*------------------------------------------------------------------------ * 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 */; }
/*------------------------------------------------------------------------ * 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 */; }
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; }
int mmu_initialize(void) { enable_paging(); return -1; }