Skip to content

MIPS: ll/lld raise spurious EXCP_AdEL above useg under UC_TLB_VIRTUAL #2345

Description

@retrocpugeek

Under UC_TLB_VIRTUAL, MIPS Load-Linked (ll/lld) raise a spurious Address Error (EXCP_AdEL, intno 12) for addresses at/above the useg limit (>= 0x80000000), even though an ordinary load (ld/lw) at the same address goes through the UC_HOOK_TLB_FILL hook and succeeds. This breaks emulating MIPS64 code that takes a lock above 2 GB (e.g. glibc).

Reproduced on 2.1.3 and current dev; MIPS64 BE+LE, independent of CPU model.

import unicorn
from unicorn import (Uc, UC_ARCH_MIPS, UC_MODE_MIPS64, UC_MODE_BIG_ENDIAN,
                     UC_HOOK_TLB_FILL, UC_TLB_VIRTUAL, UC_PROT_ALL, UcError)
from unicorn.mips_const import UC_MIPS_REG_S0, UC_MIPS_REG_V1

ADDR = 0x120000000  # above the MIPS useg limit; requires the virtual TLB

def identity_tlb(uc, vaddr, access, entry, user_data):
    entry.paddr = vaddr & ~0xfff
    entry.perms = UC_PROT_ALL
    return True

for opcode, name in ((0xde030000, "ld $v1, 0($s0)"), (0xc2030000, "ll $v1, 0($s0)")):
    uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS64 | UC_MODE_BIG_ENDIAN)
    uc.ctl_set_tlb_mode(UC_TLB_VIRTUAL)
    uc.hook_add(UC_HOOK_TLB_FILL, identity_tlb)
    uc.mem_map(0x10000000, 0x1000)            # code page
    uc.mem_map(ADDR, 0x1000)                  # data page (the lock word)
    uc.mem_write(0x10000000, opcode.to_bytes(4, "big"))
    uc.reg_write(UC_MIPS_REG_S0, ADDR)
    try:
        uc.emu_start(0x10000000, 0x10000004, 0, 1)
        print("  %-16s OK" % name)
    except UcError as e:
        print("  %-16s ERROR: %s" % (name, e))

Output:

  ld $v1, 0($s0)   OK
  ll $v1, 0($s0)   ERROR: Unhandled CPU exception (UC_ERR_EXCEPTION)

Root cause: the ll/lld helpers (HELPER_LD_ATOMIC in qemu/target/mips/op_helper.c) perform the load via the soft-TLB (which honors the virtual TLB) but additionally call do_translate_address() to populate CP0_LLAddr. That walks the MIPS segments via get_physical_address() and returns TLBRET_BADADDR for an address outside useg (UX unset), raising EXCP_AdEL and bypassing the virtual TLB. sc/scd are unaffected (they use tcg_gen_atomic_cmpxchg_tl, which never calls do_translate_address).

Fix + regression test ready; PR to follow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions