unicorn-engine / unicorn

Unicorn CPU emulator framework (ARM, AArch64, M68K, Mips, Sparc, PowerPC, RiscV, S390x, TriCore, X86)
http://www.unicorn-engine.org
GNU General Public License v2.0
7.34k stars 1.31k forks source link

Support for EL3 system registers #1819

Open SilentVoid13 opened 1 year ago

SilentVoid13 commented 1 year ago

Hi, it looks like Unicorn currently doesn't support some EL3 registers on ARM architectures (spsr_el3, scr_el3, cptr_el3, ...) and throws an interrupt 1 when encountering an instruction such as msr scr_el3, x0.

I wanted to ask how hard the addition of those registers is? I'm willing to give it a try. Does it just require some small modifications in the uc_arm64_reg structure and the reg_read and reg_write functions in qemu/target/arm/unicorn_aarch64.c or is it more complex? I'm not familiar with the codebase, so I may be missing something.

Thank you!

wtdcode commented 1 year ago

In most cases, the work is to write the value to the register or expose relevant helpers to users if any. For scr_el3, it could be probably env->cp15.scr_el3.

SilentVoid13 commented 1 year ago

Hey @wtdcode, ty for your answer! What's with UC_ARM64_REG_CP_REG (e.g. https://github.com/unicorn-engine/unicorn/blob/master/include/unicorn/arm64.h#L316). It looks like this is the preferred way to modify system registers, and the rest is depreciated. I'm not sure I understand how to use it though. How can I extend it to add new EL3 registers support?

wtdcode commented 1 year ago

Oh wait, I think the coprocessor you would like to write should be covered by UC_ARM64_REG_CP_REG?

SilentVoid13 commented 1 year ago

You're correct I tracked down the problem to a permission issue. It looks like Unicorn executes in EL1 and we therefore don't have the permission to access an EL3 register.

Then my question is: how can I context switch to EL3 in Unicorn? It doesn't look like there is handy method to do that, and manipulating PSTATE doesn't work since this is a startup setting, in pure QEMU you would specify secure=on, not sure if that's possible here.

sfwhittaker commented 1 year ago

I hit the same kind of issue and solved with this hacky method:

    void HookCodeCallback(uc_engine* uc, uint64_t address, uint32_t size, void* userData)
    {
        static bool firstTime = true;

        if (firstTime)
        {
            uint64_t el3Pstate = 13;
            uc_err ucErr = uc_reg_write(uc, UC_ARM64_REG_PSTATE, &el3Pstate);

            if (UC_ERR_OK != ucErr)
            {
                printf("UNABLE TO SET PSTATE\n");
            }

            firstTime = false;
        }

Thanks,

Simon