Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unicorn 2 regression: ARM mode transition from USR32 to SVC32 is ineffective #1500

Closed
gerph opened this issue Nov 24, 2021 · 2 comments
Closed

Comments

@gerph
Copy link
Contributor

gerph commented Nov 24, 2021

Unicorn 2 is failng to allow the transition from USR32 to SVC32 using direct register access.
No emulated code is involved - the system state does not change. It is as if the unicorn environment is enforcing the emulated environment's restrictions on the CPSR.

Source environment

I built unicorn on the dev branch at sha 558fb9c.
This is after the fix for #1494 (which relates to corruption of banked registers on a mode change).
This has been tested on OSX system on Intel hardware (10.14.6)

Failure mode

The failures appears to be that once you are in USR32, an unprivileged, you are unable programatically to enter a privileged mode. This is necessary for a number of reasons, not least of which is providing entry to SVC32 when a SWI call is made, or IRQ32 when an interrupt is being forced.

What are we testing?

We want to set up the state of the system, and observe that we can freely change moves.

Sequence of tests

  1. Set up SVC32 mode
    • CPSR = 0x40000093 (SVC32)
    • sp_svc = 0x12345678
    • Dump the registers (they look fine)
  2. Set up UND32 mode
    • CPSR = 0x4000009b (UND32)
    • SPSR = 0x40000093 (SVC32)
    • sp_und = 0xDEAD0000
    • Dump the registers (they look fine)
  3. Set up USR32 mode
    • CPSR = 0x40000090 (USR32)
    • sp_usr = 0x0010000
    • Dump the registers (they look fine)
  4. Reenter SVC32 mode
    • CPSR = 0x40000093 (SVC32)
    • Dump the registers (the mode has not changed - we're still in USR32 with USR32 registers)

What is the problem?

The emulation environment should be able to be manipulated in ways that would not be allowed for the emulated system. This allows the operating system to initialise its state and begin execution of code. At present it is unable to execute any system calls because once in USR32 we can never get out.

Test code

Test code which exhibits this problem:

#!/usr/bin/env python
# Sample code for ARM of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>

import sys
from unicorn import *
from unicorn.arm_const import *

reg_map = [
        UC_ARM_REG_R0,
        UC_ARM_REG_R1,
        UC_ARM_REG_R2,
        UC_ARM_REG_R3,
        UC_ARM_REG_R4,
        UC_ARM_REG_R5,
        UC_ARM_REG_R6,
        UC_ARM_REG_R7,
        UC_ARM_REG_R8,
        UC_ARM_REG_R9,
        UC_ARM_REG_R10,
        UC_ARM_REG_R11,
        UC_ARM_REG_R12,
        UC_ARM_REG_SP,
        UC_ARM_REG_LR,
        UC_ARM_REG_PC,
    ]
arm_names = [
        'r0', 'r1', 'r2', 'r3',
        'r4', 'r5', 'r6', 'r7',
        'r8', 'r9', 'r10', 'r11',
        'r12', 'sp', 'lr', 'pc'
    ]


def dump_registers(uc):
    print("Registers: ")
    for rn in range(0, 16):
        value = uc.reg_read(reg_map[rn])
        sys.stdout.write("  %3s : 0x%08x" % (arm_names[rn], value))
        if rn % 4 == 3:
            sys.stdout.write("\n")
    print("  CPSR = 0x{:08x}".format(uc.reg_read(UC_ARM_REG_CPSR)))
    print("  SPSR = 0x{:08x}".format(uc.reg_read(UC_ARM_REG_SPSR)))


# Test ARM
def test_arm():
    print("Testing under Unicorn : {!r}".format(uc_version()))
    print("Header version: {!r}".format((UC_VERSION_MAJOR, UC_VERSION_MINOR, UC_VERSION_EXTRA)))

    print("Changing ARM modes")
    try:
        # Initialize emulator in ARM mode
        mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)

        # initialize machine registers in different modes
        mu.reg_write(UC_ARM_REG_CPSR, 0x40000093)   # Current mode = SVC32 mode
        mu.reg_write(UC_ARM_REG_R13, 0x12345678)    # SVC stack value
        print("--- Should be in SVC32, with R13 = 0x12345678")
        dump_registers(mu)

        mu.reg_write(UC_ARM_REG_CPSR, 0x4000009b)   # Current mode = UND32 mode
        mu.reg_write(UC_ARM_REG_SPSR, 0x40000093)   # Saved mode = SVC32 mode
        mu.reg_write(UC_ARM_REG_R13, 0xDEAD0000)    # UND stack value
        print("--- Should be in UND32, with R13 = 0xDEAD0000")
        dump_registers(mu)

        mu.reg_write(UC_ARM_REG_CPSR, 0x40000090)   # Current mode = USR32 mode
        mu.reg_write(UC_ARM_REG_R13, 0x0010000)     # USR stack value
        print("--- Should be in UND32, with R13 = 0x00010000")
        dump_registers(mu)

        mu.reg_write(UC_ARM_REG_CPSR, 0x40000093)   # Current mode = SVC32 mode
        print("--- Should be in SVC32, with R13 = 0x12345678")
        dump_registers(mu)

    except UcError as e:
        print("ERROR: %s" % e)


if __name__ == '__main__':
    test_arm()

Failing output (Unicorn 2)

This produces the following output on Unicorn 2 (failing output):

Testing under Unicorn : (2, 0, 262656L)
Header version: (2, 0, 0)
Changing ARM modes
--- Should be in SVC32, with R13 = 0x12345678
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0x12345678   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x40000093
  SPSR = 0x00000000
--- Should be in UND32, with R13 = 0xDEAD0000
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0xdead0000   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x4000009b
  SPSR = 0x40000093
--- Should be in UND32, with R13 = 0x00010000
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0x00010000   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x40000090
  SPSR = 0x00000000
--- Should be in SVC32, with R13 = 0x12345678
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0x00010000   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x40000090
  SPSR = 0x00000000

The final register dump should have sp = 0x12345678, and CPSR = 0x40000093

Successful output (Unicorn 1)

Testing under Unicorn : (1, 0, 256L)
Header version: (1, 0, 2)
Changing ARM modes
--- Should be in SVC32, with R13 = 0x12345678
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0x12345678   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x40000093
  SPSR = 0x00000000
--- Should be in UND32, with R13 = 0xDEAD0000
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0xdead0000   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x4000009b
  SPSR = 0x40000093
--- Should be in UND32, with R13 = 0x00010000
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0x00010000   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x40000090
  SPSR = 0x00000000
--- Should be in SVC32, with R13 = 0x12345678
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0x12345678   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x40000093
  SPSR = 0x00000000
@wtdcode
Copy link
Member

wtdcode commented Nov 25, 2021

Thanks for detailed report and I would have a look ASAP.

wtdcode added a commit that referenced this issue Dec 23, 2021
@wtdcode
Copy link
Member

wtdcode commented Dec 23, 2021

Fixed in 4f73d75

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants