Commit | Line | Data |
---|---|---|
80fbb69a GOC |
1 | #ifndef _ASM_DESC_H_ |
2 | #define _ASM_DESC_H_ | |
3 | ||
4 | #ifndef __ASSEMBLY__ | |
5 | #include <asm/desc_defs.h> | |
6 | #include <asm/ldt.h> | |
881c2975 | 7 | #include <asm/mmu.h> |
54cd0eac | 8 | #include <linux/smp.h> |
80fbb69a GOC |
9 | |
10 | static inline void fill_ldt(struct desc_struct *desc, struct user_desc *info) | |
11 | { | |
12 | desc->limit0 = info->limit & 0x0ffff; | |
13 | desc->base0 = info->base_addr & 0x0000ffff; | |
14 | ||
15 | desc->base1 = (info->base_addr & 0x00ff0000) >> 16; | |
16 | desc->type = (info->read_exec_only ^ 1) << 1; | |
17 | desc->type |= info->contents << 2; | |
18 | desc->s = 1; | |
19 | desc->dpl = 0x3; | |
20 | desc->p = info->seg_not_present ^ 1; | |
21 | desc->limit = (info->limit & 0xf0000) >> 16; | |
22 | desc->avl = info->useable; | |
23 | desc->d = info->seg_32bit; | |
24 | desc->g = info->limit_in_pages; | |
25 | desc->base2 = (info->base_addr & 0xff000000) >> 24; | |
26 | } | |
27 | ||
881c2975 GOC |
28 | extern struct desc_ptr idt_descr; |
29 | extern gate_desc idt_table[]; | |
80fbb69a | 30 | |
54cd0eac GOC |
31 | #ifdef CONFIG_X86_64 |
32 | extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; | |
33 | extern struct desc_ptr cpu_gdt_descr[]; | |
34 | /* the cpu gdt accessor */ | |
35 | #define get_cpu_gdt_table(x) ((struct desc_struct *)cpu_gdt_descr[x].address) | |
36 | #else | |
37 | struct gdt_page { | |
38 | struct desc_struct gdt[GDT_ENTRIES]; | |
39 | } __attribute__((aligned(PAGE_SIZE))); | |
40 | DECLARE_PER_CPU(struct gdt_page, gdt_page); | |
41 | ||
42 | static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) | |
43 | { | |
44 | return per_cpu(gdt_page, cpu).gdt; | |
45 | } | |
46 | #endif | |
47 | ||
48 | #ifdef CONFIG_PARAVIRT | |
49 | #include <asm/paravirt.h> | |
50 | #else | |
51 | #define load_TR_desc() native_load_tr_desc() | |
52 | #define load_gdt(dtr) native_load_gdt(dtr) | |
53 | #define load_idt(dtr) native_load_idt(dtr) | |
54 | #define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr)) | |
55 | #define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt)) | |
56 | ||
57 | #define store_gdt(dtr) native_store_gdt(dtr) | |
58 | #define store_idt(dtr) native_store_idt(dtr) | |
59 | #define store_tr(tr) (tr = native_store_tr()) | |
60 | #define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt)) | |
61 | ||
62 | #define load_TLS(t, cpu) native_load_tls(t, cpu) | |
63 | #define set_ldt native_set_ldt | |
64 | ||
65 | #define write_ldt_entry(dt, entry, desc) \ | |
66 | native_write_ldt_entry(dt, entry, desc) | |
67 | #define write_gdt_entry(dt, entry, desc, type) \ | |
68 | native_write_gdt_entry(dt, entry, desc, type) | |
69 | #define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g) | |
70 | #endif | |
71 | ||
72 | static inline void native_write_idt_entry(gate_desc *idt, int entry, | |
73 | const gate_desc *gate) | |
74 | { | |
75 | memcpy(&idt[entry], gate, sizeof(*gate)); | |
76 | } | |
77 | ||
78 | static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry, | |
79 | const void *desc) | |
80 | { | |
81 | memcpy(&ldt[entry], desc, 8); | |
82 | } | |
83 | ||
84 | static inline void native_write_gdt_entry(struct desc_struct *gdt, int entry, | |
85 | const void *desc, int type) | |
86 | { | |
87 | unsigned int size; | |
88 | switch (type) { | |
89 | case DESC_TSS: | |
90 | size = sizeof(tss_desc); | |
91 | break; | |
92 | case DESC_LDT: | |
93 | size = sizeof(ldt_desc); | |
94 | break; | |
95 | default: | |
96 | size = sizeof(struct desc_struct); | |
97 | break; | |
98 | } | |
99 | memcpy(&gdt[entry], desc, size); | |
100 | } | |
101 | ||
102 | static inline void set_tssldt_descriptor(struct ldttss_desc64 *d, | |
103 | unsigned long tss, unsigned type, | |
104 | unsigned size) | |
105 | { | |
106 | memset(d, 0, sizeof(*d)); | |
107 | d->limit0 = size & 0xFFFF; | |
108 | d->base0 = PTR_LOW(tss); | |
109 | d->base1 = PTR_MIDDLE(tss) & 0xFF; | |
110 | d->type = type; | |
111 | d->p = 1; | |
112 | d->limit1 = (size >> 16) & 0xF; | |
113 | d->base2 = (PTR_MIDDLE(tss) >> 8) & 0xFF; | |
114 | d->base3 = PTR_HIGH(tss); | |
115 | } | |
116 | ||
117 | static inline void pack_descriptor(struct desc_struct *desc, unsigned long base, | |
118 | unsigned long limit, unsigned char type, | |
119 | unsigned char flags) | |
120 | { | |
121 | desc->a = ((base & 0xffff) << 16) | (limit & 0xffff); | |
122 | desc->b = (base & 0xff000000) | ((base & 0xff0000) >> 16) | | |
123 | (limit & 0x000f0000) | ((type & 0xff) << 8) | | |
124 | ((flags & 0xf) << 20); | |
125 | desc->p = 1; | |
126 | } | |
127 | ||
128 | static inline void pack_ldt(ldt_desc *ldt, unsigned long addr, | |
129 | unsigned size) | |
130 | { | |
131 | ||
132 | #ifdef CONFIG_X86_64 | |
133 | set_tssldt_descriptor(ldt, | |
134 | addr, DESC_LDT, size); | |
135 | #else | |
136 | pack_descriptor(ldt, (unsigned long)addr, | |
137 | size, | |
138 | 0x80 | DESC_LDT, 0); | |
139 | #endif | |
140 | } | |
141 | ||
142 | static inline void native_set_ldt(const void *addr, unsigned int entries) | |
143 | { | |
144 | if (likely(entries == 0)) | |
145 | __asm__ __volatile__("lldt %w0"::"q" (0)); | |
146 | else { | |
147 | unsigned cpu = smp_processor_id(); | |
148 | ldt_desc ldt; | |
149 | ||
150 | pack_ldt(&ldt, (unsigned long)addr, | |
151 | entries * sizeof(ldt) - 1); | |
152 | write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, | |
153 | &ldt, DESC_LDT); | |
154 | __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); | |
155 | } | |
156 | } | |
157 | ||
158 | static inline void native_load_tr_desc(void) | |
159 | { | |
160 | asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); | |
161 | } | |
162 | ||
163 | static inline void native_load_gdt(const struct desc_ptr *dtr) | |
164 | { | |
165 | asm volatile("lgdt %0"::"m" (*dtr)); | |
166 | } | |
167 | ||
168 | static inline void native_load_idt(const struct desc_ptr *dtr) | |
169 | { | |
170 | asm volatile("lidt %0"::"m" (*dtr)); | |
171 | } | |
172 | ||
173 | static inline void native_store_gdt(struct desc_ptr *dtr) | |
174 | { | |
175 | asm volatile("sgdt %0":"=m" (*dtr)); | |
176 | } | |
177 | ||
178 | static inline void native_store_idt(struct desc_ptr *dtr) | |
179 | { | |
180 | asm volatile("sidt %0":"=m" (*dtr)); | |
181 | } | |
182 | ||
183 | static inline unsigned long native_store_tr(void) | |
184 | { | |
185 | unsigned long tr; | |
186 | asm volatile("str %0":"=r" (tr)); | |
187 | return tr; | |
188 | } | |
189 | ||
190 | static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) | |
191 | { | |
192 | unsigned int i; | |
193 | struct desc_struct *gdt = get_cpu_gdt_table(cpu); | |
194 | ||
195 | for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) | |
196 | gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; | |
197 | } | |
198 | ||
96a388de TG |
199 | #ifdef CONFIG_X86_32 |
200 | # include "desc_32.h" | |
201 | #else | |
202 | # include "desc_64.h" | |
203 | #endif | |
80fbb69a | 204 | |
881c2975 GOC |
205 | #define _LDT_empty(info) (\ |
206 | (info)->base_addr == 0 && \ | |
207 | (info)->limit == 0 && \ | |
208 | (info)->contents == 0 && \ | |
209 | (info)->read_exec_only == 1 && \ | |
210 | (info)->seg_32bit == 0 && \ | |
211 | (info)->limit_in_pages == 0 && \ | |
212 | (info)->seg_not_present == 1 && \ | |
213 | (info)->useable == 0) | |
214 | ||
215 | #ifdef CONFIG_X86_64 | |
216 | #define LDT_empty(info) (_LDT_empty(info) && ((info)->lm == 0)) | |
217 | #else | |
218 | #define LDT_empty(info) (_LDT_empty(info)) | |
219 | #endif | |
220 | ||
221 | static inline void clear_LDT(void) | |
222 | { | |
223 | set_ldt(NULL, 0); | |
224 | } | |
225 | ||
226 | /* | |
227 | * load one particular LDT into the current CPU | |
228 | */ | |
229 | static inline void load_LDT_nolock(mm_context_t *pc) | |
230 | { | |
231 | set_ldt(pc->ldt, pc->size); | |
232 | } | |
233 | ||
234 | static inline void load_LDT(mm_context_t *pc) | |
235 | { | |
236 | preempt_disable(); | |
237 | load_LDT_nolock(pc); | |
238 | preempt_enable(); | |
239 | } | |
240 | ||
cc697852 GOC |
241 | static inline unsigned long get_desc_base(struct desc_struct *desc) |
242 | { | |
243 | return desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24); | |
244 | } | |
245 | ||
881c2975 GOC |
246 | #else |
247 | /* | |
248 | * GET_DESC_BASE reads the descriptor base of the specified segment. | |
249 | * | |
250 | * Args: | |
251 | * idx - descriptor index | |
252 | * gdt - GDT pointer | |
253 | * base - 32bit register to which the base will be written | |
254 | * lo_w - lo word of the "base" register | |
255 | * lo_b - lo byte of the "base" register | |
256 | * hi_b - hi byte of the low word of the "base" register | |
257 | * | |
258 | * Example: | |
259 | * GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah) | |
260 | * Will read the base address of GDT_ENTRY_ESPFIX_SS and put it into %eax. | |
261 | */ | |
262 | #define GET_DESC_BASE(idx, gdt, base, lo_w, lo_b, hi_b) \ | |
263 | movb idx*8+4(gdt), lo_b; \ | |
264 | movb idx*8+7(gdt), hi_b; \ | |
265 | shll $16, base; \ | |
266 | movw idx*8+2(gdt), lo_w; | |
267 | ||
268 | ||
269 | #endif /* __ASSEMBLY__ */ | |
270 | ||
80fbb69a | 271 | #endif |