Search code examples
assemblyarmprocessor

Change ARM Mode to System Mode (CPSR) on ARMv8-A


I am using an ARM Cortex A53 (4-core) processor (ARMv8 architecture) in 32-bit mode. I need to use this instruction to enter system mode:

cpsid if, #0x1F

but this instruction, cps, makes my system crash. On the ARM1176JZF-S (ARMv6 architecture), this exact line worked flawlessly. I looked into it and it seems to have to do with a low privilege level, but svc instruction does not solve the issue as I thought it would. What do I need to do to accomplish system mode in this architecture?

Source for control bits: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344i/ch02s14s08.html

This is where I got CPS info from (in changing system modes): http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0527a/index.html


Solution

  • My code to get out of hyp mode (assume no config.txt on the sd card) for both the pi2 and the pi3:

    mrs r0,cpsr
    bic r0,r0,#0x1F
    orr r0,r0,#0x13
    msr spsr_cxsf,r0
    add r0,pc,#4
    msr ELR_hyp,r0
    eret
    

    Lots of folks at the baremetal forum on the raspberry pi site, and there are variations on this theme. Unlike the good old days you cant just change the cpsr once in HYP mode, but if you look at the eret instruction it accepts a new cpsr as well as branching (takes a new lr to feed to the pc) not really a return but a way to change the cpsr. This is how the baremetal folks I know about are doing it.

    There are of course assuptions required here to make this work and they happen to work with the pi.

    If you have a config.txt then you need to be a little careful, the bootstrap code the GPU places for the arm "sorts" the cores and lets core 0 through as well as putting all of them in HYP mode. (both pi2 and pi3), if you choose to defeat that:

    kernel_old=1
    disable_commandline_tags=1
    

    then it is up to you to sort the cores

        mrs x0,mpidr_el1
        mov x1,#0xC1000000
        bic x1,x0,x1
        cbz x1,zero
    not_zero:
        wfi
        b not_zero
    zero:
    

    so you dont have all four of them running the same code almost in parallel...