1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Purgatory setup code 4 * 5 * Copyright IBM Corp. 2018 6 * 7 * Author(s): Philipp Rudo <prudo@linux.vnet.ibm.com> 8 */ 9 10 #include <linux/linkage.h> 11 #include <asm/asm-offsets.h> 12 #include <asm/page.h> 13 #include <asm/sigp.h> 14 #include <asm/ptrace.h> 15 16 /* The purgatory is the code running between two kernels. It's main purpose 17 * is to verify that the next kernel was not corrupted after load and to 18 * start it. 19 * 20 * If the next kernel is a crash kernel there are some peculiarities to 21 * consider: 22 * 23 * First the purgatory is called twice. Once only to verify the 24 * sha digest. So if the crash kernel got corrupted the old kernel can try 25 * to trigger a stand-alone dumper. And once to actually load the crash kernel. 26 * 27 * Second the purgatory also has to swap the crash memory region with its 28 * destination at address 0. As the purgatory is part of crash memory this 29 * requires some finesse. The tactic here is that the purgatory first copies 30 * itself to the end of the destination and then swaps the rest of the 31 * memory running from there. 32 */ 33 34 #define bufsz purgatory_end-stack 35 36 .macro MEMCPY dst,src,len 37 lgr %r0,\dst 38 lgr %r1,\len 39 lgr %r2,\src 40 lgr %r3,\len 41 42 20: mvcle %r0,%r2,0 43 jo 20b 44 .endm 45 46 .macro MEMSWAP dst,src,buf,len 47 10: larl %r0,purgatory_end 48 larl %r1,stack 49 slgr %r0,%r1 50 cgr \len,%r0 51 jh 11f 52 lgr %r4,\len 53 j 12f 54 11: lgr %r4,%r0 55 56 12: MEMCPY \buf,\dst,%r4 57 MEMCPY \dst,\src,%r4 58 MEMCPY \src,\buf,%r4 59 60 agr \dst,%r4 61 agr \src,%r4 62 sgr \len,%r4 63 64 cghi \len,0 65 jh 10b 66 .endm 67 68 .macro START_NEXT_KERNEL base subcode 69 lg %r4,kernel_entry-\base(%r13) 70 lg %r5,load_psw_mask-\base(%r13) 71 ogr %r4,%r5 72 stg %r4,0(%r0) 73 74 xgr %r0,%r0 75 lghi %r1,\subcode 76 diag %r0,%r1,0x308 77 .endm 78 79 .text 80 .balign PAGE_SIZE 81 SYM_CODE_START(purgatory_start) 82 /* The purgatory might be called after a diag308 so better set 83 * architecture and addressing mode. 84 */ 85 lhi %r1,1 86 sigp %r1,%r0,SIGP_SET_ARCHITECTURE 87 sam64 88 89 larl %r5,gprregs 90 stmg %r6,%r15,0(%r5) 91 92 basr %r13,0 93 .base_crash: 94 95 /* Setup stack */ 96 larl %r15,purgatory_end-STACK_FRAME_OVERHEAD 97 98 /* If the next kernel is KEXEC_TYPE_CRASH the purgatory is called 99 * directly with a flag passed in %r2 whether the purgatory shall do 100 * checksum verification only (%r2 = 0 -> verification only). 101 * 102 * Check now and preserve over C function call by storing in 103 * %r10 with 104 * 1 -> checksum verification only 105 * 0 -> load new kernel 106 */ 107 lghi %r10,0 108 lg %r11,kernel_type-.base_crash(%r13) 109 cghi %r11,1 /* KEXEC_TYPE_CRASH */ 110 jne .do_checksum_verification 111 cghi %r2,0 /* checksum verification only */ 112 jne .do_checksum_verification 113 lghi %r10,1 114 115 .do_checksum_verification: 116 brasl %r14,verify_sha256_digest 117 118 cghi %r10,1 /* checksum verification only */ 119 je .return_old_kernel 120 cghi %r2,0 /* checksum match */ 121 jne .disabled_wait 122 123 /* If the next kernel is a crash kernel the purgatory has to swap 124 * the mem regions first. 125 */ 126 cghi %r11,1 /* KEXEC_TYPE_CRASH */ 127 je .start_crash_kernel 128 129 /* start normal kernel */ 130 START_NEXT_KERNEL .base_crash 0 131 132 .return_old_kernel: 133 lmg %r6,%r15,gprregs-.base_crash(%r13) 134 br %r14 135 136 .disabled_wait: 137 lpswe disabled_wait_psw-.base_crash(%r13) 138 139 .start_crash_kernel: 140 /* Location of purgatory_start in crash memory */ 141 larl %r0,.base_crash 142 larl %r1,purgatory_start 143 slgr %r0,%r1 144 lgr %r8,%r13 145 sgr %r8,%r0 146 147 /* Destination for this code i.e. end of memory to be swapped. */ 148 larl %r0,purgatory_end 149 larl %r1,purgatory_start 150 slgr %r0,%r1 151 lg %r9,crash_size-.base_crash(%r13) 152 sgr %r9,%r0 153 154 /* Destination in crash memory, i.e. same as r9 but in crash memory. */ 155 lg %r10,crash_start-.base_crash(%r13) 156 agr %r10,%r9 157 158 /* Buffer location (in crash memory) and size. As the purgatory is 159 * behind the point of no return it can re-use the stack as buffer. 160 */ 161 larl %r11,purgatory_end 162 larl %r12,stack 163 slgr %r11,%r12 164 165 MEMCPY %r12,%r9,%r11 /* dst -> (crash) buf */ 166 MEMCPY %r9,%r8,%r11 /* self -> dst */ 167 168 /* Jump to new location. */ 169 lgr %r7,%r9 170 larl %r0,.jump_to_dst 171 larl %r1,purgatory_start 172 slgr %r0,%r1 173 agr %r7,%r0 174 br %r7 175 176 .jump_to_dst: 177 basr %r13,0 178 .base_dst: 179 180 /* clear buffer */ 181 MEMCPY %r12,%r10,%r11 /* (crash) buf -> (crash) dst */ 182 183 /* Load new buffer location after jump */ 184 larl %r7,stack 185 lgr %r0,%r7 186 larl %r1,purgatory_start 187 slgr %r0,%r1 188 agr %r10,%r0 189 MEMCPY %r10,%r7,%r11 /* (new) buf -> (crash) buf */ 190 191 /* Now the code is set up to run from its designated location. Start 192 * swapping the rest of crash memory now. 193 * 194 * The registers will be used as follow: 195 * 196 * %r0-%r4 reserved for macros defined above 197 * %r5-%r6 tmp registers 198 * %r7 pointer to current struct sha region 199 * %r8 index to iterate over all sha regions 200 * %r9 pointer in crash memory 201 * %r10 pointer in old kernel 202 * %r11 total size (still) to be moved 203 * %r12 pointer to buffer 204 */ 205 lgr %r12,%r7 206 lgr %r11,%r9 207 lghi %r10,0 208 lg %r9,crash_start-.base_dst(%r13) 209 lghi %r8,16 /* KEXEC_SEGMENTS_MAX */ 210 larl %r7,purgatory_sha_regions 211 212 j .loop_first 213 214 /* Loop over all purgatory_sha_regions. */ 215 .loop_next: 216 aghi %r8,-1 217 cghi %r8,0 218 je .loop_out 219 220 aghi %r7,__KEXEC_SHA_REGION_SIZE 221 222 .loop_first: 223 lg %r5,__KEXEC_SHA_REGION_START(%r7) 224 cghi %r5,0 225 je .loop_next 226 227 /* Copy [end last sha region, start current sha region) */ 228 /* Note: kexec_sha_region->start points in crash memory */ 229 sgr %r5,%r9 230 MEMCPY %r9,%r10,%r5 231 232 agr %r9,%r5 233 agr %r10,%r5 234 sgr %r11,%r5 235 236 /* Swap sha region */ 237 lg %r6,__KEXEC_SHA_REGION_LEN(%r7) 238 MEMSWAP %r9,%r10,%r12,%r6 239 sg %r11,__KEXEC_SHA_REGION_LEN(%r7) 240 j .loop_next 241 242 .loop_out: 243 /* Copy rest of crash memory */ 244 MEMCPY %r9,%r10,%r11 245 246 /* start crash kernel */ 247 START_NEXT_KERNEL .base_dst 1 248 SYM_CODE_END(purgatory_start) 249 250 SYM_DATA_LOCAL(load_psw_mask, .long 0x00080000,0x80000000) 251 .balign 8 252 SYM_DATA_LOCAL(disabled_wait_psw, .quad 0x0002000180000000,.do_checksum_verification) 253 SYM_DATA_LOCAL(gprregs, .fill 10,8,0) 254 SYM_DATA(purgatory_sha256_digest, .skip 32) 255 SYM_DATA(purgatory_sha_regions, .skip 16*__KEXEC_SHA_REGION_SIZE) 256 SYM_DATA(kernel_entry, .skip 8) 257 SYM_DATA(kernel_type, .skip 8) 258 SYM_DATA(crash_start, .skip 8) 259 SYM_DATA(crash_size, .skip 8) 260 .balign PAGE_SIZE 261 SYM_DATA_START_LOCAL(stack) 262 /* The buffer to move this code must be as big as the code. */ 263 .skip stack-purgatory_start 264 .balign PAGE_SIZE 265 SYM_DATA_END_LABEL(stack, SYM_L_LOCAL, purgatory_end)
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.