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/sigp.h> 16 17/* 18 * Save register context in absolute 0 lowcore and call swsusp_save() to 19 * create in-memory kernel image. The context is saved in the designated 20 * "store status" memory locations (see POP). 21 * We return from this function twice. The first time during the suspend to 22 * disk process. The second time via the swsusp_arch_resume() function 23 * (see below) in the resume process. 24 * This function runs with disabled interrupts. 25 */ 26 .section .text 27ENTRY(swsusp_arch_suspend) 28 stmg %r6,%r15,__SF_GPRS(%r15) 29 lgr %r1,%r15 30 aghi %r15,-STACK_FRAME_OVERHEAD 31 stg %r1,__SF_BACKCHAIN(%r15) 32 33 /* Deactivate DAT */ 34 stnsm __SF_EMPTY(%r15),0xfb 35 36 /* Store prefix register on stack */ 37 stpx __SF_EMPTY(%r15) 38 39 /* Save prefix register contents for lowcore copy */ 40 llgf %r10,__SF_EMPTY(%r15) 41 42 /* Get pointer to save area */ 43 lghi %r1,0x1000 44 45 /* Save CPU address */ 46 stap __LC_EXT_CPU_ADDR(%r0) 47 48 /* Store registers */ 49 mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ 50 stfpc 0x31c(%r1) /* store fpu control */ 51 std 0,0x200(%r1) /* store f0 */ 52 std 1,0x208(%r1) /* store f1 */ 53 std 2,0x210(%r1) /* store f2 */ 54 std 3,0x218(%r1) /* store f3 */ 55 std 4,0x220(%r1) /* store f4 */ 56 std 5,0x228(%r1) /* store f5 */ 57 std 6,0x230(%r1) /* store f6 */ 58 std 7,0x238(%r1) /* store f7 */ 59 std 8,0x240(%r1) /* store f8 */ 60 std 9,0x248(%r1) /* store f9 */ 61 std 10,0x250(%r1) /* store f10 */ 62 std 11,0x258(%r1) /* store f11 */ 63 std 12,0x260(%r1) /* store f12 */ 64 std 13,0x268(%r1) /* store f13 */ 65 std 14,0x270(%r1) /* store f14 */ 66 std 15,0x278(%r1) /* store f15 */ 67 stam %a0,%a15,0x340(%r1) /* store access registers */ 68 stctg %c0,%c15,0x380(%r1) /* store control registers */ 69 stmg %r0,%r15,0x280(%r1) /* store general registers */ 70 71 stpt 0x328(%r1) /* store timer */ 72 stck __SF_EMPTY(%r15) /* store clock */ 73 stckc 0x330(%r1) /* store clock comparator */ 74 75 /* Update cputime accounting before going to sleep */ 76 lg %r0,__LC_LAST_UPDATE_TIMER 77 slg %r0,0x328(%r1) 78 alg %r0,__LC_SYSTEM_TIMER 79 stg %r0,__LC_SYSTEM_TIMER 80 mvc __LC_LAST_UPDATE_TIMER(8),0x328(%r1) 81 lg %r0,__LC_LAST_UPDATE_CLOCK 82 slg %r0,__SF_EMPTY(%r15) 83 alg %r0,__LC_STEAL_TIMER 84 stg %r0,__LC_STEAL_TIMER 85 mvc __LC_LAST_UPDATE_CLOCK(8),__SF_EMPTY(%r15) 86 87 /* Activate DAT */ 88 stosm __SF_EMPTY(%r15),0x04 89 90 /* Set prefix page to zero */ 91 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) 92 spx __SF_EMPTY(%r15) 93 94 /* Save absolute zero pages */ 95 larl %r2,suspend_zero_pages 96 lg %r2,0(%r2) 97 lghi %r4,0 98 lghi %r3,2*PAGE_SIZE 99 lghi %r5,2*PAGE_SIZE 1001: mvcle %r2,%r4,0 101 jo 1b 102 103 /* Copy lowcore to absolute zero lowcore */ 104 lghi %r2,0 105 lgr %r4,%r10 106 lghi %r3,2*PAGE_SIZE 107 lghi %r5,2*PAGE_SIZE 1081: mvcle %r2,%r4,0 109 jo 1b 110 111 /* Save image */ 112 brasl %r14,swsusp_save 113 114 /* Restore prefix register and return */ 115 lghi %r1,0x1000 116 spx 0x318(%r1) 117 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) 118 lghi %r2,0 119 br %r14 120 121/* 122 * Restore saved memory image to correct place and restore register context. 123 * Then we return to the function that called swsusp_arch_suspend(). 124 * swsusp_arch_resume() runs with disabled interrupts. 125 */ 126ENTRY(swsusp_arch_resume) 127 stmg %r6,%r15,__SF_GPRS(%r15) 128 lgr %r1,%r15 129 aghi %r15,-STACK_FRAME_OVERHEAD 130 stg %r1,__SF_BACKCHAIN(%r15) 131 132 /* Make all free pages stable */ 133 lghi %r2,1 134 brasl %r14,arch_set_page_states 135 136 /* Deactivate DAT */ 137 stnsm __SF_EMPTY(%r15),0xfb 138 139 /* Set prefix page to zero */ 140 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) 141 spx __SF_EMPTY(%r15) 142 143 /* Restore saved image */ 144 larl %r1,restore_pblist 145 lg %r1,0(%r1) 146 ltgr %r1,%r1 147 jz 2f 1480: 149 lg %r2,8(%r1) 150 lg %r4,0(%r1) 151 iske %r0,%r4 152 lghi %r3,PAGE_SIZE 153 lghi %r5,PAGE_SIZE 1541: 155 mvcle %r2,%r4,0 156 jo 1b 157 lg %r2,8(%r1) 158 sske %r0,%r2 159 lg %r1,16(%r1) 160 ltgr %r1,%r1 161 jnz 0b 1622: 163 ptlb /* flush tlb */ 164 165 /* Reset System */ 166 larl %r1,restart_entry 167 larl %r2,.Lrestart_diag308_psw 168 og %r1,0(%r2) 169 stg %r1,0(%r0) 170 larl %r1,.Lnew_pgm_check_psw 171 epsw %r2,%r3 172 stm %r2,%r3,0(%r1) 173 mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1) 174 lghi %r0,0 175 diag %r0,%r0,0x308 176restart_entry: 177 lhi %r1,1 178 sigp %r1,%r0,SIGP_SET_ARCHITECTURE 179 sam64 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 larl %r3,_sclp_print_early 203 lghi %r1,0 204 sam31 205 sigp %r1,%r0,SIGP_SET_ARCHITECTURE 206 basr %r14,%r3 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 lfpc 0x31c(%r13) /* load fpu control */ 242 ld 0,0x200(%r13) /* load f0 */ 243 ld 1,0x208(%r13) /* load f1 */ 244 ld 2,0x210(%r13) /* load f2 */ 245 ld 3,0x218(%r13) /* load f3 */ 246 ld 4,0x220(%r13) /* load f4 */ 247 ld 5,0x228(%r13) /* load f5 */ 248 ld 6,0x230(%r13) /* load f6 */ 249 ld 7,0x238(%r13) /* load f7 */ 250 ld 8,0x240(%r13) /* load f8 */ 251 ld 9,0x248(%r13) /* load f9 */ 252 ld 10,0x250(%r13) /* load f10 */ 253 ld 11,0x258(%r13) /* load f11 */ 254 ld 12,0x260(%r13) /* load f12 */ 255 ld 13,0x268(%r13) /* load f13 */ 256 ld 14,0x270(%r13) /* load f14 */ 257 ld 15,0x278(%r13) /* load f15 */ 258 259 /* Load old stack */ 260 lg %r15,0x2f8(%r13) 261 262 /* Save prefix register */ 263 mvc __SF_EMPTY(4,%r15),0x318(%r13) 264 265 /* Restore absolute zero pages */ 266 lghi %r2,0 267 larl %r4,suspend_zero_pages 268 lg %r4,0(%r4) 269 lghi %r3,2*PAGE_SIZE 270 lghi %r5,2*PAGE_SIZE 2711: mvcle %r2,%r4,0 272 jo 1b 273 274 /* Restore prefix register */ 275 spx __SF_EMPTY(%r15) 276 277 /* Activate DAT */ 278 stosm __SF_EMPTY(%r15),0x04 279 280 /* Make all free pages unstable */ 281 lghi %r2,0 282 brasl %r14,arch_set_page_states 283 284 /* Call arch specific early resume code */ 285 brasl %r14,s390_early_resume 286 287 /* Return 0 */ 288 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) 289 lghi %r2,0 290 br %r14 291 292 .section .data..nosave,"aw",@progbits 293 .align 8 294.Ldisabled_wait_31: 295 .long 0x000a0000,0x00000000 296.Lpanic_string: 297 .asciz "Resume not possible because suspend CPU is no longer available" 298 .align 8 299.Lrestart_diag308_psw: 300 .long 0x00080000,0x80000000 301.Lrestart_suspend_psw: 302 .quad 0x0000000180000000,restart_suspend 303.Lnew_pgm_check_psw: 304 .quad 0,pgm_check_entry 305.Lresume_cpu: 306 .byte 0,0 307