1 |
1275 |
phoenix |
#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
|