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