mirror of
https://github.com/emu-russia/pureikyubu.git
synced 2025-04-02 10:42:15 -04:00
Docs: New TODO moved to EMU, old renamed to old_todo Docs: Old coding style is deprecated (old_style.txt) Docs: Removed mention about CubeDocumented and fixed old emails RE: boot.s, proved first asm line (lis instruction parameter) RE: Added PAL and NTSC Boot and IPL IDA files RE: Some work on NTSC IPL (identified many lib calls, including OS, GX) RE: Added EXI Bootrom descrambler by segher RE: GXInit RE: Internal GX lib structures (GXPrivate.h) RE: More details on lomem (OS versions) RE: OSInit and OS.c RE: OSAlloc (heap allocator) RE: Very first code of Metrowerk runtime (__start.c) Docs: Added copy of http://gcdev.narod.ru Source\Utils: Command processor (Cmd.c) Source\Utils: File wrapper Source\Utils: Gekko disasm cleaned up and ported to plain C Source\Utils: Double-linked lists Source\Utils: Ported old Profiler code Source\Utils: String utils
409 lines
9.7 KiB
Text
409 lines
9.7 KiB
Text
|
|
-------------------------------------------------------------------------------
|
|
-= NINTENDO GAMECUBE Initial Program Loader RE =-
|
|
-------------------------------------------------------------------------------
|
|
|
|
IPL, or bootrom is located inside on-board Macronix chip (near Flipper),
|
|
and connected to EXI bus.
|
|
|
|
IPL have mapped CPU address space at 0xFFFnnnnn, so exception prefix
|
|
bit 25 (IP) in MSR is set after CPU reset and system reset vector offset
|
|
is 0xFFF00100.
|
|
|
|
Small program, called 'BS' is loading actual program code (menu, RTC stuff)
|
|
at 0x81300000. This part is called 'BS2'. Probably 'BS' stands for 'Boot
|
|
System', like OS is 'Operating System'.
|
|
|
|
IPL cant be readed after boot neither using CPU, not special EXI bus reads.
|
|
After loading of BS2, BS disabling IPL access, by clearing 17th bit of
|
|
0xCC006800, then it sets MSR[IP] bit to normal mode (pointing lower memory),
|
|
and jumps to BS2 code entrypoint.
|
|
|
|
BS2 was written on C, using official SDK libraries, probably earlier than
|
|
1.0. __start.c seems to be same as usual, except that there is no OSInit()
|
|
call (old versions should call OSInit() in main, instead of __start).
|
|
|
|
Here is the short description of start() routine (you can easily find full
|
|
version in your SDK ;) :
|
|
|
|
// 81300000
|
|
__start:
|
|
__init_registers() // set stack pointer and static bases (r2, r13)
|
|
__init_hardware() // paired-singles and cache init
|
|
__init_data() // clear bss ?
|
|
|
|
. // here goes Debug Monitor stuff
|
|
.
|
|
.
|
|
|
|
DBInit() // debug monitor init :)
|
|
__init_user() // cpp init
|
|
main() // that's actually, IPL (BS2) code
|
|
jmp exit() // halt CPU
|
|
|
|
|
|
main() reversing :
|
|
------------------
|
|
|
|
// 813006D4 (in BS2.c)
|
|
main()
|
|
{
|
|
BS2Init();
|
|
OSInit();
|
|
|
|
AD16Init();
|
|
AD16WriteReg(0x800);
|
|
|
|
DVDInit();
|
|
AD16WriteReg(0x900);
|
|
|
|
CARDInit();
|
|
AD16WriteReg(0xa00);
|
|
|
|
0x81302104(); // SRAM, real-time clock (check ?)
|
|
|
|
__VIInit(0);
|
|
VIInit();
|
|
AD16WriteReg(0xb00);
|
|
|
|
0x813004e4(); // setup perf. monitor
|
|
__SyncTime(); // update CPU timer by RTC value
|
|
0x813022c0(); // perform initial DVD actions and fall back into menu
|
|
|
|
PADSetSpec(5); // set pad type ('spec') to production
|
|
PADInit();
|
|
|
|
AD16WriteReg(0xc00);
|
|
|
|
BS2Menu(); // here goes intro and main menu... (BIG one!)
|
|
|
|
OSHalt("BS2 ERROR >>> SHOULD NEVER REACH HERE");
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
static float ZeroF;
|
|
|
|
// 8130045C
|
|
void BS2Init()
|
|
{
|
|
// clear lower memory
|
|
memset(0x80000000, 0, 256);
|
|
memset(0x80003000, 0, 256);
|
|
|
|
__OSInitBATs();
|
|
|
|
// set memory size to 24MB
|
|
*(u32 *)0x80000028 = 0x01800000;
|
|
|
|
// set console type to default retail 1
|
|
*(u32 *)0x8000002c = 1;
|
|
|
|
// upgrade retail
|
|
*(u32 *)0x8000002c += *(u32 *)0xcc00302c >> 28;
|
|
|
|
*(u32 *)&ZeroF = -1;
|
|
__OSInitFPRs();
|
|
}
|
|
|
|
// 813003A0 (removed after SDK 1.0 release)
|
|
void __OSInitBATs()
|
|
{
|
|
__asm
|
|
{
|
|
isync
|
|
li r4, 0
|
|
mtspr DBAT2L, r4
|
|
mtspr DBAT2U, r4
|
|
mtspr DBAT3L, r4
|
|
mtspr DBAT3U, r4
|
|
mtspr IBAT1L, r4
|
|
mtspr IBAT1U, r4
|
|
mtspr IBAT2L, r4
|
|
mtspr IBAT2U, r4
|
|
mtspr IBAT3L, r4
|
|
mtspr IBAT3U, r4
|
|
isync
|
|
}
|
|
}
|
|
|
|
// 813003D8 (from OS.c)
|
|
void __OSInitFPRs()
|
|
{
|
|
// FP is already initialzied in __start(),
|
|
// so just invalidate all FPRs.
|
|
__asm
|
|
{
|
|
lfs f0, ZeroF
|
|
fmr f1, f0
|
|
fmr f2, f0
|
|
fmr f3, f0
|
|
. e
|
|
. t
|
|
. c
|
|
fmr f31, f0
|
|
}
|
|
}
|
|
|
|
// maybe later
|
|
0x81302104()
|
|
{
|
|
__OSLockSram();
|
|
__OSCheckSram();
|
|
__OSGetRTC();
|
|
OSTickToCalendarTime();
|
|
memset();
|
|
__OSUnlockSram();
|
|
__OSSyncSram();
|
|
}
|
|
|
|
// maybe later
|
|
0x813004e4()
|
|
{
|
|
OSDisableInterrupts();
|
|
OSGetTick();
|
|
OSGetTick();
|
|
OSGetTick();
|
|
__div2i();
|
|
__div2i();
|
|
PPCMtpmc1();
|
|
PPCMtmmcr0();
|
|
OSGetTick();
|
|
OSGetTick();
|
|
PPCMtmmcr0();
|
|
PPCMfpmc1();
|
|
__div2i();
|
|
__div2i();
|
|
__div2i();
|
|
OSRestoreInterrupts();
|
|
}
|
|
|
|
// update time-base registers by RTC (real-time clock) value
|
|
// RTC is number of seconds, since 01 January 00:00:00 2000
|
|
void __SyncTime()
|
|
{
|
|
OSTick rtcValue;
|
|
OSSram* sram = __OSLockSram();
|
|
|
|
if( __OSGetRTC(&rtcValue) == TRUE )
|
|
{
|
|
// counterBias can be negative value
|
|
rtcValue += sram->counterBias;
|
|
__OSSetTime( (OSTime)rtcValue * OS_TIMER_CLOCK );
|
|
}
|
|
|
|
__OSUnlockSram(0);
|
|
}
|
|
|
|
static int BS2State = 0;
|
|
|
|
// just wrapper..
|
|
0x813022c0()
|
|
{
|
|
BS2State = BS2Mach();
|
|
}
|
|
|
|
// 81300A70
|
|
// located in __FILE__ = "BS2Mach.c"
|
|
int BS2Mach()
|
|
{
|
|
static int state = 0;
|
|
BOOL level = OSDisableInterrupts();
|
|
|
|
switch(state)
|
|
{
|
|
case 0:
|
|
[r13 - 0x7dc8] = 0x800030d4;
|
|
state = 1;
|
|
|
|
case 1:
|
|
__OSGetSystemTime();
|
|
... some checks
|
|
... lot of mulhwu, subfe and other strange instructions :)
|
|
... lazy to find corresponding macro in os.h
|
|
if(fail) break;
|
|
state = 2;
|
|
|
|
// Install DVD cover callback
|
|
case 2:
|
|
if([r13 - 0x7da8] == 0)
|
|
{
|
|
r3 = [r13 - 0x7dc8]
|
|
[r3] = 0
|
|
[r13 - 0x7dc4] = 0
|
|
[r13 - 0x7dac] = 1
|
|
DVDLowSetResetCoverCallback(0);
|
|
DVDReset();
|
|
[r13 - 0x7da8] = 1
|
|
(s64)[r13 - 0x7d9c] = __OSGetSystemTime();
|
|
break;
|
|
}
|
|
|
|
__OSGetSystemTime();
|
|
bla bla bla
|
|
another checks :)
|
|
if(fail) break;
|
|
|
|
DVDLowSetResetCoverCallback(0x813007d8);
|
|
DVDReset();
|
|
state = 3;
|
|
|
|
// Read Disk information (ID)
|
|
case 3:
|
|
DVDReadDiskID(0x8145e620 + 64, 0x80000000, 0x813007e4);
|
|
state = 4;
|
|
break;
|
|
|
|
.
|
|
.
|
|
.
|
|
.
|
|
.
|
|
.
|
|
.
|
|
|
|
// Leave immidiately ?
|
|
case 16:
|
|
break;
|
|
|
|
default:
|
|
OSHalt("BS2 ERROR >> UNKNOWN STATE");
|
|
}
|
|
|
|
OSRestoreInterrupts(level);
|
|
|
|
return (DVDLowGetCoverStatus() == 1) ? 19 : step;
|
|
}
|
|
|
|
// 81301154
|
|
void BS2Menu()
|
|
{
|
|
|
|
BS2InitAlloc();
|
|
|
|
}
|
|
|
|
static OSHeapHandler BS2Heap;
|
|
|
|
// 81307EA8
|
|
void BS2InitAlloc()
|
|
{
|
|
u8 *arenaLo;
|
|
u8 *arenaHi;
|
|
u8 *arenaNew;
|
|
|
|
arenaLo = OSGetArenaLo();
|
|
arenaLo = (void *)OSRoundUp32B(arenaLo);
|
|
arenaHi = OSGetArenaHi();
|
|
arenaHi = (void *)OSRoundDown32B(arenaHi);
|
|
|
|
arenaNew = OSInitAlloc(0x80800000, arenaHi, 2);
|
|
OSSetArenaLo(arenaHi);
|
|
|
|
BS2Heap = OSCreateHeap(arenaLo, arenaHi);
|
|
OSSetCurrentHeap(BS2Heap);
|
|
|
|
OSAddToHeap(BS2Heap, arenaNew, 0x81100000);
|
|
|
|
BS2CheckAlloc();
|
|
}
|
|
|
|
// 81307F34
|
|
void BS2CheckAlloc()
|
|
{
|
|
OSCheckHeap(BS2Heap);
|
|
}
|
|
|
|
// 81307F58
|
|
void *OSAlloc(long size)
|
|
{
|
|
void *ptr;
|
|
|
|
if((ptr = OSAlloc(size)) == 0)
|
|
{
|
|
OSPanic(?);
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
|
|
here is the MAP of BS2 libraries code :
|
|
---------------------------------------
|
|
|
|
813014C8 DEMOInit (*)
|
|
81307F58 OSAlloc (*)
|
|
813327BC PPCMtmmcr0 ;; PPC
|
|
813327C4 PPCMfpmc1
|
|
813327CC PPCMtpmc1
|
|
81332814 OSInit ;; OS
|
|
81332EF0 OSInitAlarm
|
|
81332F3C OSCreateAlarm
|
|
81333688 OSAllocFromHeap
|
|
81333784 OSSetCurrentHeap
|
|
81333794 OSInitAlloc
|
|
81333804 OSCreateHeap
|
|
81333870 OSAddToHeap
|
|
813338D0 OSCheckHeap
|
|
813344C0 OSGetStackPointer
|
|
8133491C OSReport
|
|
8133499C OSPanic
|
|
81334AA4 PPCHalt
|
|
81334D4C EXIImm ;; OS EXI (not standalone)
|
|
81335134 EXISync
|
|
813353C8 EXIProbeReset
|
|
8133570C EXISelect
|
|
81335838 EXIDeselect
|
|
81335D6C EXILock
|
|
81335E60 EXIUnlock
|
|
81335F54 AD16Init
|
|
81336090 AD16WriteReg
|
|
813361B0 OSDisableInterrupts
|
|
813361C4 OSEnableInterrupts
|
|
813361D8 OSRestoreInterrupts
|
|
81336DD8 __OSGetRTC
|
|
813372B0 __OSLockSram
|
|
81337658 __OSUnlockSram
|
|
813376A0 __OSSyncSram
|
|
813376B0 __OSCheckSram
|
|
81338504 OSInitThreadQueue
|
|
8133939C OSGetTick
|
|
813393B8 __OSSetTime
|
|
8133943C __OSGetSystemTime
|
|
8133963C OSTicksToCalendarTime
|
|
8133AC50 DVDLowGetCoverStatus ;; DVD
|
|
8133AB18 DVDLowReset
|
|
8133ABD4 DVDLowSetResetCoverCallback
|
|
8133B5F0 DVDInit
|
|
8133CD18 DVDReadDiskID
|
|
8133D0EC DVDReset
|
|
8133DBE0 __VIInit ;; VI
|
|
8133DDC8 VIInit
|
|
8133E6C0 VIConfigure
|
|
8133F0B4 VIGetTvFormat
|
|
81343114 CARDInit ;; CARD
|
|
813480D4 GXInit ;; GX
|
|
81349148 GXInitFifoBase
|
|
81349230 GXSetCPUFifo
|
|
81349340 GXSetGPFifo
|
|
813494B8 __GXFifoInit
|
|
8134B0AC __GXPEInit
|
|
8135A178 __div2i ;; LIBC
|
|
8135A394 __mod2i
|
|
8135B494 vprintf
|
|
|
|
(*) that function was slighty modified particulary for BS2 ?
|
|
|
|
note : European PAL IPL v. 1.0 was used.
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
org -- ogamespec@gmail.com
|
|
|
|
Thanks to tmbinc and titanik for their great work!
|
|
|
|
links :
|
|
GCDEV headquarters : http://www.gcdev.com, http://www.gcdev.com/forums
|
|
|
|
brief description of BS2 run-flow you can find in awesome Titanik's 'GAMECUBE
|
|
LOW-LEVEL INFO'.
|