Add support 1st generation Brain (#9)

* Add support 1st generation Brain

Address information was given by pepepper.
Thank you!

* Use CamelCase to name enum types

* Update BrainLILODrv.cpp

Co-authored-by: Takumi Sueda <puhitaku@gmail.com>

* simplify BrainGen enum types

* Remove redundant debu log

* Fix Gen2 and later addresses

Co-authored-by: Toshifumi NISHINAGA <tnishinaga.dev@gmail.com>
Co-authored-by: Toshifumi NISHINAGA <tnishinaga@users.noreply.github.com>
Co-authored-by: pepepper <hollyholly2014@outlook.jp>
This commit is contained in:
Takumi Sueda 2022-09-23 00:41:59 +09:00 committed by GitHub
parent c826f2581e
commit 98a6ae1c54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 138 additions and 52 deletions

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
*.dll *.dll
*.exe *.exe
*.o

View File

@ -47,6 +47,30 @@
typedef void (*FileSystemPowerFunctionProc)(DWORD); typedef void (*FileSystemPowerFunctionProc)(DWORD);
static FileSystemPowerFunctionProc FileSystemPowerFunction; static FileSystemPowerFunctionProc FileSystemPowerFunction;
// GEN1
// VA
#define BOOTLOADER_PRELOADADDR_GEN1 (uint8_t *)0xa0250000
#define BOOTLOADER_LOADADDR_GEN1 (uint8_t *)0xa3f00000
#define PHYSICAL_INVOKER_INSTALLADDR_GEN1 (uint8_t *)0xb0000000
#define TMPA910_REMAP_REGISTER_ADDRESS (uint32_t *)0xaa000004
// PA
#define BOOTLOADER_LOADADDR_GEN1_PA (uint8_t *)0x43f00000
// DEFAULT(GEN2)
// VA
#define BOOTLOADER_PRELOADADDR (uint8_t *)0xa0000000
#define BOOTLOADER_LOADADDR (uint8_t *)0xa0200000
#define PHYSICAL_INVOKER_INSTALLADDR (uint8_t *)0xa8000000
// PA
#define BOOTLOADER_LOADADDR_PA (uint8_t *)0x40200000
// VA
uint8_t *bootloader_preload_address = NULL;
uint8_t *bootloader_load_address = NULL;
uint8_t *physical_invoker_install_address = NULL;
// PA
uint8_t *bootloader_load_address_pa = NULL;
DWORD fileSize; DWORD fileSize;
int row; int row;
int screenW; int screenW;
@ -56,20 +80,14 @@ static void outputDebugMessage(const wchar_t *format, ...)
{ {
wchar_t buffer[256] = {0}; wchar_t buffer[256] = {0};
va_list args; va_list args;
RECT rcScreen = { RECT rcScreen = {.left = 0, .top = 0, .right = screenW, .bottom = screenH};
.left = 0,
.top = 0,
.right = screenW,
.bottom = screenH
};
va_start(args, format); va_start(args, format);
vswprintf(buffer, format, args); vswprintf(buffer, format, args);
va_end(args); va_end(args);
OutputDebugString(buffer); OutputDebugString(buffer);
ExtTextOut(GetDC(NULL), 0, row * 14, ETO_CLIPPED, &rcScreen, ExtTextOut(GetDC(NULL), 0, row * 14, ETO_CLIPPED, &rcScreen, buffer, wcslen(buffer), NULL);
buffer, wcslen(buffer), NULL);
row++; row++;
} }
@ -83,42 +101,23 @@ static void disableInterrupts()
: "r0"); : "r0");
} }
static void EDNA2_physicalInvoker() extern "C" void EDNA2_physicalInvoker();
static void EnableMemoryRemapGen1()
{ {
// r0-r7=params *TMPA910_REMAP_REGISTER_ADDRESS = 1;
// r8=proc address outputDebugMessage(L"BrainLILO: memory remap enable for Gen1\n");
asm volatile("nop\n" // who cares interrupt vectors?
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"msr cpsr_c, #211\n" // to supervisor mode
"mov r9, #0\n"
"mcr p15,0,r9,c13,c0,0\n" // clear fcse PID
"mrc p15,0,r9,c1,c0,0\n" // read ctrl regs
"bic r9, r9, #5\n" // disable MMU/DCache
"bic r9, r9, #4096\n" // disable ICache
"orr r9, r9, #8192\n" // and reset vectors to upper
"mcr p15,0,r9,c1,c0,0\n" // write ctrl regs
"mov r9, #0\n"
"mcr p15,0,r9,c7,c7,0\n" // invalidate cache
"mcr p15,0,r9,c8,c7,0\n" // invalidate tlb
"mov pc, r8\n"
"nop\n"
"nop\n");
} }
static void EDNA2_installPhysicalInvoker() static void EDNA2_installPhysicalInvoker(BrainGen gen)
{ {
void *ptr = (void *)0xa8000000; if (gen == Gen1)
outputDebugMessage(L"BrainLILO: copying PhysicalInvoker to 0x%p from 0x%p\n", {
ptr, &EDNA2_physicalInvoker); EnableMemoryRemapGen1();
memcpy(ptr, (const void *)&EDNA2_physicalInvoker, 64 * 4); }
outputDebugMessage(L"BrainLILO: copying PhysicalInvoker to 0x%p from 0x%p\n", physical_invoker_install_address,
&EDNA2_physicalInvoker);
memcpy(physical_invoker_install_address, (const void *)&EDNA2_physicalInvoker, 64 * 4);
// clearCache(); // clearCache();
} }
@ -131,8 +130,7 @@ __attribute__((noreturn)) static void EDNA2_runPhysicalInvoker()
"mcr p15,0,r0,c1,c0,0\n" // write ctrl regs "mcr p15,0,r0,c1,c0,0\n" // write ctrl regs
); );
for (DWORD i = 0; i < fileSize; i++) memcpy(bootloader_load_address, bootloader_preload_address, fileSize);
*((char *)(0xa0200000 + i)) = *((char *)(0xa0000000 + i));
asm volatile("ldr r0, =0x0000\n" asm volatile("ldr r0, =0x0000\n"
"ldr r1, =0x0000\n" "ldr r1, =0x0000\n"
@ -142,26 +140,28 @@ __attribute__((noreturn)) static void EDNA2_runPhysicalInvoker()
"ldr r5, =0x0000\n" "ldr r5, =0x0000\n"
"ldr r6, =0x0000\n" "ldr r6, =0x0000\n"
"ldr r7, =0x0000\n" "ldr r7, =0x0000\n"
"ldr r8, =0x40200000\n" "mov r8, %[textbase]\n"
"ldr r9, =0x0000\n" "ldr r9, =0x0000\n"
"mrc p15,0,r10,c1,c0,0\n" // read ctrl regs "mrc p15,0,r10,c1,c0,0\n" // read ctrl regs
"bic r10, r10, #5\n" // disable MMU/DCache "bic r10, r10, #5\n" // disable MMU/DCache
"mcr p15,0,r10,c1,c0,0\n" // write ctrl regs "mcr p15,0,r10,c1,c0,0\n" // write ctrl regs
"swi #0\n" // jump! "swi #0\n" // jump!
); : /* no outputs */
: [textbase] "r"(bootloader_load_address_pa)
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10");
// never reach here // never reach here
while (true) while (true)
; ;
} }
__attribute__((noreturn)) static DWORD EDNA2_callKernelEntryPoint() __attribute__((noreturn)) static DWORD EDNA2_callKernelEntryPoint(BrainGen gen)
{ {
outputDebugMessage(L"BrainLILO: disabling interrupts"); outputDebugMessage(L"BrainLILO: disabling interrupts");
disableInterrupts(); disableInterrupts();
outputDebugMessage(L"BrainLILO: injecting code to internal ram"); outputDebugMessage(L"BrainLILO: injecting code to internal ram");
EDNA2_installPhysicalInvoker(); EDNA2_installPhysicalInvoker(gen);
outputDebugMessage(L"BrainLILO: invoking"); outputDebugMessage(L"BrainLILO: invoking");
Sleep(1000); Sleep(1000);
@ -173,12 +173,54 @@ static void ShowMessage(std::wstring msg, std::wstring title, UINT typ)
MessageBox(NULL, msg.c_str(), title.c_str(), typ); MessageBox(NULL, msg.c_str(), title.c_str(), typ);
} }
static void SetAddress(BrainGen gen)
{
switch (gen)
{
case Gen1:
// VA
bootloader_preload_address = BOOTLOADER_PRELOADADDR_GEN1;
bootloader_load_address = BOOTLOADER_LOADADDR_GEN1;
physical_invoker_install_address = PHYSICAL_INVOKER_INSTALLADDR_GEN1;
// PA
bootloader_load_address_pa = BOOTLOADER_LOADADDR_GEN1_PA;
break;
default:
// Gen2?
// VA
bootloader_preload_address = BOOTLOADER_PRELOADADDR;
bootloader_load_address = BOOTLOADER_LOADADDR;
physical_invoker_install_address = PHYSICAL_INVOKER_INSTALLADDR;
// PA
bootloader_load_address_pa = BOOTLOADER_LOADADDR_PA;
}
}
static BrainGen SelectGen(std::wstring model)
{
BrainGen brainGen = UnknownGen;
if (model == L"gen1.bin")
{
brainGen = Gen1;
}
else if (model == L"u-boot.bin")
{
brainGen = UnknownGen;
}
else
{
brainGen = Gen2Or3;
}
return brainGen;
}
static bool doLinux() static bool doLinux()
{ {
std::wifstream iVersion; std::wifstream iVersion;
std::wstring line, model; std::wstring line, model;
std::wregex modelRe(L"[A-Z]{2}-[A-Z0-9]+"); std::wregex modelRe(L"[A-Z]{2}-[A-Z0-9]+");
std::wsmatch match; std::wsmatch match;
BrainGen brain_gen = UnknownGen;
std::wstring fn(L"\\Storage Card\\loader\\"); std::wstring fn(L"\\Storage Card\\loader\\");
HANDLE hUBoot; HANDLE hUBoot;
@ -207,7 +249,9 @@ static bool doLinux()
if (iter != models.end()) if (iter != models.end())
{ {
model = iter->second; model = iter->second;
} else { }
else
{
outputDebugMessage(L"BrainLILO: internal model name %s is unknown, falling back to u-boot.bin", model.c_str()); outputDebugMessage(L"BrainLILO: internal model name %s is unknown, falling back to u-boot.bin", model.c_str());
model = L"u-boot.bin"; model = L"u-boot.bin";
} }
@ -215,6 +259,9 @@ static bool doLinux()
fn += model; fn += model;
outputDebugMessage(L"BrainLILO: opening Bootloader file: %s", fn.c_str()); outputDebugMessage(L"BrainLILO: opening Bootloader file: %s", fn.c_str());
brain_gen = SelectGen(model);
SetAddress(brain_gen);
hUBoot = CreateFile(fn.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); hUBoot = CreateFile(fn.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hUBoot == INVALID_HANDLE_VALUE) if (hUBoot == INVALID_HANDLE_VALUE)
{ {
@ -228,8 +275,8 @@ static bool doLinux()
fileSize = GetFileSize(hUBoot, NULL); fileSize = GetFileSize(hUBoot, NULL);
outputDebugMessage(L"BrainLILO: bootloader file size %d Byte", fileSize); outputDebugMessage(L"BrainLILO: bootloader file size %d Byte", fileSize);
outputDebugMessage(L"BrainLILO: preloading bootloader to 0x%p...", 0xa0000000); outputDebugMessage(L"BrainLILO: preloading bootloader to 0x%p...", bootloader_preload_address);
if (!ReadFile(hUBoot, (void *)0xa0000000, fileSize, &wReadSize, NULL)) if (!ReadFile(hUBoot, (void *)bootloader_preload_address, fileSize, &wReadSize, NULL))
{ {
outputDebugMessage(L"BrainLILO: could not read the bootloader"); outputDebugMessage(L"BrainLILO: could not read the bootloader");
ShowMessage(L"Could not read the bootloader", L"BrainLILO", MB_ICONWARNING); ShowMessage(L"Could not read the bootloader", L"BrainLILO", MB_ICONWARNING);
@ -243,7 +290,7 @@ static bool doLinux()
FileSystemPowerFunction(FSNOTIFY_POWER_OFF); FileSystemPowerFunction(FSNOTIFY_POWER_OFF);
outputDebugMessage(L"BrainLILO: starting bootloader call sequence..."); outputDebugMessage(L"BrainLILO: starting bootloader call sequence...");
EDNA2_callKernelEntryPoint(); EDNA2_callKernelEntryPoint(brain_gen);
return true; return true;
} }

30
EDNA2_physicalInvoker.S Normal file
View File

@ -0,0 +1,30 @@
.align 4
.global EDNA2_physicalInvoker
EDNA2_physicalInvoker:
// r0-r7=params
// r8=proc address
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
msr cpsr_c, #211 // to supervisor mode
mov r9, #0
mcr p15,0,r9,c13,c0,0 // clear fcse PID
mrc p15,0,r9,c1,c0,0 // read ctrl regs
bic r9, r9, #5 // disable MMU/DCache
bic r9, r9, #4096 // disable ICache
orr r9, r9, #8192 // and reset vectors to upper
mcr p15,0,r9,c1,c0,0 // write ctrl regs
mov r9, #0
mcr p15,0,r9,c7,c7,0 // invalidate cache
mcr p15,0,r9,c8,c7,0 // invalidate tlb
mov pc, r8
nop
nop

View File

@ -42,8 +42,8 @@ BrainLILO.dll: BrainLILO.cpp
$(CXX) BrainLILO.cpp -o BrainLILO.dll $(DLLFLAGS) $(CXX) BrainLILO.cpp -o BrainLILO.dll $(DLLFLAGS)
$(STRIP) BrainLILO.dll $(STRIP) BrainLILO.dll
BrainLILODrv.dll: BrainLILODrv.cpp BrainLILODrv.dll: BrainLILODrv.cpp EDNA2_physicalInvoker.S
$(CXX) BrainLILODrv.cpp -o BrainLILODrv.dll $(DRVFLAGS) $(CXX) BrainLILODrv.cpp EDNA2_physicalInvoker.S -o BrainLILODrv.dll $(DRVFLAGS)
$(STRIP) BrainLILODrv.dll $(STRIP) BrainLILODrv.dll
BrainLILO.exe: bootloader.cpp BrainLILO.exe: bootloader.cpp

View File

@ -72,3 +72,10 @@ const std::map<std::wstring, std::wstring> models = {
{L"ED-SB7", L"gen3_7.bin"}, // SB7 {L"ED-SB7", L"gen3_7.bin"}, // SB7
{L"ED-SR3", L"gen3_7.bin"}, // SR3 {L"ED-SR3", L"gen3_7.bin"}, // SR3
}; };
typedef enum
{
UnknownGen,
Gen1,
Gen2Or3
} BrainGen;