00001 00002 /* Author: Ratish J. Punnoose, 2006 00003 * This file is part of TiROS, the Tickless Real-Time Operating System. 00004 * Copyright(c) 2006, 2007: Ratish J. Punnoose. 00005 * Copyright(c) 2006 Sandia Corporation. Under the terms of Contract 00006 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains 00007 * certain rights in this software. 00008 * 00009 * TiROS is free software; you can redistribute it and/or modify it under 00010 * the terms of the GNU General Public License as published by the Free 00011 * Software Foundation; either version 2 or (at your option) any later version. 00012 * 00013 * TiROS is distributed in the hope that it will be useful, but WITHOUT ANY 00014 * WARRANTY; without even the implied warranty of MERCHANTABILITY or 00015 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 00016 * for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License along 00019 * with TiROS; if not, write to the Free Software Foundation, Inc., 00020 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 00021 * 00022 * As a special exception, if other files instantiate templates or use macros 00023 * or inline functions from this file, or you compile this file and link it 00024 * with other works to produce a work based on this file, this file does not 00025 * by itself cause the resulting work to be covered by the GNU General Public 00026 * License. However the source code for this file must still be made available 00027 * in accordance with section (3) of the GNU General Public License. 00028 * 00029 * This exception does not invalidate any other reasons why a work based on 00030 * this file might be covered by the GNU General Public License. 00031 * 00032 */ 00033 00034 00035 /** \file 00036 * @brief Posix port of the RTOS. 00037 * 00038 * @page posix_port Posix HAL 00039 * This port makes a posix system look like real 00040 * hardware to TiROS. TiROS runs within a posix process. 00041 * This port provides the 00042 * context switching and time 00043 * functions to TiROS. 00044 * It simulates interrupts using posix signals. 00045 * The posix port does not use kernel traps (They work 00046 * on Linux but do not work reliably on Cygwin). 00047 * The signal implementation under Cygwin is such that storing and 00048 * restoring a context within a signal handler does not work 00049 * properly. So we bypass this for the Cygwin environment and use 00050 * direct Win32 api calls. 00051 * This port has been tested on Linux 2.6.x kernel series/Glibc and on 00052 * Cygwin 5.1. 00053 * This port does not work on Mac OS X (as of 10.4), because the 00054 * needed posix functions are not implemented. 00055 * 00056 * This port does not allow the time to be set. 00057 * 00058 * Currently, this port does not use the user provided stack memory 00059 * for the task stack. This port stores the context on the user 00060 * provided memory. For the task stack, it allocates new memory 00061 * (memory size defined by TIROS_POSIX_STKSZ) 00062 * 00063 * <H2> Configuration Options: </H2> 00064 * <DL> 00065 * <DT> PORT_TIMER_TYPE : <DD>Options are 1 or 2. Setting PORT_TIMER_TYPE to 1 00066 * uses the system real time. Setting PORT_TIMER_TYPE to 2, uses the 00067 * process time. This option is irrelevant to Cygwin as only real time 00068 * is available. 00069 * <DT> TIROS_POSIX_STKSZ : <DD> The stack size allocated to each task. 00070 * When os_task_create is called, the stack location and stack size 00071 * for the task are passed along to the port. The Posix port stores 00072 * the context at this provided stack location. The context size is 00073 * fixed based on the registers etc. The rest of this provided stack 00074 * is unused. The stack for the task is allocated separately using a 00075 * mmap. By default, this stack is 16384 bytes. This was done because 00076 * sometimes simple calls like printf on a posix system will easily 00077 * overrun a small stack (tens of bytes) that might be specified for an embedded 00078 * system. Allocating a larger stack on a posix system might help in 00079 * running the code on both platforms without modification. Override 00080 * the default by specifying TIROS_POSIX_STKSZ. 00081 * </DL> 00082 * 00083 * 00084 * <H2>Writing ISRs for the Posix port</H2> 00085 * The posix port uses unix/posix 00086 * signals to fake interrupts. Interrupt handlers are thus signal 00087 * handlers. The posix port does not use kernel traps (for 00088 * compatibility). So the form of the ISR must be as follows. 00089 * 00090 * \code 00091 * extern int halint_kernel_trap_flagged; // Flag in hal 00092 * extern uint8_t os_isr_nesting; 00093 * void signal_handler(int sig) 00094 * { 00095 * OS_ISR_BEGIN(); 00096 * halint_kernel_trap_flagged = 0; 00097 * // Perform actions 00098 * xxx(); 00099 * 00100 * // Re-enable interrupts if desired 00101 * if (os_isr_nesting < TIROS_MAX_ISR_NESTING) { 00102 * OS_INT_ENABLE(); 00103 * yyy(); 00104 * } 00105 * zzz(); 00106 * // End actions 00107 * OS_ISR_END(); 00108 * if (halint_kernel_trap_flagged) { 00109 * hal_ctxt_switch(); 00110 * } 00111 * } 00112 * \endcode 00113 * 00114 */ 00115 00116 00117 00118 #ifndef __POSIX_TIROS_PORT_H 00119 #define __POSIX_TIROS_PORT_H 00120 00121 00122 /*@ignore@*/ 00123 #include "proj_config.h" 00124 /*@end@*/ 00125 00126 00127 #include <signal.h> 00128 #include <stdint.h> 00129 00130 #define subtime_t long 00131 #define LT_INLINE static inline 00132 00133 00134 #include <tiros/tr_time.h> 00135 #include "porttime.h" 00136 00137 00138 /* Define the value of infinite time for this port */ 00139 #define TRPORT_INF_TIME {~0 , ~0 } 00140 00141 00142 /* The posix port does not use register passing. It is almost 00143 impossible to implement in a portable manner. */ 00144 /* #define TIROS_REGISTER_PASSING */ 00145 00146 00147 00148 00149 #ifndef TIROS_POSIX_STKSZ 00150 #define TIROS_POSIX_STKSZ 16384 00151 #endif 00152 00153 /* Define basic types for the hardware word, boolean, and pointer */ 00154 typedef uintptr_t osword_t; 00155 typedef void* osptr_t; 00156 typedef osword_t* osstkptr_t; 00157 typedef void (* osfnptr_t)(void *); 00158 typedef uintptr_t osptrword_t; 00159 00160 #define ILLEGAL_STACK ((osstkptr_t) ~0) 00161 #define ILLEGAL_ADDR ((osptr_t) ~0) 00162 00163 00164 /* Port specific function implemented in tr_port.c */ 00165 00166 /* \name Context_switching_functions 00167 * @{ */ 00168 00169 #ifdef __CYGWIN__ 00170 00171 #include <windows.h> 00172 typedef CONTEXT ctxt_t; 00173 00174 /* The context includes the registers, a place for storing the signal 00175 * state, and in this case, a location where the pointer to the true 00176 * posix stack can be stored */ 00177 #define TRPORT_MIN_CTXT_SZ ( (sizeof(ctxt_t) + sizeof(sigset_t) + sizeof(osstkptr_t) )/sizeof(osword_t) ) 00178 00179 #else 00180 #include <ucontext.h> 00181 typedef ucontext_t ctxt_t; 00182 #define TRPORT_MIN_CTXT_SZ ( (sizeof(ctxt_t) + sizeof(osstkptr_t))/sizeof(osword_t) ) 00183 00184 00185 #endif 00186 00187 /* \brief Initialize the stack for a task. 00188 * @param stk Pointer to the stack. 00189 * @param stacksize Size of the stack. 00190 * @param PC Program counter. 00191 * @param init_arg Initial argument passed to the task 00192 * @return The pointer to the task context to be used in load/save context. */ 00193 osstkptr_t hal_stk_init(osword_t *stk, osword_t stacksize, 00194 osfnptr_t pc, 00195 osptr_t init_arg); 00196 00197 00198 00199 00200 /* Enable critical section calls in the the called function 00201 * 00202 * This has to be called at the beginning of the function before 00203 * calling OS_CRITICAL_BEGIN or OS_CRITICAL_END. This should be the 00204 * first call after variable declaration. These section should not 00205 * be added within an ISR if Interrupt nesting is turned on, because 00206 * the interrupt nesting adds this in automatically, and duplication 00207 * will result in compiler complaints. */ 00208 #define OS_PORT_CRITICAL_ENABLE() \ 00209 sigset_t signal_status_old; \ 00210 sigset_t signal_status_new; 00211 00212 #define OS_PORT_ISR_BEGIN() \ 00213 extern uint8_t os_isr_nesting; \ 00214 os_isr_nesting++; 00215 00216 00217 00218 00219 /* Begin a critical section 00220 * 00221 * The current interrupt state is saved in signal_status and then 00222 * interrupts are disabled */ 00223 #define OS_PORT_CRITICAL_BEGIN() \ 00224 sigfillset(&signal_status_new); \ 00225 sigprocmask(SIG_SETMASK, &signal_status_new, &signal_status_old); 00226 00227 /* 00228 #define OS_PORT_CRITICAL_BEGIN() \ 00229 sigemptyset(&signal_status_new); \ 00230 sigaddset(&signal_status_new, SIGALRM); \ 00231 sigaddset(&signal_status_new, SIGVTALRM); \ 00232 sigprocmask(SIG_SETMASK, &signal_status_new, &signal_status_old); 00233 */ 00234 00235 /* End a critical section 00236 * 00237 * The saved interrupt state is restored */ 00238 #define OS_PORT_CRITICAL_END() \ 00239 sigprocmask(SIG_SETMASK, &signal_status_old, 0); 00240 00241 00242 static inline void OS_PORT_INT_ENABLE(void) 00243 { 00244 sigset_t signal_status; 00245 sigemptyset(&signal_status); 00246 sigprocmask(SIG_SETMASK, &signal_status, 0); 00247 } 00248 00249 00250 static inline void OS_PORT_INT_DISABLE(void) 00251 { 00252 sigset_t signal_status; 00253 sigfillset(&signal_status); 00254 sigprocmask(SIG_SETMASK, &signal_status, 0); 00255 } 00256 00257 00258 00259 /* Context switch from user level (non-ISR) 00260 * This function is called from within an OS call, to switch the 00261 * running process. It also provides a return value. This is a 00262 * pseudo return-value. This function does not actually determine 00263 * the value returned. The return value is set by hal_retval_set 00264 * which is often invoked when waking the process up from a blocked 00265 * state. 00266 * The function takes the following form 00267 * \code 00268 * osstkptr_t hal_ctxt_switch(void) 00269 * { 00270 * osstkptr_t ctxtptr = storecurrcontext_on_stk(); 00271 * ctxtptr = osint_taskswitcher(ctxtptr); 00272 * loadnewcontext_from_stk(ctxtptr); 00273 * } 00274 * \endcode 00275 * @return Return value. */ 00276 osstkptr_t hal_ctxt_switch(void); 00277 00278 00279 void hal_ctxt_load(osstkptr_t ctxt_ptr); 00280 00281 00282 /* @} End context switching functions */ 00283 00284 00285 00286 00287 00288 void hal_time_get(trtime_t *t); 00289 int hal_time_set(const trtime_t *t); 00290 00291 00292 /* \brief Set an alarm. 00293 * When the alarm is reached, osint_alarm_reached is called 00294 * @param lt Pointer to time */ 00295 void hal_alarm_set(const trtime_t *lt); 00296 00297 void hal_init(void); 00298 00299 00300 00301 00302 00303 00304 extern int halint_kernel_trap_flagged; 00305 00306 00307 00308 00309 static inline void OS_KERNEL_TRAP(void) 00310 { halint_kernel_trap_flagged = 1; } 00311 00312 00313 00314 00315 00316 /* 10 us response time */ 00317 #define TRPORT_RESPONSE_TIME {0, 10000} 00318 00319 00320 /* Port options are 0, 1. 00321 * 1 - uses the system real time. 00322 * 2 - uses the process time. */ 00323 #ifndef PORT_TIMER_TYPE 00324 #define PORT_TIMER_TYPE 1 00325 #endif 00326 00327 00328 00329 #ifdef TIROSINT_DATA_DEBUG 00330 /* Compute the program counter, from the stored context (stack 00331 * pointer) 00332 * This function is used for debugging. Implement this by extracting 00333 * the program counter out of the stack pointer if possible. 00334 * 00335 * @param stkptr The stkptr that is used by the hal to save/load 00336 * context. 00337 * @return The program counter */ 00338 osptr_t hal_pc_from_ctxt(osstkptr_t stkptr); 00339 00340 /* Return the maximum stack occupancy of the task. 00341 * This hal implemented function should provide the 00342 * maximum stack occupancy of the task whose context is given. 00343 * This is used for debugging. It is valid for this function to 00344 * return 0, if this information is not readily extractable. 00345 * @param ctxt_ptr Context of the task. 00346 * @param base_stkptr The initialization stack value for this task 00347 * that was passed to hal_stk_init 00348 * @param stksize The initial stack size for this task that was 00349 * passed to hal_stk_init 00350 * @return The maximum stack occupancy */ 00351 osword_t hal_stkusage_max(osstkptr_t ctxt_ptr, osstkptr_t base_stkptr, 00352 osword_t stksize); 00353 00354 /* Return the current stack occupancy of the task. 00355 * This hal implemented function should provide the 00356 * current stack occupancy of the task whose context is given. 00357 * This is used for debugging. It is valid for this function to 00358 * return 0, if this information is not readily extractable. 00359 * @param ctxt_ptr Context of the task. 00360 * @param base_stkptr The initialization stack value for this task 00361 * that was passed to hal_stk_init 00362 * @param stksize The initial stack size for this task that was 00363 * passed to hal_stk_init 00364 * @return The current stack occupancy */ 00365 osword_t hal_stkusage_curr(osstkptr_t ctxt_ptr, osstkptr_t base_stkptr, 00366 osword_t stksize); 00367 00368 00369 #endif 00370 00371 00372 00373 #endif /* End of tr_port.h */