Skip to contentSkip to conversation

__restore_processor_state() fixes

PATCH Applied Andy Lutomirski 7 participants 13 messages Dec 14, 2017 – Dec 15, 2017

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover __restore_processor_state() fixes

__restore_processor_state() was spaghetti code, made no sense, and had bugs. And I broke resume on 32-bit systems. This series cleans it up and fixes it (hopefully!).

Andy Lutomirski (3):
x86/power/64: Use struct desc_ptr for the IDT in struct saved_context x86/power/32: Move SYSENTER MSR restoration to fix_processor_context() x86/power: Make restore_processor_context() sane

 arch/x86/include/asm/suspend_32.h |  8 +++-
 arch/x86/include/asm/suspend_64.h | 19 ++++++--
 arch/x86/power/cpu.c              | 99 ++++++++++++++++++---------------------
 3 files changed, 67 insertions(+), 59 deletions(-)
Signature · 1 line
2.13.6
#1 lore raw

PATCH 1/3 x86/power/64: Use struct desc_ptr for the IDT in struct saved_context

x86_64's saved_context nonsensically used separate idt_limit and idt_base fields and then cast &idt_limit to struct desc_ptr *. This was correct (with -fno-strict-aliasing), but it's confusing, served no purpose, and required ifdeffery. Just use struct desc_ptr directly.

---
 arch/x86/include/asm/suspend_64.h |  3 +--
 arch/x86/power/cpu.c              | 11 +----------
 2 files changed, 2 insertions(+), 12 deletions(-)
