[PATCH] i386: Basic definitions for i386-pda
authorJeremy Fitzhardinge <jeremy@goop.org>
Thu, 7 Dec 2006 01:14:02 +0000 (02:14 +0100)
committerAndi Kleen <andi@basil.nowhere.org>
Thu, 7 Dec 2006 01:14:02 +0000 (02:14 +0100)
This patch has the basic definitions of struct i386_pda, and the segment
selector in the GDT.

asm-i386/pda.h is more or less a direct copy of asm-x86_64/pda.h.  The most
interesting difference is the use of _proxy_pda, which is used to give gcc a
model for the actual memory operations on the real pda structure.  No actual
reference is ever made to _proxy_pda, so it is never defined.

Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Cc: Chuck Ebbert <76306.1226@compuserve.com>
Cc: Zachary Amsden <zach@vmware.com>
Cc: Jan Beulich <jbeulich@novell.com>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
arch/i386/kernel/head.S
include/asm-i386/pda.h [new file with mode: 0644]
include/asm-i386/segment.h

index b1f1df1..4a83384 100644 (file)
@@ -585,7 +585,7 @@ ENTRY(cpu_gdt_table)
        .quad 0x004092000000ffff        /* 0xc8 APM DS    data */
 
        .quad 0x00c0920000000000        /* 0xd0 - ESPFIX SS */
-       .quad 0x0000000000000000        /* 0xd8 - unused */
+       .quad 0x0000000000000000        /* 0xd8 - PDA */
        .quad 0x0000000000000000        /* 0xe0 - unused */
        .quad 0x0000000000000000        /* 0xe8 - unused */
        .quad 0x0000000000000000        /* 0xf0 - unused */
diff --git a/include/asm-i386/pda.h b/include/asm-i386/pda.h
new file mode 100644 (file)
index 0000000..4c39ccb
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+   Per-processor Data Areas
+   Jeremy Fitzhardinge <jeremy@goop.org> 2006
+   Based on asm-x86_64/pda.h by Andi Kleen.
+ */
+#ifndef _I386_PDA_H
+#define _I386_PDA_H
+
+#include <linux/stddef.h>
+
+struct i386_pda
+{
+       struct i386_pda *_pda;          /* pointer to self */
+};
+
+extern struct i386_pda *_cpu_pda[];
+
+#define cpu_pda(i)     (_cpu_pda[i])
+
+#define pda_offset(field) offsetof(struct i386_pda, field)
+
+extern void __bad_pda_field(void);
+
+/* This variable is never instantiated.  It is only used as a stand-in
+   for the real per-cpu PDA memory, so that gcc can understand what
+   memory operations the inline asms() below are performing.  This
+   eliminates the need to make the asms volatile or have memory
+   clobbers, so gcc can readily analyse them. */
+extern struct i386_pda _proxy_pda;
+
+#define pda_to_op(op,field,val)                                                \
+       do {                                                            \
+               typedef typeof(_proxy_pda.field) T__;                   \
+               if (0) { T__ tmp__; tmp__ = (val); }                    \
+               switch (sizeof(_proxy_pda.field)) {                     \
+               case 1:                                                 \
+                       asm(op "b %1,%%gs:%c2"                          \
+                           : "+m" (_proxy_pda.field)                   \
+                           :"ri" ((T__)val),                           \
+                            "i"(pda_offset(field)));                   \
+                       break;                                          \
+               case 2:                                                 \
+                       asm(op "w %1,%%gs:%c2"                          \
+                           : "+m" (_proxy_pda.field)                   \
+                           :"ri" ((T__)val),                           \
+                            "i"(pda_offset(field)));                   \
+                       break;                                          \
+               case 4:                                                 \
+                       asm(op "l %1,%%gs:%c2"                          \
+                           : "+m" (_proxy_pda.field)                   \
+                           :"ri" ((T__)val),                           \
+                            "i"(pda_offset(field)));                   \
+                       break;                                          \
+               default: __bad_pda_field();                             \
+               }                                                       \
+       } while (0)
+
+#define pda_from_op(op,field)                                          \
+       ({                                                              \
+               typeof(_proxy_pda.field) ret__;                         \
+               switch (sizeof(_proxy_pda.field)) {                     \
+               case 1:                                                 \
+                       asm(op "b %%gs:%c1,%0"                          \
+                           : "=r" (ret__)                              \
+                           : "i" (pda_offset(field)),                  \
+                             "m" (_proxy_pda.field));                  \
+                       break;                                          \
+               case 2:                                                 \
+                       asm(op "w %%gs:%c1,%0"                          \
+                           : "=r" (ret__)                              \
+                           : "i" (pda_offset(field)),                  \
+                             "m" (_proxy_pda.field));                  \
+                       break;                                          \
+               case 4:                                                 \
+                       asm(op "l %%gs:%c1,%0"                          \
+                           : "=r" (ret__)                              \
+                           : "i" (pda_offset(field)),                  \
+                             "m" (_proxy_pda.field));                  \
+                       break;                                          \
+               default: __bad_pda_field();                             \
+               }                                                       \
+               ret__; })
+
+/* Return a pointer to a pda field */
+#define pda_addr(field)                                                        \
+       ((typeof(_proxy_pda.field) *)((unsigned char *)read_pda(_pda) + \
+                                     pda_offset(field)))
+
+#define read_pda(field) pda_from_op("mov",field)
+#define write_pda(field,val) pda_to_op("mov",field,val)
+#define add_pda(field,val) pda_to_op("add",field,val)
+#define sub_pda(field,val) pda_to_op("sub",field,val)
+#define or_pda(field,val) pda_to_op("or",field,val)
+
+#endif /* _I386_PDA_H */
index b7ab596..5bdda79 100644 (file)
@@ -39,7 +39,7 @@
  *  25 - APM BIOS support 
  *
  *  26 - ESPFIX small SS
- *  27 - unused
+ *  27 - PDA                           [ per-cpu private data area ]
  *  28 - unused
  *  29 - unused
  *  30 - unused
@@ -74,6 +74,9 @@
 #define GDT_ENTRY_ESPFIX_SS            (GDT_ENTRY_KERNEL_BASE + 14)
 #define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8)
 
+#define GDT_ENTRY_PDA                  (GDT_ENTRY_KERNEL_BASE + 15)
+#define __KERNEL_PDA (GDT_ENTRY_PDA * 8)
+
 #define GDT_ENTRY_DOUBLEFAULT_TSS      31
 
 /*