/###################################################################
任務(wù)目標(biāo) :通過(guò)定時(shí)器產(chǎn)生任務(wù)切換,其中swi來(lái)實(shí)現(xiàn)多個(gè)任務(wù)之間切換
實(shí)驗(yàn)平臺(tái) : 本實(shí)驗(yàn)是基于S3C2440上實(shí)現(xiàn)
/####################################################################
工作原理 :
在運(yùn)行任務(wù)程序的時(shí)候通過(guò)定時(shí)器產(chǎn)生中斷,進(jìn)入任務(wù)優(yōu)先級(jí)調(diào)度课竣,選擇優(yōu)先級(jí)最高的任務(wù)去執(zhí)行;其中各個(gè)任務(wù)之間通過(guò)SWI軟中斷來(lái)實(shí)現(xiàn)相互切換膝晾。
難點(diǎn):在中斷模式和SVC模式下任務(wù)棧信息保存及恢復(fù),同時(shí)在SVC模式下把將要運(yùn)行的任務(wù)棧信息從該任務(wù)棧里恢復(fù)到寄存器中务冕,最后跳轉(zhuǎn)到用戶態(tài)執(zhí)行任務(wù)血当。
基本流程:
實(shí)現(xiàn)步驟:
請(qǐng)參考微內(nèi)核之任務(wù)切換。http://www.reibang.com/p/7792cdc4fd5f
增加與修改部分bug:
主要增加定時(shí)器中斷以及任務(wù)函數(shù)寄存器信息完整保存禀忆,使每次任務(wù)執(zhí)行時(shí)被中斷后能正確恢復(fù)該任務(wù)的信息臊旭,各個(gè)任務(wù)被中斷還能從中斷點(diǎn)繼續(xù)執(zhí)行。
1箩退、IRQ模式下任務(wù)棧信息保存
*IRQ模式中斷處理函數(shù)
/*#####################################################
* IRQ中斷被監(jiān)測(cè)到离熏,則下面行為被執(zhí)行:
* R14_irq = 將被執(zhí)行的下一條指令地址+4;
* SPSR_irq = CPSR
* CPSR[4:0] = 0b10010 ; Enter Supervisor mode
* CPSR[5] = 0 戴涝; Execute in ARM state
* CPSR[6] is unchanged
* CPSR[7] = 1 滋戳;Disable normal interrupts
* CPSR[8] = 1 ; Disable Imprecise Data Aborts (v6 only)
* CPSR[9] = CP15_reg1_EEbit ; Endianness on exception entry
* 執(zhí)行irq處理函數(shù)后返回原程序啥刻,可以使用如下指令:
* SUBS PC,R14,#4 ; SPSR_irq中的值自動(dòng)存儲(chǔ)到CPSR中
#######################################################*/
HandleIRQ:
SUB LR, LR, #4 /* 計(jì)算返回地址,中斷模式LR保存被中斷指令的下一條指令 */
STMDB SP!, { LR } /* 被中斷模式下的指令下一條指令 */
STMDB SP!, { R0-R14}^ /* ^表示保存user模式下R0-R14奸鸯,只針對(duì)usr模式 */
LDR R0,=IRQ_STACK /* 保存irq模式下的SP棧,用于切換到SVC模式下*/
STR SP, [R0] /* 恢復(fù)保存的寄存器值,用于調(diào)試 */
LDR R0, =LR_VAR /* 保存IRQ模式下的LR郑什,用于調(diào)試 */
STR R14, [R0]
LDR R0, =pCurTcb /* 獲取當(dāng)前任務(wù)棧的起始地址 */
LDR R2, [R0]
MRS R0, SPSR
STR R0,[R2],#4 /* SPSR存進(jìn)當(dāng)前任務(wù)棧里 */
STR R0,[R2],#4 /* CPSR存進(jìn)當(dāng)前任務(wù)棧里 */
MOV R1, SP
MOV R3,#16 /* 把IRQ模式下保存寄存器數(shù)量R0-R14 */
/* 把IRQ模式下保存寄存器數(shù)量R0-R15復(fù)制到當(dāng)前任務(wù)棧里 */
IRQ_STACK_COPY:
LDR R0,[R1],#4
STR R0,[R2],#4
SUBS R3,R3,#1
BNE IRQ_STACK_COPY
LDR LR, =int_return /* 設(shè)置調(diào)用ISR即EINT_Handle函數(shù)后的返回地址
LDR PC, =ISR_Handle /* 調(diào)用中斷服務(wù)函數(shù)府喳,在interrupt.c中 */
int_return:
LDMIA SP!, { R0-R14 }^ /* ^表示把中斷模式下SP棧里寄存器恢復(fù)到usr模式下對(duì)應(yīng)的寄存器中 */
LDMIA SP!, { PC }^ /* 中斷返回, ^表示將spsr的值復(fù)制到cpsr */
2、SVC模式下任務(wù)棧信息保存
*SVC模式中斷處理函數(shù)
/******************************************************************************
* SWI中斷進(jìn)入到SVC(超級(jí)用戶模式)蘑拯,當(dāng)SWI被執(zhí)行時(shí)钝满,下面行為被執(zhí)行:
* R14_svc = SWI指令的下一條指令;
* SPSR_svc = CPSR
* CPSR[4:0] = 0b10011 ; Enter Supervisor mode
* CPSR[5] = 0 申窘; Execute in ARM state
* CPSR[6] is unchanged
* CPSR[7] = 1 弯蚜;Disable normal interrupts
* CPSR[8] is unchanged
* CPSR[9] = CP15_reg1_EEbit ; Endianness on exception entry
* 執(zhí)行SWI函數(shù)后返回原程序剃法,可以使用如下指令:
* MOVS PC,R14 ; SPSR_svc中的值自動(dòng)存儲(chǔ)到CPSR中
******************************************************************************/
HandleSWI:
STMDB sp!, {R14} /* svc模式下R14(LR)保存user模式下的下一條指令地址PC; */
LDR R0, =LR_VAR /* 保存SVC模式下的LR碎捺,用于調(diào)試 */
STR R14, [R0]
STMDB sp!, { r0-r14}^ /* ^表示user模式下的R0-R14到SVC模式的SP中,只針對(duì)user模式 */
MRS R0, SPSR /* 不同模式之間切換贷洲,cpsr被保存在SPSR中 */
STMDB sp!, {R0} /* CPSR位置 */
STMDB sp!, {R0} /* SPSR位置 */
LDR R0, =SVC_STACK /* 保存SVC模式下的SP棧收厨,用于恢復(fù)和調(diào)試 */
STR sp, [R0]
/******************************************************************************
* 下面代碼用于監(jiān)測(cè)irq中斷觸發(fā)的SWI中斷,以便跳轉(zhuǎn)到taskSched函數(shù)執(zhí)行最高優(yōu)先級(jí)任務(wù)
******************************************************************************/
sub R0, R14, #4 /* lr -4 為指令SWI XXX的地址,低24位是軟件中斷號(hào) */
nop
ldr R1,[R0,#0] /* lr -4 為指令SWI XXX的地址,低24位是軟件中斷號(hào) */
nop
bic R1,R1,#0XFF000000 /* 取得arm指令的低24位立即數(shù) */
cmp R1,#255 /* 判斷24位立即數(shù)优构,如果是255诵叁,調(diào)用timer0_taskSched函數(shù) */
beq timer0_taskSched
/******************************************************************************
* 把寄存器值保存到當(dāng)前任務(wù)棧里,把SVC模式下保存的當(dāng)前任務(wù)棧信息保存到當(dāng)前任務(wù)棧
* tasknTcb中钦椭。以備下次調(diào)用時(shí)在恢復(fù)該任務(wù)的棧信息,是否可以直接存在棧里呢?
******************************************************************************/
LDR R0, =pCurTcb /* 獲取當(dāng)前任務(wù)棧的起始地址 */
LDR R1, [R0]
CMP R1,#0 /* 把pCurTcb值==0拧额;說(shuō)明是taskStart函數(shù);跳轉(zhuǎn)到taskBefore處執(zhí)行 */
BEQ taskBefore
LDR R0,=SVC_STACK /* 恢復(fù)異常時(shí)保存SVC模式下的SP棧指針到R2 */
LDR R2,[R0]
MOV R3,#18 /* 把SVC模式下棧信息保存到當(dāng)前任務(wù)棧地址彪腔,保存SPSR/CPSR/R0-R14寄存器 */
STACK_COPY:
LDR R0,[R2],#4
STR R0,[R1],#4
SUBS R3,R3,#1
BNE STACK_COPY
taskBefore:
sub lr, lr, #4 /* lr -4 為指令SWI XXX的地址,低24位是軟件中斷號(hào) */
ldr R3,[lr,#0] /* lr -4 為指令SWI XXX的地址,低24位是軟件中斷號(hào) */
bic R3,R3,#0XFF000000 /* 取得arm指令的低24位立即數(shù) */
cmp R3,#0 /* 判斷24位立即數(shù)侥锦,如果是0,調(diào)用usrModeSpSetup函數(shù) */
beq usrModeSpSetup
cmp R3,#1 /* 判斷24位立即數(shù)德挣,如果是1恭垦,調(diào)用task1Tcb函數(shù) */
ldr R0,=task1Tcb
ldr R0,[R0]
beq taskTcbSwitch
cmp R3,#2 /* 判斷24位立即數(shù),如果是2格嗅,調(diào)用task2Tcb函數(shù) */
ldr R0,=task2Tcb
ldr R0,[R0]
beq taskTcbSwitch
cmp R3,#3 /* 判斷24位立即數(shù)番挺,如果是3,調(diào)用task3Tcb函數(shù) */
ldr R0,=task3Tcb
ldr R0,[R0]
beq taskTcbSwitch
bne END
taskTcbSwitch:
ldr pc, =taskSwitch
/******************************************************************************
* 建立用戶模式椔鸷疲空間
******************************************************************************/
usrModeSpSetup:
mrs R0, CPSR /* Read the CPSR */
bic R0, R0, #0xdF /* Clear the mode irq fiq bits */
orr R0, R0, #0x10 /* Set the mode bits to FIQ mode */
msr cpsr_c, R0 /* 進(jìn)入用戶態(tài)建芙,并設(shè)置用戶態(tài)的SP,使能中斷 */
ldr sp, =0x33e00000 /* 設(shè)置用戶棧指針起始值 */
ldr R0, =USER_STACK /* 保存IRQ模式下的LR,用于調(diào)試 */
str sp, [R0]
ldr pc, =rootTask /* rootTask開(kāi)始用戶模式 */
timer0_taskSched:
ldr pc, =taskSched /* 在SVC模式下進(jìn)入taskSched函數(shù)調(diào)度函數(shù) */
END:
movne R0, #-1 /* 沒(méi)有該軟中斷對(duì)應(yīng)函數(shù)懂扼,出錯(cuò)返回-1 */
3禁荸、任務(wù)切換函數(shù)taskswitch修改
/***********************************************************************************
函數(shù)功能: 實(shí)現(xiàn)任務(wù)切換,調(diào)用新得任務(wù)執(zhí)行阀湿,并把控制權(quán)交給新任務(wù).
入口參數(shù): pTcb: 即將運(yùn)行的任務(wù)的TCB指針.
返 回 值: none.
***********************************************************************************/
int taskSwitch(TCB * pTcb)
{
/******************************************************************************
* 即將運(yùn)行任務(wù)的寄存器組地址, 匯編語(yǔ)言通過(guò)這個(gè)變量恢復(fù)寄存器
******************************************************************************/
nextTaskSp = &pTcb->strStackReg;
/* 即將運(yùn)行任務(wù)的TCB指針 */
pCurTcb = pTcb;
__asm__(
/******************************************************************************
* 獲取將要運(yùn)行任務(wù)的棧信息并運(yùn)行新任務(wù)
******************************************************************************/
" LDR R0, =nextTaskSp \n\t"
" LDR R1, [R0] \n\t"
" LDMIA R1!, {R0} \n\t" /* Spsr位置 */
" MSR SPSR, R0 \n\t"
" LDMIA R1!, {R0} \n\t" /* cpsr位置 */
" MOV R13, R1 \n\t" /* 開(kāi)始恢復(fù)原用戶態(tài)任務(wù)棧信息 */
" LDMIA R13!, {R0-R12}^ \n\t" /* ^表示把任務(wù)棧里R0-R14恢復(fù)到user模式下的R0-R14中赶熟,只針對(duì)用戶模式哦 */
" ADD R13,R13,#0x4 \n\t" /* 跳過(guò)恢復(fù)用戶態(tài)的R13 */
" LDMIA R13!, {R14}^ \n\t" /* ^表示把任務(wù)棧里R0-R14恢復(fù)到user模式下的R0-R14中,只針對(duì)用戶模式哦 */
" nop \n\t"
" LDMIA R13!, {R14} \n\t" /* ^表示把任務(wù)棧里R15恢復(fù)到SVC模式下的R14中陷嘴,只針對(duì)用戶模式哦 */
" nop \n\t"
" LDR R13, =SVC_STACK \n\t" /* 保存SVC模式下的SP棧映砖,用于恢復(fù)和調(diào)試 */
" LDR R13, [R13] \n\t"
" ADD R13,R13,#0x48 \n\t" /* 恢復(fù)SVC模式下的SP棧;這里可以釋放掉SVC模式SP棧,因?yàn)橐接脩裟J?*/
" MOVS R15, R14 \n\t" /* 進(jìn)入用戶模式, SVC模式下的SPSR值恢復(fù)到USR模式下的CPSR中 */
);
return 0;
}