/*
*Author : DavidLin
*Date : 2014-11-22pm
*Email : linpeng1577@163.com or linpeng1577@gmail.com
*world : the city of SZ, in China
*Ver : 000.000.001
*history : editor time do
1)LinPeng 2014-11-22 created this file!
2)
*/
/*
*释放addr对应的物理地址
*free_page函数被free_page_tables()函数调用
*/
/*
* Free a page of memory at physical address 'addr'. Used by
* 'free_page_tables()'
*/
void free_page(unsigned long addr)
{
if(addr < LOW_MEM) { //如果是内核地址,直接退出
return; //LOW_MEM = 1M,0-640KB是内核驻留区域
}
if(addr >= HIGH_MEMORY) { //如果是最大物理地址之外,die
panic("trying to free nonexistent page");
}
addr -= LOW_MEM; //获取主内存地址(以LOW_MEM处为起始0地址)
addr >>= 12; //获取主内存管理数组偏移索引
//mem_map是全局数组,用于管理主内存
if(mem_map[addr]--) { //首先执行if(mem_map[addr])判断,接着mem_map[addr]--
return; //如果mem_map[addr] > 0,退出,表示物理页共享减一
}
mem_map[addr] = 0; //如果mem_map[addr] = 0,die
panic("trying to free free page");
}
/*
* 释放连续块,块必须4M对齐
* exit()函数调用,相对的函数是copy_page_tables()
*/
/*
* This function frees a continuos block of page tables, as needed
* by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks.
*/
int free_page_tables(unsigned long from, unsigned long size)
{
unsigned long *pg_table;
unsigned long *dir, nr;
if(from & 0x3fffff) { //4M对齐检测
panic("free_page_tables called with wrong alignment");
}
if(!from) { //0地址是内核驻留地址,不允许释放
panic("Trying to free up swapper memory space");
}
size = (size + 0x3fffff)>>22; //如果是4.1M,size取整为2。
dir = (unsigned long *)((from>>20) & 0xffc); /* _pg_dir = 0 */
//dir是页目录项,取线性地址高10位,
//右移22位,因为每个目录项占4个字节,
//所以>>22之后<<2
//等于>>20
for(; size-->0 ; dir++) {
if(!(1 & *dir)) { //如果页目录项未使用,跳过
continue;
}
pg_table = (unsigned long *)(0xfffff000 & *dir); //取页表项
for(nr = 0; nr < 1024; nr++) { //每个页表项有1024个物理页
if(1 & *pg_table) { //位0等于1表示物理页有效
free_page(0xfffff000 & *pg_table); //释放物理页
}
*pg_table = 0; //页表项内容清零
pg_table++; //指向下一个页表
}
free_page(0xfffff000 & *dir); //释放页表项
*dir = 0; //页目录项内容清零
}
invalidate(); //刷新高速缓存
return 0; //返回0表示操作成功
}
Linux-0.11内核源码分析系列:内存管理free_page()与free_page_tables()函数分析
最新推荐文章于 2023-11-04 16:21:43 发布