日期:2014-05-16  浏览次数:20834 次

《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"//如果找到了空闲页,那么执行这指令,然后把该页对应页面内存映像比