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