|  | /* | 
|  | * relocate_kernel.S - put the kernel image in place to boot | 
|  | * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com> | 
|  | * | 
|  | * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz | 
|  | * | 
|  | * This source code is licensed under the GNU General Public License, | 
|  | * Version 2.  See the file COPYING for more details. | 
|  | */ | 
|  |  | 
|  | #include <asm/reg.h> | 
|  | #include <asm/ppc_asm.h> | 
|  | #include <asm/processor.h> | 
|  |  | 
|  | #include <asm/kexec.h> | 
|  |  | 
|  | #define PAGE_SIZE      4096 /* must be same value as in <asm/page.h> */ | 
|  |  | 
|  | /* | 
|  | * Must be relocatable PIC code callable as a C function. | 
|  | */ | 
|  | .globl relocate_new_kernel | 
|  | relocate_new_kernel: | 
|  | /* r3 = page_list   */ | 
|  | /* r4 = reboot_code_buffer */ | 
|  | /* r5 = start_address      */ | 
|  |  | 
|  | li	r0, 0 | 
|  |  | 
|  | /* | 
|  | * Set Machine Status Register to a known status, | 
|  | * switch the MMU off and jump to 1: in a single step. | 
|  | */ | 
|  |  | 
|  | mr	r8, r0 | 
|  | ori     r8, r8, MSR_RI|MSR_ME | 
|  | mtspr	SPRN_SRR1, r8 | 
|  | addi	r8, r4, 1f - relocate_new_kernel | 
|  | mtspr	SPRN_SRR0, r8 | 
|  | sync | 
|  | rfi | 
|  |  | 
|  | 1: | 
|  | /* from this point address translation is turned off */ | 
|  | /* and interrupts are disabled */ | 
|  |  | 
|  | /* set a new stack at the bottom of our page... */ | 
|  | /* (not really needed now) */ | 
|  | addi	r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */ | 
|  | stw	r0, 0(r1) | 
|  |  | 
|  | /* Do the copies */ | 
|  | li	r6, 0 /* checksum */ | 
|  | mr	r0, r3 | 
|  | b	1f | 
|  |  | 
|  | 0:	/* top, read another word for the indirection page */ | 
|  | lwzu	r0, 4(r3) | 
|  |  | 
|  | 1: | 
|  | /* is it a destination page? (r8) */ | 
|  | rlwinm.	r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */ | 
|  | beq	2f | 
|  |  | 
|  | rlwinm	r8, r0, 0, 0, 19 /* clear kexec flags, page align */ | 
|  | b	0b | 
|  |  | 
|  | 2:	/* is it an indirection page? (r3) */ | 
|  | rlwinm.	r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */ | 
|  | beq	2f | 
|  |  | 
|  | rlwinm	r3, r0, 0, 0, 19 /* clear kexec flags, page align */ | 
|  | subi	r3, r3, 4 | 
|  | b	0b | 
|  |  | 
|  | 2:	/* are we done? */ | 
|  | rlwinm.	r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */ | 
|  | beq	2f | 
|  | b	3f | 
|  |  | 
|  | 2:	/* is it a source page? (r9) */ | 
|  | rlwinm.	r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */ | 
|  | beq	0b | 
|  |  | 
|  | rlwinm	r9, r0, 0, 0, 19 /* clear kexec flags, page align */ | 
|  |  | 
|  | li	r7, PAGE_SIZE / 4 | 
|  | mtctr   r7 | 
|  | subi    r9, r9, 4 | 
|  | subi    r8, r8, 4 | 
|  | 9: | 
|  | lwzu    r0, 4(r9)  /* do the copy */ | 
|  | xor	r6, r6, r0 | 
|  | stwu    r0, 4(r8) | 
|  | dcbst	0, r8 | 
|  | sync | 
|  | icbi	0, r8 | 
|  | bdnz    9b | 
|  |  | 
|  | addi    r9, r9, 4 | 
|  | addi    r8, r8, 4 | 
|  | b	0b | 
|  |  | 
|  | 3: | 
|  |  | 
|  | /* To be certain of avoiding problems with self-modifying code | 
|  | * execute a serializing instruction here. | 
|  | */ | 
|  | isync | 
|  | sync | 
|  |  | 
|  | /* jump to the entry point, usually the setup routine */ | 
|  | mtlr	r5 | 
|  | blrl | 
|  |  | 
|  | 1:	b	1b | 
|  |  | 
|  | relocate_new_kernel_end: | 
|  |  | 
|  | .globl relocate_new_kernel_size | 
|  | relocate_new_kernel_size: | 
|  | .long relocate_new_kernel_end - relocate_new_kernel | 
|  |  |