Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  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