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