Home | History | Annotate | Line # | Download | only in ldd
      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
     66 E32Dll(TDllReason)
     67 {
     68 
     69 	return KErrNone;
     70 }
     71 
     72 EXPORT_C DLogicalDevice *
     73 CreateLogicalDevice(void)
     74 {
     75 
     76 	return new E32BootLDD;
     77 }
     78 
     79 E32BootLDD::E32BootLDD(void)
     80 {
     81 	/* Nothing */
     82 }
     83 
     84 TInt
     85 E32BootLDD::Install(void)
     86 {
     87 
     88 	return SetName(&E32BootName);
     89 }
     90 
     91 void
     92 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 *
    101 E32BootLDD::CreateL(void)
    102 {
    103 
    104 	return new (ELeave) E32BootChannel(this);
    105 }
    106 
    107 
    108 E32BootChannel::E32BootChannel(DLogicalDevice *aDevice)
    109     : DLogicalChannel(aDevice)
    110 {
    111 
    112 	epoc32 = new EPOC32;
    113 	safeAddress = NULL;
    114 }
    115 
    116 void
    117 E32BootChannel::DoCancel(TInt aReqNo)
    118 {
    119 	/* Nothing */
    120 }
    121 
    122 void
    123 E32BootChannel::DoRequest(TInt aReqNo, TAny *a1, TAny *a2)
    124 {
    125 	/* Nothing */
    126 }
    127 
    128 TInt
    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
    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