ia64/xen-unstable

view xen/arch/x86/i387.c @ 9867:4d667a139318

This patch addresses CVE-2006-1056 (information leak from
fxsave/fxrstor on AMD CPUs) and also adjusts 64-bit handling so that
full 64-bit RIP/RDP values get saved/restored. More fine-grained
handling may be needed if 32-bit processes are expected to properly
see their selectors (native Linux doesn't currently do that either,
but there is a patch to adjust it there).

Original patch: Jan Beulich (based on Linux original by Andi Kleen)

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Apr 26 20:01:37 2006 +0100 (2006-04-26)
parents ee6f025fb264
children 043a4aa24781
line source
1 /*
2 * linux/arch/i386/kernel/i387.c
3 *
4 * Copyright (C) 1994 Linus Torvalds
5 *
6 * Pentium III FXSR, SSE support
7 * General FPU state handling cleanups
8 * Gareth Hughes <gareth@valinux.com>, May 2000
9 */
11 #include <xen/config.h>
12 #include <xen/sched.h>
13 #include <asm/current.h>
14 #include <asm/processor.h>
15 #include <asm/hvm/support.h>
16 #include <asm/i387.h>
18 void init_fpu(void)
19 {
20 __asm__ __volatile__ ( "fninit" );
21 if ( cpu_has_xmm )
22 load_mxcsr(0x1f80);
23 set_bit(_VCPUF_fpu_initialised, &current->vcpu_flags);
24 }
26 void save_init_fpu(struct vcpu *v)
27 {
28 unsigned long cr0 = read_cr0();
29 char *fpu_ctxt = v->arch.guest_context.fpu_ctxt.x;
31 /* This can happen, if a paravirtualised guest OS has set its CR0.TS. */
32 if ( cr0 & X86_CR0_TS )
33 clts();
35 if ( cpu_has_fxsr )
36 {
37 #ifdef __i386__
38 __asm__ __volatile__ (
39 "fxsave %0"
40 : "=m" (*fpu_ctxt) );
41 #else /* __x86_64__ */
42 /*
43 * The only way to force fxsaveq on a wide range of gas versions. On
44 * older versions the rex64 prefix works only if we force an addressing
45 * mode that doesn't require extended registers.
46 */
47 __asm__ __volatile__ (
48 "rex64/fxsave (%1)"
49 : "=m" (*fpu_ctxt) : "cdaSDb" (fpu_ctxt) );
50 #endif
52 /* Clear exception flags if FSW.ES is set. */
53 if ( unlikely(fpu_ctxt[2] & 0x80) )
54 __asm__ __volatile__ ("fnclex");
56 /*
57 * AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
58 * is pending. Clear the x87 state here by setting it to fixed
59 * values. The hypervisor data segment can be sometimes 0 and
60 * sometimes new user value. Both should be ok. Use the FPU saved
61 * data block as a safe address because it should be in L1.
62 */
63 if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
64 {
65 __asm__ __volatile__ (
66 "emms\n\t" /* clear stack tags */
67 "fildl %0" /* load to clear state */
68 : : "m" (*fpu_ctxt) );
69 }
70 }
71 else
72 {
73 __asm__ __volatile__ (
74 "fnsave %0 ; fwait"
75 : "=m" (*fpu_ctxt) );
76 }
78 clear_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags);
79 write_cr0(cr0|X86_CR0_TS);
80 }
82 void restore_fpu(struct vcpu *v)
83 {
84 char *fpu_ctxt = v->arch.guest_context.fpu_ctxt.x;
86 /*
87 * FXRSTOR can fault if passed a corrupted data block. We handle this
88 * possibility, which may occur if the block was passed to us by control
89 * tools, by silently clearing the block.
90 */
91 if ( cpu_has_fxsr )
92 {
93 __asm__ __volatile__ (
94 #ifdef __i386__
95 "1: fxrstor %0 \n"
96 #else /* __x86_64__ */
97 /* See above for why the operands/constraints are this way. */
98 "1: rex64/fxrstor (%2) \n"
99 #endif
100 ".section .fixup,\"ax\" \n"
101 "2: push %%"__OP"ax \n"
102 " push %%"__OP"cx \n"
103 " push %%"__OP"di \n"
104 " lea %0,%%"__OP"di \n"
105 " mov %1,%%ecx \n"
106 " xor %%eax,%%eax \n"
107 " rep ; stosl \n"
108 " pop %%"__OP"di \n"
109 " pop %%"__OP"cx \n"
110 " pop %%"__OP"ax \n"
111 " jmp 1b \n"
112 ".previous \n"
113 ".section __ex_table,\"a\"\n"
114 " "__FIXUP_ALIGN" \n"
115 " "__FIXUP_WORD" 1b,2b \n"
116 ".previous \n"
117 :
118 : "m" (*fpu_ctxt),
119 "i" (sizeof(v->arch.guest_context.fpu_ctxt)/4)
120 #ifdef __x86_64__
121 ,"cdaSDb" (fpu_ctxt)
122 #endif
123 );
124 }
125 else
126 {
127 __asm__ __volatile__ (
128 "frstor %0"
129 : : "m" (v->arch.guest_context.fpu_ctxt) );
130 }
131 }
133 /*
134 * Local variables:
135 * mode: C
136 * c-set-style: "BSD"
137 * c-basic-offset: 4
138 * tab-width: 4
139 * indent-tabs-mode: nil
140 * End:
141 */