#001 AppcpuInit:
#002 /* Loop until we can release the freeze lock */
#003 do
#004 {
#005 /*
#006 while (*(volatile PKSPIN_LOCK*)&KiFreezeExecutionLock == (PVOID)1);
#007 } while(InterlockedBitTestAndSet((PLONG)&KiFreezeExecutionLock,0));
第1行是指明开始应用cpu的初始化,主要与引导cpu的初始化区分开来。比如在多核的cpu里,对于操作系统的初始化,只能让一个cpu来工作,不可以多个cpu一起来引导操作系统的,否则就是乱七八糟。也许你会想使用中断来屏蔽中断,但再仔细地一想,使用指令CLI只能关闭其中一个cpu的中断,并没有办法关闭其它cpu的中断响应,因此只能使用自旋锁来解决这个问题。
第6行代码判断自旋锁KiFreezeExecutionLock是否被其它cpu锁住,如果置为1,表明已经被其它cpu锁住,在这里等到其它cpu释放为止。
第7行代码调用函数InterlockedBitTestAndSet来设置自旋锁KiFreezeExecutionLock。为了更好地理解自旋锁,有必要来查看这个函数的代码,如下:
static __inline__ BOOLEAN
InterlockedBitTestAndSet(IN LONG volatile *Base,
IN LONG Bit)
{
#if defined(_M_IX86)
LONG OldBit;
__asm__ __volatile__("lock "
"btsl %2,%1/n/t"
"sbbl %0,%0/n/t"
:"=r" (OldBit),"+m" (*Base)
:"Ir" (Bit)
: "memory");
return OldBit;
#else
return (_InterlockedOr(Base,1 << Bit) >> Bit) & 1;
#endif
}
上面函数第1个参数Base是自旋锁的指针地址,也就是要测试和设置的内存地址。第2个参数Bit是用来说明测试和设置内存地址Base的那一位的值。
lock指令是用来锁住cpu的访问内存的总线,这样只让一个cpu访问内存,达到占有这把锁的唯一性。lock为指令前缀,可以使LOCK引脚变成逻辑0,在LOCK引脚有效期间,禁止外部总线上的其它处理器存取带有LOCK前缀指令的存储器操作数。
"btsl %2,%1这行语句,就是使用btsl指令来把%1(地址Base的值)的第%2(参数Bit)位拷贝到CF标志上,然后再把把%1(地址Base的值)的第%2(参数Bit)位设置为1。
sbbl %0,%0这行语句,就是指令sbb是带借位减法指令,它利用了CF位上记录的借位值。
指令格式:sbb 操作对象1,操作对象2
功能:操作对象1=操作对象1-操作对象2-CF
按指针的运作,就是%0 - %0 – CF,经过这样运算后放回到%0。如果CF的值为1,那么返回值OldBit的值就是-1。如果CF的值为0,那么返回值OldBit的值就是0。因此返回值就反映了自旋锁内存地址Base的第Bit位的值。
通过上面的分析,可以看到就是先把内存Base地址的指定的位值设置到返回值里,然后再设置相应的值为1。因此这行语句InterlockedBitTestAndSet((PLONG)&KiFreezeExecutionLock,0),就是把KiFreezeExecutionLock的第0位的值返回,并设置它为1。如果这个函数返回1,表明这个自旋锁有cpu正在使用,继续等待下去,直到这位值返回0为止。当然返回值时,这个函数也已经把这位置为1了,其它cpu读取出来的值永远为1。这样就锁住其它cpu去执行后面的代码。