diff options
Diffstat (limited to 'arch/x86/ia32')
-rw-r--r-- | arch/x86/ia32/ia32entry.S | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 8d01cce7b6b8..5d8f987a340d 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S | |||
@@ -186,28 +186,55 @@ sysenter_dispatch: | |||
186 | testl $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) | 186 | testl $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS) |
187 | jnz sysexit_audit | 187 | jnz sysexit_audit |
188 | sysexit_from_sys_call: | 188 | sysexit_from_sys_call: |
189 | /* | ||
190 | * NB: SYSEXIT is not obviously safe for 64-bit kernels -- an | ||
191 | * NMI between STI and SYSEXIT has poorly specified behavior, | ||
192 | * and and NMI followed by an IRQ with usergs is fatal. So | ||
193 | * we just pretend we're using SYSEXIT but we really use | ||
194 | * SYSRETL instead. | ||
195 | * | ||
196 | * This code path is still called 'sysexit' because it pairs | ||
197 | * with 'sysenter' and it uses the SYSENTER calling convention. | ||
198 | */ | ||
189 | andl $~TS_COMPAT,ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) | 199 | andl $~TS_COMPAT,ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS) |
190 | /* clear IF, that popfq doesn't enable interrupts early */ | 200 | movl RIP(%rsp),%ecx /* User %eip */ |
191 | andl $~0x200,EFLAGS(%rsp) | 201 | CFI_REGISTER rip,rcx |
192 | movl RIP(%rsp),%edx /* User %eip */ | ||
193 | CFI_REGISTER rip,rdx | ||
194 | RESTORE_RSI_RDI | 202 | RESTORE_RSI_RDI |
195 | /* pop everything except ss,rsp,rflags slots */ | 203 | xorl %edx,%edx /* avoid info leaks */ |
196 | REMOVE_PT_GPREGS_FROM_STACK 3*8 | ||
197 | xorq %r8,%r8 | 204 | xorq %r8,%r8 |
198 | xorq %r9,%r9 | 205 | xorq %r9,%r9 |
199 | xorq %r10,%r10 | 206 | xorq %r10,%r10 |
200 | xorq %r11,%r11 | 207 | movl EFLAGS(%rsp),%r11d /* User eflags */ |
201 | popfq_cfi | ||
202 | /*CFI_RESTORE rflags*/ | 208 | /*CFI_RESTORE rflags*/ |
203 | popq_cfi %rcx /* User %esp */ | ||
204 | CFI_REGISTER rsp,rcx | ||
205 | TRACE_IRQS_ON | 209 | TRACE_IRQS_ON |
210 | |||
206 | /* | 211 | /* |
207 | * 32bit SYSEXIT restores eip from edx, esp from ecx. | 212 | * SYSRETL works even on Intel CPUs. Use it in preference to SYSEXIT, |
208 | * cs and ss are loaded from MSRs. | 213 | * since it avoids a dicey window with interrupts enabled. |
209 | */ | 214 | */ |
210 | ENABLE_INTERRUPTS_SYSEXIT32 | 215 | movl RSP(%rsp),%esp |
216 | |||
217 | /* | ||
218 | * USERGS_SYSRET32 does: | ||
219 | * gsbase = user's gs base | ||
220 | * eip = ecx | ||
221 | * rflags = r11 | ||
222 | * cs = __USER32_CS | ||
223 | * ss = __USER_DS | ||
224 | * | ||
225 | * The prologue set RIP(%rsp) to VDSO32_SYSENTER_RETURN, which does: | ||
226 | * | ||
227 | * pop %ebp | ||
228 | * pop %edx | ||
229 | * pop %ecx | ||
230 | * | ||
231 | * Therefore, we invoke SYSRETL with EDX and R8-R10 zeroed to | ||
232 | * avoid info leaks. R11 ends up with VDSO32_SYSENTER_RETURN's | ||
233 | * address (already known to user code), and R12-R15 are | ||
234 | * callee-saved and therefore don't contain any interesting | ||
235 | * kernel data. | ||
236 | */ | ||
237 | USERGS_SYSRET32 | ||
211 | 238 | ||
212 | CFI_RESTORE_STATE | 239 | CFI_RESTORE_STATE |
213 | 240 | ||