• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
3 *
4 *   This program is free software; you can redistribute it and/or
5 *   modify it under the terms of the GNU General Public License
6 *   as published by the Free Software Foundation, version 2.
7 *
8 *   This program is distributed in the hope that it will be useful, but
9 *   WITHOUT ANY WARRANTY; without even the implied warranty of
10 *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11 *   NON INFRINGEMENT.  See the GNU General Public License for
12 *   more details.
13 *
14 * copy new kernel into place and then call hv_reexec
15 *
16 */
17
18#include <linux/linkage.h>
19#include <arch/chip.h>
20#include <asm/page.h>
21#include <hv/hypervisor.h>
22
23#undef RELOCATE_NEW_KERNEL_VERBOSE
24
25STD_ENTRY(relocate_new_kernel)
26
27	move	r30, r0		/* page list */
28	move	r31, r1		/* address of page we are on */
29	move	r32, r2		/* start address of new kernel */
30
31	shri	r1, r1, PAGE_SHIFT
32	addi	r1, r1, 1
33	shli	sp, r1, PAGE_SHIFT
34	addi	sp, sp, -8
35	/* we now have a stack (whether we need one or not) */
36
37	moveli	r40, lo16(hv_console_putc)
38	auli	r40, r40, ha16(hv_console_putc)
39
40#ifdef RELOCATE_NEW_KERNEL_VERBOSE
41	moveli	r0, 'r'
42	jalr	r40
43
44	moveli	r0, '_'
45	jalr	r40
46
47	moveli	r0, 'n'
48	jalr	r40
49
50	moveli	r0, '_'
51	jalr	r40
52
53	moveli	r0, 'k'
54	jalr	r40
55
56	moveli	r0, '\n'
57	jalr	r40
58#endif
59
60	/*
61	 * Throughout this code r30 is pointer to the element of page
62	 * list we are working on.
63	 *
64	 * Normally we get to the next element of the page list by
65	 * incrementing r30 by four.  The exception is if the element
66	 * on the page list is an IND_INDIRECTION in which case we use
67	 * the element with the low bits masked off as the new value
68	 * of r30.
69	 *
70	 * To get this started, we need the value passed to us (which
71	 * will always be an IND_INDIRECTION) in memory somewhere with
72	 * r30 pointing at it.  To do that, we push the value passed
73	 * to us on the stack and make r30 point to it.
74	 */
75
76	sw	sp, r30
77	move	r30, sp
78	addi	sp, sp, -8
79
80	/*
81	 * On TILEPro, we need to flush all tiles' caches, since we may
82	 * have been doing hash-for-home caching there.  Note that we
83	 * must do this _after_ we're completely done modifying any memory
84	 * other than our output buffer (which we know is locally cached).
85	 * We want the caches to be fully clean when we do the reexec,
86	 * because the hypervisor is going to do this flush again at that
87	 * point, and we don't want that second flush to overwrite any memory.
88	 */
89	{
90	 move	r0, zero	 /* cache_pa */
91	 move	r1, zero
92	}
93	{
94	 auli	r2, zero, ha16(HV_FLUSH_EVICT_L2) /* cache_control */
95	 movei	r3, -1		 /* cache_cpumask; -1 means all client tiles */
96	}
97	{
98	 move	r4, zero	 /* tlb_va */
99	 move	r5, zero	 /* tlb_length */
100	}
101	{
102	 move	r6, zero	 /* tlb_pgsize */
103	 move	r7, zero	 /* tlb_cpumask */
104	}
105	{
106	 move	r8, zero	 /* asids */
107	 moveli	r20, lo16(hv_flush_remote)
108	}
109	{
110	 move	r9, zero	 /* asidcount */
111	 auli	r20, r20, ha16(hv_flush_remote)
112	}
113
114	jalr	r20
115
116	/* r33 is destination pointer, default to zero */
117
118	moveli	r33, 0
119
120.Lloop:	lw	r10, r30
121
122	andi	r9, r10, 0xf	/* low 4 bits tell us what type it is */
123	xor	r10, r10, r9	/* r10 is now value with low 4 bits stripped */
124
125	seqi	r0, r9, 0x1	/* IND_DESTINATION */
126	bzt	r0, .Ltry2
127
128	move	r33, r10
129
130#ifdef RELOCATE_NEW_KERNEL_VERBOSE
131	moveli	r0, 'd'
132	jalr	r40
133#endif
134
135	addi	r30, r30, 4
136	j	.Lloop
137
138.Ltry2:
139	seqi	r0, r9, 0x2	/* IND_INDIRECTION */
140	bzt	r0, .Ltry4
141
142	move	r30, r10
143
144#ifdef RELOCATE_NEW_KERNEL_VERBOSE
145	moveli	r0, 'i'
146	jalr	r40
147#endif
148
149	j	.Lloop
150
151.Ltry4:
152	seqi	r0, r9, 0x4	/* IND_DONE */
153	bzt	r0, .Ltry8
154
155	mf
156
157#ifdef RELOCATE_NEW_KERNEL_VERBOSE
158	moveli	r0, 'D'
159	jalr	r40
160	moveli	r0, '\n'
161	jalr	r40
162#endif
163
164	move	r0, r32
165	moveli	r1, 0		/* arg to hv_reexec is 64 bits */
166
167	moveli	r41, lo16(hv_reexec)
168	auli	r41, r41, ha16(hv_reexec)
169
170	jalr	r41
171
172	/* we should not get here */
173
174	moveli	r0, '?'
175	jalr	r40
176	moveli	r0, '\n'
177	jalr	r40
178
179	j	.Lhalt
180
181.Ltry8:	seqi	r0, r9, 0x8	/* IND_SOURCE */
182	bz	r0, .Lerr	/* unknown type */
183
184	/* copy page at r10 to page at r33 */
185
186	move	r11, r33
187
188	moveli	r0, lo16(PAGE_SIZE)
189	auli	r0, r0, ha16(PAGE_SIZE)
190	add	r33, r33, r0
191
192	/* copy word at r10 to word at r11 until r11 equals r33 */
193
194	/* We know page size must be multiple of 16, so we can unroll
195	 * 16 times safely without any edge case checking.
196	 *
197	 * Issue a flush of the destination every 16 words to avoid
198	 * incoherence when starting the new kernel.  (Now this is
199	 * just good paranoia because the hv_reexec call will also
200	 * take care of this.)
201	 */
202
2031:
204	{ lw	r0, r10; addi	r10, r10, 4 }
205	{ sw	r11, r0; addi	r11, r11, 4 }
206	{ lw	r0, r10; addi	r10, r10, 4 }
207	{ sw	r11, r0; addi	r11, r11, 4 }
208	{ lw	r0, r10; addi	r10, r10, 4 }
209	{ sw	r11, r0; addi	r11, r11, 4 }
210	{ lw	r0, r10; addi	r10, r10, 4 }
211	{ sw	r11, r0; addi	r11, r11, 4 }
212	{ lw	r0, r10; addi	r10, r10, 4 }
213	{ sw	r11, r0; addi	r11, r11, 4 }
214	{ lw	r0, r10; addi	r10, r10, 4 }
215	{ sw	r11, r0; addi	r11, r11, 4 }
216	{ lw	r0, r10; addi	r10, r10, 4 }
217	{ sw	r11, r0; addi	r11, r11, 4 }
218	{ lw	r0, r10; addi	r10, r10, 4 }
219	{ sw	r11, r0; addi	r11, r11, 4 }
220	{ lw	r0, r10; addi	r10, r10, 4 }
221	{ sw	r11, r0; addi	r11, r11, 4 }
222	{ lw	r0, r10; addi	r10, r10, 4 }
223	{ sw	r11, r0; addi	r11, r11, 4 }
224	{ lw	r0, r10; addi	r10, r10, 4 }
225	{ sw	r11, r0; addi	r11, r11, 4 }
226	{ lw	r0, r10; addi	r10, r10, 4 }
227	{ sw	r11, r0; addi	r11, r11, 4 }
228	{ lw	r0, r10; addi	r10, r10, 4 }
229	{ sw	r11, r0; addi	r11, r11, 4 }
230	{ lw	r0, r10; addi	r10, r10, 4 }
231	{ sw	r11, r0; addi	r11, r11, 4 }
232	{ lw	r0, r10; addi	r10, r10, 4 }
233	{ sw	r11, r0; addi	r11, r11, 4 }
234	{ lw	r0, r10; addi	r10, r10, 4 }
235	{ sw	r11, r0 }
236	{ flush r11    ; addi	r11, r11, 4 }
237
238	seq	r0, r33, r11
239	bzt	r0, 1b
240
241#ifdef RELOCATE_NEW_KERNEL_VERBOSE
242	moveli	r0, 's'
243	jalr	r40
244#endif
245
246	addi	r30, r30, 4
247	j	.Lloop
248
249
250.Lerr:	moveli	r0, 'e'
251	jalr	r40
252	moveli	r0, 'r'
253	jalr	r40
254	moveli	r0, 'r'
255	jalr	r40
256	moveli	r0, '\n'
257	jalr	r40
258.Lhalt:
259	moveli	r41, lo16(hv_halt)
260	auli	r41, r41, ha16(hv_halt)
261
262	jalr	r41
263	STD_ENDPROC(relocate_new_kernel)
264
265	.section .rodata,"a"
266
267	.globl relocate_new_kernel_size
268relocate_new_kernel_size:
269	.long .Lend_relocate_new_kernel - relocate_new_kernel
270