This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How to switch TMS570LS20216 from user mode into privilege mode?

Other Parts Discussed in Thread: TMS570LS2125

We didn't find description on how to switch from user mode into privilege mode inTMS 570 datasheet(Literature Number: SPNU489C)

TI Chinese techenical supporting engineer can only suggest we to find reference into ARM core documents.

We hope to get direct answer because project time pressure.

And the example soure code or API is much appreciated!

thanks a lot!

  • Yi,

    this is a pure ARM related topic, e.g. for the Cortex-R4 architecture.

    To switch (back) to a privilege mode you need to do a SuperVisor Call (SVC); the SVC was formerly named SWI.

    You can use the SVC instruction

       SVC<c> #<imm8>

       or

       SVC<c> #<imm24>

    as a call to an operating system to provide a service.

    By executing the SVC the CPU gets into a privilege mode; then you need to do the tasks you want to do in privilege mode within the SVC handler you need to write code for. At the end you need to return from the SVC exception.

    More details can be found in the "The System Level Programmers’ Model" chapter for the Supervisor Call (SVC) exception (ch B1.6.12) of the

    ARM® Architecture Reference Manual
    ARM®v7-A and ARM®v7-R edition
    ARM Lit number: DDI0406

    Kind Regards,

       Rainer

     

     

  • As Rainer said, Once you get to SWI or SVC interrupt service routine, you can modify the mode bits of SPSR by using MCR and MRC instructions. After return from SWI/SVC, SPSR in SWI/SVC will become the current CPSR.

    Regards,

    Haixiao

  • ALL CONTENT AND MATERIALS OF THIS POST ARE PROVIDED "AS IS". TI AND ITS RESPECTIVE SUPPLIERS MAKE NO REPRESENTATIONS ABOUT THE SUITABILITY OF THESE MATERIALS FOR ANY PURPOSE AND DISCLAIM ALL WARRANTIES AND CONDITIONS WITH REGARD TO THESE MATERIALS, INCLUDING BUT NOT LIMITED TO, ALL IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT OF ANY THIRD PARTY INTELLECTUAL PROPERTY RIGHT. NO LICENSE, EITHER EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, IS GRANTED BY TI.

    Some examples:

    1. In the intvecs.asm:

         .sect  ".intvecs"

           b _c_int00              ;  RESET INTERRUPT
           b #-8                   ;  UNDEFINED INSTRUCTION INTERRUPT
           b _ISR_SWI              ;  SOFTWARE INTERRUPT

    Depends on the EABI or TI ABI you chose, the '_' in front of ISR_SWI might not need.

    2. SWI.C

    /* - private - SWI INTERFACE ---------------------------------------------- */

    #pragma SWI_ALIAS(WRITE_SVC,    0)
    #pragma SWI_ALIAS(INT_SET_SYSTEM,     7)
    #pragma SWI_ALIAS(INT_SET_USER,    8)

    #define Int_SetSystem     INT_SET_SYSTEM()
    #define Int_SetUser       INT_SET_USER()

    /* definitions */
    void WRITE_SVC(unsigned int *address, unsigned int data);
    void INT_SET_SYSTEM();
    void INT_SET_USER();

    #pragma INTERRUPT(ISR_SWI, SWI)


    /*--------------------------------------------------------------------------*/
    /* NOTE: this must be compiled with -o2 and can't have more than three      */
    /*   parameters                                                      */

     

    void ISR_SWI(unsigned r0, unsigned r1, unsigned r2, unsigned r3)
    {
      asm(" ldrb  r3, [lr, #-1]");

      switch (r3)
      {
      case 0:
        /* WRITE_REGISTER_SVC */
        *(unsigned int *)r0 = r1;
        return;

       case 7:
        /* set system mode */
        asm(" mrs   r0, spsr");       // Get copy of Program Status Register
        asm(" bic   r0, r0, #0x1f");  // Clear mode bits
        asm(" orr   r0, r0, #0x1f");  // Set System Mode
        asm(" msr   spsr, r0");       // Write back modified SPSR
        return;
       
      case 8:
        /* set user mode */
        asm(" mrs   r0, spsr");       // Get copy of Program Status Register
        asm(" bic   r0, r0, #0x1f");  // Clear mode bits
        asm(" orr   r0, r0, #0x10");  // Set User Mode
        asm(" msr   spsr, r0");       // Write back modified SPSR
        return;
     
      }
    }

    3. After that, whenever you want to enter system mode:

    call:

    Int_SetSystem;

     

  • Haixiao,

    I am hoping that you can answer a few questions about the use of the software interrupts as you describe above and also I have a problem using this method on my TMS570 processor (TMS570LS2125).

    Firstly, can you post an example of more than 1 parameter being passed to the SWI? Does the first parameter end up at [lr, #-1] and the second at [lr, #-2] where you have to load the register or local variable (I am not sure which is actually used in the asm). I am not finding any reference to how to receive the parameters in the C code other than the example that you posted here in the forum.

    When I attempt to code my SWI as you have above, I noticed in your comment that the -o2 compiler option is required for the above code to work. If I do not use the -o2, the r3 register is properly loaded with the argument but the compiler seems to separate the meaning of the r3 register and the r3 local variable.

    So if the following line executes:

    asm(" ldrb  r3, [lr, #-1]");

    After this statement executes, register r3 holds the argument for the SWI but the debugger shows a different value for the local variable r3. Can you tell me why this -o2 makes the interpretation of the variables differently based on a C compiler optimization switch?

    My problem is that even with the -o2 switched used, and the R3 register and R3 local variable containing consistent values, the switch (r3) is not properly evaluating resulting in none of the cases being executed. Can you tell me what might be wrong?

    Does the processor mode set in the Current Processor Status Register (CPSR) affect the execution of the above code? Are there any other compiler switches or processor states / modes that must be set prior to the SWI being invoked?

    I have attempted to use the cgtools v4.6.3 and the latest v4.9.1 and both tests were the same, un-successful.

    Below is the dis-assembly of my code. The bold always executes and the correct case statement is not followed even though the register R3 and the local variable R3 match.

    Entry:
    0x00011594:   E92D5000 STMFD           R13!, {R12, R14}
    0x00011598:   EEF1CA10 FMXR            R12, FPSCR
    0x0001159C:   E92D1000 STMFD           R13!, {R12}
    0x000115A0:   EEF8CA10 FMXR            R12, FPEXC
    0x000115A4:   E92D1000 STMFD           R13!, {R12}
    0x000115A8:   E24DD010 SUB             R13, R13, #16
    0x000115AC:   E58D0000 STR             R0, [R13]
    0x000115B0:   E58D1004 STR             R1, [R13, #4]
    0x000115B4:   E58D2008 STR             R2, [R13, #8]
    0x000115B8:   E58D300C STR             R3, [R13, #12]
    0x000115BC:   E55E3001 LDRB            R3, [R14, #--1]
    0x000115C0:   E59DC00C LDR             R12, [R13, #12]
    0x000115C4:   E24CC001 SUB             R12, R12, #1
    0x000115C8:   E35C0008 CMP             R12, #8
    0x000115CC:   8A00002F BHI             $C$L16
    0x000115D0:   E28F0000 ADD             R0, PC, #0
    0x000115D4:   E790F10C LDR             PC, [R0, R12, LSL #2]
                $C$SW1, $C$C120:
    0x000115D8:   00011684 ANDEQ           R1, R1, R4, LSL #13
    0x000115DC:   00011674 ANDEQ           R1, R1, R4, ROR R6
    0x000115E0:   00011664 ANDEQ           R1, R1, R4, ROR #12
    0x000115E4:   00011654 ANDEQ           R1, R1, R4, ASR R6
    0x000115E8:   00011644 ANDEQ           R1, R1, R4, ASR #12
    0x000115EC:   00011634 ANDEQ           R1, R1, R4, LSR R6
    0x000115F0:   00011620 ANDEQ           R1, R1, R0, LSR #12
    0x000115F4:   00011610 ANDEQ           R1, R1, R0, LSL R6
    0x000115F8:   000115FC STREQD          R1, [R1], -R12
                $C$L7:
    0x000115FC:   E14F1000 MRS             R1, SPSR
    0x00011600:   E3C1100F BIC             R1, R1, #15
    0x00011604:   E381101F ORR             R1, R1, #31
    0x00011608:   E169F001 MSR             SPSR_cf, R1
    0x0001160C:   EA00001F B               $C$L16
                $C$L8:
    0x00011610:   E14F1000 MRS             R1, SPSR
    0x00011614:   E3C1100F BIC             R1, R1, #15
    0x00011618:   E169F001 MSR             SPSR_cf, R1
    0x0001161C:   EA00001B B               $C$L16
                $C$L9:
    0x00011620:   E14F1000 MRS             R1, SPSR
    0x00011624:   E3C1100F BIC             R1, R1, #15
    0x00011628:   E3811003 ORR             R1, R1, #3
    0x0001162C:   E169F001 MSR             SPSR_cf, R1
    0x00011630:   EA000016 B               $C$L16
                $C$L10:
    0x00011634:   E14F1000 MRS             R1, SPSR
    0x00011638:   E3C110C0 BIC             R1, R1, #192
    0x0001163C:   E169F001 MSR             SPSR_cf, R1
    0x00011640:   EA000012 B               $C$L16
                $C$L11:
    0x00011644:   E14F1000 MRS             R1, SPSR
    0x00011648:   E3C11040 BIC             R1, R1, #64
    0x0001164C:   E169F001 MSR             SPSR_cf, R1
    0x00011650:   EA00000E B               $C$L16
                $C$L12:
    0x00011654:   E14F1000 MRS             R1, SPSR
    0x00011658:   E3C11080 BIC             R1, R1, #128
    0x0001165C:   E169F001 MSR             SPSR_cf, R1
    0x00011660:   EA00000A B               $C$L16
                $C$L13:
    0x00011664:   E14F1000 MRS             R1, SPSR
    0x00011668:   E38110C0 ORR             R1, R1, #192
    0x0001166C:   E169F001 MSR             SPSR_cf, R1
    0x00011670:   EA000006 B               $C$L16
                $C$L14:
    0x00011674:   E14F1000 MRS             R1, SPSR
    0x00011678:   E3811040 ORR             R1, R1, #64
    0x0001167C:   E169F001 MSR             SPSR_cf, R1
    0x00011680:   EA000002 B               $C$L16
                $C$L15:
    0x00011684:   E14F1000 MRS             R1, SPSR
    0x00011688:   E3811080 ORR             R1, R1, #128
    0x0001168C:   E169F001 MSR             SPSR_cf, R1
                $C$L16:
    0x00011690:   E28DD010 ADD             R13, R13, #16
    0x00011694:   E8BD1000 LDMFD           R13!, {R12}
    0x00011698:   E8BD1000 LDMFD           R13!, {R12}
    0x0001169C:   E8FD9000 LDMFD           R13!, {R12, PC}^


  • When a c function is called, the CCS compiler will pass the parameters through R0-R3 and stack. The example forces the variable name as the same as the register name for easier use and comparision  between asm and c function. For some reason, with optimization, this processure don't work well.

    The example is cut-paste from a complicated function. If you only want to switch the user mode, the code can be much simpler.  Actually, by doing in following way, since it is all written in asm code, it avoid lots of potential problems.

    Suppose you call a SWI like:

    SWI #7;

    Then the CPU will jump into the SWI service routine, assume it is _SVC:

     

    _svc:    STMFD   sp!, {r0-r12,lr}     ; Save registers on stack
                  LDR   r4, [lr,#-4]         ; Load the SVC inst into R0
                  BIC    r4, r4, #0xFF000000  ; Mask out SVC number
                  ;At this point, you get the #7 in R4 and can configure the SPSR according  to the #7 you received.
                  ;Also, you can use register R0-R3 to pass parameters, and use R0-R3 at this point.
                  LDMFD   sp!, {r0-r12,pc}^    ; Restore registers and return
     
    If you prefer to write it in C: take a look at Page 99 of
    it tells you how to pass the parameters and define SWI.
     
    Regards,
    Haixiao
  • Haixiao,

    Thank you for the reply. I am a bit confused when you say that "with optimization, this procedure don't work well". In the comment, in your example, it mentions that the -o2 option must be used. -o2 will optimize register use globally. This suggests that unless you optimize the procedure does not work. That is what I am seeing when not using -o2, the register and local variable are treated separately and not as one.

    Looking at page 99 of the ARM Optimizing C/++ Compiler, SPNU151G, I am not seeing any details. Looking at your initial example, it is necessary to break in to assembler so that the parameter is loaded in to one of the registers:

    void ISR_SWI(unsigned r0, unsigned r1, unsigned r2, unsigned r3)
    {
      asm(" ldrb  r3, [lr, #-1]");

      switch (r3)

    ...

    I do not see this anywhere in the compiler documentation. Can you please explain where this process is documented? Are you referencing some other source code or document?

    As I mentioned, with or without the -o2 option, there is something wrong with the execution of the switch statement. In the debugger, even when I have a match between what the debugger thinks is the local and the register r3, the switch statement is not executing the proper case statement based on the value of r3. So if I have an r3 value of 4, the case 4: statement is not being executed. The code jumps to the function exit.

    I did find another reference in the forum that suggests that the SWI should not be used at all with the v7R architecture (Cortex-R4(f)).

    http://e2e.ti.com/support/microcontrollers/hercules/f/312/t/58964.aspx#213638

    The legacy code that I am working with is written in C as does more than manipulating the SPSR. Since the code is not properly executing the switch statement, that does not matter much as I am unable to process any of my case statements.

    Can you please advise? A working example with the TMS570LS2125 written in C would be greatly appreciated.

    Thank you.

  • '-O2' is the default setting if I remember correctly.

    I treat the SVC as a rename as the previous SWI. There should be no change in your code.

    I am also confused by what the compiler. In your post, the compiler did not check the value of the 3rd parameter using register r3, it goes through the stack. I don't know why.

    The code I published was validated on ccs3.3 and another R4 MCU. I will check how it works with the most recent cgtools.

    Regards,

    Haixiao 

  • In the recent cgtools, the compiler push the R0-R3 (parameters transfered to the sub-routine) to stack, and then load the variable from the stack

    Compiler saved R0-R3 into stack

    asm (" ldrb r3, [lr, #-1]");

    Compiler load from stack to get the value of R3.

    By doing this, the asm (" ldrb r3, [lr, #-1]") does not impact he variable at all; This is the rootcause.

    As a workaround, you can force the variables to be register variables like:

    void ISR_SWI(register unsigned r0, register unsigned r1, register unsigned r2, register unsigned r3)

    Regards,

    Haixiao

  • Haixiao,

    I think that I have discovered the problem over here. Unless -O2 is explicitly specified as an option on the command line, the code does not work. When it is added to the command line, the SWI handler performs as expected. So even though -O2 is supposed to be a default, some option is changing that allows the code to execute correctly.

    It seems that this -O2 requirement should be clearly stated where the SWI handlers are concerned!

    Thank you.

  • Hello Hai Xiao:
    Is it true only in SWI handler can I switch the CPU mode?
    I added following code in common function and execute it under use mode:
       asm(" mov r0, #1");
       asm(" mrs   r0, spsr");
       asm(" bic   r0, r0, #0x1f");
       asm(" orr   r0, r0, #0x1f");
       asm(" msr   cpsr, r0");
     
    I found Mode bits of CPSR changed from 0x13 to 0x1F.
    I also tried to add the above codes into SWI ISR. The effect of executing these code in SWI_ISR is the same as executed in common function.
    I don't know if my understanding is correct:
    If Mode bits of CPSR is 0x1F, CPU is in system mode. please confirm?
     
    And maybe there is a error in your reply ?
    asm(" msr   spsr, r0");       // Write back modified SPSR
    I tried and found it has no effect to CPSR register.
    If I change it to asm(" msr   cpsr, r0"); Mode bits in CPSR is changed.
  • Yi,

    It is not possible to write to the CPSR mode bit (0 to 4) if the CPU is in user mode. (Non privilege)

    The use of SVC (SWI) is to gain privilege and than be able to access the CPSR.

    Let me comment the following code.


    1   asm(" mrs   r0, spsr");
    2   asm(" bic   r0, r0, #0x1f");
    3   asm(" orr   r0, r0, #0x1f");
    4   asm(" msr   spsr, r0");

    Once the SVC instruction is executed, the CPU will jump in the SVC handler, and automatically save the current CPSR to the SPSR_SVC, CPSR mode bits are change to 0x13 for Supervisor and the return address is save in R14_SVC.

    Line 1 will read the SPSR_SVC in R0.
    Line 2 and 3 will change the content of R0 to set the bit 0 to 4 (Mode bit, in this case system)
    Line 4 will write back R0 in SPSR_SVC. At that point, the CPU is still in Supervisor mode, in the SVC handler.

    According to ARM documentation, the return method for a SVC handler is:

      MOVS PC,R14_SVC

    This will restore the SPSR_SVC in CPSR (Because of the S in the MOVS) and load the PC with the R14_SVC.
    The code is back to the instruction after the SVC instruction.

    In your case, you have changed the line 4 to:

    4   asm(" msr   cpsr, r0");

    After execution of line 4, the CPU is now in SYSTEM mode, but you are still in your SVC handler.
    To go back to your main code you will have to execute:
      MOV PC,R14_SVC
    This time there is no S to the mov instruction.

    Please let me know if this clarify your question.


  • I was search for some examples for using the STC and saw you response and wondered if you could point me to a useful example.

    Mike.