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