162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This file contains kexec low-level functions.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
662306a36Sopenharmony_ci * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
762306a36Sopenharmony_ci * PPC44x port. Copyright (C) 2011,  IBM Corporation
862306a36Sopenharmony_ci * 		Author: Suzuki Poulose <suzuki@in.ibm.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/reg.h>
1262306a36Sopenharmony_ci#include <asm/page.h>
1362306a36Sopenharmony_ci#include <asm/mmu.h>
1462306a36Sopenharmony_ci#include <asm/ppc_asm.h>
1562306a36Sopenharmony_ci#include <asm/kexec.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci	.text
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	/*
2062306a36Sopenharmony_ci	 * Must be relocatable PIC code callable as a C function.
2162306a36Sopenharmony_ci	 */
2262306a36Sopenharmony_ci	.globl relocate_new_kernel
2362306a36Sopenharmony_cirelocate_new_kernel:
2462306a36Sopenharmony_ci	/* r3 = page_list   */
2562306a36Sopenharmony_ci	/* r4 = reboot_code_buffer */
2662306a36Sopenharmony_ci	/* r5 = start_address      */
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#ifdef CONFIG_PPC_85xx
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	mr	r29, r3
3162306a36Sopenharmony_ci	mr	r30, r4
3262306a36Sopenharmony_ci	mr	r31, r5
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define ENTRY_MAPPING_KEXEC_SETUP
3562306a36Sopenharmony_ci#include <kernel/85xx_entry_mapping.S>
3662306a36Sopenharmony_ci#undef ENTRY_MAPPING_KEXEC_SETUP
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	mr      r3, r29
3962306a36Sopenharmony_ci	mr      r4, r30
4062306a36Sopenharmony_ci	mr      r5, r31
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	li	r0, 0
4362306a36Sopenharmony_ci#elif defined(CONFIG_44x)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/* Save our parameters */
4662306a36Sopenharmony_ci	mr	r29, r3
4762306a36Sopenharmony_ci	mr	r30, r4
4862306a36Sopenharmony_ci	mr	r31, r5
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#ifdef CONFIG_PPC_47x
5162306a36Sopenharmony_ci	/* Check for 47x cores */
5262306a36Sopenharmony_ci	mfspr	r3,SPRN_PVR
5362306a36Sopenharmony_ci	srwi	r3,r3,16
5462306a36Sopenharmony_ci	cmplwi	cr0,r3,PVR_476FPE@h
5562306a36Sopenharmony_ci	beq	setup_map_47x
5662306a36Sopenharmony_ci	cmplwi	cr0,r3,PVR_476@h
5762306a36Sopenharmony_ci	beq	setup_map_47x
5862306a36Sopenharmony_ci	cmplwi	cr0,r3,PVR_476_ISS@h
5962306a36Sopenharmony_ci	beq	setup_map_47x
6062306a36Sopenharmony_ci#endif /* CONFIG_PPC_47x */
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/*
6362306a36Sopenharmony_ci * Code for setting up 1:1 mapping for PPC440x for KEXEC
6462306a36Sopenharmony_ci *
6562306a36Sopenharmony_ci * We cannot switch off the MMU on PPC44x.
6662306a36Sopenharmony_ci * So we:
6762306a36Sopenharmony_ci * 1) Invalidate all the mappings except the one we are running from.
6862306a36Sopenharmony_ci * 2) Create a tmp mapping for our code in the other address space(TS) and
6962306a36Sopenharmony_ci *    jump to it. Invalidate the entry we started in.
7062306a36Sopenharmony_ci * 3) Create a 1:1 mapping for 0-2GiB in chunks of 256M in original TS.
7162306a36Sopenharmony_ci * 4) Jump to the 1:1 mapping in original TS.
7262306a36Sopenharmony_ci * 5) Invalidate the tmp mapping.
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * - Based on the kexec support code for FSL BookE
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci */
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/*
7962306a36Sopenharmony_ci	 * Load the PID with kernel PID (0).
8062306a36Sopenharmony_ci	 * Also load our MSR_IS and TID to MMUCR for TLB search.
8162306a36Sopenharmony_ci	 */
8262306a36Sopenharmony_ci	li	r3, 0
8362306a36Sopenharmony_ci	mtspr	SPRN_PID, r3
8462306a36Sopenharmony_ci	mfmsr	r4
8562306a36Sopenharmony_ci	andi.	r4,r4,MSR_IS@l
8662306a36Sopenharmony_ci	beq	wmmucr
8762306a36Sopenharmony_ci	oris	r3,r3,PPC44x_MMUCR_STS@h
8862306a36Sopenharmony_ciwmmucr:
8962306a36Sopenharmony_ci	mtspr	SPRN_MMUCR,r3
9062306a36Sopenharmony_ci	sync
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	/*
9362306a36Sopenharmony_ci	 * Invalidate all the TLB entries except the current entry
9462306a36Sopenharmony_ci	 * where we are running from
9562306a36Sopenharmony_ci	 */
9662306a36Sopenharmony_ci	bcl	20,31,$+4			/* Find our address */
9762306a36Sopenharmony_ci0:	mflr	r5				/* Make it accessible */
9862306a36Sopenharmony_ci	tlbsx	r23,0,r5			/* Find entry we are in */
9962306a36Sopenharmony_ci	li	r4,0				/* Start at TLB entry 0 */
10062306a36Sopenharmony_ci	li	r3,0				/* Set PAGEID inval value */
10162306a36Sopenharmony_ci1:	cmpw	r23,r4				/* Is this our entry? */
10262306a36Sopenharmony_ci	beq	skip				/* If so, skip the inval */
10362306a36Sopenharmony_ci	tlbwe	r3,r4,PPC44x_TLB_PAGEID		/* If not, inval the entry */
10462306a36Sopenharmony_ciskip:
10562306a36Sopenharmony_ci	addi	r4,r4,1				/* Increment */
10662306a36Sopenharmony_ci	cmpwi	r4,64				/* Are we done?	*/
10762306a36Sopenharmony_ci	bne	1b				/* If not, repeat */
10862306a36Sopenharmony_ci	isync
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* Create a temp mapping and jump to it */
11162306a36Sopenharmony_ci	andi.	r6, r23, 1		/* Find the index to use */
11262306a36Sopenharmony_ci	addi	r24, r6, 1		/* r24 will contain 1 or 2 */
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	mfmsr	r9			/* get the MSR */
11562306a36Sopenharmony_ci	rlwinm	r5, r9, 27, 31, 31	/* Extract the MSR[IS] */
11662306a36Sopenharmony_ci	xori	r7, r5, 1		/* Use the other address space */
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* Read the current mapping entries */
11962306a36Sopenharmony_ci	tlbre	r3, r23, PPC44x_TLB_PAGEID
12062306a36Sopenharmony_ci	tlbre	r4, r23, PPC44x_TLB_XLAT
12162306a36Sopenharmony_ci	tlbre	r5, r23, PPC44x_TLB_ATTRIB
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* Save our current XLAT entry */
12462306a36Sopenharmony_ci	mr	r25, r4
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* Extract the TLB PageSize */
12762306a36Sopenharmony_ci	li	r10, 1 			/* r10 will hold PageSize */
12862306a36Sopenharmony_ci	rlwinm	r11, r3, 0, 24, 27	/* bits 24-27 */
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/* XXX: As of now we use 256M, 4K pages */
13162306a36Sopenharmony_ci	cmpwi	r11, PPC44x_TLB_256M
13262306a36Sopenharmony_ci	bne	tlb_4k
13362306a36Sopenharmony_ci	rotlwi	r10, r10, 28		/* r10 = 256M */
13462306a36Sopenharmony_ci	b	write_out
13562306a36Sopenharmony_citlb_4k:
13662306a36Sopenharmony_ci	cmpwi	r11, PPC44x_TLB_4K
13762306a36Sopenharmony_ci	bne	default
13862306a36Sopenharmony_ci	rotlwi	r10, r10, 12		/* r10 = 4K */
13962306a36Sopenharmony_ci	b	write_out
14062306a36Sopenharmony_cidefault:
14162306a36Sopenharmony_ci	rotlwi	r10, r10, 10		/* r10 = 1K */
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ciwrite_out:
14462306a36Sopenharmony_ci	/*
14562306a36Sopenharmony_ci	 * Write out the tmp 1:1 mapping for this code in other address space
14662306a36Sopenharmony_ci	 * Fixup  EPN = RPN , TS=other address space
14762306a36Sopenharmony_ci	 */
14862306a36Sopenharmony_ci	insrwi	r3, r7, 1, 23		/* Bit 23 is TS for PAGEID field */
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* Write out the tmp mapping entries */
15162306a36Sopenharmony_ci	tlbwe	r3, r24, PPC44x_TLB_PAGEID
15262306a36Sopenharmony_ci	tlbwe	r4, r24, PPC44x_TLB_XLAT
15362306a36Sopenharmony_ci	tlbwe	r5, r24, PPC44x_TLB_ATTRIB
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	subi	r11, r10, 1		/* PageOffset Mask = PageSize - 1 */
15662306a36Sopenharmony_ci	not	r10, r11		/* Mask for PageNum */
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* Switch to other address space in MSR */
15962306a36Sopenharmony_ci	insrwi	r9, r7, 1, 26		/* Set MSR[IS] = r7 */
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	bcl	20,31,$+4
16262306a36Sopenharmony_ci1:	mflr	r8
16362306a36Sopenharmony_ci	addi	r8, r8, (2f-1b)		/* Find the target offset */
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/* Jump to the tmp mapping */
16662306a36Sopenharmony_ci	mtspr	SPRN_SRR0, r8
16762306a36Sopenharmony_ci	mtspr	SPRN_SRR1, r9
16862306a36Sopenharmony_ci	rfi
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci2:
17162306a36Sopenharmony_ci	/* Invalidate the entry we were executing from */
17262306a36Sopenharmony_ci	li	r3, 0
17362306a36Sopenharmony_ci	tlbwe	r3, r23, PPC44x_TLB_PAGEID
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/* attribute fields. rwx for SUPERVISOR mode */
17662306a36Sopenharmony_ci	li	r5, 0
17762306a36Sopenharmony_ci	ori	r5, r5, (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G)
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* Create 1:1 mapping in 256M pages */
18062306a36Sopenharmony_ci	xori	r7, r7, 1			/* Revert back to Original TS */
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	li	r8, 0				/* PageNumber */
18362306a36Sopenharmony_ci	li	r6, 3				/* TLB Index, start at 3  */
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cinext_tlb:
18662306a36Sopenharmony_ci	rotlwi	r3, r8, 28			/* Create EPN (bits 0-3) */
18762306a36Sopenharmony_ci	mr	r4, r3				/* RPN = EPN  */
18862306a36Sopenharmony_ci	ori	r3, r3, (PPC44x_TLB_VALID | PPC44x_TLB_256M) /* SIZE = 256M, Valid */
18962306a36Sopenharmony_ci	insrwi	r3, r7, 1, 23			/* Set TS from r7 */
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	tlbwe	r3, r6, PPC44x_TLB_PAGEID	/* PageID field : EPN, V, SIZE */
19262306a36Sopenharmony_ci	tlbwe	r4, r6, PPC44x_TLB_XLAT		/* Address translation : RPN   */
19362306a36Sopenharmony_ci	tlbwe	r5, r6, PPC44x_TLB_ATTRIB	/* Attributes */
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	addi	r8, r8, 1			/* Increment PN */
19662306a36Sopenharmony_ci	addi	r6, r6, 1			/* Increment TLB Index */
19762306a36Sopenharmony_ci	cmpwi	r8, 8				/* Are we done ? */
19862306a36Sopenharmony_ci	bne	next_tlb
19962306a36Sopenharmony_ci	isync
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* Jump to the new mapping 1:1 */
20262306a36Sopenharmony_ci	li	r9,0
20362306a36Sopenharmony_ci	insrwi	r9, r7, 1, 26			/* Set MSR[IS] = r7 */
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	bcl	20,31,$+4
20662306a36Sopenharmony_ci1:	mflr	r8
20762306a36Sopenharmony_ci	and	r8, r8, r11			/* Get our offset within page */
20862306a36Sopenharmony_ci	addi	r8, r8, (2f-1b)
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	and	r5, r25, r10			/* Get our target PageNum */
21162306a36Sopenharmony_ci	or	r8, r8, r5			/* Target jump address */
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	mtspr	SPRN_SRR0, r8
21462306a36Sopenharmony_ci	mtspr	SPRN_SRR1, r9
21562306a36Sopenharmony_ci	rfi
21662306a36Sopenharmony_ci2:
21762306a36Sopenharmony_ci	/* Invalidate the tmp entry we used */
21862306a36Sopenharmony_ci	li	r3, 0
21962306a36Sopenharmony_ci	tlbwe	r3, r24, PPC44x_TLB_PAGEID
22062306a36Sopenharmony_ci	sync
22162306a36Sopenharmony_ci	b	ppc44x_map_done
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci#ifdef CONFIG_PPC_47x
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/* 1:1 mapping for 47x */
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cisetup_map_47x:
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	/*
23062306a36Sopenharmony_ci	 * Load the kernel pid (0) to PID and also to MMUCR[TID].
23162306a36Sopenharmony_ci	 * Also set the MSR IS->MMUCR STS
23262306a36Sopenharmony_ci	 */
23362306a36Sopenharmony_ci	li	r3, 0
23462306a36Sopenharmony_ci	mtspr	SPRN_PID, r3			/* Set PID */
23562306a36Sopenharmony_ci	mfmsr	r4				/* Get MSR */
23662306a36Sopenharmony_ci	andi.	r4, r4, MSR_IS@l		/* TS=1? */
23762306a36Sopenharmony_ci	beq	1f				/* If not, leave STS=0 */
23862306a36Sopenharmony_ci	oris	r3, r3, PPC47x_MMUCR_STS@h	/* Set STS=1 */
23962306a36Sopenharmony_ci1:	mtspr	SPRN_MMUCR, r3			/* Put MMUCR */
24062306a36Sopenharmony_ci	sync
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	/* Find the entry we are running from */
24362306a36Sopenharmony_ci	bcl	20,31,$+4
24462306a36Sopenharmony_ci2:	mflr	r23
24562306a36Sopenharmony_ci	tlbsx	r23, 0, r23
24662306a36Sopenharmony_ci	tlbre	r24, r23, 0			/* TLB Word 0 */
24762306a36Sopenharmony_ci	tlbre	r25, r23, 1			/* TLB Word 1 */
24862306a36Sopenharmony_ci	tlbre	r26, r23, 2			/* TLB Word 2 */
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/*
25262306a36Sopenharmony_ci	 * Invalidates all the tlb entries by writing to 256 RPNs(r4)
25362306a36Sopenharmony_ci	 * of 4k page size in all  4 ways (0-3 in r3).
25462306a36Sopenharmony_ci	 * This would invalidate the entire UTLB including the one we are
25562306a36Sopenharmony_ci	 * running from. However the shadow TLB entries would help us
25662306a36Sopenharmony_ci	 * to continue the execution, until we flush them (rfi/isync).
25762306a36Sopenharmony_ci	 */
25862306a36Sopenharmony_ci	addis	r3, 0, 0x8000			/* specify the way */
25962306a36Sopenharmony_ci	addi	r4, 0, 0			/* TLB Word0 = (EPN=0, VALID = 0) */
26062306a36Sopenharmony_ci	addi	r5, 0, 0
26162306a36Sopenharmony_ci	b	clear_utlb_entry
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* Align the loop to speed things up. from head_44x.S */
26462306a36Sopenharmony_ci	.align	6
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ciclear_utlb_entry:
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	tlbwe	r4, r3, 0
26962306a36Sopenharmony_ci	tlbwe	r5, r3, 1
27062306a36Sopenharmony_ci	tlbwe	r5, r3, 2
27162306a36Sopenharmony_ci	addis	r3, r3, 0x2000			/* Increment the way */
27262306a36Sopenharmony_ci	cmpwi	r3, 0
27362306a36Sopenharmony_ci	bne	clear_utlb_entry
27462306a36Sopenharmony_ci	addis	r3, 0, 0x8000
27562306a36Sopenharmony_ci	addis	r4, r4, 0x100			/* Increment the EPN */
27662306a36Sopenharmony_ci	cmpwi	r4, 0
27762306a36Sopenharmony_ci	bne	clear_utlb_entry
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/* Create the entries in the other address space */
28062306a36Sopenharmony_ci	mfmsr	r5
28162306a36Sopenharmony_ci	rlwinm	r7, r5, 27, 31, 31		/* Get the TS (Bit 26) from MSR */
28262306a36Sopenharmony_ci	xori	r7, r7, 1			/* r7 = !TS */
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	insrwi	r24, r7, 1, 21			/* Change the TS in the saved TLB word 0 */
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/*
28762306a36Sopenharmony_ci	 * write out the TLB entries for the tmp mapping
28862306a36Sopenharmony_ci	 * Use way '0' so that we could easily invalidate it later.
28962306a36Sopenharmony_ci	 */
29062306a36Sopenharmony_ci	lis	r3, 0x8000			/* Way '0' */
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	tlbwe	r24, r3, 0
29362306a36Sopenharmony_ci	tlbwe	r25, r3, 1
29462306a36Sopenharmony_ci	tlbwe	r26, r3, 2
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	/* Update the msr to the new TS */
29762306a36Sopenharmony_ci	insrwi	r5, r7, 1, 26
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	bcl	20,31,$+4
30062306a36Sopenharmony_ci1:	mflr	r6
30162306a36Sopenharmony_ci	addi	r6, r6, (2f-1b)
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	mtspr	SPRN_SRR0, r6
30462306a36Sopenharmony_ci	mtspr	SPRN_SRR1, r5
30562306a36Sopenharmony_ci	rfi
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/*
30862306a36Sopenharmony_ci	 * Now we are in the tmp address space.
30962306a36Sopenharmony_ci	 * Create a 1:1 mapping for 0-2GiB in the original TS.
31062306a36Sopenharmony_ci	 */
31162306a36Sopenharmony_ci2:
31262306a36Sopenharmony_ci	li	r3, 0
31362306a36Sopenharmony_ci	li	r4, 0				/* TLB Word 0 */
31462306a36Sopenharmony_ci	li	r5, 0				/* TLB Word 1 */
31562306a36Sopenharmony_ci	li	r6, 0
31662306a36Sopenharmony_ci	ori	r6, r6, PPC47x_TLB2_S_RWX	/* TLB word 2 */
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	li	r8, 0				/* PageIndex */
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	xori	r7, r7, 1			/* revert back to original TS */
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ciwrite_utlb:
32362306a36Sopenharmony_ci	rotlwi	r5, r8, 28			/* RPN = PageIndex * 256M */
32462306a36Sopenharmony_ci						/* ERPN = 0 as we don't use memory above 2G */
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	mr	r4, r5				/* EPN = RPN */
32762306a36Sopenharmony_ci	ori	r4, r4, (PPC47x_TLB0_VALID | PPC47x_TLB0_256M)
32862306a36Sopenharmony_ci	insrwi	r4, r7, 1, 21			/* Insert the TS to Word 0 */
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	tlbwe	r4, r3, 0			/* Write out the entries */
33162306a36Sopenharmony_ci	tlbwe	r5, r3, 1
33262306a36Sopenharmony_ci	tlbwe	r6, r3, 2
33362306a36Sopenharmony_ci	addi	r8, r8, 1
33462306a36Sopenharmony_ci	cmpwi	r8, 8				/* Have we completed ? */
33562306a36Sopenharmony_ci	bne	write_utlb
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/* make sure we complete the TLB write up */
33862306a36Sopenharmony_ci	isync
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/*
34162306a36Sopenharmony_ci	 * Prepare to jump to the 1:1 mapping.
34262306a36Sopenharmony_ci	 * 1) Extract page size of the tmp mapping
34362306a36Sopenharmony_ci	 *    DSIZ = TLB_Word0[22:27]
34462306a36Sopenharmony_ci	 * 2) Calculate the physical address of the address
34562306a36Sopenharmony_ci	 *    to jump to.
34662306a36Sopenharmony_ci	 */
34762306a36Sopenharmony_ci	rlwinm	r10, r24, 0, 22, 27
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	cmpwi	r10, PPC47x_TLB0_4K
35062306a36Sopenharmony_ci	bne	0f
35162306a36Sopenharmony_ci	li	r10, 0x1000			/* r10 = 4k */
35262306a36Sopenharmony_ci	bl	1f
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci0:
35562306a36Sopenharmony_ci	/* Defaults to 256M */
35662306a36Sopenharmony_ci	lis	r10, 0x1000
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	bcl	20,31,$+4
35962306a36Sopenharmony_ci1:	mflr	r4
36062306a36Sopenharmony_ci	addi	r4, r4, (2f-1b)			/* virtual address  of 2f */
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	subi	r11, r10, 1			/* offsetmask = Pagesize - 1 */
36362306a36Sopenharmony_ci	not	r10, r11			/* Pagemask = ~(offsetmask) */
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	and	r5, r25, r10			/* Physical page */
36662306a36Sopenharmony_ci	and	r6, r4, r11			/* offset within the current page */
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	or	r5, r5, r6			/* Physical address for 2f */
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/* Switch the TS in MSR to the original one */
37162306a36Sopenharmony_ci	mfmsr	r8
37262306a36Sopenharmony_ci	insrwi	r8, r7, 1, 26
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	mtspr	SPRN_SRR1, r8
37562306a36Sopenharmony_ci	mtspr	SPRN_SRR0, r5
37662306a36Sopenharmony_ci	rfi
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci2:
37962306a36Sopenharmony_ci	/* Invalidate the tmp mapping */
38062306a36Sopenharmony_ci	lis	r3, 0x8000			/* Way '0' */
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	clrrwi	r24, r24, 12			/* Clear the valid bit */
38362306a36Sopenharmony_ci	tlbwe	r24, r3, 0
38462306a36Sopenharmony_ci	tlbwe	r25, r3, 1
38562306a36Sopenharmony_ci	tlbwe	r26, r3, 2
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	/* Make sure we complete the TLB write and flush the shadow TLB */
38862306a36Sopenharmony_ci	isync
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci#endif
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cippc44x_map_done:
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	/* Restore the parameters */
39662306a36Sopenharmony_ci	mr	r3, r29
39762306a36Sopenharmony_ci	mr	r4, r30
39862306a36Sopenharmony_ci	mr	r5, r31
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	li	r0, 0
40162306a36Sopenharmony_ci#else
40262306a36Sopenharmony_ci	li	r0, 0
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	/*
40562306a36Sopenharmony_ci	 * Set Machine Status Register to a known status,
40662306a36Sopenharmony_ci	 * switch the MMU off and jump to 1: in a single step.
40762306a36Sopenharmony_ci	 */
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	mr	r8, r0
41062306a36Sopenharmony_ci	ori     r8, r8, MSR_RI|MSR_ME
41162306a36Sopenharmony_ci	mtspr	SPRN_SRR1, r8
41262306a36Sopenharmony_ci	addi	r8, r4, 1f - relocate_new_kernel
41362306a36Sopenharmony_ci	mtspr	SPRN_SRR0, r8
41462306a36Sopenharmony_ci	sync
41562306a36Sopenharmony_ci	rfi
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci1:
41862306a36Sopenharmony_ci#endif
41962306a36Sopenharmony_ci	/* from this point address translation is turned off */
42062306a36Sopenharmony_ci	/* and interrupts are disabled */
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/* set a new stack at the bottom of our page... */
42362306a36Sopenharmony_ci	/* (not really needed now) */
42462306a36Sopenharmony_ci	addi	r1, r4, KEXEC_CONTROL_PAGE_SIZE - 8 /* for LR Save+Back Chain */
42562306a36Sopenharmony_ci	stw	r0, 0(r1)
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/* Do the copies */
42862306a36Sopenharmony_ci	li	r6, 0 /* checksum */
42962306a36Sopenharmony_ci	mr	r0, r3
43062306a36Sopenharmony_ci	b	1f
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci0:	/* top, read another word for the indirection page */
43362306a36Sopenharmony_ci	lwzu	r0, 4(r3)
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci1:
43662306a36Sopenharmony_ci	/* is it a destination page? (r8) */
43762306a36Sopenharmony_ci	rlwinm.	r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
43862306a36Sopenharmony_ci	beq	2f
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	rlwinm	r8, r0, 0, 0, 19 /* clear kexec flags, page align */
44162306a36Sopenharmony_ci	b	0b
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci2:	/* is it an indirection page? (r3) */
44462306a36Sopenharmony_ci	rlwinm.	r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
44562306a36Sopenharmony_ci	beq	2f
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	rlwinm	r3, r0, 0, 0, 19 /* clear kexec flags, page align */
44862306a36Sopenharmony_ci	subi	r3, r3, 4
44962306a36Sopenharmony_ci	b	0b
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci2:	/* are we done? */
45262306a36Sopenharmony_ci	rlwinm.	r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
45362306a36Sopenharmony_ci	beq	2f
45462306a36Sopenharmony_ci	b	3f
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci2:	/* is it a source page? (r9) */
45762306a36Sopenharmony_ci	rlwinm.	r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
45862306a36Sopenharmony_ci	beq	0b
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	rlwinm	r9, r0, 0, 0, 19 /* clear kexec flags, page align */
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	li	r7, PAGE_SIZE / 4
46362306a36Sopenharmony_ci	mtctr   r7
46462306a36Sopenharmony_ci	subi    r9, r9, 4
46562306a36Sopenharmony_ci	subi    r8, r8, 4
46662306a36Sopenharmony_ci9:
46762306a36Sopenharmony_ci	lwzu    r0, 4(r9)  /* do the copy */
46862306a36Sopenharmony_ci	xor	r6, r6, r0
46962306a36Sopenharmony_ci	stwu    r0, 4(r8)
47062306a36Sopenharmony_ci	dcbst	0, r8
47162306a36Sopenharmony_ci	sync
47262306a36Sopenharmony_ci	icbi	0, r8
47362306a36Sopenharmony_ci	bdnz    9b
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	addi    r9, r9, 4
47662306a36Sopenharmony_ci	addi    r8, r8, 4
47762306a36Sopenharmony_ci	b	0b
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci3:
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	/* To be certain of avoiding problems with self-modifying code
48262306a36Sopenharmony_ci	 * execute a serializing instruction here.
48362306a36Sopenharmony_ci	 */
48462306a36Sopenharmony_ci	isync
48562306a36Sopenharmony_ci	sync
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	mfspr	r3, SPRN_PIR /* current core we are running on */
48862306a36Sopenharmony_ci	mr	r4, r5 /* load physical address of chunk called */
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/* jump to the entry point, usually the setup routine */
49162306a36Sopenharmony_ci	mtlr	r5
49262306a36Sopenharmony_ci	blrl
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci1:	b	1b
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cirelocate_new_kernel_end:
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	.globl relocate_new_kernel_size
49962306a36Sopenharmony_cirelocate_new_kernel_size:
50062306a36Sopenharmony_ci	.long relocate_new_kernel_end - relocate_new_kernel
501