1 /* SPDX-License-Identifier: GPL-2.0 */
3 * S390 64-bit swsusp implementation
5 * Copyright IBM Corp. 2009
7 * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
8 * Michael Holzheu <holzheu@linux.vnet.ibm.com>
11 #include <linux/linkage.h>
13 #include <asm/ptrace.h>
14 #include <asm/thread_info.h>
15 #include <asm/asm-offsets.h>
19 * Save register context in absolute 0 lowcore and call swsusp_save() to
20 * create in-memory kernel image. The context is saved in the designated
21 * "store status" memory locations (see POP).
22 * We return from this function twice. The first time during the suspend to
23 * disk process. The second time via the swsusp_arch_resume() function
24 * (see below) in the resume process.
25 * This function runs with disabled interrupts.
28 ENTRY(swsusp_arch_suspend)
29 stmg %r6,%r15,__SF_GPRS(%r15)
31 aghi %r15,-STACK_FRAME_OVERHEAD
32 stg %r1,__SF_BACKCHAIN(%r15)
34 /* Store FPU registers */
35 brasl %r14,save_fpu_regs
38 stnsm __SF_EMPTY(%r15),0xfb
40 /* Store prefix register on stack */
43 /* Save prefix register contents for lowcore copy */
44 llgf %r10,__SF_EMPTY(%r15)
46 /* Get pointer to save area */
49 /* Save CPU address */
50 stap __LC_EXT_CPU_ADDR(%r0)
53 mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */
54 stam %a0,%a15,0x340(%r1) /* store access registers */
55 stctg %c0,%c15,0x380(%r1) /* store control registers */
56 stmg %r0,%r15,0x280(%r1) /* store general registers */
58 stpt 0x328(%r1) /* store timer */
59 stck __SF_EMPTY(%r15) /* store clock */
60 stckc 0x330(%r1) /* store clock comparator */
62 /* Update cputime accounting before going to sleep */
63 lg %r0,__LC_LAST_UPDATE_TIMER
65 alg %r0,__LC_SYSTEM_TIMER
66 stg %r0,__LC_SYSTEM_TIMER
67 mvc __LC_LAST_UPDATE_TIMER(8),0x328(%r1)
68 lg %r0,__LC_LAST_UPDATE_CLOCK
69 slg %r0,__SF_EMPTY(%r15)
70 alg %r0,__LC_STEAL_TIMER
71 stg %r0,__LC_STEAL_TIMER
72 mvc __LC_LAST_UPDATE_CLOCK(8),__SF_EMPTY(%r15)
75 stosm __SF_EMPTY(%r15),0x04
77 /* Set prefix page to zero */
78 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
81 /* Save absolute zero pages */
82 larl %r2,suspend_zero_pages
90 /* Copy lowcore to absolute zero lowcore */
99 brasl %r14,swsusp_save
101 /* Restore prefix register and return */
104 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
109 * Restore saved memory image to correct place and restore register context.
110 * Then we return to the function that called swsusp_arch_suspend().
111 * swsusp_arch_resume() runs with disabled interrupts.
113 ENTRY(swsusp_arch_resume)
114 stmg %r6,%r15,__SF_GPRS(%r15)
116 aghi %r15,-STACK_FRAME_OVERHEAD
117 stg %r1,__SF_BACKCHAIN(%r15)
119 /* Make all free pages stable */
121 brasl %r14,arch_set_page_states
124 stnsm __SF_EMPTY(%r15),0xfb
126 /* Set prefix page to zero */
127 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
130 /* Restore saved image */
131 larl %r1,restore_pblist
153 larl %r1,restart_entry
154 larl %r2,.Lrestart_diag308_psw
157 larl %r1,.Lnew_pgm_check_psw
160 mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1)
165 sigp %r1,%r0,SIGP_SET_ARCHITECTURE
168 larl %r1,smp_cpu_mt_shift
173 sigp %r1,%r0,SIGP_SET_MULTI_THREADING
174 brc 8,smt_done /* accepted */
175 brc 2,smt_loop /* busy, try again */
178 larl %r1,.Lnew_pgm_check_psw
182 /* Switch to original suspend CPU */
183 larl %r1,.Lresume_cpu /* Resume CPU address: r2 */
186 llgh %r1,__LC_EXT_CPU_ADDR(%r0) /* Suspend CPU address: r1 */
188 je restore_registers /* r1 = r2 -> nothing to do */
189 larl %r4,.Lrestart_suspend_psw /* Set new restart PSW */
190 mvc __LC_RST_NEW_PSW(16,%r0),0(%r4)
192 sigp %r9,%r1,SIGP_INITIAL_CPU_RESET /* sigp initial cpu reset */
193 brc 8,4f /* accepted */
194 brc 2,3b /* busy, try again */
196 /* Suspend CPU not available -> panic */
197 larl %r15,init_thread_union
198 ahi %r15,1<<(PAGE_SHIFT+THREAD_SIZE_ORDER)
199 larl %r2,.Lpanic_string
200 larl %r3,sclp_early_printk
203 sigp %r1,%r0,SIGP_SET_ARCHITECTURE
205 larl %r3,.Ldisabled_wait_31
208 /* Switch to suspend CPU */
209 sigp %r9,%r1,SIGP_RESTART /* sigp restart to suspend CPU */
210 brc 2,4b /* busy, try again */
212 sigp %r9,%r2,SIGP_STOP /* sigp stop to current resume CPU */
213 brc 2,5b /* busy, try again */
217 larl %r1,.Lresume_cpu
220 sigp %r9,%r2,SIGP_SENSE /* sigp sense, wait for resume CPU */
221 brc 8,7b /* accepted, status 0, still running */
222 brc 2,7b /* busy, try again */
223 tmll %r9,0x40 /* Test if resume CPU is stopped */
227 /* Restore registers */
228 lghi %r13,0x1000 /* %r1 = pointer to save area */
230 /* Ignore time spent in suspended state. */
232 stck __LC_LAST_UPDATE_CLOCK(%r1)
233 spt 0x328(%r13) /* reprogram timer */
234 //sckc 0x330(%r13) /* set clock comparator */
236 lctlg %c0,%c15,0x380(%r13) /* load control registers */
237 lam %a0,%a15,0x340(%r13) /* load access registers */
242 /* Save prefix register */
243 mvc __SF_EMPTY(4,%r15),0x318(%r13)
245 /* Restore absolute zero pages */
247 larl %r4,suspend_zero_pages
254 /* Restore prefix register */
258 stosm __SF_EMPTY(%r15),0x04
260 /* Make all free pages unstable */
262 brasl %r14,arch_set_page_states
264 /* Call arch specific early resume code */
265 brasl %r14,s390_early_resume
268 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
272 .section .data..nosave,"aw",@progbits
275 .long 0x000a0000,0x00000000
277 .asciz "Resume not possible because suspend CPU is no longer available\n"
279 .Lrestart_diag308_psw:
280 .long 0x00080000,0x80000000
281 .Lrestart_suspend_psw:
282 .quad 0x0000000180000000,restart_suspend
284 .quad 0,pgm_check_entry