Skip to content

MIPS emulation goes into “Branch in delay / forbidden slot” scenario when virtual tlb is enabled #2272

@palant

Description

@palant

The application I tried to emulate was producing Unhandled CPU exception consistently, this turned out to be unhandled interrupt 20, meaning EXCP_RI. I traced it back to this condition:

https://github.com/unicorn-engine/unicorn/blob/8028ec436f2d9376525352dd38ed9ed6b9f6be10/qemu/target/mips/translate.c#L6039-L6046

Now I am no MIPS expert but the code in question doesn’t seem to be putting a branch in a delay slot. Here is the reduced code:

import unicorn

uc = unicorn.Uc(
    unicorn.UC_ARCH_MIPS,
    unicorn.UC_MODE_MIPS32 | unicorn.UC_MODE_LITTLE_ENDIAN
)
uc.ctl_set_tlb_mode(unicorn.UC_TLB_VIRTUAL)

BASE = 0x1000

# b       0x1008
# lb      $v0, ($s8)
# b       0x1000
# addiu   $s0, $s0, 1
CODE = b'\x01\x00\x00\x10\x00\x00\xc2\x83\xFD\xFF\x00\x10\x01\x00\x10\x26'

uc.mem_map(BASE, 0x1000, perms=unicorn.UC_PROT_ALL)
uc.mem_write(BASE, CODE)


def hook_code(uc, addr, size, user_data):
    print(f'At address 0x{addr:x}')


uc.reg_write(unicorn.mips_const.UC_MIPS_REG_S8, BASE)
uc.hook_add(unicorn.UC_HOOK_CODE, hook_code)
uc.emu_start(BASE, BASE + len(CODE), count=20)

If I don’t enable virtual tlb this code goes into an endless loop as expected (unfortunately not an option for the real application, it has to be loaded at a high memory address). Same happens if the memory access in the delay slot of the first jump is replaced by nop or some other instruction that doesn’t access memory. But as written here the second jump triggers “reserved instruction” exception.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions