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 <asm/page.h> 11#include <asm/ptrace.h> 12#include <asm/thread_info.h> 13#include <asm/asm-offsets.h> 14 15/* 16 * Save register context in absolute 0 lowcore and call swsusp_save() to 17 * create in-memory kernel image. The context is saved in the designated 18 * "store status" memory locations (see POP). 19 * We return from this function twice. The first time during the suspend to 20 * disk process. The second time via the swsusp_arch_resume() function 21 * (see below) in the resume process. 22 * This function runs with disabled interrupts. 23 */ 24 .section .text 25 .align 4 26 .globl swsusp_arch_suspend 27swsusp_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 */ 40 llgf %r4,__SF_EMPTY(%r15) 41 42 /* Get pointer to save area */ 43 lghi %r1,0x1000 44 45 /* Save CPU address */ 46 stap __LC_CPU_ADDRESS(%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 lghi %r2,0 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 %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 */ 115 .globl swsusp_arch_resume 116swsusp_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 lghi %r3,PAGE_SIZE 142 lghi %r5,PAGE_SIZE 1431: 144 mvcle %r2,%r4,0 145 jo 1b 146 lg %r1,16(%r1) 147 ltgr %r1,%r1 148 jnz 0b 1492: 150 ptlb /* flush tlb */ 151 152 /* Reset System */ 153 larl %r1,restart_entry 154 larl %r2,.Lrestart_diag308_psw 155 og %r1,0(%r2) 156 stg %r1,0(%r0) 157 larl %r1,.Lnew_pgm_check_psw 158 epsw %r2,%r3 159 stm %r2,%r3,0(%r1) 160 mvc __LC_PGM_NEW_PSW(16,%r0),0(%r1) 161 lghi %r0,0 162 diag %r0,%r0,0x308 163restart_entry: 164 lhi %r1,1 165 sigp %r1,%r0,0x12 166 sam64 167 larl %r1,.Lnew_pgm_check_psw 168 lpswe 0(%r1) 169pgm_check_entry: 170 171 /* Switch to original suspend CPU */ 172 larl %r1,.Lresume_cpu /* Resume CPU address: r2 */ 173 stap 0(%r1) 174 llgh %r2,0(%r1) 175 llgh %r1,__LC_CPU_ADDRESS(%r0) /* Suspend CPU address: r1 */ 176 cgr %r1,%r2 177 je restore_registers /* r1 = r2 -> nothing to do */ 178 larl %r4,.Lrestart_suspend_psw /* Set new restart PSW */ 179 mvc __LC_RST_NEW_PSW(16,%r0),0(%r4) 1803: 181 sigp %r9,%r1,__SIGP_INITIAL_CPU_RESET 182 brc 8,4f /* accepted */ 183 brc 2,3b /* busy, try again */ 184 185 /* Suspend CPU not available -> panic */ 186 larl %r15,init_thread_union 187 ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) 188 larl %r2,.Lpanic_string 189 larl %r3,_sclp_print_early 190 lghi %r1,0 191 sam31 192 sigp %r1,%r0,0x12 193 basr %r14,%r3 194 larl %r3,.Ldisabled_wait_31 195 lpsw 0(%r3) 1964: 197 /* Switch to suspend CPU */ 198 sigp %r9,%r1,__SIGP_RESTART /* start suspend CPU */ 199 brc 2,4b /* busy, try again */ 2005: 201 sigp %r9,%r2,__SIGP_STOP /* stop resume (current) CPU */ 202 brc 2,5b /* busy, try again */ 2036: j 6b 204 205restart_suspend: 206 larl %r1,.Lresume_cpu 207 llgh %r2,0(%r1) 2087: 209 sigp %r9,%r2,__SIGP_SENSE /* Wait for resume CPU */ 210 brc 8,7b /* accepted, status 0, still running */ 211 brc 2,7b /* busy, try again */ 212 tmll %r9,0x40 /* Test if resume CPU is stopped */ 213 jz 7b 214 215restore_registers: 216 /* Restore registers */ 217 lghi %r13,0x1000 /* %r1 = pointer to save area */ 218 219 /* Ignore time spent in suspended state. */ 220 llgf %r1,0x318(%r13) 221 stck __LC_LAST_UPDATE_CLOCK(%r1) 222 spt 0x328(%r13) /* reprogram timer */ 223 //sckc 0x330(%r13) /* set clock comparator */ 224 225 lctlg %c0,%c15,0x380(%r13) /* load control registers */ 226 lam %a0,%a15,0x340(%r13) /* load access registers */ 227 228 lfpc 0x31c(%r13) /* load fpu control */ 229 ld 0,0x200(%r13) /* load f0 */ 230 ld 1,0x208(%r13) /* load f1 */ 231 ld 2,0x210(%r13) /* load f2 */ 232 ld 3,0x218(%r13) /* load f3 */ 233 ld 4,0x220(%r13) /* load f4 */ 234 ld 5,0x228(%r13) /* load f5 */ 235 ld 6,0x230(%r13) /* load f6 */ 236 ld 7,0x238(%r13) /* load f7 */ 237 ld 8,0x240(%r13) /* load f8 */ 238 ld 9,0x248(%r13) /* load f9 */ 239 ld 10,0x250(%r13) /* load f10 */ 240 ld 11,0x258(%r13) /* load f11 */ 241 ld 12,0x260(%r13) /* load f12 */ 242 ld 13,0x268(%r13) /* load f13 */ 243 ld 14,0x270(%r13) /* load f14 */ 244 ld 15,0x278(%r13) /* load f15 */ 245 246 /* Load old stack */ 247 lg %r15,0x2f8(%r13) 248 249 /* Restore prefix register */ 250 spx 0x318(%r13) 251 252 /* Activate DAT */ 253 stosm __SF_EMPTY(%r15),0x04 254 255 /* Make all free pages unstable */ 256 lghi %r2,0 257 brasl %r14,arch_set_page_states 258 259 /* Reinitialize the channel subsystem */ 260 brasl %r14,channel_subsystem_reinit 261 262 /* Return 0 */ 263 lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) 264 lghi %r2,0 265 br %r14 266 267 .section .data..nosave,"aw",@progbits 268 .align 8 269.Ldisabled_wait_31: 270 .long 0x000a0000,0x00000000 271.Lpanic_string: 272 .asciz "Resume not possible because suspend CPU is no longer available" 273 .align 8 274.Lrestart_diag308_psw: 275 .long 0x00080000,0x80000000 276.Lrestart_suspend_psw: 277 .quad 0x0000000180000000,restart_suspend 278.Lnew_pgm_check_psw: 279 .quad 0,pgm_check_entry 280.Lresume_cpu: 281 .byte 0,0 282