diff options
author | Stas Sergeev <stsp@aknet.ru> | 2006-12-06 20:14:01 -0500 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2006-12-06 20:14:01 -0500 |
commit | be44d2aabce2d62f72d5751d1871b6212bf7a1c7 (patch) | |
tree | 3f190dd5b5747ee83b50c4596b4801ce6c6b551c /arch/i386/kernel/traps.c | |
parent | bb81a09e55eaf7e5f798468ab971469b6f66a259 (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.c | 57 |
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 | ||
1091 | fastcall void setup_x86_bogus_stack(unsigned char * stk) | 1091 | fastcall 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), ®s->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 | |||
1117 | fastcall 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 | /* |