📄 pagealloc.c
字号:
else if(num>0)
{
num=0;
start=0;
}
for(i=start;i<=end;i++)
SetPageUsed(&mem_map[i]);
start<<=12; // i*4K 得到实际的页偏移地址
start=__va(start);
//以下代码将页面的实际的物理地址清零
memset((void*)start,0,page_num*4096);
return start;
}
//------------------------------------------------------------------------------------------
//
//
// 释放某一页面 addr 要释放的页面的物理地址
//
//
//
//-------------------------------------------------------------------------------------------
int FreePage(unsigned long addr)
{
if(addr<LOW_MEM)
{
return -1;
}
if(addr>HIGHT_MEM)
{
return -1;
}
addr=__pa(addr);
addr>>=12; //把addr转换成页面号
if(TestPageUsed(&mem_map[addr]) && !TestPageLocked(&mem_map[addr]))
{
//ConsoleWarning(" Free addr %08x mem_mep.conut =%d\n",__va(addr<<12),mem_map[addr].count);
mem_map[addr].count--;
if(mem_map[addr].count<=0)
{
mem_map[addr].count=0;
SetPageUnUsed(&mem_map[addr]);
return 0;
}
else return mem_map[addr].count;
}
return -2;
}
//------------------------------------------------------------------------------------------
//
//
// 添加某一页面 的使用计数
//
//
//
//-------------------------------------------------------------------------------------------
void AddPageCount(unsigned long addr)
{
if(addr<LOW_MEM)
{
return;
}
if(addr>HIGHT_MEM)
{
return;
}
addr=__pa(addr);
addr>>=12; //把addr转换成页面号
if(TestPageUsed(&mem_map[addr]) && !TestPageLocked(&mem_map[addr]))
{
mem_map[addr].count++;
}
}
//------------------------------------------------------------------------------------------
//
//
// 在指定的物理地址处放置一页面,即将某一页的地址索引放入页表的指定位置处
//
// page 要放置的页面真实物理地址,address 要放置页面指针的页表地址(线性地址)
//
//-------------------------------------------------------------------------------------------
unsigned long PutPage(unsigned long pg_dir,unsigned long page,unsigned long address)
{
unsigned long tmp,*page_table;
unsigned long page_phy_addr;
if(page<LOW_MEM || page>HIGHT_MEM) //若是要放入页表的页地址不在可分配空间中则出错
{
ConsoleWarning("put page error out of the page memory space 2MB~8MB addr %08x page %08x\n",
address,page);
return 0;
}
page_phy_addr=__pa(page);
if(!TestPageUsed(&mem_map[page_phy_addr>>12]))
{
ConsoleWarning("put page error mem map disgrees with the page num addr %08x page %08x\n",
address,page);
return 0;
}
page_table=(unsigned long *)(pg_dir+((address>>20)&0xffc)); //找到address对应的实际在页目录中的地址
//ConsolePrintf(" page_table %08x *page_table %08x\n",page_table,*page_table);
if((*page_table)&1)
{
page_table=(unsigned long *)(0xfffff000 & *page_table); //address对应的页表指针,注意为物理地址
page_table=(unsigned long *)__va((unsigned long)page_table);
AddPageCount((unsigned long)page_table);
}
else //若对应的页表指针不存在,则申请一个页面来存放页表
{
if(!(tmp=GetFreePage())) //<----注意这里在VM释放时要释放其页表所占页面
{ConsoleWarning("put page error --- you do not have enough memory!\n");return 0;}
*page_table=__pa(tmp)|7; //注意要把页表的物理地址放入页目录
page_table=(unsigned long *)tmp; //找到一个空闲页面来放页表
//page_table=(unsigned long *)__va((unsigned long)page_table);
}
//ConsolePrintf(" page_table %08x page_table[%d]=%08x\n",page_table,(address>>12)&0x3ff,page_phy_addr|7);
page_table[(address>>12)&0x3ff]=page_phy_addr | 7;
return page;
}
extern int nr_read;
//------------------------------------------------------------------------------------------
//
//
// 缺页故障处理函数
//
//
//
//-------------------------------------------------------------------------------------------
unsigned long NoPage(unsigned long address)
{
unsigned long page;
unsigned long put_page=0;
int i;
if(!(page=GetFreePage()))
return 0;
for(i=0;i<MAX_PROCESS;i++)
if(proc[i].procFlag==P_RUN)
{
if(!(put_page=PutPage(__va(proc[i].procTss.cr3),page,address))) return 0;
else if(i>0) AddPageCount((unsigned long)put_page);
}
if(ProcCurrent->pid!=0)
{
InvalidatePageDir(ProcCurrent->procTss.cr3);
}
else InvalidatePageDir(PG_DIR_ADDR);
//ConsolePrintf(" Get a Free Page %08x\n",page);
//if(!(put_page=PutPage(__va(PG_DIR_ADDR),page,address))) return 0;
//InvalidatePageDir(PG_DIR_ADDR);
//ConsolePrintf("Proc %d PGD %08x Put a new page %08x at address %08x\n",
// ProcCurrent->pid,ProcCurrent->procTss.cr3,put_page,address);
return put_page;
}
//------------------------------------------------------------------------------------------
//
//
// 已对齐页面拷贝
//
// 内存管理中最重要的一部分!!!
//
//-------------------------------------------------------------------------------------------
int AlignPageTableCopy(unsigned long from_pg_dir,unsigned long to_pg_dir,
unsigned long from,unsigned long to,unsigned long size)
{
unsigned long j=0;
unsigned long* from_page_table=NULL;
unsigned long* to_page_table=NULL;
unsigned long new_page_table;
unsigned long page_num=size/4096; //要拷的页面总数
unsigned long phy_addr;
if((size % 4096)) page_num++;
while(1)
{
from_page_table=(unsigned long *)(from_pg_dir+((from>>20)&0xffc)); //找到from对应的实际在页目录中的地址
to_page_table=(unsigned long *)(to_pg_dir+((to>>20)&0xffc)); //找到to对应的实际在页目录中的地址
from_page_table=(unsigned long *)(0xfffff000 & *from_page_table); //from对应的页表指针,注意为物理地址
from_page_table=(unsigned long *)__va((unsigned long)from_page_table);
if(!((*to_page_table)&1))
{
if(!(new_page_table=GetFreePage())) //新建目标页面表
{ConsoleWarning("copy page error --- you do not have enough memory!\n");return -2;}
*to_page_table=((unsigned long) __pa((unsigned long)new_page_table)) | 7;
}
to_page_table = (unsigned long *)(0xfffff000 & *to_page_table); //获得要目的页面表的地址指针
to_page_table = (unsigned long*)__va((unsigned long)to_page_table);
for(j=0;j<1024;j++)
{
phy_addr=from_page_table[(from>>12)&0x3ff] & 0xfffff000;
to_page_table[(to>>12)&0x3ff]=phy_addr | 7;
//ConsoleMsg("Proc %d Copy Page %08x FromDir %08x ToDir %08x From %08x To %08x\n",
// ProcCurrent->pid,from_pg_dir,to_pg_dir,phy_addr,from,to);
page_num--;
if(page_num==0) return 1;
from+=4096;
to+=4096;
if(((from>>12)&0x3ff)==0) break; //超出了1023 则到下一页表去
if(((to>>12)&0x3ff)==0) break;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -