Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86, gdt, hibernate: Store/load GDT for hibernate path.

The git commite7a5cd063c7b4c58417f674821d63f5eb6747e37
("x86-64, gdt: Store/load GDT for ACPI S3 or hibernate/resume path
is not needed.") assumes that for the hibernate path the booting
kernel and the resuming kernel MUST be the same. That is certainly
the case for a 32-bit kernel (see check_image_kernel and
CONFIG_ARCH_HIBERNATION_HEADER config option).

However for 64-bit kernels it is OK to have a different kernel
version (and size of the image) of the booting and resuming kernels.
Hence the above mentioned git commit introduces an regression.

This patch fixes it by introducing a 'struct desc_ptr gdt_desc'
back in the 'struct saved_context'. However instead of having in the
'save_processor_state' and 'restore_processor_state' the
store/load_gdt calls, we are only saving the GDT in the
save_processor_state.

For the restore path the lgdt operation is done in
hibernate_asm_[32|64].S in the 'restore_registers' path.

The apt reader of this description will recognize that only 64-bit
kernels need this treatment, not 32-bit. This patch adds the logic
in the 32-bit path to be more similar to 64-bit so that in the future
the unification process can take advantage of this.

[ hpa: this also reverts an inadvertent on-disk format change ]

Suggested-by: "H. Peter Anvin" <hpa@zytor.com>
Acked-by: "Rafael J. Wysocki" <rjw@sisk.pl>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Link: http://lkml.kernel.org/r/1367459610-9656-2-git-send-email-konrad.wilk@oracle.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>

authored by

Konrad Rzeszutek Wilk and committed by
H. Peter Anvin
cc456c4e 5a148af6

+24 -5
+1
arch/x86/include/asm/suspend_32.h
··· 15 15 unsigned long cr0, cr2, cr3, cr4; 16 16 u64 misc_enable; 17 17 bool misc_enable_saved; 18 + struct desc_ptr gdt_desc; 18 19 struct desc_ptr idt; 19 20 u16 ldt; 20 21 u16 tss;
+2
arch/x86/include/asm/suspend_64.h
··· 25 25 u64 misc_enable; 26 26 bool misc_enable_saved; 27 27 unsigned long efer; 28 + u16 gdt_pad; /* Unused */ 29 + struct desc_ptr gdt_desc; 28 30 u16 idt_pad; 29 31 u16 idt_limit; 30 32 unsigned long idt_base;
+3
arch/x86/kernel/asm-offsets_32.c
··· 60 60 OFFSET(IA32_RT_SIGFRAME_sigcontext, rt_sigframe, uc.uc_mcontext); 61 61 BLANK(); 62 62 63 + OFFSET(saved_context_gdt_desc, saved_context, gdt_desc); 64 + BLANK(); 65 + 63 66 /* Offset from the sysenter stack to tss.sp0 */ 64 67 DEFINE(TSS_sysenter_sp0, offsetof(struct tss_struct, x86_tss.sp0) - 65 68 sizeof(struct tss_struct));
+1
arch/x86/kernel/asm-offsets_64.c
··· 73 73 ENTRY(cr3); 74 74 ENTRY(cr4); 75 75 ENTRY(cr8); 76 + ENTRY(gdt_desc); 76 77 BLANK(); 77 78 #undef ENTRY 78 79
+10 -5
arch/x86/power/cpu.c
··· 25 25 #include <asm/cpu.h> 26 26 27 27 #ifdef CONFIG_X86_32 28 - static struct saved_context saved_context; 29 - 30 28 unsigned long saved_context_ebx; 31 29 unsigned long saved_context_esp, saved_context_ebp; 32 30 unsigned long saved_context_esi, saved_context_edi; 33 31 unsigned long saved_context_eflags; 34 - #else 35 - /* CONFIG_X86_64 */ 36 - struct saved_context saved_context; 37 32 #endif 33 + struct saved_context saved_context; 38 34 39 35 /** 40 36 * __save_processor_state - save CPU registers before creating a ··· 63 67 /* CONFIG_X86_64 */ 64 68 store_idt((struct desc_ptr *)&ctxt->idt_limit); 65 69 #endif 70 + /* 71 + * We save it here, but restore it only in the hibernate case. 72 + * For ACPI S3 resume, this is loaded via 'early_gdt_desc' in 64-bit 73 + * mode in "secondary_startup_64". In 32-bit mode it is done via 74 + * 'pmode_gdt' in wakeup_start. 75 + */ 76 + ctxt->gdt_desc.size = GDT_SIZE - 1; 77 + ctxt->gdt_desc.address = (unsigned long)get_cpu_gdt_table(smp_processor_id()); 78 + 66 79 store_tr(ctxt->tr); 67 80 68 81 /* XMM0..XMM15 should be handled by kernel_fpu_begin(). */
+4
arch/x86/power/hibernate_asm_32.S
··· 75 75 pushl saved_context_eflags 76 76 popfl 77 77 78 + /* Saved in save_processor_state. */ 79 + movl $saved_context, %eax 80 + lgdt saved_context_gdt_desc(%eax) 81 + 78 82 xorl %eax, %eax 79 83 80 84 ret
+3
arch/x86/power/hibernate_asm_64.S
··· 139 139 pushq pt_regs_flags(%rax) 140 140 popfq 141 141 142 + /* Saved in save_processor_state. */ 143 + lgdt saved_context_gdt_desc(%rax) 144 + 142 145 xorq %rax, %rax 143 146 144 147 /* tell the hibernation core that we've just restored the memory */