How Can I put ARM processor in different modes using C program?

后端 未结 2 1041
误落风尘
误落风尘 2021-01-03 15:23

I am going through different mode of ARM processor. I want to check the processor state(ex: register values) while it is in different mode.

So can someone help me to

2条回答
  •  傲寒
    傲寒 (楼主)
    2021-01-03 15:49

    If you wish to test the modes from user space, this is a difficult question. There maybe no way to go to FIQ mode, if there is no FIQ peripheral in the system. Your system may not be using Monitor mode at all, etc. To get to abort mode, you can use an invalid pointer, or use mmap. However, to answer all mode switches from user space would be book like (or impossible) without assistance from the kernel. Creating a test module with a /proc or /sys file and using the techniques below to implement the kernel code would be the most straight forward method.

    You should be aware that not all mode switch transitions are allowed. For instance, you may never switch from user mode to any other mode except through the exception mechanisms. Another issue is that each ARM mode has banked registers. One of these is the very important sp (or stack pointer) and lr (or link register) that is fundamental to 'C' code.

    It is generally more safe to use a macro of in-line assembler to bound your test snippets, than to use function calls. The test code must not call external routines. This can be difficult as using floating point, etc may result in the compiler inserting hidden sub-routine calls. You should inspect the generated assembler and provide comments for others.

     /* Get the current mode for restoration. */
     static inline unsigned int get_cpsr(void)
     {
         unsigned int rval;
         asm (" mrs %0, cpsr\n" : "=r" (rval));
         return rval;
     }
    

    You can put this in a header file. The compiler will inline the code so, you will just get the msr instruction placed within a routine.

    To change the mode use a define like,

     /* Change the mode */
     #define change_mode(mode) asm("cps %0" : : "I"(mode))
    

    Tangr's has the correct mode defines,

    #define MODE_USR        0x10   /* Never use this one, as there is no way back! */
    #define MODE_FIQ        0x11   /* banked r8-r14 */
    #define MODE_IRQ        0x12
    #define MODE_SVC        0x13
    #define MODE_MON        0x16
    #define MODE_ABT        0x17
    #define MODE_UND        0x1B
    #define MODE_SYS        0x1F   /* Same as user... */
    

    You also need to restore the previous mode,

    #define restore_mode(mode) \
         mode &= 0x1f; \
         asm(" msr cpsr, %0\n" : : "r"(mode) : "cc")
    

    Put this together as follows,

      void test_abort(void)
      {
         unsigned int old_mode = get_cpsr() & 0x1f;
         change_mode(MODE_ABT);
         /* Your test code here... must not call functions. */
         restore_mode(old_mode);
      }
    

    This answers your question directly. However, due to all of the difficulties, it is often easier to write assembler to achieve a test. I believe you were trying to leverage the existing Linux code to test all the modes. This is not an ARM-Linux design goal and without modifying the source, it will be very difficult to achieve and highly system specific if it is.

提交回复
热议问题