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 16/* 17 * Save register context in absolute 0 lowcore and call swsusp_save() to 18 * create in-memory kernel image. The context is saved in the designated 19 * "store status" memory locations (see POP). 20 * We return from this function twice. The first time during the suspend to 21 * disk process. The second time via the swsusp_arch_resume() function 22 * (see below) in the resume process. 23 * This function runs with disabled interrupts. 24 */ 25 .section .text 26ENTRY(swsusp_arch_suspend) 27 stmg %r6,%r15,__SF_GPRS(%r15) 28 lgr %r1,%r15 29 aghi %r15,-STACK_FRAME_OVERHEAD 30 stg %r1,__SF_BACKCHAIN(%r15) 31 32 /* Deactivate DAT */ 33 stnsm __SF_EMPTY(%r15),0xfb 34 35 /* Store prefix register on stack */ 36 stpx __SF_EMPTY(%r15) 37 38 /* Save prefix register contents for lowcore */ 39 llgf %r4,__SF_EMPTY(%r15) 40 41 /* Get pointer to save area */ 42 lghi %r1,0x1000 43 44 /* Save CPU address */ 45 stap __LC_EXT_CPU_ADDR(%r0) 46 47 /* Store registers */ 48 mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ 49 stfpc 0x31c(%r1) /* store fpu control */ 50 std 0,0x200(%r1) /* store f0 */ 51 std 1,0x208(%r1) /* store f1 */ 52 std 2,0x210(%r1) /* store f2 */ 53 std 3,0x218(%r1) /* store f3 */ 54 std 4,0x220(%r1) /* store f4 */ 55 std 5,0x228(%r1) /* store f5 */ 56 std 6,0x230(%r1) /* store f6 */ 57 std 7,0x238(%r1) /* store f7 */ 58 std 8,0x240(%r1) /* store f8 */ 59 std 9,0x248(%r1) /* store f9 */ 60 std 10,0x250(%r1) /* store f10 */ 61 std 11,0x258(%r1) /* store f11 */ 62 std 12,0x260(%r1) /* store f12 */ 63 std 13,0x268(%r1) /* store f13 */ 64 std 14,0x270(%r1) /* store f14 */ 65 std 15,0x278(%r1) /* store f15 */ 66 stam %a0,%a15,0x340(%r1) /* store access registers */ 67 stctg %c0,%c15,0x380(%r1) /* store control registers */ 68 stmg %r0,%r15,0x280(%r1) /* store general registers */ 69 70 stpt 0x328(%r1) /* store timer */ 71 stck __SF_EMPTY(%r15) /* store clock */ 72 stckc 0x330(%r1) /* store clock comparator */ 73 74 /* Update cputime accounting before going to sleep */ 75 lg %r0,__LC_LAST_UPDATE_TIMER 76 slg %r0,0x328(%r1) 77 alg %r0,__LC_SYSTEM_TIMER 78 stg %r0,__LC_SYSTEM_TIMER 79 mvc __LC_LAST_UPDATE_TIMER(8),0x328(%r1) 80 lg %r0,__LC_LAST_UPDATE_CLOCK 81 slg %r0,__SF_EMPTY(%r15) 82 alg %r0,__LC_STEAL_TIMER 83 stg %r0,__LC_STEAL_TIMER 84 mvc __LC_LAST_UPDATE_CLOCK(8),__SF_EMPTY(%r15) 85 86 /* Activate DAT */ 87 stosm __SF_EMPTY(%r15),0x04 88 89 /* Set prefix page to zero */ 90 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) 91 spx __SF_EMPTY(%r15) 92 93 lghi %r2,0 94 lghi %r3,2*PAGE_SIZE 95 lghi %r5,2*PAGE_SIZE 961: mvcle %r2,%r4,0 97 jo 1b 98 99 /* Save image */ 100 brasl %r14,swsusp_save 101 102 /* Restore prefix register and return */ 103 lghi %r1,0x1000 104 spx 0x318(%r1) 105 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) 106 lghi %r2,0 107 br %r14 108 109/* 110 * Restore saved memory image to correct place and restore register context. 111 * Then we return to the function that called swsusp_arch_suspend(). 112 * swsusp_arch_resume() runs with disabled interrupts. 113 */ 114ENTRY(swsusp_arch_resume) 115 stmg %r6,%r15,__SF_GPRS(%r15) 116 lgr %r1,%r15 117 aghi %r15,-STACK_FRAME_OVERHEAD 118 stg %r1,__SF_BACKCHAIN(%r15) 119 120 /* Make all free pages stable */ 121 lghi %r2,1 122 brasl %r14,arch_set_page_states 123 124 /* Deactivate DAT */ 125 stnsm __SF_EMPTY(%r15),0xfb 126 127 /* Set prefix page to zero */ 128 xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) 129 spx __SF_EMPTY(%r15) 130 131 /* Restore saved image */ 132 larl %r1,restore_pblist 133 lg %r1,0(%r1) 134 ltgr %r1,%r1 135 jz 2f 1360: 137 lg %r2,8(%r1) 138 lg %r4,0(%r1) 139 iske %r0,%r4 140 lghi %r3,PAGE_SIZE 141 lghi %r5,PAGE_SIZE 1421: 143 mvcle %r2,%r4,0 144 jo 1b 145 lg %r2,8(%r1) 146 sske %r0,%r2 147 lg %r1,16(%r1) 148 ltgr %r1,%r1 149 jnz 0b 1502: 151 ptlb /* flush tlb */ 152 153 /* Reset System */ 154 larl %r1,restart_entry 155 larl %r2,.Lrestart_diag308_psw 156 og %r1,0(%r2) 157 stg %r1,0(%r0) 158 larl %r1,.Lnew_pgm_check_psw 159 epsw %r2,%r3 160 stm %r2,%r3,0(%r1) 161 mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1) 162 lghi %r0,0 163 diag %r0,%r0,0x308 164restart_entry: 165 lhi %r1,1 166 sigp %r1,%r0,0x12 167 sam64 168 larl %r1,.Lnew_pgm_check_psw 169 lpswe 0(%r1) 170pgm_check_entry: 171 172 /* Switch to original suspend CPU */ 173 larl %r1,.Lresume_cpu /* Resume CPU address: r2 */ 174 stap 0(%r1) 175 llgh %r2,0(%r1) 176 llgh %r1,__LC_EXT_CPU_ADDR(%r0) /* Suspend CPU address: r1 */ 177 cgr %r1,%r2 178 je restore_registers /* r1 = r2 -> nothing to do */ 179 larl %r4,.Lrestart_suspend_psw /* Set new restart PSW */ 180 mvc __LC_RST_NEW_PSW(16,%r0),0(%r4) 1813: 182 sigp %r9,%r1,11 /* sigp initial cpu reset */ 183 brc 8,4f /* accepted */ 184 brc 2,3b /* busy, try again */ 185 186 /* Suspend CPU not available -> panic */ 187 larl %r15,init_thread_union 188 ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) 189 larl %r2,.Lpanic_string 190 larl %r3,_sclp_print_early 191 lghi %r1,0 192 sam31 193 sigp %r1,%r0,0x12 194 basr %r14,%r3 195 larl %r3,.Ldisabled_wait_31 196 lpsw 0(%r3) 1974: 198 /* Switch to suspend CPU */ 199 sigp %r9,%r1,6 /* sigp restart to suspend CPU */ 200 brc 2,4b /* busy, try again */ 2015: 202 sigp %r9,%r2,5 /* sigp stop to current resume CPU */ 203 brc 2,5b /* busy, try again */ 2046: j 6b 205 206restart_suspend: 207 larl %r1,.Lresume_cpu 208 llgh %r2,0(%r1) 2097: 210 sigp %r9,%r2,1 /* sigp sense, wait for resume CPU */ 211 brc 8,7b /* accepted, status 0, still running */ 212 brc 2,7b /* busy, try again */ 213 tmll %r9,0x40 /* Test if resume CPU is stopped */ 214 jz 7b 215 216restore_registers: 217 /* Restore registers */ 218 lghi %r13,0x1000 /* %r1 = pointer to save area */ 219 220 /* Ignore time spent in suspended state. */ 221 llgf %r1,0x318(%r13) 222 stck __LC_LAST_UPDATE_CLOCK(%r1) 223 spt 0x328(%r13) /* reprogram timer */ 224 //sckc 0x330(%r13) /* set clock comparator */ 225 226 lctlg %c0,%c15,0x380(%r13) /* load control registers */ 227 lam %a0,%a15,0x340(%r13) /* load access registers */ 228 229 lfpc 0x31c(%r13) /* load fpu control */ 230 ld 0,0x200(%r13) /* load f0 */ 231 ld 1,0x208(%r13) /* load f1 */ 232 ld 2,0x210(%r13) /* load f2 */ 233 ld 3,0x218(%r13) /* load f3 */ 234 ld 4,0x220(%r13) /* load f4 */ 235 ld 5,0x228(%r13) /* load f5 */ 236 ld 6,0x230(%r13) /* load f6 */ 237 ld 7,0x238(%r13) /* load f7 */ 238 ld 8,0x240(%r13) /* load f8 */ 239 ld 9,0x248(%r13) /* load f9 */ 240 ld 10,0x250(%r13) /* load f10 */ 241 ld 11,0x258(%r13) /* load f11 */ 242 ld 12,0x260(%r13) /* load f12 */ 243 ld 13,0x268(%r13) /* load f13 */ 244 ld 14,0x270(%r13) /* load f14 */ 245 ld 15,0x278(%r13) /* load f15 */ 246 247 /* Load old stack */ 248 lg %r15,0x2f8(%r13) 249 250 /* Restore prefix register */ 251 spx 0x318(%r13) 252 253 /* Activate DAT */ 254 stosm __SF_EMPTY(%r15),0x04 255 256 /* Make all free pages unstable */ 257 lghi %r2,0 258 brasl %r14,arch_set_page_states 259 260 /* Log potential guest relocation */ 261 brasl %r14,lgr_info_log 262 263 /* Reinitialize the channel subsystem */ 264 brasl %r14,channel_subsystem_reinit 265 266 /* Return 0 */ 267 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) 268 lghi %r2,0 269 br %r14 270 271 .section .data..nosave,"aw",@progbits 272 .align 8 273.Ldisabled_wait_31: 274 .long 0x000a0000,0x00000000 275.Lpanic_string: 276 .asciz "Resume not possible because suspend CPU is no longer available" 277 .align 8 278.Lrestart_diag308_psw: 279 .long 0x00080000,0x80000000 280.Lrestart_suspend_psw: 281 .quad 0x0000000180000000,restart_suspend 282.Lnew_pgm_check_psw: 283 .quad 0,pgm_check_entry 284.Lresume_cpu: 285 .byte 0,0 286