Linux0.12内核之内存管理(2)

本文主要介绍Linux0.12内核memory.c中的函数

1.void free_page(unsigned long addr)
//释放物理地址addr处的一页内存。用于free_page_tables()函数
void free_page(unsigned long addr)
{
//首先判定给定物理地址的合理性。如果物理地址addr小于内存低端1M,对此不///予处理。如果addr>=内存最高端,则显示出错并且内核停止工作
if(addr<LOW_MEM) return;
if(addr>=HIGH_MEMORY)
panic("trying to free nonexistent page");
//如果对参数验证通过,那么就根据这个物理地址换算出从内存低端开始计算的//内存页面号。页面号=(addr-LOW_MEM)/4096。可见页面号从0号开始计起。此///时addr中存放着页面号。如果该页面号对应的页面映射字节不等于0,则减1返//回。此时映射字节值应该是0,表示页面已经释放。如果对应页面字节原本就///是0,表示该物理页面本来就是空闲的,说明内核代码出问题,于是显示出错///并停机。
addr-=LOW_MEM;
addr>>=12;
if(mem_map[addr]--) return;
mem_map[addr]=0;
panic("trying to free page);
}
2.int free_page_tables(unsigned long from,unsigned long size)
//该函数释放页表连续的内存块,只处理4MB长度的内存块
//根据指定的线性地址和限长(页表个数),释放对应内存页表指定的内存块并置表项//空闲。页目录位于物理地址0开始处,共1024项,每项4字节,共占4KB。每个目录//项指定一个页表。内核页表从物理地址0x1000处开始,共4个页表。每个页表有10//24项,每项4B,因此也占4KB内存。每个页表最多可以映射1KB*4B=4M的物理内存。
//参数:from--起始线性地址;size--释放的字节长度
int free_page_tables(unsigned long from,unsigned long size)
{
unsigned long *pa_table;
unsigned long *dir,nr;

//首先检测参数from是否在4MB的边界上,因为该函数只能处理这种情况。若fr//om=0,则出错,说明释放内核和缓冲所占空间
if(from & 0x3fffff)
panic("free_page_tables called with wrong alignment")
if(!from)
panic("Trying to free up swapper memory space");

//然后计算参数size给出的长度所占的页目录项目数(4MB的进位整数倍),也即所占页表数。因为一个页表可管理4MB物理内存,所以这里用右移22位的方式把需要复制的内存长度值除以4MB。其中加上0x3fffff(即4MB-1)用于得到进位整数倍结果。即除操作若有余数则进1。例如原size=4.01MB,那么可到结果size=2。接着计算给出的线性地址对应的起始目录项。对应的目录项号=from>>22。因为每项占4字节,并且由于页目录表从物理地址0开始存放,因此实际目录项指针=目录项号<<2,也即from>>20。

size=(size+0x3fffff)>>22;
dir=(unsigned long *)((from>>20) & 0xffc);

//此时size是释放的页表个数,即页目录项数,而dir是起始目录项指针。现在开始循环操作页目录项,依次释放每个页表中的页表项(??具体什么操作叫释放)。如果当前目录项无效(p=0),表示该目录项没有使用(对应的页表不存在),则继续处理下一个目录项。否则从目录项中取出页表地址pg_table,并对该页表中1024个表项进程处理,释放有效页表项对应的物理内存页面,或者从交换设备中释放无效页表项对应的页面,即释放交换设备中对应的内存页面。

for(;size-->0;dir++)
{
if(!(1 & *dir))
continue;
pg_table=(unsigned long *)(0xfffff000 & *dir);
for(nr=0;nr<1024;nr++)
{
if(*pg_table)
{
if(1 & *pg_table)
{
free_page(0xfffff000 & *pg_table)
}
else
swap_free(*pg_table>>1);
*pg_table=0;
}
pg_table++;
}
free_page(0xfffff000 & *dir);
*dir=0;//对应页表的页目录项清零
}
invalidate();
return 0;
}

总结:

1.free_page()用于释放指定物理地址处的一页物理内存。假如物理地址对应的页号是addr,那么何谓释放?物理内存就在那里,我们所谓的获取物理内存,其实就是使用一个标志,说明我们占用了他,相对应的,所谓的释放就是清除表示,说明我们我们释放了内存,释放的本质就是:mem_map[addr]--。

2.free_page_tables()以一个页表对应的物理内存为单位,释放指定线性地址和长度(页表个数)对应的物理内存页块。不仅对管理线性地址的页目录项和页表中的页表项内容进行修改(修改其实就是清0),同时会释放对应的页表内存和页表项对应的物理内存。

Linux0.12内核之内存管理(2)

时间: 2024-08-03 14:59:45

Linux0.12内核之内存管理(2)的相关文章

Linux0.12内核之内存管理(3)

本系列的第三篇文章主要来介绍与共享物理页面相关的两个函数. //在发生缺页异常的时,首先看看能否与运行同一个文件的其他进程进行页面共享处理.该函数首先判断系统中是否有另外进程也在运行与当前进程一样的执行文件.若有,则在系统当前任务中找寻这样的任务.若找到了这样的任务就尝试与其共享指定地址处的页面.判断系统中是否有另一个进程也在执行同一个可执行文件的方法是利用进程任务数据结构中的executable字段.该字段执行进程正在执行程序的内存中的i节点,根据该i节点的引用次数i_count我们就可以判断

linux0.12内核的内存组织和进程结构

进程结构 Linux0.12中的每个进程都有如下的结构: 在gdt中占有两项,一项是tss段描述符,一项是ldt段描述符. 在task数组中占有一项,指向一页物理内存,该物理内存低端是进程控制块task_struct(里面包括tss段和ldt段),其余部分是进程的内核态堆栈. 在页目录表和页表中设置有相关项. Linux0.12中,最多只有64个进程,task数组大小也定义成了64,每个进程与一个task数组中的项一一对应.虽然gdt中有256项,但是并不是都用到.第一个gdt项保留不用,内核用

Linux 0.12内核与现代内核在内存管理上的区别

0.12内核的内存管理比较简单粗暴,内核只用了一个页目录,只能映射4G的线性空间,所以每个进程的虚拟空间(逻辑空间)只能给到64M,最多64个进程:每个进程都有对应的任务号nr,当一个进程需要分配进程空间时,只需要nr乘以64M就可以得出该进程空间的线性起始地址.然后该进程的代码段.数据段描述符里面的基址字段会被设定为(nr x 64M),同时可以为进程分配页目录项和页目录表用以承载映射关系. 之后如果进程要访问自己空间内的某个地址时就会首先用基地址与程序内32位偏移地址(逻辑地址)合成出线性地

Linux0.12内核学习之(1)——用MASM编写Boot Sector引导扇区

最近在学习Linux0.12内核,正在读<Linux内核完全剖析>.一开始就被ax86写的引导扇区弄晕了.于是Google了很多资料.最终实验了一晚上终于搞定.下面来看看我们怎么用Windows下的MASM来写个Boot Sector.因为我MASM汇编用的比较熟,所以就用MASM来写,当然,汇编只有语法差异,你用什么来写都没关系. 首先,先来说说计算机怎么启动的.经过一系列BIOS加电.系统自检后,会将硬盘0面0道1扇区的512字节(Boot Sector)加载到内存地址07c0:0000处

Linux内核之内存管理(4)--缺页处理程序

本文主要解说缺页处理程序,凝视足够具体,不再解释. //以下函数将一页内存页面映射到指定线性地址处,它返回页面的物理地址 //把一物理内存页面映射到线性地址空间指定处或者说把线性地址空间指定地址address处的页面映射到主内存区页面page上.主要工作是在相关也文件夹项和页表项中设置指定页面的信息.在处理缺页异常函数do_no_page中会调用这个函数. 參数:address--线性地址:page--是分配的主内存区中某一页面指针 static unsigned long put_page(u

linux0.12内核bootsect.S

这个文件就是0.12内核的主引导扇区代码,他的作用就是加载操作系统内核. 计算机加电,自检完毕后,BOIS就将启动设备的第一扇区加载到内存0x7c00(31KB)处,并开始从这里执行,若启动设备是硬盘的话,加载的即为该硬盘0磁道0柱面1扇区的内容,共512字节,以0xAA55为结束标志,这就是硬盘的MBR(master boot recorder). linux0.12内核bootsect.S中的代码编译后,将会写入启动设备的MBR中,它的主要工作加载操作系统内核的初始化程序setup.S和操作

Linux-0.12内核sleep_on函数分析

sleep_on用于进程休眠,原型如下: void sleep_on(struct task_struct **p) 当进程访问某个互斥资源时,如果资源被另外进程占用,当前进程就需要休眠. 假设资源的结构如下: struct res { .... struct task_struct *wait; } 其实我们参考下文件系统的i节点就会发现,i节点也是一种资源,它的结构体中就有一个变量i_wait.那么我们就用i节点举例.如果进程访问某个i节点,发现i节点被锁住,当前进程就需要睡眠:sleep_

Linux 内核开发 - 内存管理

1.1什么是内存管理 内存管理是对计算机内存进行分配和使用的技术.内存管理主要存在于多任务的操作系统中,由于内存资源极其有限,需要在不同的任务之间共享内存,内存管理的存在就是要高效.快速的非配内存,并在适当的时候回收和释放内存,以保各个任务正常的执行.最常见的内存管理机制有:段式内存管理和页式内存管理. 1.2内存中的地址 早期的16位计算中,寄存器的位宽只有16位,为了能访问到1M Bit的内存空间,CPU就采用了分段的方式来管理内存,将1M的内存分为若干个逻辑段,每个逻辑段的起始地址必须是1

Linux内核之内存管理完全剖析

linux虚拟内存管理功能 ? 大地址空间:? 进程保护:? 内存映射:? 公平的物理内存分配:? 共享虚拟内存.实现结构剖析 (1)内存映射模块(mmap):负责把磁盘文件的逻辑地址映射到虚拟地址,以及把虚拟地址映射到物理地址 (2)交换模块(swap)负责控制内存内容的换入与换出,淘汰最近没访问的页,保留最近访问的页. (3)core(核心内存管理模块):负责内存管理功能. (4)结构特定模块:实现虚拟内存的物理基础 内核空间和用户空间 Linux简化了分段机制,使得虚拟地址跟线性地址一样.