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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions