|
上周5,我在虚拟机运行MINIGUI时,发现和其和实际机器上运行的结果不一致,经跟踪分析发现SKYEYE存在BUG。
在处理Load/Store此类指令时,如果在Load/Store时发生Abort异常,在目前的SKYEYE解决方案中,会进行SwitchMode,进行一些特殊寄存器的切换(R13,R14,及FIQ模式的F8-F12),然后再进行指令的后半部分的执行(LSBase的赋值)。在这里有BUG存在。
举个例子:
LDR R0, [R13], #0x4
假设在执行这条指令前是在USER模式,当解析【R13】时,产生Data Abort,
这时SKYEYE会进行模式切换,切换到ABOR模式
(
oldbank=USERBANK, newbank=ABORTBANK
state->RegBank[oldbank][13] = state->Reg[13];
state->RegBank[oldbank][14] = state->Reg[14];
state->Reg[13] = state->RegBank[newbank][13];
state->Reg[14] = state->RegBank[newbank][14];
)
然后再执行 state->Reg[13] += 0x4的动作,注意这里的state->Reg[13]代表的是Abort模式里的R13,
而实际要操作的应该是USER模式的R13,在这里发生了错误。
参考解决方案:
1。state下ARMWord Reg[16]; 改成 ARMWord* Reg;用于指向各个模式的RegBank
2。ARMul_SwitchMode改用如下实现
ARMword
ARMul_SwitchMode ( ARMword oldmode, ARMword newmode)
{
unsigned i;
ARMword oldbank;
ARMword newbank;
oldbank = ModeToBank (oldmode);
newbank = state->Bank = ModeToBank (newmode);
/* Do we really need to do it? */
if (oldbank != newbank) {
/* Save away the old registers. */
switch (oldbank) {
case USERBANK:
break;
case IRQBANK:
case SVCBANK:
case ABORTBANK:
case UNDEFBANK:
for( i=0; i<13; i++ )
state->RegBank[USERBANK] = state->RegBank[oldbank];
state->RegBank[USERBANK][15] = state->RegBank[oldbank][15];
/*
if (newbank == FIQBANK)
for (i = 8; i < 13; i++)
state->RegBank[USERBANK] =
state->Reg;
state->RegBank[oldbank][13] = state->Reg[13];
state->RegBank[oldbank][14] = state->Reg[14];
*/
break;
case FIQBANK:
/*
for (i = 8; i < 15; i++)
state->RegBank[FIQBANK] = state->Reg;
*/
for( i=0; i<8; i++ )
state->RegBank[USERBANK] = state->RegBank[oldbank];
state->RegBank[USERBANK][15] = state->RegBank[oldbank][15];
break;
case DUMMYBANK:
for (i = 8; i < 15; i++)
state->RegBank[DUMMYBANK] = 0;
break;
default:
abort ();
}
/* Restore the new registers. */
state->Reg = state->RegBank[newbank];
switch (newbank) {
case USERBANK:
break;
case IRQBANK:
case SVCBANK:
case ABORTBANK:
case UNDEFBANK:
/*
if (oldbank == FIQBANK)
for (i = 8; i < 13; i++)
state->Reg =
state->RegBank[USERBANK];
state->Reg[13] = state->RegBank[newbank][13];
state->Reg[14] = state->RegBank[newbank][14];
*/
for( i=0; i<13; i++ )
state->Reg = state->RegBank[USERBANK];
state->Reg[15] = state->RegBank[USERBANK][15];
break;
case FIQBANK:
/*
for (i = 8; i < 15; i++)
state->Reg = state->RegBank[FIQBANK];
*/
for( i=0; i<8; i++ )
state->Reg = state->RegBank[USERBANK];
state->Reg[15] = state->RegBank[USERBANK][15];
break;
case DUMMYBANK:
for (i = 8; i < 15; i++)
state->Reg = 0;
break;
default:
abort ();
}
}
return newmode;
}
3。在ARMemu.c的switch ((int) BITS (20, 27))代码前增加下面的语句,用于记录指令执行前的reg和bank
ARMword* Reg = state->Reg;
int obank = this->Bank;
switch ((int) BITS (20, 27)) {
4。将LSBase = val; 的地方改用nlLSBase(val);目的就是进行存在模式切换时,非公用寄存器的维护
#define nlLSBase( val ) Reg[LHSReg] = (val); if( obank != state->Bank )BankRegisterMapping( Reg, LHSReg, obank )static void BankRegisterMapping( ARMword* oreg, int index, int obank )
{
if( index == 13 || index == 14 )
return;
if( index <= 7 || index == 15 )
{
state->Reg[index] = oreg[index];
return;
}
//8 - 14
if( obank == FIQBANK )
return;
int nbank = state->Bank;
if( nbank != FIQBANK )
state->Reg[index] = oreg[index];
}
[ 本帖最后由 zyjjingle 于 2008-11-11 23:10 编辑 ] |
|