首页 > 代码库 > 《linux 内核完全剖析》get_free_page(void)
《linux 内核完全剖析》get_free_page(void)
get_free_page(void) 分析极其资料整理
实现在swap.c 里面
程序功能概述:
首先在内存映射字节位图中查找值为0的字节项,然后把对应物理内存页面清零,如果得到的页面地址值大于实际物理内存容量则重新寻找。如果没有找到空闲页面则去调用执行交换处理,并重新查找。最后返回空闲物理地址。
我一开始没能比较熟练的掌握嵌入式汇编,所以又把问题的难度拔高了。。。如果熟练的掌握嵌入式汇编的话,不至于被卡这么久
:"=a" (__res)
:"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
"D" (mem_map+PAGING_PAGES-1)
:"di","cx","dx");
这里把输出寄存器指定为%eax, 并保存到变量__res中。返回是%0,这个是指令操作数,%0 代表 第一个占位符,即上面“=a” ax寄存器
%1 %2 %3 %4 分别代表代表 ax di cx dx 寄存器
输入
%1(ax = 0) -0
%2 (LOW_MEM) 这里并不是指定到di寄存器,“i”是说明这是个直接操作数。 这个定义为0x1000 是pg0 的起始位置。《注释》书上说“内存字节位图管理的起始位置” 这里有点小含糊,我郁闷了好一会儿,各种发帖子问。。。各种纠结其实我觉得这么描述不是很好,为啥不直接了当的很直白的说这里是mem_map第一个元素对应的内存页捏?我还以为mem_map就放在0x1000。mem_map是个全局变量,是不会放在0x1000的
%3 ecx = PAGING_PAGES
%4 edi = mem_map+PAGING_PAGES-1 这其实是mem_map最后一个元素的地址
限定符 | 意义 |
"m"、"v"、"o" | 内存单元 |
"r" | 任何寄存器 |
"q" | 寄存器eax、ebx、ecx、edx之一 |
"i"、"h" | 直接操作数 |
"E"和"F" | 浮点数 |
"g" | 任意 |
"a"、"b"、"c"、"d" | 分别表示寄存器eax、ebx、ecx和edx |
"S"和"D" | 寄存器esi、edi |
"I" | 常数(0至31) |
对于这些输入输出寄存器一定要理解好
"std ; repne ; scasb\n\t"
这行代码的作用是“置为方向,al(0) 与对应每个页面的di 做比较”
个人觉得,这句话,不要纠结。。。知道它真正做了什么就OK了。
这行代码会查询edi寄存器储存的地址处的值是否为0,每次循环(repeat 一次)
判断是否为0"jne 1f\n\t" 如果不是0,就跳转到嵌入式汇编结束的位置
如果是,执行跳转指令后面的
unsigned long get_free_page(void) { register unsigned long __res asm("ax"); repeat: __asm__("std ; repne ; scasb\n\t"//执行完scasb之后ecx - 1, edi -1 "jne 1f\n\t"//如果在mem_map里没有知道值为0的数组元素,即代表free page的位。那么这个时候所有的页都处于占用状态,get free page 第一次失败 "movb $1,1(%%edi)\n\t"//如果找到了空闲页,那么执行这指令,然后把该页对应页面内存映像比特位置1.表示占用此页。注意edi寄存器的初始值是LOW_MEM 0x1000 "sall $12,%%ecx\n\t" "addl %2,%%ecx\n\t"// ecx 储存了页面数右移12位并且加上LOW_MEM,即可得到对应页面的地址 "movl %%ecx,%%edx\n\t"//把页面地址保存到edx里面去 "movl $1024,%%ecx\n\t"//赋值1024给ecx "leal 4092(%%edx),%%edi\n\t"//edx+4092得到该页面最后一个字节的地址,然后赋值给edi "rep ; stosl\n\t"//edi所指的内存反向清0 "movl %%edx,%%eax\n" "1:" :"=a" (__res) :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES), "D" (mem_map+PAGING_PAGES-1) :"di","cx","dx"); if (__res >= HIGH_MEMORY) goto repeat; if (!__res && swap_out()) goto repeat; return __res; }
其实我到现在才知道,linux 0.12的内核管理的内存就16M。也就是说,也就4个memory page,也刚好是内核代码的4个memory page
纠结了这么久,也算是可以放下了,其实真正还是没有把最细致的地方搞懂,但是我觉得对于x86的嵌入式汇编,目前水平重要的是掌握linux设计的思想是如果实现的,尽自己最大的能力去印证代码和理论设计思想是一致。只要不是妨碍整理的理解,可以暂时先把问题放一放,以后功力好了,问题也就自然不是问题了。
下面是我收集到,关于这个get _free_page讨论的一些写帖子
http://www.oldlinux.org/oldlinux/archiver/?tid-13694.html
http://www.oldlinux.org/oldlinux/archiver/?tid-6763.html
http://www.oldlinux.org/oldlinux/archiver/?tid-6777.html
我觉得oldlinux中文站对于中国读者来说太重要了,希望赵博能够一直维护下去。力挺赵博