📄 page.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 + -