linux内核0.11 获取第一个空闲物理内存页的函数 get_free_page函数 问题

第70行,ecx存的就是找到的第一个空闲物理页面的地址码? 注意 "c"(PAGING_PAGES)
前面#define PAGING_MEMORY (15*1024*1024)
#define PAGING_PAGES (PAGING_MEMORY >> 12)
PAGING_PAGES不就是主内存的页面总数吗?ecx怎么变成了找到的空闲页面的!!!!!
ecx存的就是找到的第一个空闲物理页面的页号吗?

问题关键在于理解以下指令:
"std ; repne ; scasb\n\t"
1、std:方向位DF置位,即DI进行自减操作。
2、repne; scasb
这两条组合指令实现循环比较。ecx初值为15*1024,al=0,di初值为&mem_map[15*1024-1],即从数组mem_map的最后一项开始,依次与al(=0)进行比较。假设数组第i项mem_map[i]==0,则结束循环,此时ecx=i, edi=&mem_map[i-1](因为ecx初值为15*1024,di初值为数组最后一项15*1024-1的地址)。找到空闲页面后,将该数组项置1,即*(edi+1)=mem_map[i]=1,即语句“movb $1,1(%%edi)”实现的功能。此时,ecx即为空闲页面索引。
几点说明:
1、rep循环结束条件:
Repeat Prefix Termination Condition 1 Termination Condition 2
REP RCX or (E)CX = 0 None
REPE/REPZ RCX or (E)CX = 0 ZF = 0
REPNE/REPNZ RCX or (E)CX = 0 ZF = 1

2、rep循环执行顺序:
WHILE CountReg ≠ 0
DO
Service pending interrupts (if any);
Execute associated string instruction; // 1、执行相关指令。例如scansb指令,除了执行al与*di的比较外,di也会被影响,即di自减1(当DF==1时)或自加1(当DF==0时)
CountReg ← (CountReg – 1); // 2、ECX自减
IF CountReg = 0 // 3、判断ECX是否已减到0
THEN exit WHILE loop; FI;
IF (Repeat prefix is REPZ or REPE) and (ZF = 0) // 4、最后才判断其他相关标志。
or (Repeat prefix is REPNZ or REPNE) and (ZF = 1)
THEN exit WHILE loop; FI;
OD;
3、scasb指令对di的影响:
After the comparison, the (E)DI register is incremented or decremented automatically according to the setting of
the DF flag in the EFLAGS register. If the DF flag is 0, the (E)DI register is incremented; if the DF flag is 1, the (E)DI
register is decremented. The register is incremented or decremented by 1 for byte operations, by 2 for word operations, and by 4 for doubleword operations.

以上指令请参考《Intel 64 and IA-32 Architectures Software Developer's Manual》。
温馨提示:答案为网友推荐,仅供参考
第1个回答  2014-10-22
198 unsigned long get_free_page(void)
199{
200 unsigned long result;
201
202repeat:
203 __asm__("std ; repne ; scasb\n\t"
204 "jne 1f\n\t"
205 "movb $1,1(%%edi)\n\t"
206 "sall $12,%%ecx\n\t"
207 ...
215 :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
216 "D" (mem_map+PAGING_PAGES-1)
217 :"di","cx","dx");
...
223 }
224 if (!result && swap_out())
225 goto repeat;
226 return result;
227}

在这段代码中, 没有存在中断屏蔽cli , 而在fork系统调用中直接使用这个函数, 如果在执行到204的时候被中断, 并且其他进程也调用fork系统调用执行完这个函数, 这样就会导致同一页被引用两次, 而mark数值 1 而造成数据重复的错误. 不知道会不会造成这样子的错误.本回答被网友采纳