root/arch/s390/kernel/swsusp.S

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

/* [<][>][^][v][top][bottom][index][help] */