diff options
author | Jeremy Fitzhardinge <jeremy@goop.org> | 2008-07-23 17:21:18 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-24 06:30:06 -0400 |
commit | 38ffbe66d59051fd9cfcfc8545f164700e2fa3bc (patch) | |
tree | 37e76db49cc86b3da550a62f36d101c7269d262e | |
parent | 338b9bb3adac0d2c5a1e180491d9b001d624c402 (diff) |
x86/paravirt/xen: properly fill out the ldt ops
LTP testing showed that Xen does not properly implement
sys_modify_ldt(). This patch does the final little bits needed to
make the ldt work properly.
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/kernel/ldt.c | 9 | ||||
-rw-r--r-- | arch/x86/kernel/paravirt.c | 4 | ||||
-rw-r--r-- | arch/x86/xen/enlighten.c | 23 | ||||
-rw-r--r-- | include/asm-x86/desc.h | 10 | ||||
-rw-r--r-- | include/asm-x86/paravirt.h | 13 |
5 files changed, 57 insertions, 2 deletions
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index 3fee2aa50f3f..4895e0634d22 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c | |||
@@ -51,6 +51,8 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload) | |||
51 | memset(newldt + oldsize * LDT_ENTRY_SIZE, 0, | 51 | memset(newldt + oldsize * LDT_ENTRY_SIZE, 0, |
52 | (mincount - oldsize) * LDT_ENTRY_SIZE); | 52 | (mincount - oldsize) * LDT_ENTRY_SIZE); |
53 | 53 | ||
54 | paravirt_alloc_ldt(newldt, mincount); | ||
55 | |||
54 | #ifdef CONFIG_X86_64 | 56 | #ifdef CONFIG_X86_64 |
55 | /* CHECKME: Do we really need this ? */ | 57 | /* CHECKME: Do we really need this ? */ |
56 | wmb(); | 58 | wmb(); |
@@ -75,6 +77,7 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload) | |||
75 | #endif | 77 | #endif |
76 | } | 78 | } |
77 | if (oldsize) { | 79 | if (oldsize) { |
80 | paravirt_free_ldt(oldldt, oldsize); | ||
78 | if (oldsize * LDT_ENTRY_SIZE > PAGE_SIZE) | 81 | if (oldsize * LDT_ENTRY_SIZE > PAGE_SIZE) |
79 | vfree(oldldt); | 82 | vfree(oldldt); |
80 | else | 83 | else |
@@ -86,10 +89,13 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload) | |||
86 | static inline int copy_ldt(mm_context_t *new, mm_context_t *old) | 89 | static inline int copy_ldt(mm_context_t *new, mm_context_t *old) |
87 | { | 90 | { |
88 | int err = alloc_ldt(new, old->size, 0); | 91 | int err = alloc_ldt(new, old->size, 0); |
92 | int i; | ||
89 | 93 | ||
90 | if (err < 0) | 94 | if (err < 0) |
91 | return err; | 95 | return err; |
92 | memcpy(new->ldt, old->ldt, old->size * LDT_ENTRY_SIZE); | 96 | |
97 | for(i = 0; i < old->size; i++) | ||
98 | write_ldt_entry(new->ldt, i, old->ldt + i * LDT_ENTRY_SIZE); | ||
93 | return 0; | 99 | return 0; |
94 | } | 100 | } |
95 | 101 | ||
@@ -126,6 +132,7 @@ void destroy_context(struct mm_struct *mm) | |||
126 | if (mm == current->active_mm) | 132 | if (mm == current->active_mm) |
127 | clear_LDT(); | 133 | clear_LDT(); |
128 | #endif | 134 | #endif |
135 | paravirt_free_ldt(mm->context.ldt, mm->context.size); | ||
129 | if (mm->context.size * LDT_ENTRY_SIZE > PAGE_SIZE) | 136 | if (mm->context.size * LDT_ENTRY_SIZE > PAGE_SIZE) |
130 | vfree(mm->context.ldt); | 137 | vfree(mm->context.ldt); |
131 | else | 138 | else |
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 94da4d52d798..d8f2277be5a0 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c | |||
@@ -348,6 +348,10 @@ struct pv_cpu_ops pv_cpu_ops = { | |||
348 | .write_ldt_entry = native_write_ldt_entry, | 348 | .write_ldt_entry = native_write_ldt_entry, |
349 | .write_gdt_entry = native_write_gdt_entry, | 349 | .write_gdt_entry = native_write_gdt_entry, |
350 | .write_idt_entry = native_write_idt_entry, | 350 | .write_idt_entry = native_write_idt_entry, |
351 | |||
352 | .alloc_ldt = paravirt_nop, | ||
353 | .free_ldt = paravirt_nop, | ||
354 | |||
351 | .load_sp0 = native_load_sp0, | 355 | .load_sp0 = native_load_sp0, |
352 | 356 | ||
353 | #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) | 357 | #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 9ff6e3cbf08f..06219e60e9c8 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -325,6 +325,26 @@ static unsigned long xen_store_tr(void) | |||
325 | return 0; | 325 | return 0; |
326 | } | 326 | } |
327 | 327 | ||
328 | static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries) | ||
329 | { | ||
330 | unsigned pages = roundup(entries * LDT_ENTRY_SIZE, PAGE_SIZE); | ||
331 | void *v = ldt; | ||
332 | int i; | ||
333 | |||
334 | for(i = 0; i < pages; i += PAGE_SIZE) | ||
335 | make_lowmem_page_readonly(v + i); | ||
336 | } | ||
337 | |||
338 | static void xen_free_ldt(struct desc_struct *ldt, unsigned entries) | ||
339 | { | ||
340 | unsigned pages = roundup(entries * LDT_ENTRY_SIZE, PAGE_SIZE); | ||
341 | void *v = ldt; | ||
342 | int i; | ||
343 | |||
344 | for(i = 0; i < pages; i += PAGE_SIZE) | ||
345 | make_lowmem_page_readwrite(v + i); | ||
346 | } | ||
347 | |||
328 | static void xen_set_ldt(const void *addr, unsigned entries) | 348 | static void xen_set_ldt(const void *addr, unsigned entries) |
329 | { | 349 | { |
330 | struct mmuext_op *op; | 350 | struct mmuext_op *op; |
@@ -1220,6 +1240,9 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { | |||
1220 | .load_gs_index = xen_load_gs_index, | 1240 | .load_gs_index = xen_load_gs_index, |
1221 | #endif | 1241 | #endif |
1222 | 1242 | ||
1243 | .alloc_ldt = xen_alloc_ldt, | ||
1244 | .free_ldt = xen_free_ldt, | ||
1245 | |||
1223 | .store_gdt = native_store_gdt, | 1246 | .store_gdt = native_store_gdt, |
1224 | .store_idt = native_store_idt, | 1247 | .store_idt = native_store_idt, |
1225 | .store_tr = xen_store_tr, | 1248 | .store_tr = xen_store_tr, |
diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h index a44c4dc70590..24a524f5e1a2 100644 --- a/include/asm-x86/desc.h +++ b/include/asm-x86/desc.h | |||
@@ -97,7 +97,15 @@ static inline int desc_empty(const void *ptr) | |||
97 | native_write_gdt_entry(dt, entry, desc, type) | 97 | native_write_gdt_entry(dt, entry, desc, type) |
98 | #define write_idt_entry(dt, entry, g) \ | 98 | #define write_idt_entry(dt, entry, g) \ |
99 | native_write_idt_entry(dt, entry, g) | 99 | native_write_idt_entry(dt, entry, g) |
100 | #endif | 100 | |
101 | static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries) | ||
102 | { | ||
103 | } | ||
104 | |||
105 | static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries) | ||
106 | { | ||
107 | } | ||
108 | #endif /* CONFIG_PARAVIRT */ | ||
101 | 109 | ||
102 | static inline void native_write_idt_entry(gate_desc *idt, int entry, | 110 | static inline void native_write_idt_entry(gate_desc *idt, int entry, |
103 | const gate_desc *gate) | 111 | const gate_desc *gate) |
diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h index fbbde93f12d6..db9b0647b346 100644 --- a/include/asm-x86/paravirt.h +++ b/include/asm-x86/paravirt.h | |||
@@ -124,6 +124,9 @@ struct pv_cpu_ops { | |||
124 | int entrynum, const void *desc, int size); | 124 | int entrynum, const void *desc, int size); |
125 | void (*write_idt_entry)(gate_desc *, | 125 | void (*write_idt_entry)(gate_desc *, |
126 | int entrynum, const gate_desc *gate); | 126 | int entrynum, const gate_desc *gate); |
127 | void (*alloc_ldt)(struct desc_struct *ldt, unsigned entries); | ||
128 | void (*free_ldt)(struct desc_struct *ldt, unsigned entries); | ||
129 | |||
127 | void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t); | 130 | void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t); |
128 | 131 | ||
129 | void (*set_iopl_mask)(unsigned mask); | 132 | void (*set_iopl_mask)(unsigned mask); |
@@ -824,6 +827,16 @@ do { \ | |||
824 | (aux) = __aux; \ | 827 | (aux) = __aux; \ |
825 | } while (0) | 828 | } while (0) |
826 | 829 | ||
830 | static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries) | ||
831 | { | ||
832 | PVOP_VCALL2(pv_cpu_ops.alloc_ldt, ldt, entries); | ||
833 | } | ||
834 | |||
835 | static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries) | ||
836 | { | ||
837 | PVOP_VCALL2(pv_cpu_ops.free_ldt, ldt, entries); | ||
838 | } | ||
839 | |||
827 | static inline void load_TR_desc(void) | 840 | static inline void load_TR_desc(void) |
828 | { | 841 | { |
829 | PVOP_VCALL0(pv_cpu_ops.load_tr_desc); | 842 | PVOP_VCALL0(pv_cpu_ops.load_tr_desc); |