Paging.c

来源:互联网 发布:网络兼职交入会费可靠吗 编辑:程序博客网 时间:2024/06/17 17:21
#include <geekos/string.h>#include <geekos/int.h>#include <geekos/idt.h>#include <geekos/kthread.h>#include <geekos/kassert.h>#include <geekos/screen.h>#include <geekos/mem.h>#include <geekos/malloc.h>#include <geekos/gdt.h>#include <geekos/segment.h>#include <geekos/user.h>#include <geekos/vfs.h>#include <geekos/crc32.h>#include <geekos/paging.h>/* ---------------------------------------------------------------------- * Public data * ---------------------------------------------------------------------- */pde_t *g_kernel_pde;static void *Bitmap;static struct Paging_Device *pagingDevice;static int numPagingDiskPages;/* ---------------------------------------------------------------------- * Private functions/data * ---------------------------------------------------------------------- */#define SECTORS_PER_PAGE (PAGE_SIZE / SECTOR_SIZE)/* * flag to indicate if debugging paging code */int debugFaults = 0;#define Debug(args...) if (debugFaults) Print(args)void checkPaging(){unsigned long reg=0;__asm__ __volatile__( "movl %%cr0, %0" : "=a" (reg));Print("Paging on ? : %d\n", (reg & (1<<31)) != 0);}/* * Print diagnostic information for a page fault. */static void Print_Fault_Info(uint_t address, faultcode_t faultCode){extern uint_t g_freePageCount;Print("Pid %d, Page Fault received, at address %x (%d pages free)\n",      g_currentThread->pid, address, g_freePageCount);if (faultCode.protectionViolation)Print ("   Protection Violation, ");elsePrint ("   Non-present page, ");if (faultCode.writeFault)Print ("Write Fault, ");elsePrint ("Read Fault, ");if (faultCode.userModeFault)Print ("in User Mode\n");elsePrint ("in Supervisor Mode\n");}int Alloc_User_Page(pde_t * pageDir,uint_t startAddress,uint_t sizeInMemory);bool Free_Pages_User_Process(pde_t * page_dir);/*static*/void Page_Fault_Handler(struct Interrupt_State* state){ulong_t address;faultcode_t faultCode;KASSERT(!Interrupts_Enabled());/* Get the address that caused the page fault */address = Get_Page_Fault_Address();Debug("Page fault @%lx\n", address);/* Get the fault code */faultCode = *((faultcode_t *) &(state->errorCode));struct User_Context* userContext = g_currentThread->userContext;//写错误,缺页情况为堆栈生长到新页if(faultCode.writeFault){int res;res=Alloc_User_Page(userContext->pageDir,Round_Down_To_Page(address),PAGE_SIZE);if(res==-1){Exit(-1);}return ;}//读错误,分两种缺页情况else{Print("read fault\n");//先找到虚拟地址对应的页表项ulong_t page_dir_addr=address >> 22;ulong_t page_addr=(address << 10) >> 22;pde_t * page_dir_entry=(pde_t*)userContext->pageDir+page_dir_addr;pte_t * page_entry= NULL;Print("address=%x\n",address);Print("userContext->pageDir=%x\n",userContext->pageDir);Print("page_dir_entry=%x\n",page_dir_entry);if(page_dir_entry->present){Print("page_dir_entry->present=%x\n",page_dir_entry->present);page_entry=(pte_t*)((page_dir_entry->pageTableBaseAddr) << 12);page_entry+=page_addr;Print("page_entry=%x\n",page_entry);Print("*page_entry=%x\n",*page_entry);Print("page_entry->present=%x\n",page_entry->present);Print("page_entry->pageBaseAddr=%x\n",(page_entry->pageBaseAddr)<<12);}else{//非法地址访问的缺页情况Print_Fault_Info(address,faultCode);Exit(-1);}if(page_entry->kernelInfo!=KINFO_PAGE_ON_DISK){Print("page_entry->kernelInfo=%x\n",page_entry->kernelInfo);//非法地址访问的缺页情况Print_Fault_Info(address,faultCode);Exit(-1);}//因为页保存在磁盘pagefile引起的缺页int pagefile_index = page_entry->pageBaseAddr;void * paddr=Alloc_Pageable_Page(page_entry,Round_Down_To_Page(address));if(paddr==NULL){Print("no more page/n");Exit(-1);}*((uint_t*)page_entry)=0;page_entry->present=1;page_entry->flags=VM_WRITE | VM_READ | VM_USER;page_entry->globalPage = 0;page_entry->pageBaseAddr = (ulong_t)paddr>>12;//从页面文件中把页读到内存中Enable_Interrupts();//Read_From_Paging_File(paddr,Round_Down_To_Page(address), pagefile_index,page_entry);Read_From_Paging_File(paddr,Round_Down_To_Page(address), pagefile_index);Disable_Interrupts();//释放页面文件中的空间Free_Space_On_Paging_File(pagefile_index);return ;}}void Init_VM(struct Boot_Info *bootInfo){/* * Hints: * - Build kernel page directory and page tables * - Call Enable_Paging() with the kernel page directory * - Install an interrupt handler for interrupt 14, *   page fault * - Do not map a page at address 0; this will help trap *   null pointer references */int  kernel_pde_entries;int  whole_pages;int  i,j;uint_t mem_addr;pte_t * cur_pte;//计算物理内存的页数whole_pages=bootInfo->memSizeKB/4;//Print("whole pages are %d/n",whole_pages);//计算内核页目录中要多少个目录项,才能完全映射所有的物理内存页。kernel_pde_entries=whole_pages/NUM_PAGE_DIR_ENTRIES+(whole_pages%NUM_PAGE_DIR_ENTRIES==0 ? 0:1);//为内核页目录分配一页空间g_kernel_pde=(pde_t *)Alloc_Page();KASSERT(g_kernel_pde!=NULL);//将页中所有位清0memset(g_kernel_pde,0,PAGE_SIZE);pde_t * cur_pde_entry;cur_pde_entry=g_kernel_pde;mem_addr=0;for(i=0; i<kernel_pde_entries-1; i++){cur_pde_entry->present=1;cur_pde_entry->flags=VM_WRITE;cur_pde_entry->globalPage=1;cur_pte=(pte_t *)Alloc_Page();KASSERT(cur_pte!=NULL);//初始化最后一个页目录表项和对应的页表。注意,页表中的页表项不一定足够1024个cur_pde_entry->present=1;cur_pde_entry->flags=VM_WRITE;cur_pde_entry->globalPage=1;cur_pte=(pte_t *)Alloc_Page();KASSERT(cur_pte!=NULL);memset(cur_pte,0,PAGE_SIZE);cur_pde_entry->pageTableBaseAddr=(uint_t)cur_pte>>12;int last_pagetable_num;last_pagetable_num=whole_pages%NUM_PAGE_TABLE_ENTRIES;//注意当last_pagetable_num=0时,意味着最后一个页目录项对应的页表是满的,就是说页表中1024个页表项都指向一个有效的页。if(last_pagetable_num==0){last_pagetable_num=NUM_PAGE_TABLE_ENTRIES;}for(j=0; j<last_pagetable_num; j++){cur_pte->present=1;cur_pte->flags=VM_WRITE;cur_pte->globalPage=1;cur_pte->pageBaseAddr=mem_addr>>12;cur_pte++;mem_addr+=PAGE_SIZE;}//从现在开始,系统的寻址必须经过分页机制转换,以前仅仅经过分段机制转换Enable_Paging(g_kernel_pde);Install_Interrupt_Handler(14,Page_Fault_Handler);//TODO("Build initial kernel page directory and page tables");}}void Init_Paging(void){pagingDevice=Get_Paging_Device();if(pagingDevice==NULL){Print("can not find pagefile/n");return;}numPagingDiskPages=pagingDevice->numSectors/SECTORS_PER_PAGE;//为pagefile中每一页设置标示位Bitmap=Create_Bit_Set(numPagingDiskPages);//  TODO("Initialize paging file data structures");}int Find_Space_On_Paging_File(void){KASSERT(!Interrupts_Enabled());return Find_First_Free_Bit(Bitmap, numPagingDiskPages);//TODO("Find free page in paging file");}void Free_Space_On_Paging_File(int pagefileIndex){KASSERT(!Interrupts_Enabled());KASSERT(0 <= pagefileIndex && pagefileIndex < numPagingDiskPages);Clear_Bit(Bitmap,pagefileIndex);//TODO("Free page in paging file");}void Write_To_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex){struct Page *page = Get_Page((ulong_t) paddr);KASSERT(!(page->flags & PAGE_PAGEABLE)); KASSERT((page->flags & PAGE_LOCKED));if(0<=pagefileIndex && pagefileIndex<numPagingDiskPages){int i;for(i=0; i<SECTORS_PER_PAGE; i++){Block_Write(    pagingDevice->dev,    pagefileIndex*SECTORS_PER_PAGE + i + (pagingDevice->startSector),    paddr+i*SECTOR_SIZE);}Set_Bit(Bitmap,pagefileIndex);}else{Print("Write_To_Paging_File: pagefileIndex out of range!/n");Exit(-1);}//  TODO("Write page data to paging file");}void Read_From_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex){struct Page *page = Get_Page((ulong_t) paddr);KASSERT(!(page->flags & PAGE_PAGEABLE)); page->flags = page->flags & ~PAGE_PAGEABLE;//TODO("Read page data from paging file");}