QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 1411|回复: 2

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

[复制链接]
发表于 2008-11-10 16:18:49 | 显示全部楼层 |阅读模式
上周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 编辑 ]
 楼主| 发表于 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 编辑 ]
回复

使用道具 举报

发表于 2008-12-13 10:03:16 | 显示全部楼层

可否上传修改后文件

可否上传修改后文件,我照楼主的方法修改了不行,楼主可否上传修改后文件?另:楼主的skyeye是哪个版本。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-11-2 08:19 , Processed in 0.058784 second(s), 16 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表