1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * S390 64-bit swsusp implementation 4 * 5 * Copyright IBM Corp. 2009 6 * 7 * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> 8 * Michael Holzheu <holzheu@linux.vnet.ibm.com> 9 */ 10 11#include <linux/linkage.h> 12#include <asm/page.h> 13#include <asm/ptrace.h> 14#include <asm/thread_info.h> 15#include <asm/asm-offsets.h> 16#include <asm/nospec-insn.h> 17#include <asm/sigp.h> 18 19/* 20 * Save register context in absolute 0 lowcore and call swsusp_save() to 21 * create in-memory kernel image. The context is saved in the designated 22 * "store status" memory locations (see POP). 23 * We return from this function twice. The first time during the suspend to 24 * disk process. The second time via the swsusp_arch_resume() function 25 * (see below) in the resume process. 26 * This function runs with disabled interrupts. 27 */ 28 GEN_BR_THUNK %r14 29 30 .section .text 31ENTRY(swsusp_arch_suspend) 32 stmg %r6,%r15,__SF_GPRS(%r15) 33 lgr %r1,%r15 34 aghi %r15,-STACK_FRAME_OVERHEAD 35 stg %r1,__SF_BACKCHAIN(%r15) 36 37 /* Store FPU registers */ 38 brasl %r14,save_fpu_regs 39 40 /* Deactivate DAT */ 41 stnsm __SF_EMPTY(%r15),0xfb 42 43 /* Store prefix register on stack */ 44 stpx __SF_EMPTY(%r15) 45 46 /* Save prefix register contents for lowcore copy */ 47 llgf %r10,__SF_EMPTY(%r15) 48 49 /* Get pointer to save area */ 50 lghi %r1,0x1000 51 52 /* Save CPU address */ 53 stap __LC_EXT_CPU_ADDR(%r0) 54 55 /* Store registers */ 56 mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ 57 stam %a0,%a15,0x340(%r1) /* store access registers */ 58 stctg %c0,%c15,0x380(%r1) /* store control registers */ 59 stmg %r0,%r15,0x280(%r1) /* store general registers */ 60 61 stpt 0x328(%r1) /* store timer */ 62 stck __SF_EMPTY(%r15) /* store clock */ 63 stckc 0x330(%r1) /* store clock comparator */ 64 65 /* Update cputime accounting before going to sleep */ 66 lg %r0,__LC_LAST_UPDATE_TIMER 67 slg %r0,0x328(%r1) 68 alg %r0,__LC_SYSTEM_TIMER 69 stg %r0,__LC_SYSTEM_TIMER 70 mvc __LC_LAST_UPDATE_TIMER(8),0x328(%r1) 71 lg %r0,__LC_LAST_UPDATE_CLOCK 72 slg %r0,__SF_EMPTY(%r15) 73 alg %r0,__LC_STEAL_TIMER 74 stg %r0,__LC_STEAL_TIMER 75 mvc __LC_LAST_UPDATE_CLOCK(8),__SF_EMPTY(%r15) 76 77 /* Activate DAT */ 78 stosm __SF_EMPTY(%r15),0x04 79 80 /* Set prefix page to zero */ 81 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) 82 spx __SF_EMPTY(%r15) 83 84 /* Save absolute zero pages */ 85 larl %r2,suspend_zero_pages 86 lg %r2,0(%r2) 87 lghi %r4,0 88 lghi %r3,2*PAGE_SIZE 89 lghi %r5,2*PAGE_SIZE 901: mvcle %r2,%r4,0 91 jo 1b 92 93 /* Copy lowcore to absolute zero lowcore */ 94 lghi %r2,0 95 lgr %r4,%r10 96 lghi %r3,2*PAGE_SIZE 97 lghi %r5,2*PAGE_SIZE 981: mvcle %r2,%r4,0 99 jo 1b 100 101 /* Save image */ 102 brasl %r14,swsusp_save 103 104 /* Restore prefix register and return */ 105 lghi %r1,0x1000 106 spx 0x318(%r1) 107 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) 108 lghi %r2,0 109 BR_EX %r14 110 111/* 112 * Restore saved memory image to correct place and restore register context. 113 * Then we return to the function that called swsusp_arch_suspend(). 114 * swsusp_arch_resume() runs with disabled interrupts. 115 */ 116ENTRY(swsusp_arch_resume) 117 stmg %r6,%r15,__SF_GPRS(%r15) 118 lgr %r1,%r15 119 aghi %r15,-STACK_FRAME_OVERHEAD 120 stg %r1,__SF_BACKCHAIN(%r15) 121 122 /* Make all free pages stable */ 123 lghi %r2,1 124 brasl %r14,arch_set_page_states 125 126 /* Deactivate DAT */ 127 stnsm __SF_EMPTY(%r15),0xfb 128 129 /* Set prefix page to zero */ 130 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) 131 spx __SF_EMPTY(%r15) 132 133 /* Restore saved image */ 134 larl %r1,restore_pblist 135 lg %r1,0(%r1) 136 ltgr %r1,%r1 137 jz 2f 1380: 139 lg %r2,8(%r1) 140 lg %r4,0(%r1) 141 iske %r0,%r4 142 lghi %r3,PAGE_SIZE 143 lghi %r5,PAGE_SIZE 1441: 145 mvcle %r2,%r4,0 146 jo 1b 147 lg %r2,8(%r1) 148 sske %r0,%r2 149 lg %r1,16(%r1) 150 ltgr %r1,%r1 151 jnz 0b 1522: 153 ptlb /* flush tlb */ 154 155 /* Reset System */ 156 larl %r1,restart_entry 157 larl %r2,.Lrestart_diag308_psw 158 og %r1,0(%r2) 159 stg %r1,0(%r0) 160 larl %r1,.Lnew_pgm_check_psw 161 epsw %r2,%r3 162 stm %r2,%r3,0(%r1) 163 mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1) 164 lghi %r0,0 165 diag %r0,%r0,0x308 166restart_entry: 167 lhi %r1,1 168 sigp %r1,%r0,SIGP_SET_ARCHITECTURE 169 sam64 170#ifdef CONFIG_SMP 171 larl %r1,smp_cpu_mt_shift 172 icm %r1,15,0(%r1) 173 jz smt_done 174 llgfr %r1,%r1 175smt_loop: 176 sigp %r1,%r0,SIGP_SET_MULTI_THREADING 177 brc 8,smt_done /* accepted */ 178 brc 2,smt_loop /* busy, try again */ 179smt_done: 180#endif 181 larl %r1,.Lnew_pgm_check_psw 182 lpswe 0(%r1) 183pgm_check_entry: 184 185 /* Switch to original suspend CPU */ 186 larl %r1,.Lresume_cpu /* Resume CPU address: r2 */ 187 stap 0(%r1) 188 llgh %r2,0(%r1) 189 llgh %r1,__LC_EXT_CPU_ADDR(%r0) /* Suspend CPU address: r1 */ 190 cgr %r1,%r2 191 je restore_registers /* r1 = r2 -> nothing to do */ 192 larl %r4,.Lrestart_suspend_psw /* Set new restart PSW */ 193 mvc __LC_RST_NEW_PSW(16,%r0),0(%r4) 1943: 195 sigp %r9,%r1,SIGP_INITIAL_CPU_RESET /* sigp initial cpu reset */ 196 brc 8,4f /* accepted */ 197 brc 2,3b /* busy, try again */ 198 199 /* Suspend CPU not available -> panic */ 200 larl %r15,init_thread_union 201 aghi %r15,1<<(PAGE_SHIFT+THREAD_SIZE_ORDER) 202 aghi %r15,-STACK_FRAME_OVERHEAD 203 larl %r2,.Lpanic_string 204 brasl %r14,sclp_early_printk_force 205 larl %r3,.Ldisabled_wait_31 206 lpsw 0(%r3) 2074: 208 /* Switch to suspend CPU */ 209 sigp %r9,%r1,SIGP_RESTART /* sigp restart to suspend CPU */ 210 brc 2,4b /* busy, try again */ 2115: 212 sigp %r9,%r2,SIGP_STOP /* sigp stop to current resume CPU */ 213 brc 2,5b /* busy, try again */ 2146: j 6b 215 216restart_suspend: 217 larl %r1,.Lresume_cpu 218 llgh %r2,0(%r1) 2197: 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 */ 224 jz 7b 225 226restore_registers: 227 /* Restore registers */ 228 lghi %r13,0x1000 /* %r1 = pointer to save area */ 229 230 /* Ignore time spent in suspended state. */ 231 llgf %r1,0x318(%r13) 232 stck __LC_LAST_UPDATE_CLOCK(%r1) 233 spt 0x328(%r13) /* reprogram timer */ 234 //sckc 0x330(%r13) /* set clock comparator */ 235 236 lctlg %c0,%c15,0x380(%r13) /* load control registers */ 237 lam %a0,%a15,0x340(%r13) /* load access registers */ 238 239 /* Load old stack */ 240 lg %r15,0x2f8(%r13) 241 242 /* Save prefix register */ 243 mvc __SF_EMPTY(4,%r15),0x318(%r13) 244 245 /* Restore absolute zero pages */ 246 lghi %r2,0 247 larl %r4,suspend_zero_pages 248 lg %r4,0(%r4) 249 lghi %r3,2*PAGE_SIZE 250 lghi %r5,2*PAGE_SIZE 2511: mvcle %r2,%r4,0 252 jo 1b 253 254 /* Restore prefix register */ 255 spx __SF_EMPTY(%r15) 256 257 /* Activate DAT */ 258 stosm __SF_EMPTY(%r15),0x04 259 260 /* Make all free pages unstable */ 261 lghi %r2,0 262 brasl %r14,arch_set_page_states 263 264 /* Call arch specific early resume code */ 265 brasl %r14,s390_early_resume 266 267 /* Return 0 */ 268 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) 269 lghi %r2,0 270 BR_EX %r14 271 272 .section .data..nosave,"aw",@progbits 273 .align 8 274.Ldisabled_wait_31: 275 .long 0x000a0000,0x00000000 276.Lpanic_string: 277 .asciz "Resume not possible because suspend CPU is no longer available\n" 278 .align 8 279.Lrestart_diag308_psw: 280 .long 0x00080000,0x80000000 281.Lrestart_suspend_psw: 282 .quad 0x0000000180000000,restart_suspend 283.Lnew_pgm_check_psw: 284 .quad 0,pgm_check_entry 285.Lresume_cpu: 286 .byte 0,0 287