Abstract
UC/OS2 是即時系統核心,跟其它微型作業系統一樣,它沒有shell, file system, network stack…等,所以對porting來說,改動的幅度不大
原始碼可在此網頁查看
在porting的過程中只需改動5個檔案,分別是
1.OS_CPU_A.s:增加4個函式的實作(OSStartHighRdy, OSIntCtxSw, OSCtxSw, OS_CPU_SR_Save, OS_CPU_SR_Restore)
2.OS_CPU_C.c:實做process stack的存放方式,和critical section進入和離開的函式
3.OS_CPU.H:宣告相關cpu-specified的變數
4.Vector.s:實做IRQ中斷時的uc/os context switch
5.timer.c:呼叫OS的計時函式
OS_CPU.H
宣告以ARM cpu資料型太為基準的OS相關的變數
typedef unsigned char BOOLEAN;
typedef unsigned char INT8U;
typedef signed char INT8S;
typedef unsigned short INT16U;
typedef signed short INT16S;
typedef unsigned int INT32U;
typedef signed int INT32S;
typedef float FP32;
typedef double FP64;
typedef INT32U OS_STK;
OS_CPU_C .c
1. 設置Process Stack(function name:OSTaskStkInit)
根據uc/os2的文件,當我們用OSTaskCreateExt去建立process時,會需要宣告這個process所需要用到的stack address,而uc/os2做context switch時,會根據stack內所存的內容而決定context switch時所需替換的暫存器和PC.uc/os2運作在ARM SVC模式,所以我們要存R0-R14,PC,和SPSR這些暫存器的值
在OSTaskStkInit內可看到程式碼如下
OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
{
INT32U *stk;
stk = (INT32U*)ptos;
*stk-- = (INT32U)task;
*stk-- = (INT32U)0x14141414; //R14(LR)
*stk-- = (INT32U)0x12121212; //R12
*stk-- = (INT32U)0x11111111; //R11
*stk-- = (INT32U)0x10101010; //R10
*stk-- = (INT32U)0x09090909; //R9
*stk-- = (INT32U)0x08080808; //R8
*stk-- = (INT32U)0x07070707; //R7
*stk-- = (INT32U)0x06060606; //R6
*stk-- = (INT32U)0x05050505; //R5
*stk-- = (INT32U)0x04040404; //R4
*stk-- = (INT32U)0x03030303; //R3
*stk-- = (INT32U)0x02020202; //R2
*stk-- = (INT32U)0x01010101; //R1
*stk-- = (INT32U)(pdata); //R0
*stk = (INT32U)0x13; //SPSR(SVC MODE)
return ((OS_STK *)stk);
}
2.Critical section的進入與離開(OS_ENTER_CRITICAL and OS_EXIT_CRITICAL)
這個函式目的在保存CPU切換模式時的CPSR暫存器的值
OS_CPU_A .s
1. OSStartHighRdy
此函式是uc/os2執行時呼叫的第一個函式,它會尋找最高優先權的process並執行它
; OSRunning = TRUE
LDR R0, =OSRunning //程式執行變數
MOV R1, #1
STRB R1, [R0]
; Load First Task//把第一個high ready process拿來執行
LDR R0, OSTCBHighRdy ; Load address of OSTCBHighRdy
LDR SP, [R0] ; Load SP of task
//開始還原最高優先權process的執行環境
LDMFD SP!, {R1} ; get spsr of first task
MSR SPSR_cxsf, R1
LDMFD SP!, {R0-R12, LR, PC}^ ;run first task!
OSCtxSw
STMFD SP!, {LR} ; save context of previous task
STMFD SP!, {LR}
STMFD SP!, {R0-R12}
MRS R4, CPSR//保存CPSR
STMFD SP!, {R4}
LDR R4, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP;
LDR R5, [R4]
STR SP, [R5]
LDR R4, =OSPrioCur ; OSPrioCur = OSPrioHighRdy
LDR R6, =OSPrioHighRdy
LDRB R6, [R6]
STRB R6, [R4]
LDR R4, =OSTCBCur ; OSTCBCur = OSTCBHighRdy
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
STR R6, [R4]
LDR SP, [R6] ; SP = OSTCBCur->OSTCBStkPtr
LDMFD SP!, {R4}
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task's context
2. OSCtxSw
此函式是在OS_Sched函式內呼叫,uc/os2執行context switch的時間點有兩個
(1)當函式執行OSTimeDly函式時
(2)當CPU碰到中斷時
而OSCtxSw是當第一個情況發生時(當函式執行OSTimeDly函式時)會呼叫的函式,所以,假設我們目前有兩個process分別是PA和PB,當PA執行到OSTimeDly,CPU會保存PA目前執行環境的所有暫存器並從process queue裡面拿出最高優先權的process,也就是PB,取得PB的TCB(task control buffer),並從PB的TCB內取得它的stack,然後根據PB stack的內容,逐一還原PB的執行環境
3. OSIntCtxSw
OSIntCtxSw這個函式是當第二個情況發生時(當CPU碰到中斷時)會呼叫的函式,當中斷執行完畢時,CPU會執行這個context switch函式,因為前一個執行的process已經在IRQ中斷周期發生前保存了自己的執行環境,所以這個函式只要選擇最高優先權的PROCESS並執行它就可以了
OSIntCtxSw
LDR R4, =OSPrioCur ; OSPrioCur = OSPrioHighRdy
LDR R5, =OSPrioHighRdy
LDRB R6, [R5]
STRB R6, [R4]
LDR R4, =OSTCBCur ; OSTCBCur = OSTCBHighRdy
LDR R5, =OSTCBHighRdy
LDR R6, [R5]
STR R6, [R4]
LDR SP, [R6] ; SP = OSTCBCur->OSTCBStkPtr
LDMFD SP!, {R4}
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task's context
vector.s
1. IRQ_Handler
因為已經切換到IRQ模式,所以我們暫存器的LR,CPSR都已經改變了,當ARM切換IRQ中斷時,會把上一個模式的CPSR存在SPSR,所以我們所要做的動作如下
(1)計算LR和保存LR和SPSR
STMFD SP!, {R0-R2}
MOV R1, SP
ADD SP, SP, #12//把IRQ SP的指標還原,我們只是暫時借用
SUB R2, LR, #4
MRS R0, SPSR
(2)切換還SVC模式並保存PROCESS CONTEXT
MSR CPSR_c, #Mode_SVC | I_BIT | F_BIT
STMFD SP!, {R2} ; PC
STMFD SP!, {LR} ; LR
STMFD SP!, {R3-R12} ; R3-R12
LDMFD R1, {R4-R6} ; get R1-R3 from IRQ's stack
STMFD SP!, {R4-R6} ; push task's R1-R3
STMFD SP!, {R0} ; push task's spsr
(3)呼叫OSIntEnter,切換回IRQ模式,並執行IRQ routine,再切回SVC模式然後再呼叫OSIntExit,並還原上一個PROCESS的執行環境
BL OSIntEnter
; switch to interrupt mode
MSR CPSR_c, #Mode_IRQ | I_BIT | F_BIT ; change to IRQ mode and disable IRQ,FIQ
BL ISR_IRQ
;restore task after interrupt routine is finished
MSR CPSR_c, #Mode_SVC | I_BIT | F_BIT ; change to SVC mdoe
BL OSIntExit
LDMFD SP!, {R4}
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task's context
timer.c
1. Timer0_ISR
在timer ISR內執行系統計時函式OSTimeTick()
void Timer0_ISR(void)
{
OSTimeTick();
}
留言