This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / arch / ppc / kernel / relocate_kernel.S
1 /*
2  * relocate_kernel.S - put the kernel image in place to boot
3  * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
4  *
5  * GAMECUBE/PPC32 port Copyright (C) 2004 Albert Herranz
6  *
7  * This source code is licensed under the GNU General Public License,
8  * Version 2.  See the file COPYING for more details.
9  */
10
11 #include <asm/reg.h>
12 #include <asm/ppc_asm.h>
13 #include <asm/processor.h>
14
15 #include <asm/kexec.h>
16
17 #define PAGE_SIZE      4096 /* must be same value as in <asm/page.h> */
18
19 /* returns  r3 = relocated address of sym */
20 /* modifies r0 */
21 #define RELOC_SYM(sym) \
22         mflr    r3; \
23         bl      1f; \
24 1:      mflr    r0; \
25         mtlr    r3; \
26         lis     r3, 1b@ha; \
27         ori     r3, r3, 1b@l; \
28         subf    r0, r3, r0; \
29         lis     r3, sym@ha; \
30         ori     r3, r3, sym@l; \
31         add     r3, r3, r0
32
33         /*
34          * Must be relocatable PIC code callable as a C function.
35          */
36         .globl relocate_new_kernel
37 relocate_new_kernel:
38         /* r3 = indirection_page   */
39         /* r4 = reboot_code_buffer */
40         /* r5 = start_address      */
41
42         li      r0, 0
43
44         /* Set Machine Status Register to a known status */
45         mr      r8, r0
46         ori     r8, r8, MSR_RI|MSR_ME
47         mtmsr   r8
48         isync
49
50         /* from this point address translation is turned off */
51         /* and interrupts are disabled */
52
53         /* set a new stack at the bottom of our page... */
54         /* (not really needed now) */
55         addi    r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */
56         stw     r0, 0(r1)
57
58         /* Do the copies */
59         li      r6, 0 /* checksum */
60         subi    r3, r3, 4
61
62 0:      /* top, read another word for the indirection page */
63         lwzu    r0, 4(r3)
64
65         /* is it a destination page? (r8) */
66         rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
67         beq     1f
68
69         rlwinm  r8, r0, 0, 0, 19 /* clear kexec flags, page align */
70         b       0b
71
72 1:      /* is it an indirection page? (r3) */
73         rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
74         beq     1f
75
76         rlwinm  r3, r0, 0, 0, 19 /* clear kexec flags, page align */
77         subi    r3, r3, 4
78         b       0b
79
80 1:      /* are we done? */
81         rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
82         beq     1f
83         b       2f
84
85 1:      /* is it a source page? (r9) */
86         rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
87         beq     0b
88
89         rlwinm  r9, r0, 0, 0, 19 /* clear kexec flags, page align */
90
91         li      r7, PAGE_SIZE / 4
92         mtctr   r7
93         subi    r9, r9, 4
94         subi    r8, r8, 4
95 9:
96         lwzu    r0, 4(r9)  /* do the copy */
97         xor     r6, r6, r0
98         stwu    r0, 4(r8)
99         dcbst   0, r8
100         sync
101         icbi    0, r8
102         bdnz    9b
103
104         addi    r9, r9, 4
105         addi    r8, r8, 4
106         b       0b
107
108 2:
109
110         /* To be certain of avoiding problems with self-modifying code
111          * execute a serializing instruction here.
112          */
113         isync
114         sync
115
116         /* jump to the entry point, usually the setup routine */
117         mtlr    r5
118         blrl
119
120 1:      b       1b
121
122 relocate_new_kernel_end:
123
124         .globl relocate_new_kernel_size
125 relocate_new_kernel_size:
126         .long relocate_new_kernel_end - relocate_new_kernel
127