zyjjingle 发表于 2008-11-10 16:18:49

ARMemu 发现的BUG及解决方案参考

上周5,我在虚拟机运行MINIGUI时,发现和其和实际机器上运行的结果不一致,经跟踪分析发现SKYEYE存在BUG。

在处理Load/Store此类指令时,如果在Load/Store时发生Abort异常,在目前的SKYEYE解决方案中,会进行SwitchMode,进行一些特殊寄存器的切换(R13,R14,及FIQ模式的F8-F12),然后再进行指令的后半部分的执行(LSBase的赋值)。在这里有BUG存在。
举个例子:
LDR R0, , #0x4
假设在执行这条指令前是在USER模式,当解析【R13】时,产生Data Abort,
这时SKYEYE会进行模式切换,切换到ABOR模式

oldbank=USERBANK, newbank=ABORTBANK
                        state->RegBank = state->Reg;
                        state->RegBank = state->Reg;
                        state->Reg = state->RegBank;
                        state->Reg = state->RegBank;
)
然后再执行 state->Reg += 0x4的动作,注意这里的state->Reg代表的是Abort模式里的R13,
而实际要操作的应该是USER模式的R13,在这里发生了错误。

参考解决方案:
1。state下ARMWord Reg; 改成 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 = state->RegBank;
                        state->RegBank = state->RegBank;
/*
                        if (newbank == FIQBANK)
                                for (i = 8; i < 13; i++)
                                        state->RegBank =
                                                state->Reg;
                        state->RegBank = state->Reg;
                        state->RegBank = state->Reg;
*/
                        break;
                case FIQBANK:
                        /*
                        for (i = 8; i < 15; i++)
                                state->RegBank = state->Reg;
                        */
                        for( i=0; i<8; i++ )
                                state->RegBank = state->RegBank;
                        state->RegBank = state->RegBank;
                        break;
                case DUMMYBANK:
                        for (i = 8; i < 15; i++)
                                state->RegBank = 0;
                        break;
                default:
                        abort ();
                }
               
                /* Restore the new registers.*/
                state->Reg = state->RegBank;
                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;
                        state->Reg = state->RegBank;
                        state->Reg = state->RegBank;
                        */
                        for( i=0; i<13; i++ )
                                state->Reg = state->RegBank;
                        state->Reg = state->RegBank;
                        break;
                case FIQBANK:
                        /*
                        for (i = 8; i < 15; i++)
                                state->Reg = state->RegBank;
                        */
                        for( i=0; i<8; i++ )
                                state->Reg = state->RegBank;
                        state->Reg = state->RegBank;
                        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 = (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 = oreg;
                return;
        }
       
        //8 - 14
        if( obank == FIQBANK )
                return;

        int nbank = state->Bank;
        if( nbank != FIQBANK )
                state->Reg = oreg;
}

[ 本帖最后由 zyjjingle 于 2008-11-11 23:10 编辑 ]

zyjjingle 发表于 2008-11-12 11:16:41

回复 1# zyjjingle 的帖子

另外:LoadMult,LoadSMult,StoreMult,StoreSMult的异常处理部分要做些调整
       ARMword* Reg = state->Reg;
            int obank = state->Bank;
            。。。。。。
      L_ldm_makeabort:
        if (state->Aborted)
        {
                                    //异常处理
                TAKEABORT;
                                 //回写到异常前的模式
                if( state->lateabtSig )
                if (BIT (21) && LHSReg != 15)
                {
                        nlLSBase( WBBase );
                }
        }
        else if (BIT (21) && LHSReg != 15)
        {
                LSBase = WBBase;
        }

[ 本帖最后由 zyjjingle 于 2008-11-12 11:19 编辑 ]

originallovehom 发表于 2008-12-13 10:03:16

可否上传修改后文件

可否上传修改后文件,我照楼主的方法修改了不行,楼主可否上传修改后文件?另:楼主的skyeye是哪个版本。
页: [1]
查看完整版本: ARMemu 发现的BUG及解决方案参考