xref: /netbsd-src/sys/arch/epoc32/stand/e32boot/ldd/e32boot.cpp (revision d7b7d02e733839920043e74f8c8422b1708f098c)
1 /*	$NetBSD: e32boot.cpp,v 1.1 2013/04/28 12:11:27 kiyohara Exp $	*/
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 
39 class E32BootLDD : public DLogicalDevice {
40 public:
41 	E32BootLDD(void);
42 	virtual TInt Install(void);
43 	virtual void GetCaps(TDes8 &) const;
44 	virtual DLogicalChannel *CreateL(void);
45 };
46 
47 class E32BootChannel : public DLogicalChannel {
48 public:
49 	E32BootChannel(DLogicalDevice *);
50 
51 protected:
52 	virtual void DoCancel(TInt);
53 	virtual void DoRequest(TInt, TAny *, TAny *);
54 	virtual TInt DoControl(TInt, TAny *, TAny *);
55 
56 private:
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. */
65 GLDEF_C TInt
E32Dll(TDllReason)66 E32Dll(TDllReason)
67 {
68 
69 	return KErrNone;
70 }
71 
72 EXPORT_C DLogicalDevice *
CreateLogicalDevice(void)73 CreateLogicalDevice(void)
74 {
75 
76 	return new E32BootLDD;
77 }
78 
E32BootLDD(void)79 E32BootLDD::E32BootLDD(void)
80 {
81 	/* Nothing */
82 }
83 
84 TInt
Install(void)85 E32BootLDD::Install(void)
86 {
87 
88 	return SetName(&E32BootName);
89 }
90 
91 void
GetCaps(TDes8 & aDes) const92 E32BootLDD::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 
100 DLogicalChannel *
CreateL(void)101 E32BootLDD::CreateL(void)
102 {
103 
104 	return new (ELeave) E32BootChannel(this);
105 }
106 
107 
E32BootChannel(DLogicalDevice * aDevice)108 E32BootChannel::E32BootChannel(DLogicalDevice *aDevice)
109     : DLogicalChannel(aDevice)
110 {
111 
112 	epoc32 = new EPOC32;
113 	safeAddress = NULL;
114 }
115 
116 void
DoCancel(TInt aReqNo)117 E32BootChannel::DoCancel(TInt aReqNo)
118 {
119 	/* Nothing */
120 }
121 
122 void
DoRequest(TInt aReqNo,TAny * a1,TAny * a2)123 E32BootChannel::DoRequest(TInt aReqNo, TAny *a1, TAny *a2)
124 {
125 	/* Nothing */
126 }
127 
128 TInt
DoControl(TInt aFunction,TAny * a1,TAny * a2)129 E32BootChannel::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 
166 TInt
BootNetBSD(NetBSD * netbsd,struct btinfo_common * bootinfo)167 E32BootChannel::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 							\
210 mmu_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 							\
258 next_section:						\
259 	ldmia	sp!, {r5 - r7};				\
260 							\
261 next_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 							\
290 fin:							\
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;				\
301 next_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 							\
311 btinfo_none:						\
312 	/* ENOMEM */					\
313 	add	r2, r12, #0x800;			\
314 	mov	r1, #640;				\
315 	mov	r0, #0x00ff0000;			\
316 	orr	r0, r0, #0x00ff;			\
317 98:							\
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;			\
324 99:							\
325 	str	r0, [r2], #4;				\
326 	subs	r1, r1, #4;				\
327 	bgt	99b;					\
328 100:							\
329 	b	100b;					\
330 							\
331 btinfo_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;				\
337 next_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 							\
359 join_desc:	/* Join r8 descriptor to r9. */		\
360 	add	r5, r5, r2;				\
361 	str	r5, [r9, #8];				\
362 	b	next_desc;				\
363 							\
364 split_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;					\
380 1:							\
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 */	\
387 2:							\
388 	stmia	r9, {r4 - r6};				\
389 	b	next_bootinfo;				\
390 							\
391 fixuped:						\
392 	/* Jump to miniloader. Our LR is entry-point! */\
393 	add	pc, r12, #0x400;			\
394 							\
395 vtop:							\
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 							\
408 invalid:						\
409 	mov	r0, #-1;				\
410 	mov	pc, lr;					\
411 							\
412 valid:							\
413 	cmp	r3, #0x2;				\
414 	bgt	3f;					\
415 	beq	2f;					\
416 							\
417 1:	/* Coarse L2 */					\
418 	mov	r2, #10;				\
419 	b	l2;					\
420 							\
421 2:	/* 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 							\
430 3:	/* Fine L2 */					\
431 	mov	r2, #12;				\
432 l2:							\
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 							\
458 miniloader_start:					\
459 	b	miniloader;				\
460 							\
461 copy:							\
462 	/*						\
463 	 * void copy(dest, src, len)			\
464 	 */						\
465 	cmp	r0, r1;					\
466 	bgt	rcopy;					\
467 lcopy:							\
468 	ldr	r3, [r1], #4;				\
469 	str	r3, [r0], #4;				\
470 	subs	r2, r2, #4;				\
471 	bgt	lcopy;					\
472 	mov	pc, lr;					\
473 rcopy:							\
474 	subs	r2, r2, #4;				\
475 	ldr	r3, [r1, r2];				\
476 	str	r3, [r0, r2];				\
477 	bgt	rcopy;					\
478 	mov	pc, lr;					\
479 							\
480 							\
481 miniloader:						\
482 	/*						\
483 	 * r11	entry-point				\
484 	 * r12	bootinfo				\
485 	 * sp	load-descriptor				\
486 	 */						\
487 load:							\
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 							\
495 end:							\
496 	mov	r0, r12;				\
497 	mov	pc, r11;				\
498 	nop;						\
499 	nop;						\
500 miniloader_end:						\
501 							\
502 	"
503 	::"r"(ttb),
504 	  "r"(safeAddress),
505 	  "r"(mmu_disabled)
506 	);
507 
508 	/* NOTREACHED */
509 
510 	return -1;
511 }
512