1/*	$NetBSD$	*/
2/*
3 * Copyright (c) 2012, 2013 KIYOHARA Takashi
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <e32base.h>
29#include <e32def.h>
30#include <e32std.h>
31
32#include "cpu.h"
33#include "e32boot.h"
34#include "ekern.h"
35#include "epoc32.h"
36#include "netbsd.h"
37
38
39class E32BootLDD : public DLogicalDevice {
40public:
41	E32BootLDD(void);
42	virtual TInt Install(void);
43	virtual void GetCaps(TDes8 &) const;
44	virtual DLogicalChannel *CreateL(void);
45};
46
47class E32BootChannel : public DLogicalChannel {
48public:
49	E32BootChannel(DLogicalDevice *);
50
51protected:
52	virtual void DoCancel(TInt);
53	virtual void DoRequest(TInt, TAny *, TAny *);
54	virtual TInt DoControl(TInt, TAny *, TAny *);
55
56private:
57	EPOC32 *epoc32;
58	TAny *safeAddress;
59
60	TInt BootNetBSD(NetBSD *, struct btinfo_common *);
61};
62
63
64/* E32Dll() function is required by all DLLs. */
65GLDEF_C TInt
66E32Dll(TDllReason)
67{
68
69	return KErrNone;
70}
71
72EXPORT_C DLogicalDevice *
73CreateLogicalDevice(void)
74{
75
76	return new E32BootLDD;
77}
78
79E32BootLDD::E32BootLDD(void)
80{
81	/* Nothing */
82}
83
84TInt
85E32BootLDD::Install(void)
86{
87
88	return SetName(&E32BootName);
89}
90
91void
92E32BootLDD::GetCaps(TDes8 &aDes) const
93{
94	TVersion version(0, 0, 0);	/* XXXXX: What is it? Don't check? */
95
96	aDes.FillZ(aDes.MaxLength());
97	aDes.Copy((TUint8 *)&version, Min(aDes.MaxLength(), sizeof(version)));
98}
99
100DLogicalChannel *
101E32BootLDD::CreateL(void)
102{
103
104	return new (ELeave) E32BootChannel(this);
105}
106
107
108E32BootChannel::E32BootChannel(DLogicalDevice *aDevice)
109    : DLogicalChannel(aDevice)
110{
111
112	epoc32 = new EPOC32;
113	safeAddress = NULL;
114}
115
116void
117E32BootChannel::DoCancel(TInt aReqNo)
118{
119	/* Nothing */
120}
121
122void
123E32BootChannel::DoRequest(TInt aReqNo, TAny *a1, TAny *a2)
124{
125	/* Nothing */
126}
127
128TInt
129E32BootChannel::DoControl(TInt aFunction, TAny *a1, TAny *a2)
130{
131
132	switch (aFunction) {
133	case KE32BootGetProcessorID:
134	{
135		TInt id;
136
137		__asm("mrc	p15, 0, %0, c0, c0" : "=r"(id));
138		*(TUint *)a1 = id;
139		break;
140	}
141
142	case KE32BootSetSafeAddress:
143	{
144		safeAddress = (TAny *)PAGE_ALIGN(a1);
145		break;
146	}
147
148	case KE32BootBootNetBSD:
149	{
150		NetBSD *netbsd = (NetBSD *)a1;
151		struct btinfo_common *bootinfo = (struct btinfo_common *)a2;
152
153		BootNetBSD(netbsd, bootinfo);
154
155		/* NOTREACHED */
156
157		break;
158	}
159
160	default:
161		break;
162	}
163	return KErrNone;
164}
165
166TInt
167E32BootChannel::BootNetBSD(NetBSD *netbsd, struct btinfo_common *bootinfo)
168{
169	TAny *mmu_disabled, *ttb;
170
171	__asm("adr %0, mmu_disabled" : "=r"(mmu_disabled));
172	mmu_disabled = epoc32->GetPhysicalAddress(mmu_disabled);
173	/*
174	 * ARMv3 can't read TTB from CP15 C1.
175	 * Also can't read Control Register.
176	 */
177	ttb = epoc32->GetPhysicalAddress(epoc32->GetTTB());
178
179	__asm __volatile("				\
180	mrs	r12, cpsr;				\
181	/* Clear PSR_MODE and Interrupts */		\
182	bic	r12, r12, #0xdf;			\
183	/* Disable Interrupts(IRQ/FIQ) */		\
184	orr	r12, r12, #(3 << 6);			\
185	/* Set SVC32 MODE */				\
186	orr	r12, r12, #0x13;			\
187	msr	cpsr_c, r12;				\
188							\
189	ldr	r10, [%0, #0x0];			\
190	ldr	sp, [%0, #0x4];				\
191	ldr	lr, [%0, #0x8];				\
192	mov	r12, %1;				\
193	" :: "r"(netbsd), "r"(bootinfo));
194
195	__asm __volatile("				\
196	mov	r7, %2;					\
197	mov	r8, %1;					\
198	mov	r9, %0;					\
199							\
200	/* Set all domains to 15 */			\
201	mov	r0, #0xffffffff;			\
202	mcr	p15, 0, r0, c3, c0;			\
203							\
204	/* Disable MMU */				\
205	mov	r0, #0x38; /* WBUF | 32BP | 32BD */	\
206	mcr	p15, 0, r0, c1, c0, 0;			\
207							\
208	mov	pc, r7;					\
209							\
210mmu_disabled:						\
211	/*						\
212	 * r8	safe address(maybe frame-buffer address)\
213	 * r9	ttb					\
214	 * r10	buffer (netbsd)				\
215	 * r11	memory descriptor			\
216	 * r12	bootinfo				\
217	 * sp	load descriptor				\
218	 * lr	entry point				\
219	 */						\
220	/* save lr to r7 before call functions. */	\
221	mov	r7, lr;					\
222							\
223	mov	r0, r8;					\
224	mov	r1, r9;					\
225	bl	vtop;					\
226	mov	r8, r0;					\
227							\
228	/*						\
229	 * Copy bootinfo to safe address.		\
230	 * That addr used to framebuffer by EPOC32.	\
231	 */						\
232	mov	r0, r12;				\
233	mov	r1, r9;					\
234	bl	vtop;					\
235	mov	r1, r0;					\
236	mov	r12, r8;				\
237	mov	r0, r8;					\
238	mov	r2, #0x400;				\
239	bl	copy;					\
240							\
241	/* save lr(r7) to r8. it is no need. */		\
242	mov	r8, r7;					\
243							\
244	/* Copy loader to safe address + 0x400. */	\
245	add	r0, r12, #0x400;			\
246	adr	r1, miniloader_start;			\
247	adr	r2, miniloader_end;			\
248	sub	r2, r2, r1;				\
249	bl	copy;					\
250							\
251	/* Make load-descriptor to safe addr + 0x800. */\
252	mov	r0, sp;					\
253	mov	r1, r9;					\
254	bl	vtop;					\
255	mov	sp, r0;					\
256	add	r4, r12, #0x800;			\
257							\
258next_section:						\
259	ldmia	sp!, {r5 - r7};				\
260							\
261next_page:						\
262	add	r0, r10, r6;				\
263	mov	r1, r9;					\
264	bl	vtop;					\
265	/* vtop returns set mask to r2 */		\
266	orr	r2, r0, r2;				\
267	add	r2, r2, #1;				\
268	sub	r2, r2,	r0;				\
269	cmp	r2, r7;					\
270	movgt	r2, r7;					\
271	mov	r1, r0;					\
272	mov	r0, r5;					\
273	stmia	r4!, {r0 - r2};				\
274	add	r5, r5, r2;				\
275	add	r6, r6, r2;				\
276	subs	r7, r7, r2;				\
277	bgt	next_page;				\
278							\
279	ldr	r0, [sp];				\
280	cmp	r0, #0xffffffff;			\
281	beq	fin;					\
282	/* Pad to section align. */			\
283	str	r5, [r4], #4;				\
284	mov	r6, #0xffffffff;			\
285	str	r6, [r4], #4;				\
286	sub	r2, r0, r5;				\
287	str	r2, [r4], #4;				\
288	b	next_section;				\
289							\
290fin:							\
291	stmia	r4, {r5 - r7};				\
292	add	sp, r12, #0x800;			\
293							\
294	/* save lr(r8) to r11. r11 is no need. */	\
295	mov	r11, r8;				\
296							\
297	/* Fixup load-descriptor by BTINFO_MEMORY. */	\
298	mov	r10, r12;				\
299	mov	r9, sp;					\
300	add	r8, sp, #12;				\
301next_bootinfo:						\
302	ldmia	r10, {r0, r1};				\
303	cmp	r1, #0;		/* BTINFO_NONE */	\
304	beq	btinfo_none;				\
305							\
306	cmp	r1, #2;		/* BTINFO_MEMORY */	\
307	beq	btinfo_memory;				\
308	add	r10, r10, r0;				\
309	b	next_bootinfo;				\
310							\
311btinfo_none:						\
312	/* ENOMEM */					\
313	add	r2, r12, #0x800;			\
314	mov	r1, #640;				\
315	mov	r0, #0x00ff0000;			\
316	orr	r0, r0, #0x00ff;			\
31798:							\
318	str	r0, [r2], #4;				\
319	subs	r1, r1, #4;				\
320	bgt	98b;					\
321	mov	r1, #640;				\
322	mov	r0, #0xff000000;			\
323	orr	r0, r0, #0xff00;			\
32499:							\
325	str	r0, [r2], #4;				\
326	subs	r1, r1, #4;				\
327	bgt	99b;					\
328100:							\
329	b	100b;					\
330							\
331btinfo_memory:						\
332	ldmia	r10!, {r4 - r7};			\
333	ldr	r4, [r9, #0];				\
334	subs	r4, r4, r6;				\
335	addgt	r6, r6, r4;				\
336	subgt	r7, r7, r4;				\
337next_desc:						\
338	ldmia	r9, {r3 - r5};				\
339	ldmia	r8!, {r0 - r2};				\
340	add	r3, r3, r5;				\
341	add	r4, r4, r5;				\
342	cmp	r3, r0;					\
343	cmpeq	r4, r1;					\
344	beq	join_desc;				\
345							\
346	ldr	r3, [r9, #0];				\
347	cmp	r3, r6;					\
348	strlt	r6, [r9, #0];	/* Fixup */		\
349	cmp	r5, r7;					\
350	bgt	split_desc;				\
351	add	r6, r6, r5;				\
352	sub	r7, r7, r5;				\
353	add	r9, r9, #12;				\
354	stmia	r9, {r0 - r2};				\
355	cmp	r0, #0xffffffff;			\
356	beq	fixuped;				\
357	b	next_desc;				\
358							\
359join_desc:	/* Join r8 descriptor to r9. */		\
360	add	r5, r5, r2;				\
361	str	r5, [r9, #8];				\
362	b	next_desc;				\
363							\
364split_desc:	/* Split r9 descriptor. */		\
365	ldr	r3, [r9, #0];				\
366	ldr	r4, [r9, #4];				\
367	str	r7, [r9, #8];				\
368							\
369	sub	r6, r5, r7;				\
370	add	r5, r4, r7;				\
371	add	r4, r3, r7;				\
372	sub	r8, r8, #12;	/* Back to prev desc */	\
373	add	r9, r9, #12;/* Point to splited desc */ \
374							\
375	cmp	r8, r9;					\
376	bne	2f;					\
377	add	r0, r8, #12;				\
378	mov	r1, r8;					\
379	mov	r2, #0;					\
3801:							\
381	ldr	r3, [r8, r2];				\
382	add	r2, r2, #12;				\
383	cmp	r3, #0xffffffff;			\
384	bne	1b;					\
385	bl	copy;					\
386	add	r8, r8, #12; /* Point to moved desc */	\
3872:							\
388	stmia	r9, {r4 - r6};				\
389	b	next_bootinfo;				\
390							\
391fixuped:						\
392	/* Jump to miniloader. Our LR is entry-point! */\
393	add	pc, r12, #0x400;			\
394							\
395vtop:							\
396	/*						\
397	 * paddr vtop(vaddr, ttb)			\
398	 */						\
399	bic	r2, r0, #0x000f0000; /* L1_ADDR_BITS */	\
400	bic	r2, r2, #0x0000ff00; /* L1_ADDR_BITS */	\
401	bic	r2, r2, #0x000000ff; /* L1_ADDR_BITS */	\
402	mov	r2, r2, lsr #(20 - 2);			\
403	ldr	r1, [r1, r2];				\
404	and	r3, r1, #0x3;	/* L1_TYPE_MASK */	\
405	cmp	r3, #0;					\
406	bne	valid;					\
407							\
408invalid:						\
409	mov	r0, #-1;				\
410	mov	pc, lr;					\
411							\
412valid:							\
413	cmp	r3, #0x2;				\
414	bgt	3f;					\
415	beq	2f;					\
416							\
4171:	/* Coarse L2 */					\
418	mov	r2, #10;				\
419	b	l2;					\
420							\
4212:	/* Section */					\
422	mov	r2, #0xff000000;    /* L1_S_ADDR_MASK */\
423	add	r2, r2, #0x00f00000;/* L1_S_ADDR_MASK */\
424	mvn	r2, r2;					\
425	bic	r3, r1, r2;				\
426	and	r0, r0, r2;				\
427	orr	r0, r3, r0;				\
428	mov	pc, lr;					\
429							\
4303:	/* Fine L2 */					\
431	mov	r2, #12;				\
432l2:							\
433	mov	r3, #1;					\
434	mov	r3, r3, lsl r2;				\
435	sub	r3, r3, #1;				\
436	bic	r1, r1, r3;	/* L2 table */		\
437	mov	r3, r0, lsl #12;			\
438	mov	r3, r3, lsr #12;			\
439	sub	r2, r2, #22;				\
440	rsb	r2, r2, #0;				\
441	mov	r3, r3, lsr r2;	/* index for L2 */	\
442	ldr	r1, [r1, r3, lsl #2];			\
443	and	r3, r1, #0x3;	/* L2_TYPE_MASK */	\
444	cmp	r3, #0;					\
445	beq	invalid;				\
446	cmp	r3, #2;					\
447	movlt	r2, #16;	/* L2_L_SHIFT */	\
448	moveq	r2, #12;	/* L2_S_SHIFT */	\
449	movgt	r2, #10;	/* L2_T_SHIFT */	\
450	mov	r3, #1;					\
451	mov	r2, r3, lsl r2;				\
452	sub	r2, r2, #1;				\
453	bic	r3, r1, r2;				\
454	and	r0, r0, r2;				\
455	orr	r0, r3, r0;				\
456	mov	pc, lr;					\
457							\
458miniloader_start:					\
459	b	miniloader;				\
460							\
461copy:							\
462	/*						\
463	 * void copy(dest, src, len)			\
464	 */						\
465	cmp	r0, r1;					\
466	bgt	rcopy;					\
467lcopy:							\
468	ldr	r3, [r1], #4;				\
469	str	r3, [r0], #4;				\
470	subs	r2, r2, #4;				\
471	bgt	lcopy;					\
472	mov	pc, lr;					\
473rcopy:							\
474	subs	r2, r2, #4;				\
475	ldr	r3, [r1, r2];				\
476	str	r3, [r0, r2];				\
477	bgt	rcopy;					\
478	mov	pc, lr;					\
479							\
480							\
481miniloader:						\
482	/*						\
483	 * r11	entry-point				\
484	 * r12	bootinfo				\
485	 * sp	load-descriptor				\
486	 */						\
487load:							\
488	ldmia	sp!, {r0 - r2};				\
489	cmp	r0, #0xffffffff;			\
490	beq	end;					\
491	cmp	r1, #0xffffffff;/* Skip section align */\
492	blne	copy;		 /* or copy */		\
493	b	load;					\
494							\
495end:							\
496	mov	r0, r12;				\
497	mov	pc, r11;				\
498	nop;						\
499	nop;						\
500miniloader_end:						\
501							\
502	"
503	::"r"(ttb),
504	  "r"(safeAddress),
505	  "r"(mmu_disabled)
506	);
507
508	/* NOTREACHED */
509
510	return -1;
511}
512