mirror of https://github.com/zeldaret/tp.git
Add __start.c for Wii builds (#3034)
This commit is contained in:
parent
db8ae465ac
commit
47daf0b4ed
|
|
@ -8,6 +8,9 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DVD_DEVICE_CODE_READ (1 << 15)
|
||||
#define MAKE_DVD_DEVICE_CODE(x) (DVD_DEVICE_CODE_READ | (x))
|
||||
|
||||
#define DVD_ASSERTMSGLINE(line, cond, msg) \
|
||||
if (!(cond)) \
|
||||
OSPanic(__FILE__, line, msg)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,267 @@
|
|||
/**
|
||||
* For more details, see:
|
||||
* https://www.gc-forever.com/yagcd/chap4.html#sec4
|
||||
* https://www.gc-forever.com/yagcd/chap13.html#sec13
|
||||
* https://wiibrew.org/wiki/Memory_map
|
||||
*/
|
||||
|
||||
#ifndef _RVL_SDK_OS_HARDWARE_H
|
||||
#define _RVL_SDK_OS_HARDWARE_H
|
||||
|
||||
#include "revolution/dvd.h"
|
||||
#include "revolution/os.h"
|
||||
#include "revolution/os/OSContext.h"
|
||||
#include "revolution/os/OSThread.h"
|
||||
#include "revolution/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Forward declarations
|
||||
typedef struct OSExecParams;
|
||||
|
||||
// Derive offsets for use with OSAddress functions
|
||||
#define __DEF_ADDR_OFFSETS(name, addr) \
|
||||
static const u32 OS_PHYS_##name = (addr) - 0x80000000; \
|
||||
static const u32 OS_CACHED_##name = (addr); \
|
||||
static const u32 OS_UNCACHED_##name = (addr) + (0xC0000000 - 0x80000000);
|
||||
|
||||
// Define a global variable in *CACHED* MEM1.
|
||||
// Can be accessed directly or with OSAddress functions.
|
||||
#define OS_DEF_GLOBAL_VAR(type, name, addr) \
|
||||
/* Memory-mapped value for direct access */ \
|
||||
type OS_##name AT_ADDRESS(addr); \
|
||||
__DEF_ADDR_OFFSETS(name, addr)
|
||||
|
||||
// Define a global array in *CACHED* MEM1.
|
||||
// Can be accessed directly or with OSAddress functions.
|
||||
#define OS_DEF_GLOBAL_ARR(type, name, arr, addr) \
|
||||
/* Memory-mapped value for direct access */ \
|
||||
type OS_##name arr AT_ADDRESS(addr); \
|
||||
__DEF_ADDR_OFFSETS(name, addr)
|
||||
|
||||
// Define an global variable in the hardware-register range.
|
||||
#define OS_DEF_HW_REG(type, name, addr) \
|
||||
/* Memory-mapped value for direct access */ \
|
||||
type OS_##name AT_ADDRESS(addr);
|
||||
|
||||
typedef enum {
|
||||
OS_BOOT_MAGIC_BOOTROM = 0xD15EA5E,
|
||||
OS_BOOT_MAGIC_JTAG = 0xE5207C22,
|
||||
} OSBootMagic;
|
||||
|
||||
typedef struct OSDebugInterface {
|
||||
/* 0x0 */ int usingDebugger;
|
||||
/* 0x4 */ u32 exceptionMask;
|
||||
/* 0x8 */ void* exceptionHook;
|
||||
/* 0xC */ void* exceptionHookLR;
|
||||
} OSDebugInterface;
|
||||
|
||||
typedef struct OSBI2 {
|
||||
/* 0x0 */ u32 dbgMonitorSize;
|
||||
/* 0x4 */ u32 simulatedMemSize;
|
||||
/* 0x8 */ u32 argumentOfs;
|
||||
/* 0xC */ u32 debugFlag;
|
||||
/* 0x10 */ u32 trackLocation;
|
||||
/* 0x14 */ u32 trackSize;
|
||||
/* 0x18 */ u32 countryCode;
|
||||
u32 WORD_0x1C;
|
||||
u32 lastInsert;
|
||||
/* 0x24 */ u32 padSpec;
|
||||
/* 0x28 */ u32 totalTextDataLimit;
|
||||
/* 0x2C */ u32 simulatedMem2Size;
|
||||
} OSBI2;
|
||||
|
||||
/**
|
||||
* 0x80000000 - 0x80000100
|
||||
*/
|
||||
// clang-format off
|
||||
OS_DEF_GLOBAL_VAR(OSBootInfo, BOOT_INFO, 0x80000000);
|
||||
OS_DEF_GLOBAL_VAR(OSDebugInterface, DEBUG_INTERFACE, 0x80000040);
|
||||
OS_DEF_GLOBAL_ARR(u8, DB_INTEGRATOR_HOOK, [0x24], 0x80000060);
|
||||
OS_DEF_GLOBAL_VAR(struct OSContext*, CURRENT_CONTEXT_PHYS, 0x800000C0);
|
||||
OS_DEF_GLOBAL_VAR(u32, PREV_INTR_MASK, 0x800000C4);
|
||||
OS_DEF_GLOBAL_VAR(u32, CURRENT_INTR_MASK, 0x800000C8);
|
||||
OS_DEF_GLOBAL_VAR(u32, TV_FORMAT, 0x800000CC);
|
||||
OS_DEF_GLOBAL_VAR(u32, ARAM_SIZE, 0x800000D0);
|
||||
OS_DEF_GLOBAL_VAR(struct OSContext*, CURRENT_CONTEXT, 0x800000D4);
|
||||
OS_DEF_GLOBAL_VAR(struct OSContext*, CURRENT_FPU_CONTEXT, 0x800000D8);
|
||||
OS_DEF_GLOBAL_VAR(OSThreadQueue, THREAD_QUEUE, 0x800000DC);
|
||||
OS_DEF_GLOBAL_VAR(OSThread*, CURRENT_THREAD, 0x800000E4);
|
||||
OS_DEF_GLOBAL_VAR(u32, DEBUG_MONITOR_SIZE, 0x800000E8);
|
||||
OS_DEF_GLOBAL_VAR(void*, DEBUG_MONITOR, 0x800000EC);
|
||||
OS_DEF_GLOBAL_VAR(u32, SIMULATED_MEM_SIZE, 0x800000F0);
|
||||
OS_DEF_GLOBAL_VAR(OSBI2*, DVD_BI2, 0x800000F4);
|
||||
OS_DEF_GLOBAL_VAR(u32, BUS_CLOCK_SPEED, 0x800000F8);
|
||||
OS_DEF_GLOBAL_VAR(u32, CPU_CLOCK_SPEED, 0x800000FC);
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
* 0x80003000 - 0x80003F00
|
||||
*/
|
||||
// clang-format off
|
||||
OS_DEF_GLOBAL_ARR(void*, EXCEPTION_TABLE, [15], 0x80003000);
|
||||
OS_DEF_GLOBAL_VAR(void*, INTR_HANDLER_TABLE, 0x80003040);
|
||||
OS_DEF_GLOBAL_VAR(void*, FIRST_REL, 0x800030C8);
|
||||
OS_DEF_GLOBAL_VAR(void*, LAST_REL, 0x800030CC);
|
||||
OS_DEF_GLOBAL_VAR(void*, REL_NAME_TABLE, 0x800030D0);
|
||||
OS_DEF_GLOBAL_VAR(u32, DOL_TOTAL_TEXT_DATA, 0x800030D4);
|
||||
OS_DEF_GLOBAL_VAR(s64, SYSTEM_TIME, 0x800030D8);
|
||||
OS_DEF_GLOBAL_VAR(u8, PAD_FLAGS, 0x800030E3);
|
||||
OS_DEF_GLOBAL_VAR(u16, GC_PAD_3_BTN, 0x800030E4);
|
||||
OS_DEF_GLOBAL_VAR(volatile u16, DVD_DEVICE_CODE, 0x800030E6);
|
||||
OS_DEF_GLOBAL_VAR(u8, BI2_DEBUG_FLAG, 0x800030E8);
|
||||
OS_DEF_GLOBAL_VAR(u8, PAD_SPEC, 0x800030E9);
|
||||
OS_DEF_GLOBAL_VAR(struct OSExecParams*, DOL_EXEC_PARAMS, 0x800030F0);
|
||||
OS_DEF_GLOBAL_VAR(u32, PHYSICAL_MEM1_SIZE, 0x80003100);
|
||||
OS_DEF_GLOBAL_VAR(u32, SIMULATED_MEM1_SIZE, 0x80003104);
|
||||
OS_DEF_GLOBAL_VAR(void*, USABLE_MEM1_START, 0x8000310C);
|
||||
OS_DEF_GLOBAL_VAR(void*, USABLE_MEM1_END, 0x80003110);
|
||||
OS_DEF_GLOBAL_VAR(u32, PHYSICAL_MEM2_SIZE, 0x80003118);
|
||||
OS_DEF_GLOBAL_VAR(u32, SIMULATED_MEM2_SIZE, 0x8000311C);
|
||||
OS_DEF_GLOBAL_VAR(void*, ACCESSIBLE_MEM2_END, 0x80003120);
|
||||
OS_DEF_GLOBAL_VAR(void*, USABLE_MEM2_START, 0x80003124);
|
||||
OS_DEF_GLOBAL_VAR(void*, USABLE_MEM2_END, 0x80003128);
|
||||
OS_DEF_GLOBAL_VAR(void*, IPC_BUFFER_START, 0x80003130);
|
||||
OS_DEF_GLOBAL_VAR(void*, IPC_BUFFER_END, 0x80003134);
|
||||
OS_DEF_GLOBAL_VAR(u32, HOLLYWOOD_REV, 0x80003138);
|
||||
OS_DEF_GLOBAL_VAR(u32, IOS_VERSION, 0x80003140);
|
||||
OS_DEF_GLOBAL_VAR(u32, IOS_BUILD_DATE, 0x80003144);
|
||||
OS_DEF_GLOBAL_VAR(void*, IOS_HEAP_START, 0x80003148);
|
||||
OS_DEF_GLOBAL_VAR(void*, IOS_HEAP_END, 0x8000314C);
|
||||
OS_DEF_GLOBAL_VAR(u32, GDDR_VENDOR_CODE, 0x80003158);
|
||||
OS_DEF_GLOBAL_VAR(u8, BOOT_PROGRAM_TARGET, 0x8000315C);
|
||||
OS_DEF_GLOBAL_VAR(u8, APPLOADER_TARGET, 0x8000315D);
|
||||
OS_DEF_GLOBAL_VAR(int, MIOS_SHUTDOWN_FLAG, 0x80003164);
|
||||
OS_DEF_GLOBAL_VAR(u32, CURRENT_APP_NAME, 0x80003180);
|
||||
OS_DEF_GLOBAL_VAR(u8, CURRENT_APP_TYPE, 0x80003184);
|
||||
OS_DEF_GLOBAL_VAR(u32, MINIMUM_IOS_VERSION, 0x80003188);
|
||||
OS_DEF_GLOBAL_VAR(u32, NAND_TITLE_LAUNCH_CODE, 0x8000318C);
|
||||
OS_DEF_GLOBAL_VAR(u32, NAND_TITLE_RETURN_CODE, 0x80003190);
|
||||
OS_DEF_GLOBAL_VAR(u32, BOOT_PARTITION_TYPE, 0x80003194);
|
||||
OS_DEF_GLOBAL_VAR(u32, BOOT_PARTITION_OFFSET, 0x80003198);
|
||||
OS_DEF_GLOBAL_ARR(u8, NWC24_USER_ID_BUFFER, [32], 0x800031C0);
|
||||
OS_DEF_GLOBAL_VAR(u64, NWC24_USER_ID, 0x800031C0);
|
||||
OS_DEF_GLOBAL_ARR(u8, SC_PRDINFO, [0x100], 0x80003800);
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
* PI hardware globals
|
||||
*/
|
||||
volatile u32 PI_HW_REGS[] AT_ADDRESS(0xCC003000);
|
||||
typedef enum {
|
||||
PI_INTSR, //!< 0xCC003000
|
||||
PI_INTMR, //!< 0xCC003004
|
||||
PI_REG_0x8, //!< 0xCC003008
|
||||
PI_REG_0xC, //!< 0xCC00300C
|
||||
PI_REG_0x10, //!< 0xCC003010
|
||||
PI_REG_0x14, //!< 0xCC003014
|
||||
PI_REG_0x18, //!< 0xCC003018
|
||||
PI_REG_0x1C, //!< 0xCC00301C
|
||||
PI_REG_0x20, //!< 0xCC003020
|
||||
PI_RESET, //!< 0xCC003024
|
||||
// . . .
|
||||
} PIHwReg;
|
||||
|
||||
// INTSR - Interrupt Cause Register
|
||||
#define PI_INTSR_ERROR (1 << 0)
|
||||
#define PI_INTSR_RSW (1 << 1)
|
||||
#define PI_INTSR_DI (1 << 2)
|
||||
#define PI_INTSR_SI (1 << 3)
|
||||
#define PI_INTSR_EXI (1 << 4)
|
||||
#define PI_INTSR_AI (1 << 5)
|
||||
#define PI_INTSR_DSP (1 << 6)
|
||||
#define PI_INTSR_MEM (1 << 7)
|
||||
#define PI_INTSR_VI (1 << 8)
|
||||
#define PI_INTSR_PE_TOKEN (1 << 9)
|
||||
#define PI_INTSR_PE_FINISH (1 << 10)
|
||||
#define PI_INTSR_CP (1 << 11)
|
||||
#define PI_INTSR_DEBUG (1 << 12)
|
||||
#define PI_INTSR_HSP (1 << 13)
|
||||
#define PI_INTSR_ACR (1 << 14)
|
||||
#define PI_INTSR_RSWST (1 << 16)
|
||||
|
||||
// INTMR - Interrupt Mask Register
|
||||
#define PI_INTMR_ERROR (1 << 0)
|
||||
#define PI_INTMR_RSW (1 << 1)
|
||||
#define PI_INTMR_DI (1 << 2)
|
||||
#define PI_INTMR_SI (1 << 3)
|
||||
#define PI_INTMR_EXI (1 << 4)
|
||||
#define PI_INTMR_AI (1 << 5)
|
||||
#define PI_INTMR_DSP (1 << 6)
|
||||
#define PI_INTMR_MEM (1 << 7)
|
||||
#define PI_INTMR_VI (1 << 8)
|
||||
#define PI_INTMR_PE_TOKEN (1 << 9)
|
||||
#define PI_INTMR_PE_FINISH (1 << 10)
|
||||
#define PI_INTMR_CP (1 << 11)
|
||||
#define PI_INTMR_DEBUG (1 << 12)
|
||||
#define PI_INTMR_HSP (1 << 13)
|
||||
#define PI_INTMR_ACR (1 << 14)
|
||||
|
||||
/**
|
||||
* MI hardware registers
|
||||
*/
|
||||
volatile u16 MI_HW_REGS[] AT_ADDRESS(0xCC004000);
|
||||
typedef enum {
|
||||
MI_PAGE_MEM0_H, //!< 0xCC004000
|
||||
MI_PAGE_MEM0_L, //!< 0xCC004002
|
||||
MI_PAGE_MEM1_H, //!< 0xCC004004
|
||||
MI_PAGE_MEM1_L, //!< 0xCC004006
|
||||
MI_PAGE_MEM2_H, //!< 0xCC004008
|
||||
MI_PAGE_MEM2_L, //!< 0xCC00400A
|
||||
MI_PAGE_MEM3_H, //!< 0xCC00400C
|
||||
MI_PAGE_MEM3_L, //!< 0xCC00400E
|
||||
MI_PROT_MEM0, //!< 0xCC004010
|
||||
MI_PROT_MEM1, //!< 0xCC004012
|
||||
MI_PROT_MEM2, //!< 0xCC004014
|
||||
MI_PROT_MEM3, //!< 0xCC004016
|
||||
MI_REG_0x18, //!< 0xCC004018
|
||||
MI_REG_0x1A, //!< 0xCC00401A
|
||||
MI_INTMR, //!< 0xCC00401C
|
||||
MI_INTSR, //!< 0xCC00401E
|
||||
MI_REG_0x20, //!< 0xCC004020
|
||||
MI_ADDRLO, //!< 0xCC004022
|
||||
MI_ADDRHI, //!< 0xCC004024
|
||||
MI_REG_0x26, //!< 0xCC004026
|
||||
MI_REG_0x28, //!< 0xCC004028
|
||||
// . . .
|
||||
} MIHwReg;
|
||||
|
||||
// INTMR - Interrupt Mask Register
|
||||
#define MI_INTMR_MEM0 (1 << 0)
|
||||
#define MI_INTMR_MEM1 (1 << 1)
|
||||
#define MI_INTMR_MEM2 (1 << 2)
|
||||
#define MI_INTMR_MEM3 (1 << 3)
|
||||
#define MI_INTMR_ADDR (1 << 4)
|
||||
|
||||
// INTSR - Interrupt Cause Register
|
||||
#define MI_INTSR_MEM0 (1 << 0)
|
||||
#define MI_INTSR_MEM1 (1 << 1)
|
||||
#define MI_INTSR_MEM2 (1 << 2)
|
||||
#define MI_INTSR_MEM3 (1 << 3)
|
||||
#define MI_INTSR_ADDR (1 << 4)
|
||||
|
||||
/**
|
||||
* DI hardware globals
|
||||
*/
|
||||
// clang-format off
|
||||
OS_DEF_HW_REG(volatile unsigned long, DI_DMA_ADDR, 0xCD006014);
|
||||
OS_DEF_HW_REG(volatile unsigned long, DI_CONFIG, 0xCD006024);
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
* Misc/unknown globals
|
||||
*/
|
||||
// clang-format off
|
||||
OS_DEF_HW_REG(volatile unsigned long, UNK_CD000034, 0xCD000034);
|
||||
OS_DEF_HW_REG(volatile unsigned long, UNK_CD800180, 0xCD800180);
|
||||
OS_DEF_HW_REG(volatile unsigned long, UNK_CD8001CC, 0xCD8001CC);
|
||||
OS_DEF_HW_REG(volatile unsigned long, UNK_CD8001D0, 0xCD8001D0);
|
||||
// clang-format on
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,376 @@
|
|||
#include "revolution/revolution.h"
|
||||
#include "revolution/os/OSHardware.h"
|
||||
#include "__ppc_eabi_linker.h"
|
||||
|
||||
extern void InitMetroTRK();
|
||||
extern void exit(int);
|
||||
extern int main(int argc, char* argv[]);
|
||||
extern void __init_user(void);
|
||||
extern void InitMetroTRK_BBA(void);
|
||||
extern void DBInit();
|
||||
|
||||
__declspec(section ".init") extern void __check_pad3(void);
|
||||
__declspec(section ".init") extern void __set_debug_bba(void);
|
||||
__declspec(section ".init") extern u8 __get_debug_bba(void);
|
||||
__declspec(section ".init") extern void __start(void);
|
||||
__declspec(section ".init") extern void __init_registers(void);
|
||||
__declspec(section ".init") extern void __init_data(void);
|
||||
__declspec(section ".init") extern void __init_hardware(void);
|
||||
__declspec(section ".init") extern void __flush_cache(void* addr, u32 size);
|
||||
|
||||
extern u8 Debug_BBA;
|
||||
|
||||
__declspec(section ".init") void __check_pad3(void) {
|
||||
if ((*(u16*)0x800030E4 & 0xEEF) == 0xEEF) {
|
||||
OSResetSystem(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(section ".init") void __set_debug_bba(void) { Debug_BBA = 1; }
|
||||
|
||||
__declspec(section ".init") u8 __get_debug_bba(void) { return Debug_BBA; }
|
||||
|
||||
__declspec(section ".init") __declspec(weak) asm void __start(void) {
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
nofralloc
|
||||
|
||||
// Setup hardware
|
||||
bl __init_registers
|
||||
bl __init_hardware
|
||||
|
||||
// Create first stack frame
|
||||
li r0, -1
|
||||
// Parameter save
|
||||
stwu r1, -8(r1)
|
||||
// LR save (-1 to signify first frame)
|
||||
stw r0, 4(r1)
|
||||
// Back chain (-1 to signify first frame)
|
||||
stw r0, 0(r1)
|
||||
|
||||
// Setup ROM/BSS
|
||||
bl __init_data
|
||||
|
||||
// Clear debugger exception mask
|
||||
li r0, 0
|
||||
lis r6, (OS_DEBUG_INTERFACE + OSDebugInterface.exceptionMask)@ha
|
||||
addi r6, r6, (OS_DEBUG_INTERFACE + OSDebugInterface.exceptionMask)@l
|
||||
stw r0, 0(r6)
|
||||
|
||||
/**
|
||||
* Check the BI2 debug flag to determine how to call InitMetroTRK.
|
||||
*
|
||||
* This can be done by either checking the value from the DVD
|
||||
* (OSBI2.debugFlag), or by checking the global OS_BI2_DEBUG_FLAG.
|
||||
*
|
||||
* If the DVD BI2 is available, it is prioritized over the global value.
|
||||
*/
|
||||
lis r6, OS_DVD_BI2@ha
|
||||
addi r6, r6, OS_DVD_BI2@l
|
||||
lwz r6, 0(r6)
|
||||
cmplwi r6, 0
|
||||
beq _no_dvd_bi2 // <- NULL BI2, try the OS global
|
||||
|
||||
// Use the DVD's flag
|
||||
lwz r7, OSBI2.debugFlag(r6)
|
||||
b _handle_bi2_debug_flag
|
||||
|
||||
/**
|
||||
* At this point, we do one last check to decide whether we want to
|
||||
* setup the TRK debugger.
|
||||
*
|
||||
* If the OS boot info specifies an arena hi, we grab the BI2 debug
|
||||
* flag using the global OS_BI2_DEBUG_FLAG.
|
||||
*
|
||||
* (This must be some heuristic, but I don't understand it)
|
||||
*/
|
||||
_no_dvd_bi2:
|
||||
lis r5, (OS_BOOT_INFO + OSBootInfo.arenaHi)@ha
|
||||
addi r5, r5, (OS_BOOT_INFO + OSBootInfo.arenaHi)@l
|
||||
lwz r5, 0(r5)
|
||||
cmplwi r5, 0
|
||||
beq _check_for_exec_args // <- NULL arena hi, don't setup the debugger
|
||||
|
||||
// Grab the global BI2 debug flag
|
||||
lis r7, OS_BI2_DEBUG_FLAG@ha
|
||||
addi r7, r7, OS_BI2_DEBUG_FLAG@l
|
||||
lwz r7, 0(r7)
|
||||
|
||||
/**
|
||||
* The BI2 debug flag/level decides how to set up TRK.
|
||||
*
|
||||
* Most importantly, it decides how InitMetroTRKCommTable is called, by
|
||||
* specifying a type of hardware.
|
||||
*
|
||||
* ID 1: NDEV hardware
|
||||
* ID 2: BBA hardware
|
||||
* Anything else: "Unknown" to TRK, defaults to GDEV hardware
|
||||
*
|
||||
* BI2 debug level maps to TRK comm hardware ID as follows:
|
||||
* - BI2 Level 2 -> ID 0 (GDEV)
|
||||
* - BI2 Level 3 -> ID 1 (NDEV)
|
||||
* - BI2 Level 4 -> ID 2 (BBA)
|
||||
*/
|
||||
_handle_bi2_debug_flag:
|
||||
// BI2 Debug Level 3: Init TRK as GDEV hardware
|
||||
li r5, 0
|
||||
cmplwi r7, 2
|
||||
beq _call_init_metro_trk
|
||||
|
||||
// BI2 Debug Level 2: Init TRK as NDEV hardware
|
||||
cmplwi r7, 3
|
||||
li r5, 1
|
||||
beq _call_init_metro_trk
|
||||
|
||||
// BI2 Debug Level 4: Init TRK as BBA hardware
|
||||
// *Any other debug level is ignored*
|
||||
cmplwi r7, 4
|
||||
bne _check_for_exec_args // <- Ignore debug level, goto next step
|
||||
/**
|
||||
* I think at one point this used to call InitMetroTRK as they set
|
||||
* r5 here; however, in this version it goes unused.
|
||||
*
|
||||
* What currently happens is __set_debug_bba sets Debug_BBA, which
|
||||
* will result in a call to InitMetroTRK_BBA after the OS is
|
||||
* initialized.
|
||||
*
|
||||
* Maybe this is a leftover from how things worked before
|
||||
* InitMetroTRK_BBA was written?
|
||||
*/
|
||||
li r5, 2
|
||||
bl __set_debug_bba
|
||||
b _check_for_exec_args
|
||||
|
||||
/**
|
||||
* Call InitMetroTRK
|
||||
* The MetroTRK hardware ID is specified in r5
|
||||
*/
|
||||
_call_init_metro_trk:
|
||||
lis r6, InitMetroTRK@ha
|
||||
addi r6, r6, InitMetroTRK@l
|
||||
mtlr r6
|
||||
blrl
|
||||
|
||||
/**
|
||||
* After setting up the hardware and the debugger, we next setup
|
||||
* the program arguments. This label checks whether any arguments
|
||||
* exist.
|
||||
*
|
||||
* BI2 contains an offset from itself to the argument data, which
|
||||
* is formatted as follows:
|
||||
*
|
||||
* typedef struct BI2Args {
|
||||
* int argc;
|
||||
* union {
|
||||
* char* argument;
|
||||
* u32 offset;
|
||||
* } argv[];
|
||||
* } BI2Args;
|
||||
*/
|
||||
_check_for_exec_args:
|
||||
lis r6, OS_DVD_BI2@ha
|
||||
addi r6, r6, OS_DVD_BI2@l
|
||||
lwz r5, 0(r6)
|
||||
cmplwi r5, 0
|
||||
beq+ _no_args // <- No BI2 to get args from
|
||||
|
||||
lwz r6, OSBI2.argumentOfs(r5)
|
||||
cmplwi r6, 0
|
||||
beq+ _no_args // <- Invalid argument offset in BI2
|
||||
|
||||
// Calculate pointer to argument data
|
||||
add r6, r5, r6
|
||||
// First integer value is the argument count
|
||||
lwz r14, 0(r6)
|
||||
cmplwi r14, 0
|
||||
beq _no_args // <- Argument count is zero
|
||||
|
||||
// BI2 args + 0x8, used to adjust MEM1 later
|
||||
addi r15, r6, 4
|
||||
// Move argc to the counter to prepare the loop
|
||||
mtctr r14
|
||||
|
||||
/**
|
||||
* This loop unpacks the arguments by converting them from offsets
|
||||
* to pointers, in-place.
|
||||
*
|
||||
* The offsets are relative to the start of the BI2, so we just
|
||||
* add the offset to the BI2 pointer and write it back.
|
||||
*/
|
||||
_unpack_args_loop:
|
||||
// Skip over argc
|
||||
addi r6, r6, 4
|
||||
// Load argument offset
|
||||
lwz r7, 0(r6)
|
||||
// Convert offset to pointer
|
||||
add r7, r7, r5
|
||||
// Store pointer
|
||||
stw r7, 0(r6)
|
||||
bdnz _unpack_args_loop
|
||||
|
||||
/**
|
||||
* Both the MEM1 arena hi and the MEM1 limit are adjusted to
|
||||
* preserve the BI2 args.
|
||||
*
|
||||
* They are set to eight bytes into the BI2 arguments,
|
||||
* rounded down to the nearest 32 bytes.
|
||||
*/
|
||||
lis r5, (OS_BOOT_INFO + OSBootInfo.arenaHi)@ha
|
||||
addi r5, r5, (OS_BOOT_INFO + OSBootInfo.arenaHi)@l
|
||||
clrrwi r7, r15, 5
|
||||
stw r7, 0(r5)
|
||||
|
||||
lis r5, OS_USABLE_MEM1_END@ha
|
||||
addi r5, r5, OS_USABLE_MEM1_END@l
|
||||
clrrwi r7, r15, 5
|
||||
stw r7, 0(r5)
|
||||
b _init_os
|
||||
|
||||
/**
|
||||
* Either there was no BI2 available, or it did not contain any arguments
|
||||
*/
|
||||
_no_args:
|
||||
li r14, 0 // argc = 0
|
||||
li r15, 0 // argv = NULL
|
||||
|
||||
/**
|
||||
* Here, the OS and its debug monitor are initialized, and
|
||||
* then we check if we should call __check_pad3.
|
||||
*
|
||||
* __check_pad3 is called before future initialization if the disk
|
||||
* drive device code is 0x0001, or if the OS' inquiry fails (emulation
|
||||
* or some debug hardware?)
|
||||
*
|
||||
* The apploader reads the button state of the fourth GCN controller
|
||||
* and writes it to GC_PAD_3_BTN (zero-indexed), which is used in
|
||||
* __check_pad3. WiiBrew states that this is for GameCube NR disc
|
||||
* support, so that could explain the unusual DVD device code address.
|
||||
*/
|
||||
_init_os:
|
||||
// Initialize the OS and its debug monitor
|
||||
bl DBInit
|
||||
bl OSInit
|
||||
|
||||
// Load DVD device code address
|
||||
lis r4, OS_DVD_DEVICE_CODE@ha
|
||||
addi r4, r4, OS_DVD_DEVICE_CODE@l
|
||||
lhz r3, 0(r4)
|
||||
// Check whether OS inquiry failed
|
||||
andi. r5, r3, DVD_DEVICE_CODE_READ
|
||||
beq _call_check_pad3 // <- Bit 0 is NOT set (fail)
|
||||
// 0x0001 may be a real ID or a failsafe (see OS.c:InquiryCallback)
|
||||
andi. r3, r3, (~DVD_DEVICE_CODE_READ) & 0xFFFF
|
||||
cmplwi r3, 0x0001
|
||||
bne _check_debug_bba // <- NOT 0x0001 device code address
|
||||
_call_check_pad3:
|
||||
bl __check_pad3
|
||||
|
||||
/**
|
||||
* If the BI2 debug level from earlier was set to four, we need to
|
||||
* initialize the debugger for BBA hardware.
|
||||
*/
|
||||
_check_debug_bba:
|
||||
bl __get_debug_bba
|
||||
cmplwi r3, 1
|
||||
bne _after_init_metro_trk_bba // <- Debug_BBA == false
|
||||
bl InitMetroTRK_BBA
|
||||
|
||||
/**
|
||||
* 1. Initialize C++ runtime
|
||||
* 2. Call main(argc, argv)
|
||||
* 3. Teardown C++ runtime
|
||||
*/
|
||||
_after_init_metro_trk_bba:
|
||||
bl __init_user
|
||||
mr r3, r14
|
||||
mr r4, r15
|
||||
bl main
|
||||
b exit // <- Will halt CPU
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
static inline void __copy_rom_section(void* dst, const void* src, size_t size) {
|
||||
if (size == 0 || dst == src) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(dst, src, size);
|
||||
__flush_cache(dst, size);
|
||||
}
|
||||
|
||||
static inline void __init_bss_section(void* dst, size_t size) {
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(dst, 0, size);
|
||||
}
|
||||
|
||||
__declspec(section ".init") static asm void __init_registers(void) {
|
||||
#ifdef __MWERKS__ // clang-format off
|
||||
nofralloc
|
||||
|
||||
li r0, 0
|
||||
li r3, 0
|
||||
li r4, 0
|
||||
li r5, 0
|
||||
li r6, 0
|
||||
li r7, 0
|
||||
li r8, 0
|
||||
li r9, 0
|
||||
li r10, 0
|
||||
li r11, 0
|
||||
li r12, 0
|
||||
li r14, 0
|
||||
li r15, 0
|
||||
li r16, 0
|
||||
li r17, 0
|
||||
li r18, 0
|
||||
li r19, 0
|
||||
li r20, 0
|
||||
li r21, 0
|
||||
li r22, 0
|
||||
li r23, 0
|
||||
li r24, 0
|
||||
li r25, 0
|
||||
li r26, 0
|
||||
li r27, 0
|
||||
li r28, 0
|
||||
li r29, 0
|
||||
li r30, 0
|
||||
li r31, 0
|
||||
|
||||
lis r1, _stack_addr@h
|
||||
ori r1, r1, _stack_addr@l
|
||||
lis r2, _SDA2_BASE_@h
|
||||
ori r2, r2, _SDA2_BASE_@l
|
||||
lis r13, _SDA_BASE_@h
|
||||
ori r13, r13, _SDA_BASE_@l
|
||||
|
||||
blr
|
||||
#endif // clang-format on
|
||||
}
|
||||
|
||||
__declspec(section ".init") static void __init_data(void) {
|
||||
const __rom_copy_info* rs;
|
||||
const __bss_init_info* bs;
|
||||
|
||||
rs = _rom_copy_info;
|
||||
while (1) {
|
||||
if (rs->size == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
__copy_rom_section(rs->addr, rs->rom, rs->size);
|
||||
rs++;
|
||||
}
|
||||
|
||||
bs = _bss_init_info;
|
||||
while (1) {
|
||||
if (bs->size == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
__init_bss_section(bs->addr, bs->size);
|
||||
bs++;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue