rtai-core/include/asm-i386/rtai_xeno.h

00001 /*
00002  * Copyright (C) 2001,2002,2003 Philippe Gerum <rpm@xenomai.org>.
00003  *
00004  * Xenomai is free software; you can redistribute it and/or modify it
00005  * under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * Xenomai is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with Xenomai; if not, write to the Free Software Foundation,
00016  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  *
00018  * As a special exception, the RTAI project gives permission
00019  * for additional uses of the text contained in its release of
00020  * Xenomai.
00021  *
00022  * The exception is that, if you link the Xenomai libraries with other
00023  * files to produce an executable, this does not by itself cause the
00024  * resulting executable to be covered by the GNU General Public License.
00025  * Your use of that executable is in no way restricted on account of
00026  * linking the Xenomai libraries code into it.
00027  *
00028  * This exception does not however invalidate any other reasons why
00029  * the executable file might be covered by the GNU General Public
00030  * License.
00031  *
00032  * This exception applies only to the code released by the
00033  * RTAI project under the name Xenomai.  If you copy code from other
00034  * RTAI project releases into a copy of Xenomai, as the General Public
00035  * License permits, the exception does not apply to the code that you
00036  * add in this way.  To avoid misleading anyone as to the status of
00037  * such modified files, you must delete this exception notice from
00038  * them.
00039  *
00040  * If you write modifications of your own for Xenomai, it is your
00041  * choice whether to permit this exception to apply to your
00042  * modifications. If you do not wish that, delete this exception
00043  * notice.
00044  *
00045  * This file implements the interface between the Xenomai nucleus and
00046  * RTAI/Adeos in kernel space.
00047  */
00048 
00049 #ifndef _RTAI_ASM_I386_XENO_H
00050 #define _RTAI_ASM_I386_XENO_H
00051 
00052 #include <linux/kernel.h>
00053 #include <linux/version.h>
00054 #include <linux/module.h>
00055 #include <linux/slab.h>
00056 #include <linux/errno.h>
00057 #include <linux/adeos.h>
00058 #include <asm/uaccess.h>
00059 #include <asm/param.h>
00060 #include <asm/mmu_context.h>
00061 #include <rtai_config.h>
00062 #include <asm/rtai_hal.h>
00063 #include <asm/rtai_xnatomic.h>
00064 #include <xenomai/shadow.h>
00065 
00066 #define MODULE_PARM_VALUE(parm) (parm)
00067 #ifndef MODULE_LICENSE
00068 #define MODULE_LICENSE(s)
00069 #endif /* MODULE_LICENSE */
00070 
00071 typedef unsigned long spl_t;
00072 
00073 #define splhigh(x)  rtai_local_irq_save(x)
00074 #define splexit(x)  rtai_local_irq_restore(x)
00075 #define splnone()   rtai_sti()
00076 #define spltest()   rtai_local_irq_test()
00077 #define splget(x)   rtai_local_irq_flags(x)
00078 
00079 #define XNARCH_DEFAULT_TICK   1000000 /* ns, i.e. 1ms */
00080 #define XNARCH_IRQ_MAX        NR_IRQS
00081 #define XNARCH_HOST_TICK      (1000000000UL/HZ)
00082 #define XNARCH_APERIODIC_PREC 1000 /* 1us, aperiodic precision */
00083 #define XNARCH_SCHED_LATENCY  CONFIG_RTAI_SCHED_8254_LATENCY
00084 
00085 #define XNARCH_THREAD_COOKIE  (THIS_MODULE)
00086 #define XNARCH_THREAD_STACKSZ 4096
00087 #define XNARCH_ROOT_STACKSZ   0 /* Only a placeholder -- no stack */
00088 
00089 #define xnarch_printf                printk /* Yup! This is safe under ARTI */
00090 #define xnarch_ullmod(ull,uld,rem)   (xnarch_ulldiv(ull,uld,rem), (*rem))
00091 #define xnarch_ulldiv                rtai_ulldiv
00092 #define xnarch_imuldiv               rtai_imuldiv
00093 #define xnarch_llimd                 rtai_llimd
00094 #define xnarch_get_cpu_tsc           rtai_rdtsc
00095 
00096 struct xnthread;
00097 struct xnmutex;
00098 struct module;
00099 struct task_struct;
00100 
00101 #define xnarch_stack_size(tcb)  ((tcb)->stacksize)
00102 #define xnarch_fpu_ptr(tcb)     ((tcb)->fpup)
00103 
00104 typedef struct xnarchtcb {      /* Per-thread arch-dependent block */
00105 
00106     /* Kernel mode side */
00107     union i387_union fpuenv __attribute__ ((aligned (16))); /* FPU backup area */
00108     unsigned stacksize;         /* Aligned size of stack (bytes) */
00109     unsigned long *stackbase;   /* Stack space */
00110     unsigned long esp;          /* Saved ESP for kernel-based threads */
00111     unsigned long eip;          /* Saved EIP for kernel-based threads */
00112     struct module *module;      /* Creator's module */
00113 
00114     /* User mode side */
00115     struct task_struct *user_task;      /* Shadowed user-space task */
00116     struct task_struct *active_task;    /* Active user-space task */
00117 
00118     unsigned long *espp;        /* Pointer to ESP backup area (&esp or &user->thread.esp) */
00119     unsigned long *eipp;        /* Pointer to EIP backup area (&eip or &user->thread.eip) */
00120     union i387_union *fpup;     /* Pointer to the FPU backup area (&fpuenv or &user->thread.i387.f[x]save */
00121 
00122 } xnarchtcb_t;
00123 
00124 typedef struct xnarch_fltinfo {
00125 
00126     unsigned vector;
00127     long errcode;
00128     struct pt_regs *regs;
00129 
00130 } xnarch_fltinfo_t;
00131 
00132 #define xnarch_fault_trap(fi)  ((fi)->vector)
00133 #define xnarch_fault_code(fi)  ((fi)->errcode)
00134 #define xnarch_fault_pc(fi)    ((fi)->regs->eip)
00135 
00136 #ifdef __cplusplus
00137 extern "C" {
00138 #endif
00139 
00140 static inline unsigned long long xnarch_tsc_to_ns (unsigned long long ts) {
00141     return xnarch_llimd(ts,1000000000,RTAI_CPU_FREQ);
00142 }
00143 
00144 static inline unsigned long long xnarch_ns_to_tsc (unsigned long long ns) {
00145     return xnarch_llimd(ns,RTAI_CPU_FREQ,1000000000);
00146 }
00147 
00148 static inline unsigned long long xnarch_get_cpu_time (void) {
00149     return xnarch_tsc_to_ns(xnarch_get_cpu_tsc());
00150 }
00151 
00152 static inline unsigned long long xnarch_get_cpu_freq (void) {
00153     return RTAI_CPU_FREQ;
00154 }
00155 
00156 #define xnarch_halt(emsg) \
00157 do { \
00158     adeos_set_printk_sync(adp_current); \
00159     xnarch_printf("Xenomai: fatal: %s\n",emsg); \
00160     BUG(); \
00161 } while(0)
00162 
00163 int xnarch_setimask(int imask);
00164 
00165 #ifdef XENO_INTR_MODULE
00166 
00167 static inline int xnarch_hook_irq (unsigned irq,
00168                                    void (*handler)(unsigned irq,
00169                                                    void *cookie),
00170                                    void *cookie)
00171 {
00172     int err = rt_request_irq(irq,handler,cookie);
00173 
00174     if (!err)
00175         rt_enable_irq(irq);
00176 
00177     return err;
00178 }
00179 
00180 static inline int xnarch_release_irq (unsigned irq) {
00181 
00182     return rt_release_irq(irq);
00183 }
00184 
00185 static inline int xnarch_enable_irq (unsigned irq)
00186 
00187 {
00188     if (irq >= XNARCH_IRQ_MAX)
00189         return -EINVAL;
00190 
00191     rt_enable_irq(irq);
00192 
00193     return 0;
00194 }
00195 
00196 static inline int xnarch_disable_irq (unsigned irq)
00197 
00198 {
00199     if (irq >= XNARCH_IRQ_MAX)
00200         return -EINVAL;
00201 
00202     rt_disable_irq(irq);
00203 
00204     return 0;
00205 }
00206 
00207 static inline void xnarch_isr_chain_irq (unsigned irq) {
00208     rt_pend_linux_irq(irq);
00209 }
00210 
00211 static inline void xnarch_isr_enable_irq (unsigned irq) {
00212     rt_enable_irq(irq);
00213 }
00214 
00215 #endif /* XENO_INTR_MODULE */
00216 
00217 #ifdef XENO_POD_MODULE
00218 
00219 void xnpod_welcome_thread(struct xnthread *);
00220 
00221 void xnpod_delete_thread(struct xnthread *,
00222                          struct xnmutex *mutex);
00223 
00224 static inline void xnarch_start_timer (int ns, void (*tickhandler)(void))
00225 
00226 {
00227     if (ns > 0) /* Periodic setup. */
00228         {
00229         unsigned period = (unsigned)xnarch_llimd(ns,RTAI_FREQ_8254,1000000000);
00230         rt_request_timer(tickhandler,period > LATCH ? LATCH : period,0);
00231         }
00232     else  /* Aperiodic setup. */
00233         rt_request_timer(tickhandler,0,0);
00234 }
00235 
00236 static inline void xnarch_leave_root (xnarchtcb_t *rootcb)
00237 
00238 {
00239     TRACE_RTAI_SWITCHTO_RT(0);
00240     set_bit(0,&rtai_cpu_realtime);
00241     /* Remember the preempted non-RT task pointer. */
00242     rootcb->user_task = rootcb->active_task = rtai_get_current(0);
00243     /* So that xnarch_save_fpu() will operate on the right FPU area. */
00244     rootcb->fpup = &rootcb->user_task->thread.i387;
00245 }
00246 
00247 static inline void xnarch_enter_root (xnarchtcb_t *rootcb) {
00248     TRACE_RTAI_SWITCHTO_LINUX(0);
00249     clear_bit(0,&rtai_cpu_realtime);
00250 }
00251 
00252 static inline void __switch_threads(xnarchtcb_t *out_tcb,
00253                                     xnarchtcb_t *in_tcb,
00254                                     struct task_struct *outproc,
00255                                     struct task_struct *inproc)
00256 {
00257         __asm__ __volatile__( \
00258         "pushl %%ecx\n\t" \
00259         "pushl %%edi\n\t" \
00260         "pushl %%ebp\n\t" \
00261         "movl %0,%%ecx\n\t" \
00262         "movl %%esp,(%%ecx)\n\t" \
00263         "movl %1,%%ecx\n\t" \
00264         "movl $1f,(%%ecx)\n\t" \
00265         "movl %2,%%ecx\n\t" \
00266         "movl %3,%%edi\n\t" \
00267         "movl (%%ecx),%%esp\n\t" \
00268         "pushl (%%edi)\n\t" \
00269         "testl %%edx,%%edx\n\t" \
00270         "jne  __switch_to\n\t" \
00271         "ret\n\t" \
00272 "1:      popl %%ebp\n\t" \
00273         "popl %%edi\n\t" \
00274         "popl %%ecx\n\t" \
00275       : /* no output */ \
00276       : "m" (out_tcb->espp), \
00277         "m" (out_tcb->eipp), \
00278         "m" (in_tcb->espp), \
00279         "m" (in_tcb->eipp), \
00280         "b" (out_tcb), \
00281         "S" (in_tcb), \
00282         "a" (outproc), \
00283         "d" (inproc));
00284 }
00285 
00286 static inline void xnarch_switch_to (xnarchtcb_t *out_tcb,
00287                                      xnarchtcb_t *in_tcb)
00288 {
00289     struct task_struct *outproc = out_tcb->active_task;
00290     struct task_struct *inproc = in_tcb->user_task;
00291     static int cr0;
00292 
00293     if (out_tcb->user_task)
00294         {
00295         __asm__ __volatile__ ("movl %%cr0,%0": "=r" (cr0));
00296         clts();
00297         }
00298 
00299     in_tcb->active_task = inproc ?: outproc;
00300 
00301     if (inproc && inproc != outproc)
00302         {
00303         struct mm_struct *oldmm = outproc->active_mm;
00304 
00305 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
00306         switch_mm(oldmm,inproc->active_mm,inproc,0);
00307 #else /* >= 2.6.0 */
00308         switch_mm(oldmm,inproc->active_mm,inproc);
00309 #endif /* < 2.6.0 */
00310 
00311         if (!inproc->mm)
00312 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
00313             enter_lazy_tlb(oldmm,inproc,0);
00314 #else /* >= 2.6.0 */
00315             enter_lazy_tlb(oldmm,inproc);
00316 #endif /* < 2.6.0 */
00317         }
00318 
00319     __switch_threads(out_tcb,in_tcb,outproc,inproc);
00320 
00321     /* If TS was set for the restored user-space thread, set it
00322        back. */
00323 
00324     if (out_tcb->user_task && (cr0 & 0x8) != 0)
00325         stts();
00326 }
00327 
00328 static inline void xnarch_finalize_and_switch (xnarchtcb_t *dead_tcb,
00329                                                xnarchtcb_t *next_tcb) {
00330     xnarch_switch_to(dead_tcb,next_tcb);
00331 }
00332 
00333 static inline void xnarch_finalize_no_switch (xnarchtcb_t *dead_tcb) {
00334     /* Empty */
00335 }
00336 
00337 static inline void xnarch_save_fpu (xnarchtcb_t *tcb)
00338 
00339 {
00340 #ifdef CONFIG_RTAI_FPU_SUPPORT
00341 
00342     if (!tcb->user_task) /* __switch_to() will take care otherwise. */
00343         {
00344         if (cpu_has_fxsr)
00345             __asm__ __volatile__ ("fxsave %0; fnclex" : "=m" (*tcb->fpup));
00346         else
00347             __asm__ __volatile__ ("fnsave %0; fwait" : "=m" (*tcb->fpup));
00348         }
00349 
00350 #endif /* CONFIG_RTAI_FPU_SUPPORT */
00351 }
00352 
00353 static inline void xnarch_restore_fpu (xnarchtcb_t *tcb)
00354 
00355 {
00356 #ifdef CONFIG_RTAI_FPU_SUPPORT
00357 
00358     if (tcb->user_task)
00359         {
00360         if (!tcb->user_task->used_math)
00361             return;     /* Uninit fpu area -- do not restore. */
00362 
00363         /* Tell Linux that this task has altered the state of the FPU
00364            hardware. */
00365         set_tsk_used_fpu(tcb->user_task);
00366         }
00367 
00368     /* Restore the FPU hardware with valid fp registers from a
00369        user-space or kernel thread. */
00370 
00371     clts();
00372 
00373     if (cpu_has_fxsr)
00374         __asm__ __volatile__ ("fxrstor %0": /* no output */ : "m" (*tcb->fpup));
00375     else
00376         __asm__ __volatile__ ("frstor %0": /* no output */ : "m" (*tcb->fpup));
00377 
00378 #endif /* CONFIG_RTAI_FPU_SUPPORT */
00379 }
00380 
00381 static inline void xnarch_init_root_tcb (xnarchtcb_t *tcb,
00382                                          struct xnthread *thread,
00383                                          const char *name)
00384 {
00385     tcb->module = THIS_MODULE;
00386     tcb->user_task = current;
00387     tcb->active_task = NULL;
00388     tcb->esp = 0;
00389     tcb->espp = &tcb->esp;
00390     tcb->eipp = &tcb->eip;
00391     tcb->fpup = &current->thread.i387;
00392 }
00393 
00394 static inline void xnarch_init_tcb (xnarchtcb_t *tcb, void *adcookie) {
00395 
00396     tcb->module = (struct module *)adcookie;
00397     tcb->user_task = NULL;
00398     tcb->active_task = NULL;
00399     tcb->espp = &tcb->esp;
00400     tcb->eipp = &tcb->eip;
00401     tcb->fpup = &tcb->fpuenv;
00402     /* Must be followed by xnarch_init_thread(). */
00403 }
00404 
00405 static void xnarch_thread_redirect (struct xnthread *self,
00406                                     int imask,
00407                                     void(*entry)(void *),
00408                                     void *cookie)
00409 {
00410     rtai_local_irq_restore(!!imask);
00411     xnpod_welcome_thread(self);
00412     entry(cookie);
00413     xnpod_delete_thread(self,NULL);
00414 }
00415 
00416 static inline void xnarch_init_thread (xnarchtcb_t *tcb,
00417                                        void (*entry)(void *),
00418                                        void *cookie,
00419                                        int imask,
00420                                        struct xnthread *thread,
00421                                        char *name)
00422 {
00423     unsigned long **psp = (unsigned long **)&tcb->esp;
00424 
00425     tcb->eip = (unsigned long)&xnarch_thread_redirect;
00426     tcb->esp = (unsigned long)tcb->stackbase;
00427     **psp = 0;  /* Commit bottom stack memory */
00428     *psp = (unsigned long *)(((unsigned long)*psp + tcb->stacksize - 0x10) & ~0xf);
00429     *--(*psp) = (unsigned long)cookie;
00430     *--(*psp) = (unsigned long)entry;
00431     *--(*psp) = (unsigned long)imask;
00432     *--(*psp) = (unsigned long)thread;
00433     *--(*psp) = 0;
00434 }
00435 
00436 #ifdef CONFIG_RTAI_FPU_SUPPORT
00437 
00438 static inline void xnarch_init_fpu (xnarchtcb_t *tcb)
00439 
00440 {
00441     /* Initialize the FPU for an emerging kernel-based RT thread. This
00442        must be run on behalf of the emerging thread. */
00443 
00444     __asm__ __volatile__ ("clts; fninit");
00445 
00446     if (cpu_has_xmm)
00447         load_mxcsr(0x1f80);
00448 }
00449 
00450 #else /* !CONFIG_RTAI_FPU_SUPPORT */
00451 
00452 static inline void xnarch_init_fpu (xnarchtcb_t *tcb) {
00453 }
00454 
00455 #endif /* CONFIG_RTAI_FPU_SUPPORT */
00456 
00457 int xnarch_setimask (int imask)
00458 
00459 {
00460     spl_t s;
00461     splhigh(s);
00462     splexit(!!imask);
00463     return !!s;
00464 }
00465 
00466 static inline void xnarch_relay_tick (void) {
00467 
00468     rt_pend_linux_irq(RTAI_TIMER_8254_IRQ);
00469 }
00470 
00471 #define xnarch_notify_ready() /* Nullified */
00472 
00473 #endif /* XENO_POD_MODULE */
00474 
00475 #ifdef XENO_SHADOW_MODULE
00476 
00477 static inline void xnarch_init_shadow_tcb (xnarchtcb_t *tcb,
00478                                            struct xnthread *thread,
00479                                            const char *name)
00480 {
00481     struct task_struct *task = current;
00482 
00483     tcb->module = THIS_MODULE;
00484     tcb->user_task = task;
00485     tcb->active_task = NULL;
00486     tcb->esp = 0;
00487     tcb->espp = &task->thread.esp;
00488     tcb->eipp = &task->thread.eip;
00489     tcb->fpup = &task->thread.i387;
00490 }
00491 
00492 #endif /* XENO_SHADOW_MODULE */
00493 
00494 #ifdef XENO_HEAP_MODULE
00495 
00496 void *xnarch_sysalloc (unsigned bytes) {
00497 
00498     return kmalloc(bytes,GFP_ATOMIC);
00499 }
00500 
00501 void xnarch_sysfree (void *chunk, unsigned bytes) {
00502 
00503     kfree(chunk);
00504 }
00505 
00506 #else /* !XENO_HEAP_MODULE */
00507 
00508 void *xnarch_sysalloc(unsigned bytes);
00509 
00510 void xnarch_sysfree(void *chunk,
00511                     unsigned bytes);
00512 
00513 #endif /* XENO_HEAP_MODULE */
00514 
00515 #ifdef XENO_TIMER_MODULE
00516 
00517 static unsigned long xnarch_timer_calibration;
00518 
00519 void xnarch_calibrate_timer (void) {
00520     /* Compute the time needed to program the 8254 PIT in aperiodic
00521        mode. The stored value is expressed in CPU ticks. */
00522     xnarch_timer_calibration = xnarch_ns_to_tsc(rtai_calibrate_8254());
00523 }
00524 
00525 static void xnarch_program_timer_shot (unsigned long long delay) /* <= in CPU ticks */
00526 
00527 {
00528     if (delay < xnarch_timer_calibration)
00529         /* If the delay value is lower than the time needed to program
00530            the PIT, increase it to a sane minimum so that we don't
00531            lose a tick. */
00532         delay = xnarch_timer_calibration;
00533 
00534     rt_set_timer_delay(rtai_imuldiv(delay,RTAI_FREQ_8254,RTAI_CPU_FREQ));
00535 }
00536 
00537 static inline void xnarch_stop_timer (void) {
00538     rt_free_timer();
00539 }
00540 
00541 #endif /* XENO_TIMER_MODULE */
00542 
00543 #ifdef XENO_MAIN_MODULE
00544 
00545 int xnpod_trap_fault(xnarch_fltinfo_t *fltinfo);
00546 
00547 void xnarch_calibrate_timer(void);
00548 
00549 static RT_TRAP_HANDLER xnarch_old_trap_handler;
00550 
00551 static int xnarch_trap_fault (int vector,
00552                               int signo,
00553                               struct pt_regs *regs,
00554                               void *dummy)
00555 {
00556     xnarch_fltinfo_t fltinfo;
00557 
00558     fltinfo.vector = vector;
00559     fltinfo.errcode = regs->orig_eax;
00560     fltinfo.regs = regs;
00561 
00562     return xnpod_trap_fault(&fltinfo);
00563 }
00564 
00565 static inline int xnarch_init (void)
00566 
00567 {
00568     xnarch_old_trap_handler = rt_set_trap_handler(&xnarch_trap_fault);
00569     xnarch_calibrate_timer();
00570     return xnshadow_init();
00571 }
00572 
00573 static inline void xnarch_exit (void) {
00574 
00575     xnshadow_cleanup();
00576     rt_set_trap_handler(xnarch_old_trap_handler);
00577 }
00578 
00579 #endif /* XENO_MAIN_MODULE */
00580 
00581 #ifdef __cplusplus
00582 }
00583 #endif
00584 
00585 /* Dashboard and graph control. */
00586 #define XNARCH_DECL_DISPLAY_CONTEXT();
00587 #define xnarch_init_display_context(obj)
00588 #define xnarch_create_display(obj,name,tag)
00589 #define xnarch_delete_display(obj)
00590 #define xnarch_post_graph(obj,state)
00591 #define xnarch_post_graph_if(obj,state,cond)
00592 
00593 #endif /* !_RTAI_ASM_I386_XENO_H */

Generated on Sat Jul 24 19:36:02 2004 for RTAI API by doxygen 1.3.4