天天看點

UCOS-II移植ARM的讀書筆記(12.20)續

  之前剛開始的時候是直接看移植代碼,後來看到後面實在看不下去了,轉過頭回去看了一個星期的核心結構,以前也看過一遍核心結構,但是有點暈暈的,現在重新看了一次清楚多了,相信回過頭來看移植部分也應該更清楚了。 現在先來掌握一下關于軟體中斷swi的内容,這是我比較發暈的源泉   軟中斷: 中斷不傳回形式:void _swi(swi_num)  swi_name(arguments) 傳回一個結果到R0中  int _swi(swi_num)  swi_name(arguments);最多可以傳回四個結果R0-R3到一個結構struct type{ int a,b,c,d}中 type(傳回類型) _value_in_regs(傳回多個結果的修飾符) _swi(swi_num) swi_name(arguments);   在ARM中實作軟中斷的方法我在blog裡面搜了很多文章也沒有看到講的通俗一點的,還是自己看ARM的移植代碼吧 首先定義了一堆軟中斷的中斷号,其中0和1的中斷服務子程式是用彙編編寫的,其他的都是在c語言編寫的中斷服務子程式SWI_Exception中。 __swi(0x00) void OS_TASK_SW(void);             

__swi(0x01) void _OSStartHighRdy(void);        

__swi(0x02) void OS_ENTER_CRITICAL(void);      

__swi(0x03) void OS_EXIT_CRITICAL(void);        __swi(0x40) void *GetOSFunctionAddr(int Index);

__swi(0x41) void *GetUsrFunctionAddr(int Index);

__swi(0x42) void OSISRBegin(void);             

__swi(0x43) int  OSISRNeedSwap(void);           __swi(0x80) void ChangeToSYSMode(void);        

__swi(0x81) void ChangeToUSRMode(void);        

__swi(0x82) void TaskIsARM(INT8U prio);        

__swi(0x83) void TaskIsTHUMB(INT8U prio);      

