linux源代码阅读笔记 get_free_page()代码分析

33 /*
 34  * Get physical address of first (actually last :-) free page, and mark it
 35  * used. If no free pages left, return 0.
 36  */
 37 unsigned long get_free_page(void)
 38 {
 39 register unsigned long __res asm("ax");
 40 
 41 __asm__("std ; repne ; scasw\n\t"
 42         "jne 1f\n\t"
 43         "movw $1,2(%%edi)\n\t"        //将对应页面的内存映像置1(使用)
 44         "sall $12,%%ecx\n\t"        //页面数*4kb=相对LOW_MEMORY的页面起始地址
45 "movl %%ecx,%%edx\n\t"    //加上LOW_MEMORY形成物理起始地址 46 "addl %2,%%edx\n\t"       //页面实际地址给edx 47 "movl $1024,%%ecx\n\t" 48 "leal 4092(%%edx),%%edi\n\t" //将该页面的末端地址给edi 49 "rep ; stosl\n\t" //将edi所指内存请0 50 "movl %%edx,%%eax\n" 51 "1:" 52 :"=a" (__res) 53 :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES), 54 "D" (mem_map+PAGING_PAGES-1) 55 :"di","cx","dx"); 56 return __res; 57 }

这段代码的作用是获取一个空闲的内存页,并且返回它的地址。

首先分析,std ; repne ;scasw 这三句的作用。首先,我们参考一下下面这这篇文章:http://blog.163.com/b____d/blog/static/7491166020099115207391/

那么,我们来分析一下这个函数里含义。首先,在这三句代码执行以前,asm已经将参数装入寄存器。即:

%1(ax=0) %2(LOW_MEM)  %3(cx=PAGING_PAGES)  %4(edi=mem_map+PAGING_PAGES-1) 。这里注意的是,参数%1 "0" (0),”0“表示使用和输出相同的寄存器。即eax。

这样,这三句话的含义就很清楚了,它的作用是从edi指代的地址搜索,如果找到0位,则返回。直到检索了PAGING_PAGES长度。

也就是说,这三句指令在mem_map[ ]数组中寻找0位,并且该0位的index存储在edx中。

 

 

疑问:系统页面长度为4096bit,为何将页面内容清0时,赋予计数器ecx的值是1024而不是4096?

答:关注这里的清零指令,rep;stosl

  STOSL指令相当于将EAX中的值保存到ES:EDI指向的地址中,若设置了EFLAGS中的方向位置位(即在STOSL指令前使用STD指令)则EDI自减4,否则(使用CLD指令)EDI自增4。

  由此可见,stosl每次将4个bit清零。因此计数器赋值1024。同理,这样是为什么edi的初始值被赋予4092而不是4095

posted @ 2015-04-16 15:02  ElNinoT  阅读(2190)  评论(0编辑  收藏  举报