Linux-0.11内存管理模块是源代码中比较难以理解的部分,现在把笔者个人的理解发表
先发Linux-0.11内核内存管理get_free_page()函数分析
寻找mem_map[0..(PAGING_PAGES-1)]中的空闲项,即mem_map[i]==0的项,如果找到,
就返回物理地址,找不到返回0
2.技巧:
这段代码为何用C嵌套汇编实现?
笔者个人认为C函数会开辟栈帧,可能会污染任务堆栈,
同时该函数需要经常频繁的调用,汇编中,寄存器级别的汇编指令操作的效率比C更高:)
3.代码分析:
(1)register unsigned long __res asm("ax");
__res是寄存器级变量,值保存在ax寄存器中,就是说对__res的操作等于ax寄存器的操作,为效率考虑
(2)__asm__("std ; repne ; scasb\n\t"
循环比较,找出mem_map[i]==0的页;
std设置DF=1,所以scasb执行递减操作,涉及寄存器al, ecx, es:(e)di三个寄存器,在函数尾部的定义中
:"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
"D" (mem_map+PAGING_PAGES-1)
:"di","cx","dx");
即有
这句指令的意思是从数组mem_map[0..(PAGING_PAGES-1)]的最后一项
mem_map[PAGING_PAGES-1]开始,比较mem_map[i]是否等于0(0值保存在al寄存器中);
每比较一
先发Linux-0.11内核内存管理get_free_page()函数分析
有时间再写其他函数或者文件的:)
/*
*Author : DavidLin
*Date : 2014-11-11pm
*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-11 created this file!
2)
*/
以下是Linus的源码:
/*
* Get physical address of first (actually last :-) free page, and mark it
* used. If no free pages left, return 0.
*/
unsigned long get_free_page(void)
{
register unsigned long __res asm("ax");
__asm__("std ; repne ; scasb\n\t"
"jne 1f\n\t"
"movb $1,1(%%edi)\n\t"
"sall $12,%%ecx\n\t"
"addl %2,%%ecx\n\t"
"movl %%ecx,%%edx\n\t"
"movl $1024,%%ecx\n\t"
"leal 4092(%%edx),%%edi\n\t"
"rep ; stosl\n\t"
"movl %%edx,%%eax\n"
"1:"
:"=a" (__res)
:"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
"D" (mem_map+PAGING_PAGES-1)
:"di","cx","dx");
return __res;
}
1.函数目的:
寻找mem_map[0..(PAGING_PAGES-1)]中的空闲项,即mem_map[i]==0的项,如果找到,
就返回物理地址,找不到返回0
2.技巧:
这段代码为何用C嵌套汇编实现?
笔者个人认为C函数会开辟栈帧,可能会污染任务堆栈,
同时该函数需要经常频繁的调用,汇编中,寄存器级别的汇编指令操作的效率比C更高:)
3.代码分析:
(1)register unsigned long __res asm("ax");
__res是寄存器级变量,值保存在ax寄存器中,就是说对__res的操作等于ax寄存器的操作,为效率考虑
(2)__asm__("std ; repne ; scasb\n\t"
循环比较,找出mem_map[i]==0的页;
std设置DF=1,所以scasb执行递减操作,涉及寄存器al, ecx, es:(e)di三个寄存器,在函数尾部的定义中
:"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
"D" (mem_map+PAGING_PAGES-1)
:"di","cx","dx");
即有
al = 0; //如果mem_map[i] == 0,表示为空闲页,否则为已分配占用,al保存0值,用于比较
ecx = PAGING_PAGES; //主内存叶表个数
es:di = (mem_map+PAGING_PAGES-1); //内存管理数组最后一项这句指令的意思是从数组mem_map[0..(PAGING_PAGES-1)]的最后一项
mem_map[PAGING_PAGES-1]开始,比较mem_map[i]是否等于0(0值保存在al寄存器中);
每比较一