arch/x86/include/asm/suspend_64.h +1 -2
index 7306e911faee..600e9e0aea51 100644
@@ -30,8 +30,7 @@ struct saved_context {
 	u16 gdt_pad; /* Unused */
 	struct desc_ptr gdt_desc;
 	u16 idt_pad;
-	u16 idt_limit;
-	unsigned long idt_base;
+	struct desc_ptr idt;
 	u16 ldt;
 	u16 tss;
 	unsigned long tr;
arch/x86/power/cpu.c +1 -10
index 5191de14f4df..472bc8c8212b 100644
@@ -82,12 +82,8 @@ static void __save_processor_state(struct saved_context *ctxt)
 	/*
 	 * descriptor tables
 	 */
-#ifdef CONFIG_X86_32
 	store_idt(&ctxt->idt);
-#else
-/* CONFIG_X86_64 */
-	store_idt((struct desc_ptr *)&ctxt->idt_limit);
-#endif
+
 	/*
 	 * We save it here, but restore it only in the hibernate case.
 	 * For ACPI S3 resume, this is loaded via 'early_gdt_desc' in 64-bit
@@ -219,12 +215,7 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
 	 * now restore the descriptor tables to their proper values
 	 * ltr is done i fix_processor_context().
 	 */
-#ifdef CONFIG_X86_32
 	load_idt(&ctxt->idt);
-#else
-/* CONFIG_X86_64 */
-	load_idt((const struct desc_ptr *)&ctxt->idt_limit);
-#endif
 
 #ifdef CONFIG_X86_64
 	/*
Signature · 1 line
2.13.6
#3 lore raw

PATCH 2/3 x86/power/32: Move SYSENTER MSR restoration to fix_processor_context()

In reply to Andy Lutomirski

x86_64 restores system call MSRs in fix_processor_context(), and x86_32 restored them along with segment registers. The 64-bit variant makes more sense, so move the 32-bit code to match the 64-bit code.

---
 arch/x86/power/cpu.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
arch/x86/power/cpu.c +3 -6
index 472bc8c8212b..033c61e6891b 100644
@@ -174,6 +174,9 @@ static void fix_processor_context(void)
 	write_gdt_entry(desc, GDT_ENTRY_TSS, &tss, DESC_TSS);
 
 	syscall_init();				/* This sets MSR_*STAR and related */
+#else
+	if (boot_cpu_has(X86_FEATURE_SEP))
+		enable_sep_cpu();
 #endif
 	load_TR_desc();				/* This does ltr */
 	load_mm_ldt(current->active_mm);	/* This does lldt */
@@ -237,12 +240,6 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
 	loadsegment(fs, ctxt->fs);
 	loadsegment(gs, ctxt->gs);
 	loadsegment(ss, ctxt->ss);
-
-	/*
-	 * sysenter MSRs
-	 */
-	if (boot_cpu_has(X86_FEATURE_SEP))
-		enable_sep_cpu();
 #else
 /* CONFIG_X86_64 */
 	asm volatile ("movw %0, %%ds" :: "r" (ctxt->ds));
Signature · 1 line
2.13.6
#5 lore raw

PATCH 3/3 x86/power: Make restore_processor_context() sane

In reply to Andy Lutomirski

My previous attempt to fix a couple of bugs in __restore_processor_context() introduced yet another bug. Rather than trying to come up with a minimal fix, let's try to clean it up for real. This patch fixes quite a few things:

- The old code saved a nonsensical subset of segment registers. The only registers that need to be saved are those that contain userspace state or those that can't be trivially restored without percpu access working. (On x86_32, we can restore percpu access by writing __KERNEL_PERCPU to %fs. On x86_64, it's easier to save and restore the kernel's GSBASE.) With this patch, we restore hardcoded values to the kernel state where applicable and explicitly restore the user state after fixing all the descriptor tables.

- We used to use an unholy mix of inline asm and C helpers for segment register access. Let's get rid of the inline asm.

Fixes 5b06bbcfc2c6 ("x86/power: Fix some ordering bugs in __restore_processor_context()")
---
 arch/x86/include/asm/suspend_32.h |  8 +++-
 arch/x86/include/asm/suspend_64.h | 16 +++++++-
 arch/x86/power/cpu.c              | 79 ++++++++++++++++++++-------------------
 3 files changed, 62 insertions(+), 41 deletions(-)
arch/x86/include/asm/suspend_32.h +7 -1
index 982c325dad33..8be6afb58471 100644
@@ -12,7 +12,13 @@
 
 /* image of the saved processor state */
 struct saved_context {
-	u16 es, fs, gs, ss;
+	/*
+	 * On x86_32, all segment registers, with the possible exception of
+	 * gs, are saved at kernel entry in pt_regs.
+	 */
+#ifdef CONFIG_X86_32_LAZY_GS
+	u16 gs;
+#endif
 	unsigned long cr0, cr2, cr3, cr4;
 	u64 misc_enable;
 	bool misc_enable_saved;
arch/x86/include/asm/suspend_64.h +14 -2
index 600e9e0aea51..a7af9f53c0cb 100644
@@ -20,8 +20,20 @@
  */
 struct saved_context {
 	struct pt_regs regs;
-	u16 ds, es, fs, gs, ss;
-	unsigned long gs_base, gs_kernel_base, fs_base;
+
+	/*
+	 * User CS and SS are saved in current_pt_regs().  The rest of the
+	 * segment selectors need to be saved and restored here.
+	 */
+	u16 ds, es, fs, gs;
+
+	/*
+	 * Usermode FSBASE and GSBASE may not match the fs and gs selectors,
+	 * so we save them separately.  We save the kernelmode GSBASE to
+	 * restore percpu access after resume.
+	 */
+	unsigned long kernelmode_gs_base, usermode_gs_base, fs_base;
+
 	unsigned long cr0, cr2, cr3, cr4, cr8;
 	u64 misc_enable;
 	bool misc_enable_saved;
arch/x86/power/cpu.c +41 -38

118 lines not on this page · raw message

Signature · 1 line
2.13.6
Tested-by on v1 3/3
#6 lore raw

Re: [PATCH urgent 3/3] x86/power: Make restore_processor_context() sane

Hi!

Quoted 15 lines

My previous attempt to fix a couple of bugs in __restore_processor_context() introduced yet another bug. Rather than trying to come up with a minimal fix, let's try to clean it up for real. This patch fixes quite a few things:

- The old code saved a nonsensical subset of segment registers. The only registers that need to be saved are those that contain userspace state or those that can't be trivially restored without percpu access working. (On x86_32, we can restore percpu access by writing __KERNEL_PERCPU to %fs. On x86_64, it's easier to save and restore the kernel's GSBASE.) With this patch, we restore hardcoded values to the kernel state where applicable and explicitly restore the user state after fixing all the descriptor tables.

Quoted 6 lines

- We used to use an unholy mix of inline asm and C helpers for segment register access. Let's get rid of the inline asm.

Fixes 5b06bbcfc2c6 ("x86/power: Fix some ordering bugs in __restore_processor_context()")

Thanks!

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Acked-by on the v1 series
#8 lore raw
In reply to Andy Lutomirski
Quoted 8 lines · CET Andy Lutomirski

__restore_processor_state() was spaghetti code, made no sense, and had bugs. And I broke resume on 32-bit systems. This series cleans it up and fixes it (hopefully!).

Andy Lutomirski (3):
x86/power/64: Use struct desc_ptr for the IDT in struct saved_context x86/power/32: Move SYSENTER MSR restoration to fix_processor_context() x86/power: Make restore_processor_context() sane

For all three:

Thanks!

#9 lore raw
Quoted 6 lines · Rafael J. Wysocki
Quoted 3 lines · CET Andy Lutomirski

__restore_processor_state() was spaghetti code, made no sense, and had bugs. And I broke resume on 32-bit systems. This series cleans it up and fixes it (hopefully!).

And I'm assuming I'll get these from the x86 -tip tree.

If not, somebody please holler, and I'll pick them up directly.

Linus

#11 lore raw
In reply to Rafael J. Wysocki
Quoted 5 lines · Rafael J. Wysocki
Quoted 4 lines · CET Andy Lutomirski

__restore_processor_state() was spaghetti code, made no sense, and had bugs. And I broke resume on 32-bit systems. This series cleans it up and fixes it (hopefully!).

Quoted 9 lines
Quoted 4 lines

Andy Lutomirski (3):
x86/power/64: Use struct desc_ptr for the IDT in struct saved_context x86/power/32: Move SYSENTER MSR restoration to fix_processor_context() x86/power: Make restore_processor_context() sane

For all three:

Works still after split up so my tested by remains. Please note Pavel gave his reported/tested-by in 3/3.

Signature · 1 line
Jarkko
Applied
#10 lore raw
In reply to Linus Torvalds
Quoted 11 lines · Linus Torvalds
Quoted 6 lines · Rafael J. Wysocki
Quoted 3 lines · CET Andy Lutomirski

__restore_processor_state() was spaghetti code, made no sense, and had bugs. And I broke resume on 32-bit systems. This series cleans it up and fixes it (hopefully!).

And I'm assuming I'll get these from the x86 -tip tree.

If not, somebody please holler, and I'll pick them up directly.

I have applied them to tip:x86/urgent with small changes to the changelogs, and will send them to you in a couple of hours.

These fixes are really nice, thanks guys for all the effort!

Thanks,

Ingo

#12 lore raw
In reply to Jarkko Nikula
Quoted 11 lines · Jarkko Nikula
Quoted 10 lines · Rafael J. Wysocki
Quoted 8 lines · CET Andy Lutomirski

__restore_processor_state() was spaghetti code, made no sense, and had bugs. And I broke resume on 32-bit systems. This series cleans it up and fixes it (hopefully!).

Andy Lutomirski (3):
x86/power/64: Use struct desc_ptr for the IDT in struct saved_context x86/power/32: Move SYSENTER MSR restoration to fix_processor_context() x86/power: Make restore_processor_context() sane

Quoted 7 lines
Quoted 4 lines

For all three:

Works still after split up so my tested by remains. Please note Pavel gave his reported/tested-by in 3/3.

Thanks, I've updated all the changelogs - and I've also added your Reported-by tag to patch #3.

Thanks,

Ingo

#7 lore raw

[tip:x86/urgent] x86/power: Make restore_processor_context() sane

In reply to Andy Lutomirski
x86/power: Make restore_processor_context() sane
Commit-ID:  7ee18d677989e99635027cee04c878950e0752b9
Gitweb:     https://git.kernel.org/tip/7ee18d677989e99635027cee04c878950e0752b9
Author:     Andy Lutomirski <[email protected]>
AuthorDate: Thu, 14 Dec 2017 13:19:07 -0800
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 15 Dec 2017 12:21:38 +0100

x86/power: Make restore_processor_context() sane

My previous attempt to fix a couple of bugs in __restore_processor_context():

5b06bbcfc2c6 ("x86/power: Fix some ordering bugs in __restore_processor_context()")

... introduced yet another bug, breaking suspend-resume.

Rather than trying to come up with a minimal fix, let's try to clean it up for real. This patch fixes quite a few things:

- The old code saved a nonsensical subset of segment registers. The only registers that need to be saved are those that contain userspace state or those that can't be trivially restored without percpu access working. (On x86_32, we can restore percpu access by writing __KERNEL_PERCPU to %fs. On x86_64, it's easier to save and restore the kernel's GSBASE.) With this patch, we restore hardcoded values to the kernel state where applicable and explicitly restore the user state after fixing all the descriptor tables.

- We used to use an unholy mix of inline asm and C helpers for segment register access. Let's get rid of the inline asm.

This fixes the reported s2ram hangs and make the code all around more logical.

---
 arch/x86/include/asm/suspend_32.h |  8 +++-
 arch/x86/include/asm/suspend_64.h | 16 +++++++-
 arch/x86/power/cpu.c              | 79 ++++++++++++++++++++-------------------
 3 files changed, 62 insertions(+), 41 deletions(-)
arch/x86/include/asm/suspend_32.h +7 -1
index 982c325..8be6afb 100644
@@ -12,7 +12,13 @@
 
 /* image of the saved processor state */
 struct saved_context {
-	u16 es, fs, gs, ss;
+	/*
+	 * On x86_32, all segment registers, with the possible exception of
+	 * gs, are saved at kernel entry in pt_regs.
+	 */
+#ifdef CONFIG_X86_32_LAZY_GS
+	u16 gs;
+#endif
 	unsigned long cr0, cr2, cr3, cr4;
 	u64 misc_enable;
 	bool misc_enable_saved;
arch/x86/include/asm/suspend_64.h +14 -2
index 600e9e0..a7af9f5 100644
@@ -20,8 +20,20 @@
  */
 struct saved_context {
 	struct pt_regs regs;
-	u16 ds, es, fs, gs, ss;
-	unsigned long gs_base, gs_kernel_base, fs_base;
+
+	/*
+	 * User CS and SS are saved in current_pt_regs().  The rest of the
+	 * segment selectors need to be saved and restored here.
+	 */
+	u16 ds, es, fs, gs;
+
+	/*
+	 * Usermode FSBASE and GSBASE may not match the fs and gs selectors,
+	 * so we save them separately.  We save the kernelmode GSBASE to
+	 * restore percpu access after resume.
+	 */
+	unsigned long kernelmode_gs_base, usermode_gs_base, fs_base;
+
 	unsigned long cr0, cr2, cr3, cr4, cr8;
 	u64 misc_enable;
 	bool misc_enable_saved;
arch/x86/power/cpu.c +41 -38

118 lines not on this page · raw message

#2 lore raw

[tip:x86/urgent] x86/power/64: Use struct desc_ptr for the IDT in struct saved_context

In reply to Andy Lutomirski
x86/power/64: Use struct desc_ptr for the IDT in struct saved_context
Commit-ID:  090edbe23ff57940fca7f57d9165ce57a826bd7a
Gitweb:     https://git.kernel.org/tip/090edbe23ff57940fca7f57d9165ce57a826bd7a
Author:     Andy Lutomirski <[email protected]>
AuthorDate: Thu, 14 Dec 2017 13:19:05 -0800
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 15 Dec 2017 12:18:29 +0100

x86/power/64: Use struct desc_ptr for the IDT in struct saved_context

x86_64's saved_context nonsensically used separate idt_limit and idt_base fields and then cast &idt_limit to struct desc_ptr *.

This was correct (with -fno-strict-aliasing), but it's confusing, served no purpose, and required #ifdeffery. Simplify this by using struct desc_ptr directly.

No change in functionality.

---
 arch/x86/include/asm/suspend_64.h |  3 +--
 arch/x86/power/cpu.c              | 11 +----------
 2 files changed, 2 insertions(+), 12 deletions(-)
arch/x86/include/asm/suspend_64.h +1 -2
index 7306e91..600e9e0 100644
@@ -30,8 +30,7 @@ struct saved_context {
 	u16 gdt_pad; /* Unused */
 	struct desc_ptr gdt_desc;
 	u16 idt_pad;
-	u16 idt_limit;
-	unsigned long idt_base;
+	struct desc_ptr idt;
 	u16 ldt;
 	u16 tss;
 	unsigned long tr;
arch/x86/power/cpu.c +1 -10
index 5191de1..472bc8c 100644
@@ -82,12 +82,8 @@ static void __save_processor_state(struct saved_context *ctxt)
 	/*
 	 * descriptor tables
 	 */
-#ifdef CONFIG_X86_32
 	store_idt(&ctxt->idt);
-#else
-/* CONFIG_X86_64 */
-	store_idt((struct desc_ptr *)&ctxt->idt_limit);
-#endif
+
 	/*
 	 * We save it here, but restore it only in the hibernate case.
 	 * For ACPI S3 resume, this is loaded via 'early_gdt_desc' in 64-bit
@@ -219,12 +215,7 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
 	 * now restore the descriptor tables to their proper values
 	 * ltr is done i fix_processor_context().
 	 */
-#ifdef CONFIG_X86_32
 	load_idt(&ctxt->idt);
-#else
-/* CONFIG_X86_64 */
-	load_idt((const struct desc_ptr *)&ctxt->idt_limit);
-#endif
 
 #ifdef CONFIG_X86_64
 	/*
#4 lore raw

[tip:x86/urgent] x86/power/32: Move SYSENTER MSR restoration to fix_processor_context()

In reply to Andy Lutomirski
x86/power/32: Move SYSENTER MSR restoration to fix_processor_context()
Commit-ID:  896c80bef4d3b357814a476663158aaf669d0fb3
Gitweb:     https://git.kernel.org/tip/896c80bef4d3b357814a476663158aaf669d0fb3
Author:     Andy Lutomirski <[email protected]>
AuthorDate: Thu, 14 Dec 2017 13:19:06 -0800
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 15 Dec 2017 12:18:29 +0100

x86/power/32: Move SYSENTER MSR restoration to fix_processor_context()

x86_64 restores system call MSRs in fix_processor_context(), and x86_32 restored them along with segment registers. The 64-bit variant makes more sense, so move the 32-bit code to match the 64-bit code.

No side effects are expected to runtime behavior.

---
 arch/x86/power/cpu.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
arch/x86/power/cpu.c +3 -6
index 472bc8c..033c61e 100644
@@ -174,6 +174,9 @@ static void fix_processor_context(void)
 	write_gdt_entry(desc, GDT_ENTRY_TSS, &tss, DESC_TSS);
 
 	syscall_init();				/* This sets MSR_*STAR and related */
+#else
+	if (boot_cpu_has(X86_FEATURE_SEP))
+		enable_sep_cpu();
 #endif
 	load_TR_desc();				/* This does ltr */
 	load_mm_ldt(current->active_mm);	/* This does lldt */
@@ -237,12 +240,6 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
 	loadsegment(fs, ctxt->fs);
 	loadsegment(gs, ctxt->gs);
 	loadsegment(ss, ctxt->ss);
-
-	/*
-	 * sysenter MSRs
-	 */
-	if (boot_cpu_has(X86_FEATURE_SEP))
-		enable_sep_cpu();
 #else
 /* CONFIG_X86_64 */
 	asm volatile ("movw %0, %%ds" :: "r" (ctxt->ds));