操作系统源码学习笔记(三) mem_init/内存映射初始化/主内存分页映射

/ 默认分类 / 0 条评论 / 411浏览

前面对主内存区起始位置的重新确定,标志着主内存区和缓冲区的位置和大小已经全都定了,下面操作系统开始调用mem_init()函数。 先对主内存区的数据进行设置(其实也就是将物理内存封装为相应的数据结构和逻辑操作)。

mem_init

源码

从上一个博客的操作系统源码可以看出,第一步进行的就是mem_init操作,下面我们来详细分析下这个函数。 先来看下源码内容:

// 分页内存15 MB,主内存区最多15M.
#define PAGING_MEMORY (15*1024*1024)
// 分页后的物理内存页面数(3840)
#define PAGING_PAGES (PAGING_MEMORY>>12)
// 指定地址映射为页号
#define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
// 页面被占用标志.
#define USED 100

void mem_init(long start_mem, long end_mem)
{
	int i;
	HIGH_MEMORY = end_mem;                  
	for (i=0 ; i<PAGING_PAGES ; i++)
		mem_map[i] = USED;
    
	i = MAP_NR(start_mem);     
	end_mem -= start_mem;
	end_mem >>= 12;            
	while (end_mem-->0)
		mem_map[i++]=0;         
}

解读

linux0.11针对的物理总内存大小是16MB,操作系统会对大于1MB的内存进行分页管理,也就是将15MB的内存进行划分,每一小块叫做一页,每页的大小是4kb,这样分页管理的页面数量就有3840个,也就是(16mb-1mb)*1024/4kb计算得到的就是3840个了。 这3840个页会被映射到一个字节数组mem_map[]中,当一个页面的内存被使用的时候就会讲对应的数组元素的字节值加1,当释放使用的页的内存的时候,就将对应的数组元素的字节值减1.所以,如果数组元素的字节值大于0,那么就表示当前页正在被使用,反之表示没有被使用。

所以,上面这段代码的实际作用也就是先将1MB到16MB范围内所有内存页面对应的内存映射字节数组项置为已占用状态,然后通过MAP_NR计算出当前主内存开始的位置对应的页是哪一个。这里start_mem其实就是4MB,因为根据之前的内存划分,我们知道,主内存占用的大小是从4MB-16MB,于是计算得到的i其实就是主内存的第一个页面在mem_map中的位置。 后面的操作就是计算当前主内存的15mb空间被分成了多少页,计算逻辑也就是用主内存结束地址减去主内存开始地址,然后将减的结果除以4kb,也就是除以页大小,得到的while循环中的end_mem其实就是主内存本分成的页面数量了。然后在while循环中将主内存的4mb-16mb所映射的页面都重新设置为未使用状态,也就是赋值为0。