SylixOS鉤子函數淺析
阿新 • • 發佈:2018-08-22
intent 周期 ack 同時 break 結束 空閑 cto 系統 1 使用背景
對定時器做相關配置,使得每隔時間T,觸發定時器中斷,可以在定時器中斷處理函數處理算法,這樣就可以周期性的執行特定的任務。但如果不想在定時器中斷處理函數中添加算法,比如說用戶只想在應用程序裏面執行他們的任務,那麽鉤子函數就是一個不錯的選擇。
2 鉤子函數的原理
本章以定時器中斷為例說明SylixOS鉤子的使用方法。
2.1 API_InterVectorIsr函數
函數原型如程序清單 2.1
程序清單 2.1
#include <SylixOS>
irqreturn_t API_InterVectorIsr (ULONG ulVector);
API_InterVectorIsr該內核接口是向量中斷的總服務入口,根據中斷號得到對應的中斷服務函數鏈表,找到具體中斷服務函數。流程圖如圖 2.1 所示。
圖 2.1 中斷向量處理流程
從流程圖可以看到,該函數入口處調用LW_CPU_INT_ENTER_HOOK。該宏的定義如程序清單 2.2所示。這就是鉤子函數的調用流程,其實就是調用一個函數指針指向的函數。
程序清單 2.2
#define LW_CPU_INT_ENTER_HOOK(ulVector, ulNesting) \
if (_K_hookKernel.HOOK_CpuIntEnter) { \
_K_hookKernel.HOOK_CpuIntEnter(ulVector, ulNesting); \
} 程序清單 2.3
LW_API
ULONG API_KernelHookSet (LW_HOOK_FUNC hookfuncPtr, ULONG ulOpt)
{
INTREG iregInterLevel;
對定時器做相關配置,使得每隔時間T,觸發定時器中斷,可以在定時器中斷處理函數處理算法,這樣就可以周期性的執行特定的任務。但如果不想在定時器中斷處理函數中添加算法,比如說用戶只想在應用程序裏面執行他們的任務,那麽鉤子函數就是一個不錯的選擇。
2 鉤子函數的原理
本章以定時器中斷為例說明SylixOS鉤子的使用方法。
2.1 API_InterVectorIsr函數
函數原型如程序清單 2.1
程序清單 2.1
#include <SylixOS>
irqreturn_t API_InterVectorIsr (ULONG ulVector);
API_InterVectorIsr該內核接口是向量中斷的總服務入口,根據中斷號得到對應的中斷服務函數鏈表,找到具體中斷服務函數。流程圖如圖 2.1 所示。
圖 2.1 中斷向量處理流程
從流程圖可以看到,該函數入口處調用LW_CPU_INT_ENTER_HOOK。該宏的定義如程序清單 2.2所示。這就是鉤子函數的調用流程,其實就是調用一個函數指針指向的函數。
程序清單 2.2
#define LW_CPU_INT_ENTER_HOOK(ulVector, ulNesting) \
if (_K_hookKernel.HOOK_CpuIntEnter) { \
_K_hookKernel.HOOK_CpuIntEnter(ulVector, ulNesting); \
}
2.2 鉤子的設置函數
SylixOS內核提供了鉤子的設置接口API_KernelHookSet,函數的實現如程序清單 2.3所示。
LW_API
ULONG API_KernelHookSet (LW_HOOK_FUNC hookfuncPtr, ULONG ulOpt)
{
INTREG iregInterLevel;
iregInterLevel = __KERNEL_ENTER_IRQ(); /* 進入內核同時關閉中斷 */ switch (ulOpt) { case LW_OPTION_THREAD_CREATE_HOOK: /* 線程建立鉤子 */ _K_hookKernel.HOOK_ThreadCreate = hookfuncPtr; break; case LW_OPTION_THREAD_DELETE_HOOK: /* 線程刪除鉤子 */ _K_hookKernel.HOOK_ThreadDelete = hookfuncPtr; break; case LW_OPTION_THREAD_SWAP_HOOK: /* 線程切換鉤子 */ _K_hookKernel.HOOK_ThreadSwap = hookfuncPtr; break; case LW_OPTION_THREAD_TICK_HOOK: /* 系統時鐘中斷鉤子 */ _K_hookKernel.HOOK_ThreadTick = hookfuncPtr; break; case LW_OPTION_THREAD_INIT_HOOK: /* 線程初始化鉤子 */ _K_hookKernel.HOOK_ThreadInit = hookfuncPtr; break; case LW_OPTION_THREAD_IDLE_HOOK: /* 空閑線程鉤子 */ _K_hookKernel.HOOK_ThreadIdle = hookfuncPtr; break; case LW_OPTION_KERNEL_INITBEGIN: /* 內核初始化開始鉤子 */ _K_hookKernel.HOOK_KernelInitBegin = hookfuncPtr; break; case LW_OPTION_KERNEL_INITEND: /* 內核初始化結束鉤子 */ _K_hookKernel.HOOK_KernelInitEnd = hookfuncPtr; break; case LW_OPTION_KERNEL_REBOOT: /* 內核重新啟動鉤子 */ _K_hookKernel.HOOK_KernelReboot = hookfuncPtr; break; case LW_OPTION_WATCHDOG_TIMER: /* 看門狗定時器鉤子 */ _K_hookKernel.HOOK_WatchDogTimer = hookfuncPtr; break; case LW_OPTION_OBJECT_CREATE_HOOK: /* 創建內核對象鉤子 */ _K_hookKernel.HOOK_ObjectCreate = hookfuncPtr; break; case LW_OPTION_OBJECT_DELETE_HOOK: /* 刪除內核對象鉤子 */ _K_hookKernel.HOOK_ObjectDelete = hookfuncPtr; break; case LW_OPTION_FD_CREATE_HOOK: /* 文件描述符創建鉤子 */ _K_hookKernel.HOOK_FdCreate = hookfuncPtr; break; case LW_OPTION_FD_DELETE_HOOK: /* 文件描述符刪除鉤子 */ _K_hookKernel.HOOK_FdDelete = hookfuncPtr; break; case LW_OPTION_CPU_IDLE_ENTER: /* CPU 進入空閑模式 */ _K_hookKernel.HOOK_CpuIdleEnter = hookfuncPtr; break; case LW_OPTION_CPU_IDLE_EXIT: /* CPU 退出空閑模式 */ _K_hookKernel.HOOK_CpuIdleExit = hookfuncPtr; break; case LW_OPTION_CPU_INT_ENTER: /* CPU 進入中斷(異常)模式 */ _K_hookKernel.HOOK_CpuIntEnter = hookfuncPtr; break; case LW_OPTION_CPU_INT_EXIT: /* CPU 退出中斷(異常)模式 */ _K_hookKernel.HOOK_CpuIntExit = hookfuncPtr; break; case LW_OPTION_STACK_OVERFLOW_HOOK: /* 堆棧溢出 */ _K_hookKernel.HOOK_StkOverflow = hookfuncPtr; break; case LW_OPTION_FATAL_ERROR_HOOK: /* 致命錯誤 */ _K_hookKernel.HOOK_FatalError = hookfuncPtr; break; case LW_OPTION_VPROC_CREATE_HOOK: /* 進程建立鉤子 */ _K_hookKernel.HOOK_VpCreate = hookfuncPtr; break; case LW_OPTION_VPROC_DELETE_HOOK: /* 進程刪除鉤子 */ _K_hookKernel.HOOK_VpDelete = hookfuncPtr; break; default: __KERNEL_EXIT_IRQ(iregInterLevel); /* 退出內核同時打開中斷 */ _ErrorHandle(ERROR_KERNEL_OPT_NULL); return (ERROR_KERNEL_OPT_NULL); } __KERNEL_EXIT_IRQ(iregInterLevel); /* 退出內核同時打開中斷 */ return (ERROR_NONE);
}
該函數可以設置各種類型鉤子函數,由此可見,只要調用API_KernelHookSet設置中斷相關的鉤子函數,當進入中斷入口的函數的入口時都會調用鉤子。
2.3 鉤子函數的定義
假設設置了中斷的鉤子函數,那麽任何中斷都會調用這個鉤子函數。現在只關心定時器中斷,因此需要用中斷號來過濾不關心的中斷。例程如程序清單 2.4所示。
程序清單 2.4
#define TIMER_INTVECTOR 69
void HookFun(ULONG ulVector,ULONG ulnest)
{
if(TIMER_INTVECTOR != ulVector)
{
return;
}
/* 用戶在此添加自己算法*/
/* 註意:不要調用中斷上下文不能執行的語句,比如sleep,printf等*/
}
這樣,系統會周期性的進入定時器中斷,處理 HookFun函數。只要知道中斷號,就可以不用知曉定時器驅動的實現機制,直接掛接想要處理的任務。
3 參考資料
《SylixOS_driver_usermanual》
SylixOS鉤子函數淺析