linux-old/include/asm-i386/system.h
<<
>>
Prefs
   1#ifndef __ASM_SYSTEM_H
   2#define __ASM_SYSTEM_H
   3
   4#include <linux/config.h>
   5#include <linux/kernel.h>
   6#include <asm/segment.h>
   7#include <linux/bitops.h> /* for LOCK_PREFIX */
   8
   9#ifdef __KERNEL__
  10
  11struct task_struct;     /* one of the stranger aspects of C forward declarations.. */
  12extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next));
  13
  14#define prepare_to_switch()     do { } while(0)
  15#define switch_to(prev,next,last) do {                                  \
  16        asm volatile("pushl %%esi\n\t"                                  \
  17                     "pushl %%edi\n\t"                                  \
  18                     "pushl %%ebp\n\t"                                  \
  19                     "movl %%esp,%0\n\t"        /* save ESP */          \
  20                     "movl %3,%%esp\n\t"        /* restore ESP */       \
  21                     "movl $1f,%1\n\t"          /* save EIP */          \
  22                     "pushl %4\n\t"             /* restore EIP */       \
  23                     "jmp __switch_to\n"                                \
  24                     "1:\t"                                             \
  25                     "popl %%ebp\n\t"                                   \
  26                     "popl %%edi\n\t"                                   \
  27                     "popl %%esi\n\t"                                   \
  28                     :"=m" (prev->thread.esp),"=m" (prev->thread.eip),  \
  29                      "=b" (last)                                       \
  30                     :"m" (next->thread.esp),"m" (next->thread.eip),    \
  31                      "a" (prev), "d" (next),                           \
  32                      "b" (prev));                                      \
  33} while (0)
  34
  35#define _set_base(addr,base) do { unsigned long __pr; \
  36__asm__ __volatile__ ("movw %%dx,%1\n\t" \
  37        "rorl $16,%%edx\n\t" \
  38        "movb %%dl,%2\n\t" \
  39        "movb %%dh,%3" \
  40        :"=&d" (__pr) \
  41        :"m" (*((addr)+2)), \
  42         "m" (*((addr)+4)), \
  43         "m" (*((addr)+7)), \
  44         "0" (base) \
  45        ); } while(0)
  46
  47#define _set_limit(addr,limit) do { unsigned long __lr; \
  48__asm__ __volatile__ ("movw %%dx,%1\n\t" \
  49        "rorl $16,%%edx\n\t" \
  50        "movb %2,%%dh\n\t" \
  51        "andb $0xf0,%%dh\n\t" \
  52        "orb %%dh,%%dl\n\t" \
  53        "movb %%dl,%2" \
  54        :"=&d" (__lr) \
  55        :"m" (*(addr)), \
  56         "m" (*((addr)+6)), \
  57         "0" (limit) \
  58        ); } while(0)
  59
  60#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) )
  61#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , ((limit)-1)>>12 )
  62
  63static inline unsigned long _get_base(char * addr)
  64{
  65        unsigned long __base;
  66        __asm__("movb %3,%%dh\n\t"
  67                "movb %2,%%dl\n\t"
  68                "shll $16,%%edx\n\t"
  69                "movw %1,%%dx"
  70                :"=&d" (__base)
  71                :"m" (*((addr)+2)),
  72                 "m" (*((addr)+4)),
  73                 "m" (*((addr)+7)));
  74        return __base;
  75}
  76
  77#define get_base(ldt) _get_base( ((char *)&(ldt)) )
  78
  79/*
  80 * Load a segment. Fall back on loading the zero
  81 * segment if something goes wrong..
  82 */
  83#define loadsegment(seg,value)                  \
  84        asm volatile("\n"                       \
  85                "1:\t"                          \
  86                "movl %0,%%" #seg "\n"          \
  87                "2:\n"                          \
  88                ".section .fixup,\"ax\"\n"      \
  89                "3:\t"                          \
  90                "pushl $0\n\t"                  \
  91                "popl %%" #seg "\n\t"           \
  92                "jmp 2b\n"                      \
  93                ".previous\n"                   \
  94                ".section __ex_table,\"a\"\n\t" \
  95                ".align 4\n\t"                  \
  96                ".long 1b,3b\n"                 \
  97                ".previous"                     \
  98                : :"m" (*(unsigned int *)&(value)))
  99
 100/*
 101 * Clear and set 'TS' bit respectively
 102 */
 103#define clts() __asm__ __volatile__ ("clts")
 104#define read_cr0() ({ \
 105        unsigned int __dummy; \
 106        __asm__( \
 107                "movl %%cr0,%0\n\t" \
 108                :"=r" (__dummy)); \
 109        __dummy; \
 110})
 111#define write_cr0(x) \
 112        __asm__("movl %0,%%cr0": :"r" (x));
 113#define stts() write_cr0(8 | read_cr0())
 114
 115#endif  /* __KERNEL__ */
 116
 117static inline unsigned long get_limit(unsigned long segment)
 118{
 119        unsigned long __limit;
 120        __asm__("lsll %1,%0"
 121                :"=r" (__limit):"r" (segment));
 122        return __limit+1;
 123}
 124
 125#define nop() __asm__ __volatile__ ("nop")
 126
 127#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
 128
 129#define tas(ptr) (xchg((ptr),1))
 130
 131struct __xchg_dummy { unsigned long a[100]; };
 132#define __xg(x) ((struct __xchg_dummy *)(x))
 133
 134
 135/*
 136 * The semantics of XCHGCMP8B are a bit strange, this is why
 137 * there is a loop and the loading of %%eax and %%edx has to
 138 * be inside. This inlines well in most cases, the cached
 139 * cost is around ~38 cycles. (in the future we might want
 140 * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
 141 * might have an implicit FPU-save as a cost, so it's not
 142 * clear which path to go.)
 143 */
 144extern inline void __set_64bit (unsigned long long * ptr,
 145                unsigned int low, unsigned int high)
 146{
 147__asm__ __volatile__ (
 148        "1:     movl (%0), %%eax;
 149                movl 4(%0), %%edx;
 150                cmpxchg8b (%0);
 151                jnz 1b"
 152        ::              "D"(ptr),
 153                        "b"(low),
 154                        "c"(high)
 155        :
 156                        "ax","dx","memory");
 157}
 158
 159extern void inline __set_64bit_constant (unsigned long long *ptr,
 160                                                 unsigned long long value)
 161{
 162        __set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
 163}
 164#define ll_low(x)       *(((unsigned int*)&(x))+0)
 165#define ll_high(x)      *(((unsigned int*)&(x))+1)
 166
 167extern void inline __set_64bit_var (unsigned long long *ptr,
 168                         unsigned long long value)
 169{
 170        __set_64bit(ptr,ll_low(value), ll_high(value));
 171}
 172
 173#define set_64bit(ptr,value) \
 174(__builtin_constant_p(value) ? \
 175 __set_64bit_constant(ptr, value) : \
 176 __set_64bit_var(ptr, value) )
 177
 178#define _set_64bit(ptr,value) \
 179(__builtin_constant_p(value) ? \
 180 __set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \
 181 __set_64bit(ptr, ll_low(value), ll_high(value)) )
 182
 183/*
 184 * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
 185 * Note 2: xchg has side effect, so that attribute volatile is necessary,
 186 *        but generally the primitive is invalid, *ptr is output argument. --ANK
 187 */
 188static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
 189{
 190        switch (size) {
 191                case 1:
 192                        __asm__ __volatile__("xchgb %b0,%1"
 193                                :"=q" (x)
 194                                :"m" (*__xg(ptr)), "0" (x)
 195                                :"memory");
 196                        break;
 197                case 2:
 198                        __asm__ __volatile__("xchgw %w0,%1"
 199                                :"=r" (x)
 200                                :"m" (*__xg(ptr)), "0" (x)
 201                                :"memory");
 202                        break;
 203                case 4:
 204                        __asm__ __volatile__("xchgl %0,%1"
 205                                :"=r" (x)
 206                                :"m" (*__xg(ptr)), "0" (x)
 207                                :"memory");
 208                        break;
 209        }
 210        return x;
 211}
 212
 213/*
 214 * Atomic compare and exchange.  Compare OLD with MEM, if identical,
 215 * store NEW in MEM.  Return the initial value in MEM.  Success is
 216 * indicated by comparing RETURN with OLD.
 217 */
 218
 219#ifdef CONFIG_X86_CMPXCHG
 220#define __HAVE_ARCH_CMPXCHG 1
 221
 222static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 223                                      unsigned long new, int size)
 224{
 225        unsigned long prev;
 226        switch (size) {
 227        case 1:
 228                __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
 229                                     : "=a"(prev)
 230                                     : "q"(new), "m"(*__xg(ptr)), "0"(old)
 231                                     : "memory");
 232                return prev;
 233        case 2:
 234                __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
 235                                     : "=a"(prev)
 236                                     : "q"(new), "m"(*__xg(ptr)), "0"(old)
 237                                     : "memory");
 238                return prev;
 239        case 4:
 240                __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
 241                                     : "=a"(prev)
 242                                     : "q"(new), "m"(*__xg(ptr)), "0"(old)
 243                                     : "memory");
 244                return prev;
 245        }
 246        return old;
 247}
 248
 249#define cmpxchg(ptr,o,n)\
 250        ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
 251                                        (unsigned long)(n),sizeof(*(ptr))))
 252    
 253#else
 254/* Compiling for a 386 proper.  Is it worth implementing via cli/sti?  */
 255#endif
 256
 257/*
 258 * Force strict CPU ordering.
 259 * And yes, this is required on UP too when we're talking
 260 * to devices.
 261 *
 262 * For now, "wmb()" doesn't actually do anything, as all
 263 * Intel CPU's follow what Intel calls a *Processor Order*,
 264 * in which all writes are seen in the program order even
 265 * outside the CPU.
 266 *
 267 * I expect future Intel CPU's to have a weaker ordering,
 268 * but I'd also expect them to finally get their act together
 269 * and add some real memory barriers if so.
 270 *
 271 * The Pentium III does add a real memory barrier with the
 272 * sfence instruction, so we use that where appropriate.
 273 */
 274#ifndef CONFIG_X86_XMM
 275#define mb()    __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
 276#else
 277#define mb()    __asm__ __volatile__ ("sfence": : :"memory")
 278#endif
 279#define rmb()   mb()
 280#define wmb()   __asm__ __volatile__ ("": : :"memory")
 281
 282#ifdef CONFIG_SMP
 283#define smp_mb()        mb()
 284#define smp_rmb()       rmb()
 285#define smp_wmb()       wmb()
 286#else
 287#define smp_mb()        barrier()
 288#define smp_rmb()       barrier()
 289#define smp_wmb()       barrier()
 290#endif
 291
 292#define set_mb(var, value) do { xchg(&var, value); } while (0)
 293#define set_wmb(var, value) do { var = value; wmb(); } while (0)
 294
 295/* interrupt control.. */
 296#define __save_flags(x)         __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
 297#define __restore_flags(x)      __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
 298#define __cli()                 __asm__ __volatile__("cli": : :"memory")
 299#define __sti()                 __asm__ __volatile__("sti": : :"memory")
 300/* used in the idle loop; sti takes one instruction cycle to complete */
 301#define safe_halt()             __asm__ __volatile__("sti; hlt": : :"memory")
 302
 303/* For spinlocks etc */
 304#define local_irq_save(x)       __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
 305#define local_irq_restore(x)    __restore_flags(x)
 306#define local_irq_disable()     __cli()
 307#define local_irq_enable()      __sti()
 308
 309#ifdef CONFIG_SMP
 310
 311extern void __global_cli(void);
 312extern void __global_sti(void);
 313extern unsigned long __global_save_flags(void);
 314extern void __global_restore_flags(unsigned long);
 315#define cli() __global_cli()
 316#define sti() __global_sti()
 317#define save_flags(x) ((x)=__global_save_flags())
 318#define restore_flags(x) __global_restore_flags(x)
 319
 320#else
 321
 322#define cli() __cli()
 323#define sti() __sti()
 324#define save_flags(x) __save_flags(x)
 325#define restore_flags(x) __restore_flags(x)
 326
 327#endif
 328
 329/*
 330 * disable hlt during certain critical i/o operations
 331 */
 332#define HAVE_DISABLE_HLT
 333void disable_hlt(void);
 334void enable_hlt(void);
 335
 336#endif
 337
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.