Skip to content

Commit

Permalink
Introduce ARM CP reg accessors
Browse files Browse the repository at this point in the history
  • Loading branch information
elicn committed Oct 6, 2024
1 parent 0c34496 commit e21dfef
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 5 deletions.
52 changes: 51 additions & 1 deletion bindings/python/unicorn/unicorn_py3/arch/arm.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from unicorn import arm_const as const

# newly introduced unicorn imports
from ..unicorn import Uc
from ..unicorn import Uc, check_maxbits
from .types import UcTupledReg, UcReg128

ARMCPReg = Tuple[int, int, int, int, int, int, int, int]
Expand Down Expand Up @@ -56,5 +56,55 @@ def _select_reg_class(cls, reg_id: int) -> Type:

return next((c for rng, c in reg_class if reg_id in rng), cls._DEFAULT_REGTYPE)

# to learn more about accessing aarch32 coprocessor registers, refer to:
# https://developer.arm.com/documentation/ddi0601/latest/AArch32-Registers

def cpr_read(self, coproc: int, opc1: int, crn: int, crm: int, opc2: int, el: int, is_64: bool) -> int:
"""Read a coprocessor register value.
Args:
coproc : coprocessor to access, value varies between 0 and 15
opc1 : opcode 1, value varies between 0 and 7
crn : coprocessor register to access (CRn), value varies between 0 and 15
crm : additional coprocessor register to access (CRm), value varies between 0 and 15
opc2 : opcode 2, value varies between 0 and 7
el : the exception level the coprocessor register belongs to, value varies between 0 and 3
is_64 : indicates whether this is a 64-bit register
Returns: value of coprocessor register
"""

assert check_maxbits(coproc, 4)
assert check_maxbits(opc1, 3)
assert check_maxbits(crn, 4)
assert check_maxbits(crm, 4)
assert check_maxbits(opc2, 3)
assert check_maxbits(el, 2) # note that unicorn currently supports only EL0 and EL1

return self.reg_read(const.UC_ARM_REG_CP_REG, (coproc, int(is_64), el, crn, crm, opc1, opc2))

def cpr_write(self, coproc: int, opc1: int, crn: int, crm: int, opc2: int, el: int, is_64: bool, value: int) -> None:
"""Write a coprocessor register value.
Args:
coproc : coprocessor to access, value varies between 0 and 15
opc1 : opcode 1, value varies between 0 and 7
crn : coprocessor register to access (CRn), value varies between 0 and 15
crm : additional coprocessor register to access (CRm), value varies between 0 and 15
opc2 : opcode 2, value varies between 0 and 7
el : the exception level the coprocessor register belongs to, value varies between 0 and 3
is_64 : indicates whether this is a 64-bit register
value : value to write
"""

assert check_maxbits(coproc, 4)
assert check_maxbits(opc1, 3)
assert check_maxbits(crn, 4)
assert check_maxbits(crm, 4)
assert check_maxbits(opc2, 3)
assert check_maxbits(el, 2) # note that unicorn currently supports only EL0 and EL1

self.reg_write(const.UC_ARM_REG_CP_REG, (coproc, int(is_64), el, crn, crm, opc1, opc2, value))


__all__ = ['UcRegCP', 'UcAArch32']
46 changes: 45 additions & 1 deletion bindings/python/unicorn/unicorn_py3/arch/arm64.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from unicorn.unicorn_const import UC_ERR_ARG, UC_HOOK_INSN

# newly introduced unicorn imports
from ..unicorn import Uc, UcError, uccallback
from ..unicorn import Uc, UcError, uccallback, check_maxbits
from .types import uc_engine, UcTupledReg, UcReg128

ARM64CPReg = Tuple[int, int, int, int, int, int]
Expand Down Expand Up @@ -100,5 +100,49 @@ def _select_reg_class(cls, reg_id: int) -> Type:

return next((c for rng, c in reg_class if reg_id in rng), cls._DEFAULT_REGTYPE)

# to learn more about accessing aarch64 coprocessor registers, refer to:
# https://developer.arm.com/documentation/ddi0601/latest/AArch64-Registers

def cpr_read(self, op0: int, op1: int, crn: int, crm: int, op2: int) -> int:
"""Read a coprocessor register value.
Args:
op0 : opcode 0, value varies between 0 and 3
op1 : opcode 1, value varies between 0 and 7
crn : coprocessor register to access (CRn), value varies between 0 and 15
crm : additional coprocessor register to access (CRm), value varies between 0 and 15
op2 : opcode 2, value varies between 0 and 7
Returns: value of coprocessor register
"""

assert check_maxbits(op0, 2)
assert check_maxbits(op1, 3)
assert check_maxbits(crn, 4)
assert check_maxbits(crm, 4)
assert check_maxbits(op2, 3)

return self.reg_read(const.UC_ARM64_REG_CP_REG, (crn, crm, op0, op1, op2))

def cpr_write(self, op0: int, op1: int, crn: int, crm: int, op2: int, value: int) -> None:
"""Write a coprocessor register value.
Args:
op0 : opcode 0, value varies between 0 and 3
op1 : opcode 1, value varies between 0 and 7
crn : coprocessor register to access (CRn), value varies between 0 and 15
crm : additional coprocessor register to access (CRm), value varies between 0 and 15
op2 : opcode 2, value varies between 0 and 7
value : value to write
"""

assert check_maxbits(op0, 2)
assert check_maxbits(op1, 3)
assert check_maxbits(crn, 4)
assert check_maxbits(crm, 4)
assert check_maxbits(op2, 3)

self.reg_write(const.UC_ARM64_REG_CP_REG, (crn, crm, op0, op1, op2, value))


__all__ = ['UcRegCP64', 'UcAArch64']
18 changes: 15 additions & 3 deletions bindings/python/unicorn/unicorn_py3/unicorn.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ def __load_uc_lib() -> ctypes.CDLL:

import inspect
import os

import sys

loaded_dlls = set()
Expand Down Expand Up @@ -209,6 +208,19 @@ def __set_prototype(fname: str, restype: Type[ctypes._CData], *argtypes: Type[ct
MMIO_WRITE_CFUNC = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint64, ctypes.c_uint, ctypes.c_uint64, ctypes.c_void_p)


def check_maxbits(value: int, nbits: int) -> bool:
"""Verify that a certain value may be represented with at most `nbits` bits.
Args:
value : numeric value to check
nbits : max number of bits allowed
Returns: `True` if `value` is represented by at most `nbits` bits, `False` otherwise
"""

return value & ~((1 << nbits) - 1) == 0


class UcError(Exception):
"""Unicorn base exception.
Expand Down Expand Up @@ -1160,8 +1172,8 @@ def context_restore(self, context: UcContext) -> None:

@staticmethod
def __ctl_encode(ctl: int, op: int, nargs: int) -> int:
assert nargs and (nargs & ~0b1111) == 0, f'nargs must not exceed value of 15 (got {nargs})'
assert op and (op & ~0b11) == 0, f'op must not exceed value of 3 (got {op})'
assert nargs and check_maxbits(nargs, 4), f'nargs must not exceed value of 15 (got {nargs})'
assert op and check_maxbits(op, 2), f'op must not exceed value of 3 (got {op})'

return (op << 30) | (nargs << 26) | ctl

Expand Down

0 comments on commit e21dfef

Please sign in to comment.