如何移植uCOS-III到Linux系統 How to Port uCOS-III on Linux OS
如何移植uCOS-III到Linux作業系統???
關於uCOS-II移植到Linux系統的核心程式碼
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
基本移植已被對映到Linux訊號,並在OS_CPU_C.C中實施;注意在這個移植方案中沒有組合語言檔案。一些功能被內聯在OS_CPU.H中。換句話說,就是這裡只有一個Linux程式(也只有一個執行緒),以及所有任務的建立和排程都是由microC/OS
- II來做的。
在當前任務堆疊進行訊號傳遞。OSTCBStkPtr是指向ucontext_t堆疊結構,供接下去使用。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
•OS_TASK_SW( ):使用Linux系統呼叫的上下文切換殺()系統呼叫,它傳送訊號SIGUSR1給自己。
•OSCtxSw( ):切換任務是做一箇中斷髮生後,一個新的任務變得準備執行,任務自願放棄CPU的。這個函式被呼叫的訊號SIGUSR1和SIGALRM的處理程式。切換是由setcontext()。
•OSTickISR( ) 是一個標準的執行程式碼,如在書中所述。它被函式OSTimeTickSigHandler()週期性地呼叫。
•OSInitHookBegin():這個鉤子是用來初始化Linux的訊號和控制程式碼。它呼叫LinuxInit()。
•LinuxInitInt( ) 已被要求使用者在最高優先順序的使用者應用任務中呼叫。它啟動時鐘節拍。
•OSTaskIdleHook( ) 是空的,休眠一段時間或直到下一次訊號被髮生(呼叫一個select()系統呼叫)。
•OSTaskStkInit( ) 初始化一個ucontext_t結構的任務堆疊和調整TCBs域。SysV系統呼叫getcontext()和makecontext(
)有助於處理此過程。
•OSStartHighRdy( ) 使用setcontext()恢復先前上下文。由於該功能只能使用一次,應該在未來的呼叫中被OSCtxSw取代。
•OS_CPU_SR:此型別對映到一個sigset_t。它是用來阻塞和恢復訊號。由於Linux移植採用了Critical
Method #3,它貫穿整個系統。
•OS_CRITICAL_METHOD:= 3; Linux移植必須記住訊號掩碼的先前狀態。
•OS_ENTER_CRITICAL( ) 是一個巨集,通過Linuxsigprocmask()系統呼叫,阻塞SIGALRM和SIGUSR1訊號。
•OS_EXIT_CRITICAL( ) 恢復訊號掩碼的先前狀態。
•OS_TASK_DEF_STK_SIZE:在Linux上的合理大小是2000words。這主要是由於處理堆疊上的訊號。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/*
* uC/OS-II
* The Real-Time Kernel
*
* Linux Port
*
* File : $Source: /proj/cvs-gfa/Micrium/Software/uCOS-II/Ports/linux-hal/os_cpu.h,v $
* By : (c) George Fankhauser, Sensaco Consulting GmbH,
* Switzerland, http://www.sensaco.com
* Version : $Revision: 1.1.1.1 $
*
* Changed by : $Author: gfa $
* $Date: 2003/11/20 10:19:14 $
*
* $Log: os_cpu.h,v $
* Revision 1.1.1.1 2003/11/20 10:19:14 gfa
* check in ucos II for linux
*
*/
/*
* \file
*
* Definition moved here so it can be used in the assembler file OS_CPU_A.ASM.
* See below for the meaning of this define
*
* \author George Fankhauser
*/
#include <unistd.h>
#include <signal.h>
#include <string.h> /// memcpy, memset used in os_task.c !
#ifndef OS_CPU_A /* skip the rest if we're including from the assembler file */
#ifdef OS_CPU_GLOBALS
#define OS_CPU_EXT
#else
#define OS_CPU_EXT extern
#endif
/*
* DATA TYPES (Compiler and architecture specific)
*/
typedef unsigned char BOOLEAN;
typedef unsigned char INT8U; /* Unsigned 8 bit quantity */
typedef signed char INT8S; /* Signed 8 bit quantity */
typedef unsigned short int INT16U; /* Unsigned 16 bit quantity */
typedef signed short int INT16S; /* Signed 16 bit quantity */
typedef unsigned int INT32U; /* Unsigned 32 bit quantity */
typedef signed int INT32S; /* Signed 32 bit quantity */
typedef float FP32; /* Single precision floating point */
typedef INT32U OS_STK; /* Each stack entry is 32 bit wide */
typedef sigset_t OS_CPU_SR; /// the 'status register' corresponds to signals
/*
* used in os_cpu_c
*/
void OSTaskSwHook (void);
/*
* linuxInit does the setup of the signal handler.
*/
void linuxInit(void);
/** linuxInitInt starts periodic interrupts. */
void linuxInitInt(void);
/*
* Macro to block interrupts (on Linux: signals)
*
* Critical method 1 which does not restore the signal state may lead to hanging
* timer interrupts, especially when debugging (i.e. real time is much faster than debug
* time).
*/
#define OS_CRITICAL_METHOD 3
/*
* We add all the virtual interrupt signals to the mask and save the old process
* signal mask to the backup 'status register'.
*/
#define OS_ENTER_CRITICAL() { sigset_t set; \
sigemptyset(&set); \
sigaddset(&set, SIGALRM); \
sigaddset(&set, SIGIO); \
sigprocmask(SIG_SETMASK, &set, &cpu_sr); \
}
/*
* Macro to unblock interrupts
*
* Here we just restore the state that was returned by previous call to sigprocmask
*/
#define OS_EXIT_CRITICAL() { sigprocmask(SIG_SETMASK, &cpu_sr, NULL); \
}
/*
* Stack grows from HIGH to LOW memory on linux x86
*/
#define OS_STK_GROWTH 1
/*
* This macro posts a Linux signal to ourselves; it is returned in the handler with the
* threads context. The SIGUSR1 handler saves the context and then calls OSCtxSw().
*
* (use OSCtxSw() directly when no sw int available)
*/
#define OS_TASK_SW() { kill(getpid(), SIGUSR1); }
#endif //OS_CPU_A
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/*
* uC/OS-II
* The Real-Time Kernel
*
* Linux Port
*
* File : $Source: /proj/cvs-gfa/Micrium/Software/uCOS-II/Ports/linux-hal/os_cpu_c.c,v $
* By : (c) George Fankhauser, Sensaco Consulting GmbH,
* Switzerland, http://www.sensaco.com
* Version : $Revision: 1.1.1.1 $
*
* Changed by : $Author: gfa $
* $Date: 2003/11/20 10:19:14 $
*
* $Log: os_cpu_c.c,v $
* Revision 1.1.1.1 2003/11/20 10:19:14 gfa
* check in ucos II for linux
*
*/
/*
* \file
* User context switching code derived from Topsy 2.0 port to Linux and Solaris
* (see http://www.tik.ee.ethz.ch/~topsy).
*
* \author George Fankhauser
*/
#define OS_CPU_GLOBALS
#include "includes.h"
#include <asm/sigcontext.h> // for context switching
#define __USE_GNU
#include <ucontext.h>
#undef __USE_GNU
#include <ucontext.h> // for context switching
#include <string.h>
#include <unistd.h> // used for syscalls:
// ualarm in Threads/unix/TMClock.c
// kill in Topsy/unix/SyscallMsg.c
// getpid in Topsy/unix/SyscallMsg.c
#include <signal.h> // used in Threads/unix/TMHal.c and
// Topsy/unix/SyscallMsg.c
#include <setjmp.h> // for contextswitches in Threads/unix/TMHal.c
#include <sys/select.h>
#include <stdio.h> // if we want to use printf...
/*
* TASK CREATION HOOK
*
* This function is called when a task is created.
* Arguments : ptcb is a pointer to the task control block of the task being created.
* Note(s) : 1) Interrupts are disabled during this call.
*/
#if OS_CPU_HOOKS_EN > 0
void OSTaskCreateHook (OS_TCB *ptcb)
{
ptcb = ptcb;
}
#endif
/*
* TASK DELETION HOOK
*
* This function is called when a task is deleted.
* \arg ptcb is a pointer to the task control block of the task being deleted.
* Note(s) : 1) Interrupts are disabled during this call.
*/
#if OS_CPU_HOOKS_EN > 0
void OSTaskDelHook (OS_TCB *ptcb)
{
ptcb = ptcb; /* Prevent compiler warning */
}
#endif
/*
* TASK SWITCH HOOK
*
* This function is called when a task switch is performed. This allows
* you to perform other operations during a context switch.
*
* Note(s) : 1) Interrupts are disabled during this call.
* 2) It is assumed that the global pointer 'OSTCBHighRdy' points to the
* TCB of the task that will be 'switched in' (i.e. the highest priority
* task) and, 'OSTCBCur' points to the task being switched out (i.e. the
* preempted task).
*/
#if (OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0)
void OSTaskSwHook (void)
{
}
#endif
/*
* STATISTIC TASK HOOK
*
* This function is called every second by uC/OS-II's statistics task.
* This allows your application to add functionality to the statistics task.
*/
#if (OS_TASK_STAT_HOOK_EN > 0)
void OSTaskStatHook (void)
{
}
#endif
/*
* TICK HOOK
*
* This function is called every tick.
* Note(s) : 1) Interrupts may or may not be ENABLED during this call.
*/
#if (OS_CPU_HOOKS_EN > 0) && (OS_TIME_TICK_HOOK_EN > 0)
void OSTimeTickHook (void)
{
}
#endif
/*
* OS INITIALIZATION HOOK
* (BEGINNING)
*
* This function is called by OSInit() at the beginning of OSInit().
* Note(s) : 1) Interrupts should be disabled during this call.
*/
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void OSInitHookBegin (void)
{
linuxInit(); /// installs the syscall handler
}
#endif
/*
* OS INITIALIZATION HOOK
* (END)
*
* This function is called by OSInit() at the end of OSInit().
* Note(s) : 1) Interrupts should be disabled during this call.
*/
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void OSInitHookEnd (void)
{
}
#endif
/*
* IDLE TASK HOOK
*
* This function is called by the idle task. This hook has been added to
* allow you to do such things as STOP the CPU to conserve power.
* Note(s) : 1) Interrupts are enabled during this call.
*
* On real hardware a power saving function would be selected.
* On Linux, we sleep a little to lower the load on the system
* or, we block until next signal is delivered by calling select().
*
* If either of these methods causes problems just leave the
* function empty.
*/
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION >= 251
void OSTaskIdleHook (void)
{
// usleep(50); /// as done in Topsy
select(0, NULL, NULL, NULL, NULL); /// as done in eCos
}
#endif
/*
* OSTCBInit() HOOK
*
* This function is called by OS_TCBInit() after setting up most of the TCB.
* \arg ptcb is a pointer to the TCB of the task being created.
* Note(s) : 1) Interrupts may or may not be ENABLED during this call.
*/
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void OSTCBInitHook (OS_TCB *ptcb)
{
ptcb = ptcb;
}
#endif
/*
* INITIALIZE A TASK'S STACK
*
* This function is called by either OSTaskCreate() or OSTaskCreateExt() to
* initialize the stack frame of the task being created. This function is highly
* processor specific.
* \arg task is a pointer to the task code
* \arg pdata is a pointer to a user supplied data area that will be passed to the task
* when the task first executes.
* \arg ptos is a pointer to the top of stack. It is assumed that 'ptos' points to the
* highest valid address on the stack.
* \arg opt specifies options that can be used to alter the behavior of OSTaskStkInit().
* \see uCOS_II.H for OS_TASK_OPT_???.
*
* \return Always returns the location of the new top-of-stack' once the processor
* registers have been placed on the stack in the proper order.
*
* Note(s) : Interrupts are enabled when your task starts executing. You can change
* this by setting this SREG to 0x00 instead. In this case, interrupts would be disabled
* upon task startup. The application code would be responsible for enabling interrupts
* at the beginning of the task code. You will need to modify OSTaskIdle() and
* OSTaskStat() so that they enable interrupts. Failure to do this will make your system
* crash!
*/
OS_STK* OSTaskStkInit (void (*task)(void* pd), void* pdata, OS_STK* ptos, INT16U opt)
{
INT32U* stk;
ucontext_t uc;
INT32U sigsize = 20 + sizeof(uc);
opt = opt; /* 'opt' is not used, prevent warning */
getcontext(&uc);
stk = (INT32U*)((int)ptos - sigsize);
uc.uc_link = NULL; /// no successor
uc.uc_mcontext.gregs[REG_EBP] = (int)stk;
uc.uc_stack.ss_sp = (void*)(((int)stk) - (OS_TASK_DEF_STK_SIZE) + sigsize); /// base address
uc.uc_stack.ss_size = OS_TASK_DEF_STK_SIZE - sigsize;
makecontext(&uc, (void*)task, 1, pdata);
memcpy(stk, &uc, sizeof(uc));
return ((OS_STK *)stk);
}
/*
* A new thread is started
*/
void OSStartHighRdy(void)
{
OSTaskSwHook();
OSRunning = TRUE;
// real work goes here...
{
ucontext_t* ucp;
ucp = (struct ucontext*)(OSTCBHighRdy->OSTCBStkPtr);
setcontext(ucp);
// not reached
}
}
/*
* called by OSIntExit()
*
* typically, after signal is handled, a potentially new thread is picked and
* resumed
*/
void OSIntCtxSw(void)
{
// on Linux this is the same as OSCtxSw; no special treats for hw/sw ints
OSCtxSw();
}
/*
* This procedure is called whenever a thread sleeps voluntarily, or, a syscall is made and the
* the thread is not the highest priority thread anymore after rescheduling.
*
* This procedure is called via software interrupt (on Linux synthetic targets: signal and
* handler).
*
* \todo setcontext is a user space implementation of calling sigprocmask and then restoring
* registers; should try (ugly) hack using sigreturn which is a real syscall
*/
void OSCtxSw(void)
{
struct ucontext* uc = (struct ucontext*)OSTCBHighRdy->OSTCBStkPtr;
// at this point, registers are already saved on stack
OSTaskSwHook();
OSTCBCur = OSTCBHighRdy;
OSPrioCur = OSPrioHighRdy;
//if (uc->uc_mcontext.fpregs == 0) {
// fprintf(stderr, "ctx sw: uc->uc_mcontext.fpregs == 0\n");
//uc->uc_mcontext.fpregs = (fpregset_t)0xbffff6cc;
//}
setcontext(uc);
}
/*
* \arg signo Signal number
* \arg info Signal info
* \arg uc User context
*/
void OSCtxSwSigHandler(int signo, siginfo_t* info, /*struct ucontext* */ void* uc)
{
/*
* Linux specific module variable of current signal context, i.e. interrupted thread
*/
OSTCBCur->OSTCBStkPtr = uc; //stk;
OSCtxSw();
}
/*
* \todo maybe wrong for linux port?
* adjust sp if nesting == 1 ???? maybe if there is a seperate interrupt stack
* linux user space port does not have a special isr stack frame layout
*/
void OSTickISR(void)
{
/// register context already saved in sig handler
OSIntEnter();
if (OSIntNesting == 1) {
//OSTCBCur->OSTCBStkPtr = $SP;
//asm("mov %%esp, %0" : "=g"(OSTCBCur->OSTCBStkPtr) : );
}
OSTimeTick(); /// adjusts counters and ready bitmaps
OSIntExit(); /// reschedules if necessary
OSIntCtxSw(); /// restore context and jump to highest prio task
}
/*
* Periodic signal handler that adjusts timers
* On Linux this is not very precise but for most applications sufficient
*
* Pick a value between 10 and 1000 Hz for the timer
*
* \todo this handler maybe executed during a restore (i.e. setcontext())
* call. This is a problem with the setcontext() user space implementation in
* Linux i386. Most SysV and Linux RISC systems don't have this. The tests
* below are an indication that this situatiuon has occured; the SIGALRM
* is then aborted...
*
* \todo If this is not fixed by adding a Linux syscall for get/setcontext, a user level
* implementation with an 'clock interrupt' lock should be used
*
* \arg signo Signal number
* \arg info Signal info
* \arg uc User context
*/
void OSTimeTickSigHandler(int signo, siginfo_t* info, /*struct ucontext* */ void* uc)
{
if ((((ucontext_t*)uc)->uc_mcontext.gregs[REG_EIP] >= (unsigned int)setcontext) &&
(((ucontext_t*)uc)->uc_mcontext.gregs[REG_EIP] (unsigned int)(setcontext + 110))) {
//fprintf(stderr, "sig timer: thread interrupted in setcontext\n");
return;
}
if (((ucontext_t*)uc)->uc_mcontext.fpregs == 0) {
//fprintf(stderr, "sig timer: uc->uc_mcontext.fpregs == 0\n");
return;
}
OSTCBCur->OSTCBStkPtr = uc; //stk;
OSTickISR();
// restore context
}
/*
* Kick the periodic clock; this must be done \e after microC/OS-II is initialised,
* typically at the end of main()
*
* Either SIGALRM or SIGVTALRM can be used
*
* Attention:This must be called by the user in the first task
*/
void linuxInitInt()
{
ualarm(1000000/OS_TICKS_PER_SEC, 1000000/OS_TICKS_PER_SEC); /// periodic mode
// alternative
//setitimer(ITIMER_VIRTUAL, 1000000/OS_TICKS_PER_SEC); /// SIGVTALRM time spent by the
/// process in User Mode
}
/*
* Setup of Linux specific stuff such as stacks, signals, handlers, mask etc.
*
* This is called inside the HAL by OSInitHookBegin()
*/
void linuxInit()
{
struct sigaction act;
sigset_t mask;
sigemptyset(&mask);
act.sa_sigaction = OSTimeTickSigHandler;
act.sa_flags = SA_SIGINFO;// | SA_ONSTACK;
act.sa_mask = mask;
sigaction(SIGALRM, &act, NULL);
sigaction(SIGVTALRM, &act, NULL);
sigemptyset(&mask);
act.sa_sigaction = OSCtxSwSigHandler;
act.sa_flags = SA_SIGINFO;// | SA_ONSTACK;
act.sa_mask = mask;
sigaction(SIGUSR1, &act, NULL);
}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
相關文章
- 把Iptables移植到嵌入式Linux系統(轉)Linux
- 將 Linux 應用程式移植到 64 位系統上Linux
- Linux 根檔案系統的移植(從入門到精通)Linux
- alsa 移植到Linux3.0Linux
- Unix、Windows、Mac OS、Linux系統故事WindowsMacLinux
- 如何移植32位程式到64位系統薦
- 未來蘋果裝置將移植 Linux 系統蘋果Linux
- 虛擬機器下linux OS如何給系統新增磁碟虛擬機Linux
- 將 Win32 程式移植到 LinuxWin32Linux
- Solaris到Linux應用的移植(轉)Linux
- 嵌入式Linux系統libmosquitto移植概述LinuxIBMUI
- 小白自制Linux開發板 三. Linux核心與檔案系統移植Linux
- Socket相關程式:從Windows移植到LinuxWindowsLinux
- 把 Linux 移植到蘋果 M1 Mac 上Linux蘋果Mac
- 如何預設啟動到 Linux 系統的舊核心Linux
- 【OS】Linux如何關閉防火牆Linux防火牆
- 如何自學Linux?初學者如何選擇Linux系統?Linux
- Windows、Linux、Unix、Mac OS X系統哪個更好用?WindowsLinuxMac
- 在 Linux 和 Mac OS X 系統上執行 .NETLinuxMac
- QT移植到Linux總結(一)tslib1.0QTLinux
- VS2008專案移植到LinuxLinux
- windows共享到linux系統檔案WindowsLinux
- 手機移植平板技術 電視裝上 Linux 系統(轉)Linux
- windows系統port監聽Windows
- 修改linux telnet的埠portLinux
- linux||mac os如何自定義shell命令LinuxMac
- Linux系統怎麼學?如何選擇合適的Linux系統?Linux
- 虹軟人臉識別——官方 Qt Demo 移植到 LinuxQTLinux
- Linux系統如何使用Fuser命令Linux
- Linux系統中grep如何使用?Linux
- 什麼是Linux?Linux系統發展前景如何?Linux
- 如何最佳化Linux系統安全?Linux學習Linux
- 【OS】Linux命令如何放到後臺執行Linux
- 【移植Linux 3.4.2核心之四】修改核心程式碼支援YAFFS檔案系統Linux
- Linux 振翼高翔 FAA 切換空中交通管制系統到 LinuxLinux
- 從rm到linux虛擬檔案系統Linux
- putty 連線到linux系統中使用中文Linux
- Linux + OS RedHat AS 5LinuxRedhat