比如在程式運作到調用OS_TASK_SW(void)函數時,就産生軟體中斷,然後就進入中斷服務子程式,按照什麼指令走呢?恩,就按照下面這個代碼,這個代碼是将軟體中斷異常處理程式挂接到核心的作用的,是在啟動代碼中實作的: LDR   PC,SWI_Addr   SWI_Addr   DCD     SoftwareInterrupt 是以當産生軟中斷之後PC就跳到了SoftwareInterrupt,這時就算真正進入了軟體異常中斷處理部分了,然後就是執行下面的彙編代碼 SoftwareInterrupt

        LDR     SP, StackSvc            ; 重新設定堆棧指針

        STMFD   SP!, {R0-R3, R12, LR}

        MOV     R1, SP                  ; R1指向參數存儲位置         MRS     R3, SPSR

        TST     R3, #T_bit              ; 中斷前是否是Thumb狀态,判斷SPSR的T位是不是為零         LDRNEH  R0, [LR,#-2]            ; 不為零即THUMB指令集: 取得Thumb狀态SWI号

        BICNE   R0, R0, #0xff00          ;在THUMB指令集中軟中斷功能号為8位,是以取低八位即為功能号

        LDREQ   R0, [LR,#-4]            ; 為零即ARM指令集: 取得arm狀态SWI号

        BICEQ   R0, R0, #0xFF000000         ;在ARM指令集中軟中斷功能号為24位,是以取低6位即為功能号

                                        ; r0 = SWI号,R1指向參數存儲位置

        CMP     R0, #1

        LDRLO   PC, =OSIntCtxSw      ;功能号為0到OSIntCtxSw執行中斷任務切換函數

        LDREQ   PC, =__OSStartHighRdy   ; SWI 0x01為第一次任務切換         BL      SWI_Exception           ;否則進入c編寫的中斷服務函數

        LDMFD   SP!, {R0-R3, R12, PC}^

StackSvc           DCD     (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4) 怎麼進入c編寫的中斷服務子程式SWI_Exception呢?通過下面的申明 IMPORT  SWI_Exception               ;軟中斷異常處理程式,表示将c程式中的該函數挂接到此段彙編代碼中 同樣的道理 EXPORT  __OSStartHighRdy            

EXPORT  OSIntCtxSw                  ;中斷退出時的入口,參見startup.s中的IRQ_Handler EXPORT  SoftwareInterrupt           ;軟中斷入口 上面的申明是将該段彙編代碼挂接到外面,是以在外部可以直接調用函數名   繼續看OS_CPU_A.S的其他部分代碼,就是兩個軟體異常中斷處理函數OSIntCtxSw和OSStarHighRdy OSIntCtxSw代碼是中斷服務子程式使得更高優先級的任務進入就緒狀态後,中斷傳回後需要切換到該任務時調用的,這是被切換的任務的CPU寄存器的值已經在響應中斷後存入了堆棧中,是以,這裡不需要重複儲存了直接切換任務即可,具體過程看代碼 OSIntCtxSw

                                                    ;下面為儲存任務環境                                                     ;當響應軟體異常中斷後進入了系統模式,在上面的代碼中我們可以看到,進入系統模式時儲存的堆棧結構從頂到底依次是:R0,R1,R2,R3,R12,LR,而在使用者模式中任務的堆棧結構應該是:OsEnterSum,CPSR,RO-12,LR,PC,是以在進行軟體中斷任務切換之前先要儲存原來任務的堆棧結構。

        LDR     R2, [SP, #20]                       ;擷取PC

        LDR     R12, [SP, #16]                      ;擷取R12

        MRS     R0, CPSR         MSR     CPSR_c, #(NoInt | SYS32Mode)

        MOV     R1, LR

        STMFD   SP!, {R1-R2}                        ;儲存LR,PC

        STMFD   SP!, {R4-R12}                       ;儲存R4-R12         MSR     CPSR_c, R0

        LDMFD   SP!, {R4-R7}                        ;擷取R0-R3

        ADD     SP, SP, #8                          ;出棧R12,PC

        MSR     CPSR_c, #(NoInt | SYS32Mode)

        STMFD   SP!, {R4-R7}                        ;儲存R0-R3

        LDR     R1, =OsEnterSum                     ;擷取OsEnterSum

        LDR     R2, [R1]

        STMFD   SP!, {R2, R3}                       ;儲存CPSR,OsEnterSum                                                     ;儲存目前任務堆棧指針到目前任務的TCB

        LDR     R1, =OSTCBCur

        LDR     R1, [R1]

        STR     SP, [R1]         BL      OSTaskSwHook                        ;調用鈎子函數

                                                    ;OSPrioCur <= OSPrioHighRdy

        LDR     R4, =OSPrioCur

        LDR     R5, =OSPrioHighRdy

        LDRB    R6, [R5]

        STRB    R6, [R4]

                                                    ;OSTCBCur <= OSTCBHighRdy

        LDR     R6, =OSTCBHighRdy

        LDR     R6, [R6]

        LDR     R4, =OSTCBCur

        STR     R6, [R4]

OSIntCtxSw_1

                                                    ;擷取新任務堆棧指針

        LDR     R4, [R6]

        ADD     SP, R4, #68                         ;17寄存器CPSR,OsEnterSum,R0-R12,LR,SP

        LDR     LR, [SP, #-8]

        MSR     CPSR_c, #(NoInt | SVC32Mode)        ;進入管理模式

        MOV     SP, R4                              ;設定堆棧指針         LDMFD   SP!, {R4, R5}                       ;CPSR,OsEnterSum

                                                    ;恢複新任務的OsEnterSum

        LDR     R3, =OsEnterSum

        STR     R4, [R3]

        MSR     SPSR_cxsf, R5                       ;恢複CPSR

        LDMFD   SP!, {R0-R12, LR, PC }^             ;運作新任務