Browse Source

[S390] hibernation: fix lowcore handling

Our swsusp_arch_suspend() backend implementation disables prefixing
by setting the contents of the prefix register to 0.
However afterwards common code functions are called which might
access percpu data structures.
Since the lowcore contains e.g. the percpu base pointer this isn't
a good idea. So fix this by copying the hibernating cpu's lowcore to
absolute address zero.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Heiko Carstens 16 năm trước cách đây
mục cha
commit
5f954c3426
2 tập tin đã thay đổi với 10 bổ sung7 xóa
  1. 2 2
      arch/s390/kernel/early.c
  2. 8 5
      arch/s390/power/swsusp_asm64.S

+ 2 - 2
arch/s390/kernel/early.c

@@ -210,7 +210,7 @@ static noinline __init void detect_machine_type(void)
 		machine_flags |= MACHINE_FLAG_VM;
 }
 
-static void early_pgm_check_handler(void)
+static __init void early_pgm_check_handler(void)
 {
 	unsigned long addr;
 	const struct exception_table_entry *fixup;
@@ -222,7 +222,7 @@ static void early_pgm_check_handler(void)
 	S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
 }
 
-void setup_lowcore_early(void)
+static noinline __init void setup_lowcore_early(void)
 {
 	psw_t psw;
 

+ 8 - 5
arch/s390/power/swsusp_asm64.S

@@ -40,11 +40,11 @@ swsusp_arch_suspend:
 	/* Store prefix register on stack */
 	stpx	__SF_EMPTY(%r15)
 
-	/* Setup base register for lowcore (absolute 0) */
-	llgf	%r1,__SF_EMPTY(%r15)
+	/* Save prefix register contents for lowcore */
+	llgf	%r4,__SF_EMPTY(%r15)
 
 	/* Get pointer to save area */
-	aghi	%r1,0x1000
+	lghi	%r1,0x1000
 
 	/* Store registers */
 	mvc	0x318(4,%r1),__SF_EMPTY(%r15)	/* move prefix to lowcore */
@@ -79,8 +79,11 @@ swsusp_arch_suspend:
 	xc	__SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
 	spx	__SF_EMPTY(%r15)
 
-	/* Setup lowcore */
-	brasl	%r14,setup_lowcore_early
+	lghi	%r2,0
+	lghi	%r3,2*PAGE_SIZE
+	lghi	%r5,2*PAGE_SIZE
+1:	mvcle	%r2,%r4,0
+	jo	1b
 
 	/* Save image */
 	brasl	%r14,swsusp_save