1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-or-later */ 2*4882a593Smuzhiyun/* 3*4882a593Smuzhiyun * This file contains kexec low-level functions. 4*4882a593Smuzhiyun * 5*4882a593Smuzhiyun * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com> 6*4882a593Smuzhiyun * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz 7*4882a593Smuzhiyun * PPC44x port. Copyright (C) 2011, IBM Corporation 8*4882a593Smuzhiyun * Author: Suzuki Poulose <suzuki@in.ibm.com> 9*4882a593Smuzhiyun */ 10*4882a593Smuzhiyun 11*4882a593Smuzhiyun#include <asm/reg.h> 12*4882a593Smuzhiyun#include <asm/page.h> 13*4882a593Smuzhiyun#include <asm/mmu.h> 14*4882a593Smuzhiyun#include <asm/ppc_asm.h> 15*4882a593Smuzhiyun#include <asm/kexec.h> 16*4882a593Smuzhiyun 17*4882a593Smuzhiyun .text 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun /* 20*4882a593Smuzhiyun * Must be relocatable PIC code callable as a C function. 21*4882a593Smuzhiyun */ 22*4882a593Smuzhiyun .globl relocate_new_kernel 23*4882a593Smuzhiyunrelocate_new_kernel: 24*4882a593Smuzhiyun /* r3 = page_list */ 25*4882a593Smuzhiyun /* r4 = reboot_code_buffer */ 26*4882a593Smuzhiyun /* r5 = start_address */ 27*4882a593Smuzhiyun 28*4882a593Smuzhiyun#ifdef CONFIG_FSL_BOOKE 29*4882a593Smuzhiyun 30*4882a593Smuzhiyun mr r29, r3 31*4882a593Smuzhiyun mr r30, r4 32*4882a593Smuzhiyun mr r31, r5 33*4882a593Smuzhiyun 34*4882a593Smuzhiyun#define ENTRY_MAPPING_KEXEC_SETUP 35*4882a593Smuzhiyun#include <kernel/fsl_booke_entry_mapping.S> 36*4882a593Smuzhiyun#undef ENTRY_MAPPING_KEXEC_SETUP 37*4882a593Smuzhiyun 38*4882a593Smuzhiyun mr r3, r29 39*4882a593Smuzhiyun mr r4, r30 40*4882a593Smuzhiyun mr r5, r31 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun li r0, 0 43*4882a593Smuzhiyun#elif defined(CONFIG_44x) 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun /* Save our parameters */ 46*4882a593Smuzhiyun mr r29, r3 47*4882a593Smuzhiyun mr r30, r4 48*4882a593Smuzhiyun mr r31, r5 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun#ifdef CONFIG_PPC_47x 51*4882a593Smuzhiyun /* Check for 47x cores */ 52*4882a593Smuzhiyun mfspr r3,SPRN_PVR 53*4882a593Smuzhiyun srwi r3,r3,16 54*4882a593Smuzhiyun cmplwi cr0,r3,PVR_476FPE@h 55*4882a593Smuzhiyun beq setup_map_47x 56*4882a593Smuzhiyun cmplwi cr0,r3,PVR_476@h 57*4882a593Smuzhiyun beq setup_map_47x 58*4882a593Smuzhiyun cmplwi cr0,r3,PVR_476_ISS@h 59*4882a593Smuzhiyun beq setup_map_47x 60*4882a593Smuzhiyun#endif /* CONFIG_PPC_47x */ 61*4882a593Smuzhiyun 62*4882a593Smuzhiyun/* 63*4882a593Smuzhiyun * Code for setting up 1:1 mapping for PPC440x for KEXEC 64*4882a593Smuzhiyun * 65*4882a593Smuzhiyun * We cannot switch off the MMU on PPC44x. 66*4882a593Smuzhiyun * So we: 67*4882a593Smuzhiyun * 1) Invalidate all the mappings except the one we are running from. 68*4882a593Smuzhiyun * 2) Create a tmp mapping for our code in the other address space(TS) and 69*4882a593Smuzhiyun * jump to it. Invalidate the entry we started in. 70*4882a593Smuzhiyun * 3) Create a 1:1 mapping for 0-2GiB in chunks of 256M in original TS. 71*4882a593Smuzhiyun * 4) Jump to the 1:1 mapping in original TS. 72*4882a593Smuzhiyun * 5) Invalidate the tmp mapping. 73*4882a593Smuzhiyun * 74*4882a593Smuzhiyun * - Based on the kexec support code for FSL BookE 75*4882a593Smuzhiyun * 76*4882a593Smuzhiyun */ 77*4882a593Smuzhiyun 78*4882a593Smuzhiyun /* 79*4882a593Smuzhiyun * Load the PID with kernel PID (0). 80*4882a593Smuzhiyun * Also load our MSR_IS and TID to MMUCR for TLB search. 81*4882a593Smuzhiyun */ 82*4882a593Smuzhiyun li r3, 0 83*4882a593Smuzhiyun mtspr SPRN_PID, r3 84*4882a593Smuzhiyun mfmsr r4 85*4882a593Smuzhiyun andi. r4,r4,MSR_IS@l 86*4882a593Smuzhiyun beq wmmucr 87*4882a593Smuzhiyun oris r3,r3,PPC44x_MMUCR_STS@h 88*4882a593Smuzhiyunwmmucr: 89*4882a593Smuzhiyun mtspr SPRN_MMUCR,r3 90*4882a593Smuzhiyun sync 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun /* 93*4882a593Smuzhiyun * Invalidate all the TLB entries except the current entry 94*4882a593Smuzhiyun * where we are running from 95*4882a593Smuzhiyun */ 96*4882a593Smuzhiyun bl 0f /* Find our address */ 97*4882a593Smuzhiyun0: mflr r5 /* Make it accessible */ 98*4882a593Smuzhiyun tlbsx r23,0,r5 /* Find entry we are in */ 99*4882a593Smuzhiyun li r4,0 /* Start at TLB entry 0 */ 100*4882a593Smuzhiyun li r3,0 /* Set PAGEID inval value */ 101*4882a593Smuzhiyun1: cmpw r23,r4 /* Is this our entry? */ 102*4882a593Smuzhiyun beq skip /* If so, skip the inval */ 103*4882a593Smuzhiyun tlbwe r3,r4,PPC44x_TLB_PAGEID /* If not, inval the entry */ 104*4882a593Smuzhiyunskip: 105*4882a593Smuzhiyun addi r4,r4,1 /* Increment */ 106*4882a593Smuzhiyun cmpwi r4,64 /* Are we done? */ 107*4882a593Smuzhiyun bne 1b /* If not, repeat */ 108*4882a593Smuzhiyun isync 109*4882a593Smuzhiyun 110*4882a593Smuzhiyun /* Create a temp mapping and jump to it */ 111*4882a593Smuzhiyun andi. r6, r23, 1 /* Find the index to use */ 112*4882a593Smuzhiyun addi r24, r6, 1 /* r24 will contain 1 or 2 */ 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun mfmsr r9 /* get the MSR */ 115*4882a593Smuzhiyun rlwinm r5, r9, 27, 31, 31 /* Extract the MSR[IS] */ 116*4882a593Smuzhiyun xori r7, r5, 1 /* Use the other address space */ 117*4882a593Smuzhiyun 118*4882a593Smuzhiyun /* Read the current mapping entries */ 119*4882a593Smuzhiyun tlbre r3, r23, PPC44x_TLB_PAGEID 120*4882a593Smuzhiyun tlbre r4, r23, PPC44x_TLB_XLAT 121*4882a593Smuzhiyun tlbre r5, r23, PPC44x_TLB_ATTRIB 122*4882a593Smuzhiyun 123*4882a593Smuzhiyun /* Save our current XLAT entry */ 124*4882a593Smuzhiyun mr r25, r4 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun /* Extract the TLB PageSize */ 127*4882a593Smuzhiyun li r10, 1 /* r10 will hold PageSize */ 128*4882a593Smuzhiyun rlwinm r11, r3, 0, 24, 27 /* bits 24-27 */ 129*4882a593Smuzhiyun 130*4882a593Smuzhiyun /* XXX: As of now we use 256M, 4K pages */ 131*4882a593Smuzhiyun cmpwi r11, PPC44x_TLB_256M 132*4882a593Smuzhiyun bne tlb_4k 133*4882a593Smuzhiyun rotlwi r10, r10, 28 /* r10 = 256M */ 134*4882a593Smuzhiyun b write_out 135*4882a593Smuzhiyuntlb_4k: 136*4882a593Smuzhiyun cmpwi r11, PPC44x_TLB_4K 137*4882a593Smuzhiyun bne default 138*4882a593Smuzhiyun rotlwi r10, r10, 12 /* r10 = 4K */ 139*4882a593Smuzhiyun b write_out 140*4882a593Smuzhiyundefault: 141*4882a593Smuzhiyun rotlwi r10, r10, 10 /* r10 = 1K */ 142*4882a593Smuzhiyun 143*4882a593Smuzhiyunwrite_out: 144*4882a593Smuzhiyun /* 145*4882a593Smuzhiyun * Write out the tmp 1:1 mapping for this code in other address space 146*4882a593Smuzhiyun * Fixup EPN = RPN , TS=other address space 147*4882a593Smuzhiyun */ 148*4882a593Smuzhiyun insrwi r3, r7, 1, 23 /* Bit 23 is TS for PAGEID field */ 149*4882a593Smuzhiyun 150*4882a593Smuzhiyun /* Write out the tmp mapping entries */ 151*4882a593Smuzhiyun tlbwe r3, r24, PPC44x_TLB_PAGEID 152*4882a593Smuzhiyun tlbwe r4, r24, PPC44x_TLB_XLAT 153*4882a593Smuzhiyun tlbwe r5, r24, PPC44x_TLB_ATTRIB 154*4882a593Smuzhiyun 155*4882a593Smuzhiyun subi r11, r10, 1 /* PageOffset Mask = PageSize - 1 */ 156*4882a593Smuzhiyun not r10, r11 /* Mask for PageNum */ 157*4882a593Smuzhiyun 158*4882a593Smuzhiyun /* Switch to other address space in MSR */ 159*4882a593Smuzhiyun insrwi r9, r7, 1, 26 /* Set MSR[IS] = r7 */ 160*4882a593Smuzhiyun 161*4882a593Smuzhiyun bl 1f 162*4882a593Smuzhiyun1: mflr r8 163*4882a593Smuzhiyun addi r8, r8, (2f-1b) /* Find the target offset */ 164*4882a593Smuzhiyun 165*4882a593Smuzhiyun /* Jump to the tmp mapping */ 166*4882a593Smuzhiyun mtspr SPRN_SRR0, r8 167*4882a593Smuzhiyun mtspr SPRN_SRR1, r9 168*4882a593Smuzhiyun rfi 169*4882a593Smuzhiyun 170*4882a593Smuzhiyun2: 171*4882a593Smuzhiyun /* Invalidate the entry we were executing from */ 172*4882a593Smuzhiyun li r3, 0 173*4882a593Smuzhiyun tlbwe r3, r23, PPC44x_TLB_PAGEID 174*4882a593Smuzhiyun 175*4882a593Smuzhiyun /* attribute fields. rwx for SUPERVISOR mode */ 176*4882a593Smuzhiyun li r5, 0 177*4882a593Smuzhiyun ori r5, r5, (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G) 178*4882a593Smuzhiyun 179*4882a593Smuzhiyun /* Create 1:1 mapping in 256M pages */ 180*4882a593Smuzhiyun xori r7, r7, 1 /* Revert back to Original TS */ 181*4882a593Smuzhiyun 182*4882a593Smuzhiyun li r8, 0 /* PageNumber */ 183*4882a593Smuzhiyun li r6, 3 /* TLB Index, start at 3 */ 184*4882a593Smuzhiyun 185*4882a593Smuzhiyunnext_tlb: 186*4882a593Smuzhiyun rotlwi r3, r8, 28 /* Create EPN (bits 0-3) */ 187*4882a593Smuzhiyun mr r4, r3 /* RPN = EPN */ 188*4882a593Smuzhiyun ori r3, r3, (PPC44x_TLB_VALID | PPC44x_TLB_256M) /* SIZE = 256M, Valid */ 189*4882a593Smuzhiyun insrwi r3, r7, 1, 23 /* Set TS from r7 */ 190*4882a593Smuzhiyun 191*4882a593Smuzhiyun tlbwe r3, r6, PPC44x_TLB_PAGEID /* PageID field : EPN, V, SIZE */ 192*4882a593Smuzhiyun tlbwe r4, r6, PPC44x_TLB_XLAT /* Address translation : RPN */ 193*4882a593Smuzhiyun tlbwe r5, r6, PPC44x_TLB_ATTRIB /* Attributes */ 194*4882a593Smuzhiyun 195*4882a593Smuzhiyun addi r8, r8, 1 /* Increment PN */ 196*4882a593Smuzhiyun addi r6, r6, 1 /* Increment TLB Index */ 197*4882a593Smuzhiyun cmpwi r8, 8 /* Are we done ? */ 198*4882a593Smuzhiyun bne next_tlb 199*4882a593Smuzhiyun isync 200*4882a593Smuzhiyun 201*4882a593Smuzhiyun /* Jump to the new mapping 1:1 */ 202*4882a593Smuzhiyun li r9,0 203*4882a593Smuzhiyun insrwi r9, r7, 1, 26 /* Set MSR[IS] = r7 */ 204*4882a593Smuzhiyun 205*4882a593Smuzhiyun bl 1f 206*4882a593Smuzhiyun1: mflr r8 207*4882a593Smuzhiyun and r8, r8, r11 /* Get our offset within page */ 208*4882a593Smuzhiyun addi r8, r8, (2f-1b) 209*4882a593Smuzhiyun 210*4882a593Smuzhiyun and r5, r25, r10 /* Get our target PageNum */ 211*4882a593Smuzhiyun or r8, r8, r5 /* Target jump address */ 212*4882a593Smuzhiyun 213*4882a593Smuzhiyun mtspr SPRN_SRR0, r8 214*4882a593Smuzhiyun mtspr SPRN_SRR1, r9 215*4882a593Smuzhiyun rfi 216*4882a593Smuzhiyun2: 217*4882a593Smuzhiyun /* Invalidate the tmp entry we used */ 218*4882a593Smuzhiyun li r3, 0 219*4882a593Smuzhiyun tlbwe r3, r24, PPC44x_TLB_PAGEID 220*4882a593Smuzhiyun sync 221*4882a593Smuzhiyun b ppc44x_map_done 222*4882a593Smuzhiyun 223*4882a593Smuzhiyun#ifdef CONFIG_PPC_47x 224*4882a593Smuzhiyun 225*4882a593Smuzhiyun /* 1:1 mapping for 47x */ 226*4882a593Smuzhiyun 227*4882a593Smuzhiyunsetup_map_47x: 228*4882a593Smuzhiyun 229*4882a593Smuzhiyun /* 230*4882a593Smuzhiyun * Load the kernel pid (0) to PID and also to MMUCR[TID]. 231*4882a593Smuzhiyun * Also set the MSR IS->MMUCR STS 232*4882a593Smuzhiyun */ 233*4882a593Smuzhiyun li r3, 0 234*4882a593Smuzhiyun mtspr SPRN_PID, r3 /* Set PID */ 235*4882a593Smuzhiyun mfmsr r4 /* Get MSR */ 236*4882a593Smuzhiyun andi. r4, r4, MSR_IS@l /* TS=1? */ 237*4882a593Smuzhiyun beq 1f /* If not, leave STS=0 */ 238*4882a593Smuzhiyun oris r3, r3, PPC47x_MMUCR_STS@h /* Set STS=1 */ 239*4882a593Smuzhiyun1: mtspr SPRN_MMUCR, r3 /* Put MMUCR */ 240*4882a593Smuzhiyun sync 241*4882a593Smuzhiyun 242*4882a593Smuzhiyun /* Find the entry we are running from */ 243*4882a593Smuzhiyun bl 2f 244*4882a593Smuzhiyun2: mflr r23 245*4882a593Smuzhiyun tlbsx r23, 0, r23 246*4882a593Smuzhiyun tlbre r24, r23, 0 /* TLB Word 0 */ 247*4882a593Smuzhiyun tlbre r25, r23, 1 /* TLB Word 1 */ 248*4882a593Smuzhiyun tlbre r26, r23, 2 /* TLB Word 2 */ 249*4882a593Smuzhiyun 250*4882a593Smuzhiyun 251*4882a593Smuzhiyun /* 252*4882a593Smuzhiyun * Invalidates all the tlb entries by writing to 256 RPNs(r4) 253*4882a593Smuzhiyun * of 4k page size in all 4 ways (0-3 in r3). 254*4882a593Smuzhiyun * This would invalidate the entire UTLB including the one we are 255*4882a593Smuzhiyun * running from. However the shadow TLB entries would help us 256*4882a593Smuzhiyun * to continue the execution, until we flush them (rfi/isync). 257*4882a593Smuzhiyun */ 258*4882a593Smuzhiyun addis r3, 0, 0x8000 /* specify the way */ 259*4882a593Smuzhiyun addi r4, 0, 0 /* TLB Word0 = (EPN=0, VALID = 0) */ 260*4882a593Smuzhiyun addi r5, 0, 0 261*4882a593Smuzhiyun b clear_utlb_entry 262*4882a593Smuzhiyun 263*4882a593Smuzhiyun /* Align the loop to speed things up. from head_44x.S */ 264*4882a593Smuzhiyun .align 6 265*4882a593Smuzhiyun 266*4882a593Smuzhiyunclear_utlb_entry: 267*4882a593Smuzhiyun 268*4882a593Smuzhiyun tlbwe r4, r3, 0 269*4882a593Smuzhiyun tlbwe r5, r3, 1 270*4882a593Smuzhiyun tlbwe r5, r3, 2 271*4882a593Smuzhiyun addis r3, r3, 0x2000 /* Increment the way */ 272*4882a593Smuzhiyun cmpwi r3, 0 273*4882a593Smuzhiyun bne clear_utlb_entry 274*4882a593Smuzhiyun addis r3, 0, 0x8000 275*4882a593Smuzhiyun addis r4, r4, 0x100 /* Increment the EPN */ 276*4882a593Smuzhiyun cmpwi r4, 0 277*4882a593Smuzhiyun bne clear_utlb_entry 278*4882a593Smuzhiyun 279*4882a593Smuzhiyun /* Create the entries in the other address space */ 280*4882a593Smuzhiyun mfmsr r5 281*4882a593Smuzhiyun rlwinm r7, r5, 27, 31, 31 /* Get the TS (Bit 26) from MSR */ 282*4882a593Smuzhiyun xori r7, r7, 1 /* r7 = !TS */ 283*4882a593Smuzhiyun 284*4882a593Smuzhiyun insrwi r24, r7, 1, 21 /* Change the TS in the saved TLB word 0 */ 285*4882a593Smuzhiyun 286*4882a593Smuzhiyun /* 287*4882a593Smuzhiyun * write out the TLB entries for the tmp mapping 288*4882a593Smuzhiyun * Use way '0' so that we could easily invalidate it later. 289*4882a593Smuzhiyun */ 290*4882a593Smuzhiyun lis r3, 0x8000 /* Way '0' */ 291*4882a593Smuzhiyun 292*4882a593Smuzhiyun tlbwe r24, r3, 0 293*4882a593Smuzhiyun tlbwe r25, r3, 1 294*4882a593Smuzhiyun tlbwe r26, r3, 2 295*4882a593Smuzhiyun 296*4882a593Smuzhiyun /* Update the msr to the new TS */ 297*4882a593Smuzhiyun insrwi r5, r7, 1, 26 298*4882a593Smuzhiyun 299*4882a593Smuzhiyun bl 1f 300*4882a593Smuzhiyun1: mflr r6 301*4882a593Smuzhiyun addi r6, r6, (2f-1b) 302*4882a593Smuzhiyun 303*4882a593Smuzhiyun mtspr SPRN_SRR0, r6 304*4882a593Smuzhiyun mtspr SPRN_SRR1, r5 305*4882a593Smuzhiyun rfi 306*4882a593Smuzhiyun 307*4882a593Smuzhiyun /* 308*4882a593Smuzhiyun * Now we are in the tmp address space. 309*4882a593Smuzhiyun * Create a 1:1 mapping for 0-2GiB in the original TS. 310*4882a593Smuzhiyun */ 311*4882a593Smuzhiyun2: 312*4882a593Smuzhiyun li r3, 0 313*4882a593Smuzhiyun li r4, 0 /* TLB Word 0 */ 314*4882a593Smuzhiyun li r5, 0 /* TLB Word 1 */ 315*4882a593Smuzhiyun li r6, 0 316*4882a593Smuzhiyun ori r6, r6, PPC47x_TLB2_S_RWX /* TLB word 2 */ 317*4882a593Smuzhiyun 318*4882a593Smuzhiyun li r8, 0 /* PageIndex */ 319*4882a593Smuzhiyun 320*4882a593Smuzhiyun xori r7, r7, 1 /* revert back to original TS */ 321*4882a593Smuzhiyun 322*4882a593Smuzhiyunwrite_utlb: 323*4882a593Smuzhiyun rotlwi r5, r8, 28 /* RPN = PageIndex * 256M */ 324*4882a593Smuzhiyun /* ERPN = 0 as we don't use memory above 2G */ 325*4882a593Smuzhiyun 326*4882a593Smuzhiyun mr r4, r5 /* EPN = RPN */ 327*4882a593Smuzhiyun ori r4, r4, (PPC47x_TLB0_VALID | PPC47x_TLB0_256M) 328*4882a593Smuzhiyun insrwi r4, r7, 1, 21 /* Insert the TS to Word 0 */ 329*4882a593Smuzhiyun 330*4882a593Smuzhiyun tlbwe r4, r3, 0 /* Write out the entries */ 331*4882a593Smuzhiyun tlbwe r5, r3, 1 332*4882a593Smuzhiyun tlbwe r6, r3, 2 333*4882a593Smuzhiyun addi r8, r8, 1 334*4882a593Smuzhiyun cmpwi r8, 8 /* Have we completed ? */ 335*4882a593Smuzhiyun bne write_utlb 336*4882a593Smuzhiyun 337*4882a593Smuzhiyun /* make sure we complete the TLB write up */ 338*4882a593Smuzhiyun isync 339*4882a593Smuzhiyun 340*4882a593Smuzhiyun /* 341*4882a593Smuzhiyun * Prepare to jump to the 1:1 mapping. 342*4882a593Smuzhiyun * 1) Extract page size of the tmp mapping 343*4882a593Smuzhiyun * DSIZ = TLB_Word0[22:27] 344*4882a593Smuzhiyun * 2) Calculate the physical address of the address 345*4882a593Smuzhiyun * to jump to. 346*4882a593Smuzhiyun */ 347*4882a593Smuzhiyun rlwinm r10, r24, 0, 22, 27 348*4882a593Smuzhiyun 349*4882a593Smuzhiyun cmpwi r10, PPC47x_TLB0_4K 350*4882a593Smuzhiyun bne 0f 351*4882a593Smuzhiyun li r10, 0x1000 /* r10 = 4k */ 352*4882a593Smuzhiyun bl 1f 353*4882a593Smuzhiyun 354*4882a593Smuzhiyun0: 355*4882a593Smuzhiyun /* Defaults to 256M */ 356*4882a593Smuzhiyun lis r10, 0x1000 357*4882a593Smuzhiyun 358*4882a593Smuzhiyun bl 1f 359*4882a593Smuzhiyun1: mflr r4 360*4882a593Smuzhiyun addi r4, r4, (2f-1b) /* virtual address of 2f */ 361*4882a593Smuzhiyun 362*4882a593Smuzhiyun subi r11, r10, 1 /* offsetmask = Pagesize - 1 */ 363*4882a593Smuzhiyun not r10, r11 /* Pagemask = ~(offsetmask) */ 364*4882a593Smuzhiyun 365*4882a593Smuzhiyun and r5, r25, r10 /* Physical page */ 366*4882a593Smuzhiyun and r6, r4, r11 /* offset within the current page */ 367*4882a593Smuzhiyun 368*4882a593Smuzhiyun or r5, r5, r6 /* Physical address for 2f */ 369*4882a593Smuzhiyun 370*4882a593Smuzhiyun /* Switch the TS in MSR to the original one */ 371*4882a593Smuzhiyun mfmsr r8 372*4882a593Smuzhiyun insrwi r8, r7, 1, 26 373*4882a593Smuzhiyun 374*4882a593Smuzhiyun mtspr SPRN_SRR1, r8 375*4882a593Smuzhiyun mtspr SPRN_SRR0, r5 376*4882a593Smuzhiyun rfi 377*4882a593Smuzhiyun 378*4882a593Smuzhiyun2: 379*4882a593Smuzhiyun /* Invalidate the tmp mapping */ 380*4882a593Smuzhiyun lis r3, 0x8000 /* Way '0' */ 381*4882a593Smuzhiyun 382*4882a593Smuzhiyun clrrwi r24, r24, 12 /* Clear the valid bit */ 383*4882a593Smuzhiyun tlbwe r24, r3, 0 384*4882a593Smuzhiyun tlbwe r25, r3, 1 385*4882a593Smuzhiyun tlbwe r26, r3, 2 386*4882a593Smuzhiyun 387*4882a593Smuzhiyun /* Make sure we complete the TLB write and flush the shadow TLB */ 388*4882a593Smuzhiyun isync 389*4882a593Smuzhiyun 390*4882a593Smuzhiyun#endif 391*4882a593Smuzhiyun 392*4882a593Smuzhiyunppc44x_map_done: 393*4882a593Smuzhiyun 394*4882a593Smuzhiyun 395*4882a593Smuzhiyun /* Restore the parameters */ 396*4882a593Smuzhiyun mr r3, r29 397*4882a593Smuzhiyun mr r4, r30 398*4882a593Smuzhiyun mr r5, r31 399*4882a593Smuzhiyun 400*4882a593Smuzhiyun li r0, 0 401*4882a593Smuzhiyun#else 402*4882a593Smuzhiyun li r0, 0 403*4882a593Smuzhiyun 404*4882a593Smuzhiyun /* 405*4882a593Smuzhiyun * Set Machine Status Register to a known status, 406*4882a593Smuzhiyun * switch the MMU off and jump to 1: in a single step. 407*4882a593Smuzhiyun */ 408*4882a593Smuzhiyun 409*4882a593Smuzhiyun mr r8, r0 410*4882a593Smuzhiyun ori r8, r8, MSR_RI|MSR_ME 411*4882a593Smuzhiyun mtspr SPRN_SRR1, r8 412*4882a593Smuzhiyun addi r8, r4, 1f - relocate_new_kernel 413*4882a593Smuzhiyun mtspr SPRN_SRR0, r8 414*4882a593Smuzhiyun sync 415*4882a593Smuzhiyun rfi 416*4882a593Smuzhiyun 417*4882a593Smuzhiyun1: 418*4882a593Smuzhiyun#endif 419*4882a593Smuzhiyun /* from this point address translation is turned off */ 420*4882a593Smuzhiyun /* and interrupts are disabled */ 421*4882a593Smuzhiyun 422*4882a593Smuzhiyun /* set a new stack at the bottom of our page... */ 423*4882a593Smuzhiyun /* (not really needed now) */ 424*4882a593Smuzhiyun addi r1, r4, KEXEC_CONTROL_PAGE_SIZE - 8 /* for LR Save+Back Chain */ 425*4882a593Smuzhiyun stw r0, 0(r1) 426*4882a593Smuzhiyun 427*4882a593Smuzhiyun /* Do the copies */ 428*4882a593Smuzhiyun li r6, 0 /* checksum */ 429*4882a593Smuzhiyun mr r0, r3 430*4882a593Smuzhiyun b 1f 431*4882a593Smuzhiyun 432*4882a593Smuzhiyun0: /* top, read another word for the indirection page */ 433*4882a593Smuzhiyun lwzu r0, 4(r3) 434*4882a593Smuzhiyun 435*4882a593Smuzhiyun1: 436*4882a593Smuzhiyun /* is it a destination page? (r8) */ 437*4882a593Smuzhiyun rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */ 438*4882a593Smuzhiyun beq 2f 439*4882a593Smuzhiyun 440*4882a593Smuzhiyun rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */ 441*4882a593Smuzhiyun b 0b 442*4882a593Smuzhiyun 443*4882a593Smuzhiyun2: /* is it an indirection page? (r3) */ 444*4882a593Smuzhiyun rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */ 445*4882a593Smuzhiyun beq 2f 446*4882a593Smuzhiyun 447*4882a593Smuzhiyun rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */ 448*4882a593Smuzhiyun subi r3, r3, 4 449*4882a593Smuzhiyun b 0b 450*4882a593Smuzhiyun 451*4882a593Smuzhiyun2: /* are we done? */ 452*4882a593Smuzhiyun rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */ 453*4882a593Smuzhiyun beq 2f 454*4882a593Smuzhiyun b 3f 455*4882a593Smuzhiyun 456*4882a593Smuzhiyun2: /* is it a source page? (r9) */ 457*4882a593Smuzhiyun rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */ 458*4882a593Smuzhiyun beq 0b 459*4882a593Smuzhiyun 460*4882a593Smuzhiyun rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */ 461*4882a593Smuzhiyun 462*4882a593Smuzhiyun li r7, PAGE_SIZE / 4 463*4882a593Smuzhiyun mtctr r7 464*4882a593Smuzhiyun subi r9, r9, 4 465*4882a593Smuzhiyun subi r8, r8, 4 466*4882a593Smuzhiyun9: 467*4882a593Smuzhiyun lwzu r0, 4(r9) /* do the copy */ 468*4882a593Smuzhiyun xor r6, r6, r0 469*4882a593Smuzhiyun stwu r0, 4(r8) 470*4882a593Smuzhiyun dcbst 0, r8 471*4882a593Smuzhiyun sync 472*4882a593Smuzhiyun icbi 0, r8 473*4882a593Smuzhiyun bdnz 9b 474*4882a593Smuzhiyun 475*4882a593Smuzhiyun addi r9, r9, 4 476*4882a593Smuzhiyun addi r8, r8, 4 477*4882a593Smuzhiyun b 0b 478*4882a593Smuzhiyun 479*4882a593Smuzhiyun3: 480*4882a593Smuzhiyun 481*4882a593Smuzhiyun /* To be certain of avoiding problems with self-modifying code 482*4882a593Smuzhiyun * execute a serializing instruction here. 483*4882a593Smuzhiyun */ 484*4882a593Smuzhiyun isync 485*4882a593Smuzhiyun sync 486*4882a593Smuzhiyun 487*4882a593Smuzhiyun mfspr r3, SPRN_PIR /* current core we are running on */ 488*4882a593Smuzhiyun mr r4, r5 /* load physical address of chunk called */ 489*4882a593Smuzhiyun 490*4882a593Smuzhiyun /* jump to the entry point, usually the setup routine */ 491*4882a593Smuzhiyun mtlr r5 492*4882a593Smuzhiyun blrl 493*4882a593Smuzhiyun 494*4882a593Smuzhiyun1: b 1b 495*4882a593Smuzhiyun 496*4882a593Smuzhiyunrelocate_new_kernel_end: 497*4882a593Smuzhiyun 498*4882a593Smuzhiyun .globl relocate_new_kernel_size 499*4882a593Smuzhiyunrelocate_new_kernel_size: 500*4882a593Smuzhiyun .long relocate_new_kernel_end - relocate_new_kernel 501