aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/entry/entry_64.S39
1 files changed, 31 insertions, 8 deletions
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index bd97161f90cb..3bb2c4302df1 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -1135,7 +1135,7 @@ END(paranoid_exit)
1135 1135
1136/* 1136/*
1137 * Save all registers in pt_regs, and switch gs if needed. 1137 * Save all registers in pt_regs, and switch gs if needed.
1138 * Return: ebx=0: need swapgs on exit, ebx=1: otherwise 1138 * Return: EBX=0: came from user mode; EBX=1: otherwise
1139 */ 1139 */
1140ENTRY(error_entry) 1140ENTRY(error_entry)
1141 cld 1141 cld
@@ -1144,9 +1144,11 @@ ENTRY(error_entry)
1144 xorl %ebx, %ebx 1144 xorl %ebx, %ebx
1145 testb $3, CS+8(%rsp) 1145 testb $3, CS+8(%rsp)
1146 jz error_kernelspace 1146 jz error_kernelspace
1147error_swapgs: 1147
1148 /* We entered from user mode */
1148 SWAPGS 1149 SWAPGS
1149error_sti: 1150
1151error_entry_done:
1150 TRACE_IRQS_OFF 1152 TRACE_IRQS_OFF
1151 ret 1153 ret
1152 1154
@@ -1165,8 +1167,15 @@ error_kernelspace:
1165 cmpq %rax, RIP+8(%rsp) 1167 cmpq %rax, RIP+8(%rsp)
1166 je bstep_iret 1168 je bstep_iret
1167 cmpq $gs_change, RIP+8(%rsp) 1169 cmpq $gs_change, RIP+8(%rsp)
1168 je error_swapgs 1170 jne error_entry_done
1169 jmp error_sti 1171
1172 /*
1173 * hack: gs_change can fail with user gsbase. If this happens, fix up
1174 * gsbase and proceed. We'll fix up the exception and land in
1175 * gs_change's error handler with kernel gsbase.
1176 */
1177 SWAPGS
1178 jmp error_entry_done
1170 1179
1171bstep_iret: 1180bstep_iret:
1172 /* Fix truncated RIP */ 1181 /* Fix truncated RIP */
@@ -1174,16 +1183,30 @@ bstep_iret:
1174 /* fall through */ 1183 /* fall through */
1175 1184
1176error_bad_iret: 1185error_bad_iret:
1186 /*
1187 * We came from an IRET to user mode, so we have user gsbase.
1188 * Switch to kernel gsbase:
1189 */
1177 SWAPGS 1190 SWAPGS
1191
1192 /*
1193 * Pretend that the exception came from user mode: set up pt_regs
1194 * as if we faulted immediately after IRET and clear EBX so that
1195 * error_exit knows that we will be returning to user mode.
1196 */
1178 mov %rsp, %rdi 1197 mov %rsp, %rdi
1179 call fixup_bad_iret 1198 call fixup_bad_iret
1180 mov %rax, %rsp 1199 mov %rax, %rsp
1181 decl %ebx /* Return to usergs */ 1200 decl %ebx
1182 jmp error_sti 1201 jmp error_entry_done
1183END(error_entry) 1202END(error_entry)
1184 1203
1185 1204
1186/* On entry, ebx is "no swapgs" flag (1: don't need swapgs, 0: need it) */ 1205/*
1206 * On entry, EBS is a "return to kernel mode" flag:
1207 * 1: already in kernel mode, don't need SWAPGS
1208 * 0: user gsbase is loaded, we need SWAPGS and standard preparation for return to usermode
1209 */
1187ENTRY(error_exit) 1210ENTRY(error_exit)
1188 movl %ebx, %eax 1211 movl %ebx, %eax
1189 RESTORE_EXTRA_REGS 1212 RESTORE_EXTRA_REGS