⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 page.c

📁 是关于页面替换算法的代码模拟
💻 C
字号:
/*
* page.c	
* Copyright (c) Inst. of Machine Intelligence at Nankai University
*/

#include "page.h"
#include <stdlib.h>
//void (*pgfault_handler)() = NULL;

struct Page pages[PAGE_NUM];	//实际上,这个数组是在内核空间,也是要占用物理页的,为简单起见,就不要求写在memory里了
struct page_list free_page_list;

phyaddr_t page2pa(struct Page* pp)
{
	uint32 idx = pp - pages;  //计算当前页 离 第一页 的距离
	phyaddr_t rtv;
	rtv = idx * PGSIZE;  //计算当前页的位移    
	return rtv;
}
struct Page* pa2page(phyaddr_t pa)
{
	struct Page* pp = NULL;
	pa = ROUNDDOWN(pa, PGSIZE);//#define ROUNDDOWN(a, n)		(a - a % (n))
	return (pages + (pa / PGSIZE));
}

int page_init()
{
	// 初始化空闲页列表
	// 比如,让最后一个物理页最先被分配
	// memory中有哪些物理页可以被使用?哪些不能?
	
	int i;
	extern int mem_end;
	free_page_list.head=NULL;
	pages[0].ref = 1;
	for(i=1;i<PAGE_NUM;i++){        
		pages[i].ref = 0;
		if(i*PGSIZE<mem_end)  //如果所引用的页在memory数组中未被使用的第一个字节的位置之前 
			pages[i].ref = 1; 
		else{
			pages[i].next=free_page_list.head;
			free_page_list.head=&pages[i];
		}
	}
	return 0;
}

struct Page* page_alloc()
{
	//从空闲页列表中分配一个页, 并返回页面指针

	struct Page* tmp=free_page_list.head;
	if(tmp!=NULL)
		free_page_list.head=free_page_list.head->next;	
	else{
		printf("Memory full!\n");
	}
	return tmp;
	
}

//插入的意思是将pp插入到va所在的地址当中去。如果是相同的则直接推出。
//如果不是相同的那么就强制把原来的pp扔出去,载入现在的pp
//这是强制插入的原因。
//还要加把pp的引用数加一。
int page_insert(viraddr_t va, struct Page* pp)
{
	//将虚拟地址映射到物理页pp上
	extern char memory[];
	extern phyaddr_t	cpu_cr3;	
	extern phyaddr_t	cpu_cr2;
	extern phyaddr_t	cpu_cr0;
	extern phyaddr_t	cpu_errcode;	
	pde_t* pgdir;
	pte_t* pgtable = 0;
	pde_t	pde = 0;
	pte_t	pte = 0;
	struct Page * get_pgt;

	
	if ((cpu_cr0 & PAGING) != PAGING)
	{
		//未分页
		printf("Error : Paging mode doesn't exist\n");	
		exit(0);
	} 
	else
	{
		pgdir = (pde_t*)(memory + cpu_cr3);
		
		pde = pgdir[PDX(va)];
		
		if ((pde & PTE_P) != PTE_P)
		{		
			get_pgt=page_alloc();   //把即将插入的页的下一个空闲页取出用以存二级页表
			pgdir[PDX(va)] = page2pa(get_pgt) | PTE_P ; //最低位或上1,表示新插入的页“在”内存中

			if (cpu_errcode==0x02)  //若为只读页的时候返回0,写的时候返回2
				pgdir[PDX(va)] = pgdir[PDX(va)] | PTE_W ; 

			get_pgt->ref ++;		
			pde = pgdir[PDX(va)];
		}	
		pgtable = (pde_t*)(memory + PTE_ADDR(pde));

		pte = pgtable[PTX(va)];

		if ((pte & PTE_P) != PTE_P)
		{
			pgtable[PTX(va)] = page2pa(pp) | PTE_P ;

			if (cpu_errcode==0x02)			
				pgtable[PTX(va)]=pgtable[PTX(va)] | PTE_W ;
			
			pp->ref ++;
			return 0;
		}
	
		if( page2pa(pp) != PTE_ADDR(pte) ){
			page_remove(va);
			pgtable[PTX(va)] = page2pa(pp) | PTE_P ;
			pp->ref ++;
		}
		return 0;
	}

}

int page_remove(viraddr_t va)
{
	//移除虚拟页
	//注意,什么时候只是取消映射,什么时候要把页重新放回到空闲页列表中?
	extern char memory[];
	extern phyaddr_t	cpu_cr3;	
	extern phyaddr_t	cpu_cr2;
	extern phyaddr_t	cpu_cr0;
	pde_t* pgdir;
	pte_t* pgtable = 0;
	pde_t	pde = 0;
	pte_t	pte = 0;
	struct Page* getpage=NULL;
	if ((cpu_cr0 & PAGING) != PAGING)
	{
		//未分页
		printf("Error : Paging mode doesn't exist\n");	
		exit(0);
	}
	else
	{
		pgdir = (pde_t*)(memory + cpu_cr3);	
		pde = pgdir[PDX(va)];
		if ((pde & PTE_P) != PTE_P)
		{		
			printf("Error: Page Directory is invalid.\n");
			exit(1);
		}			
		pgtable = (pde_t*)(memory + PTE_ADDR(pde));
		pte = pgtable[PTX(va)];	
		getpage=pa2page(PTE_ADDR(pte));	//getpage: 取出虚拟地址映射的页	
		if( getpage!= NULL)	//如果当前没有页面,直接退出
		{ 
			getpage->ref--;
			if((getpage->ref)==0){      //插入到空闲页队列当中
				getpage->next=free_page_list.head;
				free_page_list.head=getpage;	
			}
			pgtable[PTX(va)]=0;
		}
	}
	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -