aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/traps.c
diff options
context:
space:
mode:
authorStas Sergeev <stsp@aknet.ru>2006-12-06 20:14:01 -0500
committerAndi Kleen <andi@basil.nowhere.org>2006-12-06 20:14:01 -0500
commitbe44d2aabce2d62f72d5751d1871b6212bf7a1c7 (patch)
tree3f190dd5b5747ee83b50c4596b4801ce6c6b551c /arch/i386/kernel/traps.c
parentbb81a09e55eaf7e5f798468ab971469b6f66a259 (diff)
[PATCH] i386: espfix cleanup
Clean up the espfix code: - Introduced PER_CPU() macro to be used from asm - Introduced GET_DESC_BASE() macro to be used from asm - Rewrote the fixup code in asm, as calling a C code with the altered %ss appeared to be unsafe - No longer altering the stack from a .fixup section - 16bit per-cpu stack is no longer used, instead the stack segment base is patched the way so that the high word of the kernel and user %esp are the same. - Added the limit-patching for the espfix segment. (Chuck Ebbert) [jeremy@goop.org: use the x86 scaling addressing mode rather than shifting] Signed-off-by: Stas Sergeev <stsp@aknet.ru> Signed-off-by: Andi Kleen <ak@suse.de> Acked-by: Zachary Amsden <zach@vmware.com> Acked-by: Chuck Ebbert <76306.1226@compuserve.com> Acked-by: Jan Beulich <jbeulich@novell.com> Cc: Andi Kleen <ak@muc.de> Signed-off-by: Jeremy Fitzhardinge <jeremy@goop.org> Signed-off-by: Andrew Morton <akpm@osdl.org>
Diffstat (limited to 'arch/i386/kernel/traps.c')
-rw-r--r--arch/i386/kernel/traps.c57
1 files changed, 16 insertions, 41 deletions
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 56655ea8d98f..f9bb1f89d687 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -1088,49 +1088,24 @@ fastcall void do_spurious_interrupt_bug(struct pt_regs * regs,
1088#endif 1088#endif
1089} 1089}
1090 1090
1091fastcall void setup_x86_bogus_stack(unsigned char * stk) 1091fastcall unsigned long patch_espfix_desc(unsigned long uesp,
1092 unsigned long kesp)
1092{ 1093{
1093 unsigned long *switch16_ptr, *switch32_ptr;
1094 struct pt_regs *regs;
1095 unsigned long stack_top, stack_bot;
1096 unsigned short iret_frame16_off;
1097 int cpu = smp_processor_id(); 1094 int cpu = smp_processor_id();
1098 /* reserve the space on 32bit stack for the magic switch16 pointer */ 1095 struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
1099 memmove(stk, stk + 8, sizeof(struct pt_regs)); 1096 struct desc_struct *gdt = (struct desc_struct *)cpu_gdt_descr->address;
1100 switch16_ptr = (unsigned long *)(stk + sizeof(struct pt_regs)); 1097 unsigned long base = (kesp - uesp) & -THREAD_SIZE;
1101 regs = (struct pt_regs *)stk; 1098 unsigned long new_kesp = kesp - base;
1102 /* now the switch32 on 16bit stack */ 1099 unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT;
1103 stack_bot = (unsigned long)&per_cpu(cpu_16bit_stack, cpu); 1100 __u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS];
1104 stack_top = stack_bot + CPU_16BIT_STACK_SIZE; 1101 /* Set up base for espfix segment */
1105 switch32_ptr = (unsigned long *)(stack_top - 8); 1102 desc &= 0x00f0ff0000000000ULL;
1106 iret_frame16_off = CPU_16BIT_STACK_SIZE - 8 - 20; 1103 desc |= ((((__u64)base) << 16) & 0x000000ffffff0000ULL) |
1107 /* copy iret frame on 16bit stack */ 1104 ((((__u64)base) << 32) & 0xff00000000000000ULL) |
1108 memcpy((void *)(stack_bot + iret_frame16_off), &regs->eip, 20); 1105 ((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) |
1109 /* fill in the switch pointers */ 1106 (lim_pages & 0xffff);
1110 switch16_ptr[0] = (regs->esp & 0xffff0000) | iret_frame16_off; 1107 *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc;
1111 switch16_ptr[1] = __ESPFIX_SS; 1108 return new_kesp;
1112 switch32_ptr[0] = (unsigned long)stk + sizeof(struct pt_regs) +
1113 8 - CPU_16BIT_STACK_SIZE;
1114 switch32_ptr[1] = __KERNEL_DS;
1115}
1116
1117fastcall unsigned char * fixup_x86_bogus_stack(unsigned short sp)
1118{
1119 unsigned long *switch32_ptr;
1120 unsigned char *stack16, *stack32;
1121 unsigned long stack_top, stack_bot;
1122 int len;
1123 int cpu = smp_processor_id();
1124 stack_bot = (unsigned long)&per_cpu(cpu_16bit_stack, cpu);
1125 stack_top = stack_bot + CPU_16BIT_STACK_SIZE;
1126 switch32_ptr = (unsigned long *)(stack_top - 8);
1127 /* copy the data from 16bit stack to 32bit stack */
1128 len = CPU_16BIT_STACK_SIZE - 8 - sp;
1129 stack16 = (unsigned char *)(stack_bot + sp);
1130 stack32 = (unsigned char *)
1131 (switch32_ptr[0] + CPU_16BIT_STACK_SIZE - 8 - len);
1132 memcpy(stack32, stack16, len);
1133 return stack32;
1134} 1109}
1135 1110
1136/* 1111/*