hal.h

Go to the documentation of this file.
00001 
00039 #ifndef _RTAI_ASM_I386_HAL_H
00040 #define _RTAI_ASM_I386_HAL_H
00041 
00042 #include <nucleus/asm-generic/hal.h>    /* Read the generic bits. */
00043 
00044 typedef unsigned long long rthal_time_t;
00045 
00046 #define __rthal_u64tou32(ull, h, l) ({          \
00047     unsigned long long _ull = (ull);            \
00048     (l) = _ull & 0xffffffff;                    \
00049     (h) = _ull >> 32;                           \
00050 })
00051 
00052 #define __rthal_u64fromu32(h, l) ({             \
00053     unsigned long long _ull;                    \
00054     asm ( "": "=A"(_ull) : "d"(h), "a"(l));     \
00055     _ull;                                       \
00056 })
00057 
00058 /* Fast longs multiplication. */
00059 static inline __attribute_const__ unsigned long long
00060 rthal_ullmul(unsigned long m1, unsigned long m2) {
00061     /* Gcc (at least for versions 2.95 and higher) optimises correctly here. */
00062     return (unsigned long long) m1 * m2;
00063 }
00064 
00065 /* const helper for rthal_uldivrem, so that the compiler will eliminate
00066    multiple calls with same arguments, at no additionnal cost. */
00067 static inline __attribute_const__ unsigned long long
00068 __rthal_uldivrem(const unsigned long long ull, const unsigned long d) {
00069 
00070     unsigned long long ret;
00071     __asm__ ("divl %1" : "=A,A"(ret) : "r,?m"(d), "A,A"(ull));
00072     /* Exception if quotient does not fit on unsigned long. */
00073     return ret;
00074 }
00075 
00076 static inline __attribute_const__ int rthal_imuldiv (const int i,
00077                                                      const int mult,
00078                                                      const int div) {
00079 
00080     /* Returns (unsigned)i =
00081                (unsigned long long)i*(unsigned)(mult)/(unsigned)div. */
00082     const unsigned long ui = (const unsigned long) i;
00083     const unsigned long um = (const unsigned long) mult;
00084     return __rthal_uldivrem((const unsigned long long) ui * um, div);
00085 }
00086 
00087 /* Fast long long division: when the quotient and remainder fit on 32 bits.
00088    Recent compilers remove redundant calls to this function. */
00089 static inline unsigned long rthal_uldivrem(unsigned long long ull,
00090                                            const unsigned long d,
00091                                            unsigned long *const rp) {
00092 
00093     unsigned long q, r;
00094     ull = __rthal_uldivrem(ull, d);
00095     __asm__ ( "": "=d"(r), "=a"(q) : "A"(ull));
00096     if(rp)
00097         *rp = r;
00098     return q;
00099 }
00100 
00101 
00102 /* Division of an unsigned 96 bits ((h << 32) + l) by an unsigned 32 bits.
00103    Common building block for ulldiv and llimd. */
00104 static inline unsigned long long __rthal_div96by32 (const unsigned long long h,
00105                                                     const unsigned long l,
00106                                                     const unsigned long d,
00107                                                     unsigned long *const rp) {
00108 
00109     u_long rh;
00110     const u_long qh = rthal_uldivrem(h, d, &rh);
00111     const unsigned long long t = __rthal_u64fromu32(rh, l);
00112     const u_long ql = rthal_uldivrem(t, d, rp);
00113 
00114     return __rthal_u64fromu32(qh, ql);
00115 }
00116 
00117 
00118 /* Slow long long division. Uses rthal_uldivrem, hence has the same property:
00119    the compiler removes redundant calls. */
00120 static inline unsigned long long rthal_ulldiv (const unsigned long long ull,
00121                                                const unsigned long d,
00122                                                unsigned long *const rp) {
00123 
00124     unsigned long h, l;
00125     __rthal_u64tou32(ull, h, l);
00126     return __rthal_div96by32(h, l, d, rp);
00127 }
00128 
00129 /* Replaced the helper with rthal_ulldiv. */
00130 #define rthal_u64div32c rthal_ulldiv
00131 
00132 static inline __attribute_const__
00133 unsigned long long __rthal_ullimd (const unsigned long long op,
00134                                    const unsigned long m,
00135                                    const unsigned long d) {
00136 
00137     unsigned long long th, tl;
00138     u_long oph, opl, tlh, tll;
00139 
00140     __rthal_u64tou32(op, oph, opl);
00141     tl = (unsigned long long) opl * m;
00142     __rthal_u64tou32(tl, tlh, tll);
00143     th = (unsigned long long) oph * m;
00144     /* op * m == ((th + tlh) << 32) + tll */
00145 
00146     __asm__ (  "addl %1, %%eax\n\t"
00147                "adcl $0, %%edx"
00148                : "=A,A"(th)
00149                : "r,?m"(tlh), "A,A"(th) );
00150     /* op * m == (th << 32) + tll */
00151 
00152     return __rthal_div96by32(th, tll, d, NULL);
00153 }
00154 
00155 static inline __attribute_const__ long long rthal_llimd (const long long op,
00156                                                          const unsigned long m,
00157                                                          const unsigned long d) {
00158 
00159     if(op < 0LL)
00160         return -__rthal_ullimd(-op, m, d);
00161     return __rthal_ullimd(op, m, d);
00162 }
00163 
00164 static inline __attribute_const__ unsigned long ffnz (unsigned long ul) {
00165     /* Derived from bitops.h's ffs() */
00166     __asm__("bsfl %1, %0"
00167             : "=r,r" (ul)
00168             : "r,?m"  (ul));
00169     return ul;
00170 }
00171 
00172 #if defined(__KERNEL__) && !defined(__cplusplus)
00173 #include <asm/system.h>
00174 #include <asm/io.h>
00175 #include <asm/timex.h>
00176 #include <nucleus/asm/atomic.h>
00177 #include <asm/processor.h>
00178 #include <io_ports.h>
00179 #ifdef CONFIG_X86_LOCAL_APIC
00180 #include <asm/fixmap.h>
00181 #include <asm/apic.h>
00182 #endif /* CONFIG_X86_LOCAL_APIC */
00183 
00184 #define RTHAL_8254_IRQ    0
00185 
00186 #ifdef CONFIG_X86_LOCAL_APIC
00187 #define RTHAL_APIC_TIMER_VECTOR    ADEOS_SERVICE_VECTOR3
00188 #define RTHAL_APIC_TIMER_IPI       ADEOS_SERVICE_IPI3
00189 #define RTHAL_APIC_ICOUNT          ((RTHAL_TIMER_FREQ + HZ/2)/HZ)
00190 #endif /* CONFIG_X86_LOCAL_APIC */
00191 
00192 #define rthal_irq_descp(irq)  (irq_desc + irq)
00193 
00194 #ifdef CONFIG_X86_TSC
00195 static inline unsigned long long rthal_rdtsc (void) {
00196     unsigned long long t;
00197     __asm__ __volatile__( "rdtsc" : "=A" (t));
00198     return t;
00199 }
00200 #else  /* !CONFIG_X86_TSC */
00201 #define RTHAL_8254_COUNT2LATCH  0xfffe
00202 void rthal_setup_8254_tsc(void);
00203 rthal_time_t rthal_get_8254_tsc(void);
00204 #define rthal_rdtsc() rthal_get_8254_tsc()
00205 #endif /* CONFIG_X86_TSC */
00206 
00207 #if !defined(CONFIG_ADEOS_NOTHREADS)
00208 
00209 /* Since real-time interrupt handlers are called on behalf of the RTAI
00210    domain stack, we cannot infere the "current" Linux task address
00211    using %esp. We must use the suspended Linux domain's stack pointer
00212    instead. */
00213 
00214 static inline struct task_struct *rthal_root_host_task (int cpuid) {
00215     u_long stack = (u_long)adp_root->esp[cpuid] & ~(THREAD_SIZE - 1);
00216     return ((struct thread_info *)(stack))->task;
00217 }
00218 
00219 static inline struct task_struct *rthal_current_host_task (int cpuid)
00220 
00221 {
00222     int *esp;
00223 
00224     __asm__ ("movl %%esp, %0" : "=r,?m" (esp));
00225 
00226     if (esp >= rthal_domain.estackbase[cpuid] && esp < rthal_domain.estackbase[cpuid] + 2048)
00227         return rthal_root_host_task(cpuid);
00228 
00229     return get_current();
00230 }
00231 
00232 #else /* CONFIG_ADEOS_NOTHREADS */
00233 
00234 static inline struct task_struct *rthal_root_host_task (int cpuid) {
00235     return current;
00236 }
00237 
00238 static inline struct task_struct *rthal_current_host_task (int cpuid) {
00239     return current;
00240 }
00241 
00242 #endif /* !CONFIG_ADEOS_NOTHREADS */
00243 
00244 static inline void rthal_timer_program_shot (unsigned long delay)
00245 {
00246     unsigned long flags;
00247     /* Neither the 8254 nor most APICs won't trigger any interrupt
00248        upon receiving a null timer count, so don't let this
00249        happen. --rpm */
00250     if(!delay) delay = 1;
00251     rthal_hw_lock(flags);
00252 #ifdef CONFIG_X86_LOCAL_APIC
00253     /* Note: reading before writing just to work around the Pentium
00254        APIC double write bug. apic_read_around() expands to nil
00255        whenever CONFIG_X86_GOOD_APIC is set. --rpm */
00256     apic_read_around(APIC_LVTT);
00257     apic_write_around(APIC_LVTT,RTHAL_APIC_TIMER_VECTOR);
00258     apic_read_around(APIC_TMICT);
00259     apic_write_around(APIC_TMICT,delay);
00260 #else /* !CONFIG_X86_LOCAL_APIC */
00261     outb(delay & 0xff,0x40);
00262     outb(delay >> 8,0x40);
00263 #endif /* CONFIG_X86_LOCAL_APIC */
00264     rthal_hw_unlock(flags);
00265 }
00266 
00267 static const char *const rthal_fault_labels[] = {
00268     [0] = "Divide error",
00269     [1] = "Debug",
00270     [2] = "",   /* NMI is not pipelined. */
00271     [3] = "Int3",
00272     [4] = "Overflow",
00273     [5] = "Bounds",
00274     [6] = "Invalid opcode",
00275     [7] = "FPU not available",
00276     [8] = "Double fault",
00277     [9] = "FPU segment overrun",
00278     [10] = "Invalid TSS",
00279     [11] = "Segment not present",
00280     [12] = "Stack segment",
00281     [13] = "General protection",
00282     [14] = "Page fault",
00283     [15] = "Spurious interrupt",
00284     [16] = "FPU error",
00285     [17] = "Alignment check",
00286     [18] = "Machine check",
00287     [19] = "SIMD error",
00288     [20] = NULL,
00289 };
00290 
00291 #endif /* __KERNEL__ && !__cplusplus */
00292 
00295 #endif /* !_RTAI_ASM_I386_HAL_H */

Generated on Wed Jun 22 22:54:01 2005 for RTAI Fusion API by  doxygen 1.4.1