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 ahi %r15,1<<(PAGE_SHIFT+THREAD_SIZE_ORDER) 202 larl %r2,.Lpanic_string 203 lghi %r1,0 204 sam31 205 sigp %r1,%r0,SIGP_SET_ARCHITECTURE 206 brasl %r14,sclp_early_printk 207 larl %r3,.Ldisabled_wait_31 208 lpsw 0(%r3) 2094: 210 /* Switch to suspend CPU */ 211 sigp %r9,%r1,SIGP_RESTART /* sigp restart to suspend CPU */ 212 brc 2,4b /* busy, try again */ 2135: 214 sigp %r9,%r2,SIGP_STOP /* sigp stop to current resume CPU */ 215 brc 2,5b /* busy, try again */ 2166: j 6b 217 218restart_suspend: 219 larl %r1,.Lresume_cpu 220 llgh %r2,0(%r1) 2217: 222 sigp %r9,%r2,SIGP_SENSE /* sigp sense, wait for resume CPU */ 223 brc 8,7b /* accepted, status 0, still running */ 224 brc 2,7b /* busy, try again */ 225 tmll %r9,0x40 /* Test if resume CPU is stopped */ 226 jz 7b 227 228restore_registers: 229 /* Restore registers */ 230 lghi %r13,0x1000 /* %r1 = pointer to save area */ 231 232 /* Ignore time spent in suspended state. */ 233 llgf %r1,0x318(%r13) 234 stck __LC_LAST_UPDATE_CLOCK(%r1) 235 spt 0x328(%r13) /* reprogram timer */ 236 //sckc 0x330(%r13) /* set clock comparator */ 237 238 lctlg %c0,%c15,0x380(%r13) /* load control registers */ 239 lam %a0,%a15,0x340(%r13) /* load access registers */ 240 241 /* Load old stack */ 242 lg %r15,0x2f8(%r13) 243 244 /* Save prefix register */ 245 mvc __SF_EMPTY(4,%r15),0x318(%r13) 246 247 /* Restore absolute zero pages */ 248 lghi %r2,0 249 larl %r4,suspend_zero_pages 250 lg %r4,0(%r4) 251 lghi %r3,2*PAGE_SIZE 252 lghi %r5,2*PAGE_SIZE 2531: mvcle %r2,%r4,0 254 jo 1b 255 256 /* Restore prefix register */ 257 spx __SF_EMPTY(%r15) 258 259 /* Activate DAT */ 260 stosm __SF_EMPTY(%r15),0x04 261 262 /* Make all free pages unstable */ 263 lghi %r2,0 264 brasl %r14,arch_set_page_states 265 266 /* Call arch specific early resume code */ 267 brasl %r14,s390_early_resume 268 269 /* Return 0 */ 270 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) 271 lghi %r2,0 272 BR_EX %r14 273 274 .section .data..nosave,"aw",@progbits 275 .align 8 276.Ldisabled_wait_31: 277 .long 0x000a0000,0x00000000 278.Lpanic_string: 279 .asciz "Resume not possible because suspend CPU is no longer available\n" 280 .align 8 281.Lrestart_diag308_psw: 282 .long 0x00080000,0x80000000 283.Lrestart_suspend_psw: 284 .quad 0x0000000180000000,restart_suspend 285.Lnew_pgm_check_psw: 286 .quad 0,pgm_check_entry 287.Lresume_cpu: 288 .byte 0,0 289