512 lines
11 KiB
C++
512 lines
11 KiB
C++
/* $NetBSD: e32boot.cpp,v 1.1 2013/04/28 12:11:27 kiyohara Exp $ */
|
|
/*
|
|
* Copyright (c) 2012, 2013 KIYOHARA Takashi
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <e32base.h>
|
|
#include <e32def.h>
|
|
#include <e32std.h>
|
|
|
|
#include "cpu.h"
|
|
#include "e32boot.h"
|
|
#include "ekern.h"
|
|
#include "epoc32.h"
|
|
#include "netbsd.h"
|
|
|
|
|
|
class E32BootLDD : public DLogicalDevice {
|
|
public:
|
|
E32BootLDD(void);
|
|
virtual TInt Install(void);
|
|
virtual void GetCaps(TDes8 &) const;
|
|
virtual DLogicalChannel *CreateL(void);
|
|
};
|
|
|
|
class E32BootChannel : public DLogicalChannel {
|
|
public:
|
|
E32BootChannel(DLogicalDevice *);
|
|
|
|
protected:
|
|
virtual void DoCancel(TInt);
|
|
virtual void DoRequest(TInt, TAny *, TAny *);
|
|
virtual TInt DoControl(TInt, TAny *, TAny *);
|
|
|
|
private:
|
|
EPOC32 *epoc32;
|
|
TAny *safeAddress;
|
|
|
|
TInt BootNetBSD(NetBSD *, struct btinfo_common *);
|
|
};
|
|
|
|
|
|
/* E32Dll() function is required by all DLLs. */
|
|
GLDEF_C TInt
|
|
E32Dll(TDllReason)
|
|
{
|
|
|
|
return KErrNone;
|
|
}
|
|
|
|
EXPORT_C DLogicalDevice *
|
|
CreateLogicalDevice(void)
|
|
{
|
|
|
|
return new E32BootLDD;
|
|
}
|
|
|
|
E32BootLDD::E32BootLDD(void)
|
|
{
|
|
/* Nothing */
|
|
}
|
|
|
|
TInt
|
|
E32BootLDD::Install(void)
|
|
{
|
|
|
|
return SetName(&E32BootName);
|
|
}
|
|
|
|
void
|
|
E32BootLDD::GetCaps(TDes8 &aDes) const
|
|
{
|
|
TVersion version(0, 0, 0); /* XXXXX: What is it? Don't check? */
|
|
|
|
aDes.FillZ(aDes.MaxLength());
|
|
aDes.Copy((TUint8 *)&version, Min(aDes.MaxLength(), sizeof(version)));
|
|
}
|
|
|
|
DLogicalChannel *
|
|
E32BootLDD::CreateL(void)
|
|
{
|
|
|
|
return new (ELeave) E32BootChannel(this);
|
|
}
|
|
|
|
|
|
E32BootChannel::E32BootChannel(DLogicalDevice *aDevice)
|
|
: DLogicalChannel(aDevice)
|
|
{
|
|
|
|
epoc32 = new EPOC32;
|
|
safeAddress = NULL;
|
|
}
|
|
|
|
void
|
|
E32BootChannel::DoCancel(TInt aReqNo)
|
|
{
|
|
/* Nothing */
|
|
}
|
|
|
|
void
|
|
E32BootChannel::DoRequest(TInt aReqNo, TAny *a1, TAny *a2)
|
|
{
|
|
/* Nothing */
|
|
}
|
|
|
|
TInt
|
|
E32BootChannel::DoControl(TInt aFunction, TAny *a1, TAny *a2)
|
|
{
|
|
|
|
switch (aFunction) {
|
|
case KE32BootGetProcessorID:
|
|
{
|
|
TInt id;
|
|
|
|
__asm("mrc p15, 0, %0, c0, c0" : "=r"(id));
|
|
*(TUint *)a1 = id;
|
|
break;
|
|
}
|
|
|
|
case KE32BootSetSafeAddress:
|
|
{
|
|
safeAddress = (TAny *)PAGE_ALIGN(a1);
|
|
break;
|
|
}
|
|
|
|
case KE32BootBootNetBSD:
|
|
{
|
|
NetBSD *netbsd = (NetBSD *)a1;
|
|
struct btinfo_common *bootinfo = (struct btinfo_common *)a2;
|
|
|
|
BootNetBSD(netbsd, bootinfo);
|
|
|
|
/* NOTREACHED */
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return KErrNone;
|
|
}
|
|
|
|
TInt
|
|
E32BootChannel::BootNetBSD(NetBSD *netbsd, struct btinfo_common *bootinfo)
|
|
{
|
|
TAny *mmu_disabled, *ttb;
|
|
|
|
__asm("adr %0, mmu_disabled" : "=r"(mmu_disabled));
|
|
mmu_disabled = epoc32->GetPhysicalAddress(mmu_disabled);
|
|
/*
|
|
* ARMv3 can't read TTB from CP15 C1.
|
|
* Also can't read Control Register.
|
|
*/
|
|
ttb = epoc32->GetPhysicalAddress(epoc32->GetTTB());
|
|
|
|
__asm __volatile(" \
|
|
mrs r12, cpsr; \
|
|
/* Clear PSR_MODE and Interrupts */ \
|
|
bic r12, r12, #0xdf; \
|
|
/* Disable Interrupts(IRQ/FIQ) */ \
|
|
orr r12, r12, #(3 << 6); \
|
|
/* Set SVC32 MODE */ \
|
|
orr r12, r12, #0x13; \
|
|
msr cpsr_c, r12; \
|
|
\
|
|
ldr r10, [%0, #0x0]; \
|
|
ldr sp, [%0, #0x4]; \
|
|
ldr lr, [%0, #0x8]; \
|
|
mov r12, %1; \
|
|
" :: "r"(netbsd), "r"(bootinfo));
|
|
|
|
__asm __volatile(" \
|
|
mov r7, %2; \
|
|
mov r8, %1; \
|
|
mov r9, %0; \
|
|
\
|
|
/* Set all domains to 15 */ \
|
|
mov r0, #0xffffffff; \
|
|
mcr p15, 0, r0, c3, c0; \
|
|
\
|
|
/* Disable MMU */ \
|
|
mov r0, #0x38; /* WBUF | 32BP | 32BD */ \
|
|
mcr p15, 0, r0, c1, c0, 0; \
|
|
\
|
|
mov pc, r7; \
|
|
\
|
|
mmu_disabled: \
|
|
/* \
|
|
* r8 safe address(maybe frame-buffer address)\
|
|
* r9 ttb \
|
|
* r10 buffer (netbsd) \
|
|
* r11 memory descriptor \
|
|
* r12 bootinfo \
|
|
* sp load descriptor \
|
|
* lr entry point \
|
|
*/ \
|
|
/* save lr to r7 before call functions. */ \
|
|
mov r7, lr; \
|
|
\
|
|
mov r0, r8; \
|
|
mov r1, r9; \
|
|
bl vtop; \
|
|
mov r8, r0; \
|
|
\
|
|
/* \
|
|
* Copy bootinfo to safe address. \
|
|
* That addr used to framebuffer by EPOC32. \
|
|
*/ \
|
|
mov r0, r12; \
|
|
mov r1, r9; \
|
|
bl vtop; \
|
|
mov r1, r0; \
|
|
mov r12, r8; \
|
|
mov r0, r8; \
|
|
mov r2, #0x400; \
|
|
bl copy; \
|
|
\
|
|
/* save lr(r7) to r8. it is no need. */ \
|
|
mov r8, r7; \
|
|
\
|
|
/* Copy loader to safe address + 0x400. */ \
|
|
add r0, r12, #0x400; \
|
|
adr r1, miniloader_start; \
|
|
adr r2, miniloader_end; \
|
|
sub r2, r2, r1; \
|
|
bl copy; \
|
|
\
|
|
/* Make load-descriptor to safe addr + 0x800. */\
|
|
mov r0, sp; \
|
|
mov r1, r9; \
|
|
bl vtop; \
|
|
mov sp, r0; \
|
|
add r4, r12, #0x800; \
|
|
\
|
|
next_section: \
|
|
ldmia sp!, {r5 - r7}; \
|
|
\
|
|
next_page: \
|
|
add r0, r10, r6; \
|
|
mov r1, r9; \
|
|
bl vtop; \
|
|
/* vtop returns set mask to r2 */ \
|
|
orr r2, r0, r2; \
|
|
add r2, r2, #1; \
|
|
sub r2, r2, r0; \
|
|
cmp r2, r7; \
|
|
movgt r2, r7; \
|
|
mov r1, r0; \
|
|
mov r0, r5; \
|
|
stmia r4!, {r0 - r2}; \
|
|
add r5, r5, r2; \
|
|
add r6, r6, r2; \
|
|
subs r7, r7, r2; \
|
|
bgt next_page; \
|
|
\
|
|
ldr r0, [sp]; \
|
|
cmp r0, #0xffffffff; \
|
|
beq fin; \
|
|
/* Pad to section align. */ \
|
|
str r5, [r4], #4; \
|
|
mov r6, #0xffffffff; \
|
|
str r6, [r4], #4; \
|
|
sub r2, r0, r5; \
|
|
str r2, [r4], #4; \
|
|
b next_section; \
|
|
\
|
|
fin: \
|
|
stmia r4, {r5 - r7}; \
|
|
add sp, r12, #0x800; \
|
|
\
|
|
/* save lr(r8) to r11. r11 is no need. */ \
|
|
mov r11, r8; \
|
|
\
|
|
/* Fixup load-descriptor by BTINFO_MEMORY. */ \
|
|
mov r10, r12; \
|
|
mov r9, sp; \
|
|
add r8, sp, #12; \
|
|
next_bootinfo: \
|
|
ldmia r10, {r0, r1}; \
|
|
cmp r1, #0; /* BTINFO_NONE */ \
|
|
beq btinfo_none; \
|
|
\
|
|
cmp r1, #2; /* BTINFO_MEMORY */ \
|
|
beq btinfo_memory; \
|
|
add r10, r10, r0; \
|
|
b next_bootinfo; \
|
|
\
|
|
btinfo_none: \
|
|
/* ENOMEM */ \
|
|
add r2, r12, #0x800; \
|
|
mov r1, #640; \
|
|
mov r0, #0x00ff0000; \
|
|
orr r0, r0, #0x00ff; \
|
|
98: \
|
|
str r0, [r2], #4; \
|
|
subs r1, r1, #4; \
|
|
bgt 98b; \
|
|
mov r1, #640; \
|
|
mov r0, #0xff000000; \
|
|
orr r0, r0, #0xff00; \
|
|
99: \
|
|
str r0, [r2], #4; \
|
|
subs r1, r1, #4; \
|
|
bgt 99b; \
|
|
100: \
|
|
b 100b; \
|
|
\
|
|
btinfo_memory: \
|
|
ldmia r10!, {r4 - r7}; \
|
|
ldr r4, [r9, #0]; \
|
|
subs r4, r4, r6; \
|
|
addgt r6, r6, r4; \
|
|
subgt r7, r7, r4; \
|
|
next_desc: \
|
|
ldmia r9, {r3 - r5}; \
|
|
ldmia r8!, {r0 - r2}; \
|
|
add r3, r3, r5; \
|
|
add r4, r4, r5; \
|
|
cmp r3, r0; \
|
|
cmpeq r4, r1; \
|
|
beq join_desc; \
|
|
\
|
|
ldr r3, [r9, #0]; \
|
|
cmp r3, r6; \
|
|
strlt r6, [r9, #0]; /* Fixup */ \
|
|
cmp r5, r7; \
|
|
bgt split_desc; \
|
|
add r6, r6, r5; \
|
|
sub r7, r7, r5; \
|
|
add r9, r9, #12; \
|
|
stmia r9, {r0 - r2}; \
|
|
cmp r0, #0xffffffff; \
|
|
beq fixuped; \
|
|
b next_desc; \
|
|
\
|
|
join_desc: /* Join r8 descriptor to r9. */ \
|
|
add r5, r5, r2; \
|
|
str r5, [r9, #8]; \
|
|
b next_desc; \
|
|
\
|
|
split_desc: /* Split r9 descriptor. */ \
|
|
ldr r3, [r9, #0]; \
|
|
ldr r4, [r9, #4]; \
|
|
str r7, [r9, #8]; \
|
|
\
|
|
sub r6, r5, r7; \
|
|
add r5, r4, r7; \
|
|
add r4, r3, r7; \
|
|
sub r8, r8, #12; /* Back to prev desc */ \
|
|
add r9, r9, #12;/* Point to splited desc */ \
|
|
\
|
|
cmp r8, r9; \
|
|
bne 2f; \
|
|
add r0, r8, #12; \
|
|
mov r1, r8; \
|
|
mov r2, #0; \
|
|
1: \
|
|
ldr r3, [r8, r2]; \
|
|
add r2, r2, #12; \
|
|
cmp r3, #0xffffffff; \
|
|
bne 1b; \
|
|
bl copy; \
|
|
add r8, r8, #12; /* Point to moved desc */ \
|
|
2: \
|
|
stmia r9, {r4 - r6}; \
|
|
b next_bootinfo; \
|
|
\
|
|
fixuped: \
|
|
/* Jump to miniloader. Our LR is entry-point! */\
|
|
add pc, r12, #0x400; \
|
|
\
|
|
vtop: \
|
|
/* \
|
|
* paddr vtop(vaddr, ttb) \
|
|
*/ \
|
|
bic r2, r0, #0x000f0000; /* L1_ADDR_BITS */ \
|
|
bic r2, r2, #0x0000ff00; /* L1_ADDR_BITS */ \
|
|
bic r2, r2, #0x000000ff; /* L1_ADDR_BITS */ \
|
|
mov r2, r2, lsr #(20 - 2); \
|
|
ldr r1, [r1, r2]; \
|
|
and r3, r1, #0x3; /* L1_TYPE_MASK */ \
|
|
cmp r3, #0; \
|
|
bne valid; \
|
|
\
|
|
invalid: \
|
|
mov r0, #-1; \
|
|
mov pc, lr; \
|
|
\
|
|
valid: \
|
|
cmp r3, #0x2; \
|
|
bgt 3f; \
|
|
beq 2f; \
|
|
\
|
|
1: /* Coarse L2 */ \
|
|
mov r2, #10; \
|
|
b l2; \
|
|
\
|
|
2: /* Section */ \
|
|
mov r2, #0xff000000; /* L1_S_ADDR_MASK */\
|
|
add r2, r2, #0x00f00000;/* L1_S_ADDR_MASK */\
|
|
mvn r2, r2; \
|
|
bic r3, r1, r2; \
|
|
and r0, r0, r2; \
|
|
orr r0, r3, r0; \
|
|
mov pc, lr; \
|
|
\
|
|
3: /* Fine L2 */ \
|
|
mov r2, #12; \
|
|
l2: \
|
|
mov r3, #1; \
|
|
mov r3, r3, lsl r2; \
|
|
sub r3, r3, #1; \
|
|
bic r1, r1, r3; /* L2 table */ \
|
|
mov r3, r0, lsl #12; \
|
|
mov r3, r3, lsr #12; \
|
|
sub r2, r2, #22; \
|
|
rsb r2, r2, #0; \
|
|
mov r3, r3, lsr r2; /* index for L2 */ \
|
|
ldr r1, [r1, r3, lsl #2]; \
|
|
and r3, r1, #0x3; /* L2_TYPE_MASK */ \
|
|
cmp r3, #0; \
|
|
beq invalid; \
|
|
cmp r3, #2; \
|
|
movlt r2, #16; /* L2_L_SHIFT */ \
|
|
moveq r2, #12; /* L2_S_SHIFT */ \
|
|
movgt r2, #10; /* L2_T_SHIFT */ \
|
|
mov r3, #1; \
|
|
mov r2, r3, lsl r2; \
|
|
sub r2, r2, #1; \
|
|
bic r3, r1, r2; \
|
|
and r0, r0, r2; \
|
|
orr r0, r3, r0; \
|
|
mov pc, lr; \
|
|
\
|
|
miniloader_start: \
|
|
b miniloader; \
|
|
\
|
|
copy: \
|
|
/* \
|
|
* void copy(dest, src, len) \
|
|
*/ \
|
|
cmp r0, r1; \
|
|
bgt rcopy; \
|
|
lcopy: \
|
|
ldr r3, [r1], #4; \
|
|
str r3, [r0], #4; \
|
|
subs r2, r2, #4; \
|
|
bgt lcopy; \
|
|
mov pc, lr; \
|
|
rcopy: \
|
|
subs r2, r2, #4; \
|
|
ldr r3, [r1, r2]; \
|
|
str r3, [r0, r2]; \
|
|
bgt rcopy; \
|
|
mov pc, lr; \
|
|
\
|
|
\
|
|
miniloader: \
|
|
/* \
|
|
* r11 entry-point \
|
|
* r12 bootinfo \
|
|
* sp load-descriptor \
|
|
*/ \
|
|
load: \
|
|
ldmia sp!, {r0 - r2}; \
|
|
cmp r0, #0xffffffff; \
|
|
beq end; \
|
|
cmp r1, #0xffffffff;/* Skip section align */\
|
|
blne copy; /* or copy */ \
|
|
b load; \
|
|
\
|
|
end: \
|
|
mov r0, r12; \
|
|
mov pc, r11; \
|
|
nop; \
|
|
nop; \
|
|
miniloader_end: \
|
|
\
|
|
"
|
|
::"r"(ttb),
|
|
"r"(safeAddress),
|
|
"r"(mmu_disabled)
|
|
);
|
|
|
|
/* NOTREACHED */
|
|
|
|
return -1;
|
|
}
|