1 #ifndef X86_64_PDA_H
2 #define X86_64_PDA_H
3 
4 #include <linux/cache.h>
5 
6 /* Per processor datastructure. %gs points to it while the kernel runs */
7 /* To use a new field with the *_pda macros it needs to be added to tools/offset.c */
8 struct x8664_pda {
9 	unsigned long kernelstack;  /* TOS for current process */
10 	unsigned long oldrsp; 	    /* user rsp for system call */
11 	unsigned long irqrsp;	    /* Old rsp for interrupts. */
12 	struct task_struct *pcurrent;	/* Current process */
13         int irqcount;		    /* Irq nesting counter. Starts with -1 */
14 	int cpunumber;		    /* Logical CPU number */
15 	/* XXX: could be a single list */
16 	unsigned long *pgd_quick;
17 	unsigned long *pmd_quick;
18 	unsigned long *pte_quick;
19 	unsigned long pgtable_cache_sz;
20 	char *irqstackptr;	/* top of irqstack */
21 	unsigned long volatile *level4_pgt;
22 } ____cacheline_aligned;
23 
24 #define PDA_STACKOFFSET (5*8)
25 
26 #define IRQSTACK_ORDER 2
27 #define IRQSTACKSIZE (PAGE_SIZE << IRQSTACK_ORDER)
28 
29 extern struct x8664_pda cpu_pda[];
30 
31 /*
32  * There is no fast way to get the base address of the PDA, all the accesses
33  * have to mention %fs/%gs.  So it needs to be done this Torvaldian way.
34  */
35 #define sizeof_field(type,field)  (sizeof(((type *)0)->field))
36 #define typeof_field(type,field)  typeof(((type *)0)->field)
37 
38 extern void __bad_pda_field(void);
39 /* Don't use offsetof because it requires too much infrastructure */
40 #define pda_offset(field) ((unsigned long)&((struct x8664_pda *)0)->field)
41 
42 #define pda_to_op(op,field,val) do { \
43        switch (sizeof_field(struct x8664_pda, field)) { 		\
44        case 2: asm volatile(op "w %0,%%gs:%P1" :: "r" (val), "i"(pda_offset(field)):"memory"); break;	\
45        case 4: asm volatile(op "l %0,%%gs:%P1" :: "r" (val), "i"(pda_offset(field)):"memory"); break;	\
46        case 8: asm volatile(op "q %0,%%gs:%P1" :: "r" (val), "i"(pda_offset(field)):"memory"); break;	\
47        default: __bad_pda_field(); 					\
48        } \
49        } while (0)
50 
51 
52 #define pda_from_op(op,field) ({ \
53        typedef typeof_field(struct x8664_pda, field) T__; T__ ret__; \
54        switch (sizeof_field(struct x8664_pda, field)) { 		\
55        case 2: asm volatile(op "w %%gs:%P1,%0":"=r" (ret__): "i" (pda_offset(field)):"memory"); break;	\
56        case 4: asm volatile(op "l %%gs:%P1,%0":"=r" (ret__): "i" (pda_offset(field)):"memory"); break;	\
57        case 8: asm volatile(op "q %%gs:%P1,%0":"=r" (ret__): "i" (pda_offset(field)):"memory"); break;	\
58        default: __bad_pda_field(); 					\
59        } \
60        ret__; })
61 
62 
63 #define read_pda(field) pda_from_op("mov",field)
64 #define write_pda(field,val) pda_to_op("mov",field,val)
65 #define add_pda(field,val) pda_to_op("add",field,val)
66 #define sub_pda(field,val) pda_to_op("sub",field,val)
67 
68 #endif
69