1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
#include "dolphin/os/OS.h"
#include "dolphin/os/OSReboot.h"
static void* SaveStart = NULL;
static void* SaveEnd = NULL;
static volatile BOOL Prepared;
extern u32 OS_RESET_CODE AT_ADDRESS(0x800030F0);
extern u8 OS_REBOOT_BOOL AT_ADDRESS(0x800030E2); // unknown function, set to true by __OSReboot
extern u32 UNK_817FFFF8 AT_ADDRESS(0x817FFFF8);
extern u32 UNK_817FFFFC AT_ADDRESS(0x817FFFFC);
#define OS_BOOTROM_ADDR 0x81300000
typedef struct _ApploaderHeader {
/* 0x00 */ char date[16];
/* 0x10 */ u32 entry;
/* 0x14 */ u32 size;
/* 0x18 */ u32 rebootSize;
/* 0x1C */ u32 reserved2;
} ApploaderHeader; // Size: 0x20
static ApploaderHeader Header ALIGN_DECL(32);
ASM static void Run(register u32 addr) {
nofralloc
sync
isync
mtlr addr
blr
}
void ReadApploader(DVDCommandBlock* dvdCmd, void* addr, u32 offset, u32 numBytes);
void ReadApploader(DVDCommandBlock* dvdCmd, void* addr, u32 offset, u32 numBytes) {
/* Not sure if this inline is correct - might need to call other inlines */
while (Prepared == FALSE) {
}
DVDReadAbsAsyncForBS(dvdCmd, addr, numBytes, offset + 0x2440, NULL);
while (TRUE) {
switch (dvdCmd->state) {
case 0:
break;
case 1:
default:
continue;
case -1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
__OSDoHotReset(UNK_817FFFFC);
continue;
}
break;
}
}
static void Callback(s32 result, struct DVDCommandBlock* block) { Prepared = TRUE; }
void __OSReboot(u32 resetCode, u32 bootDol) {
OSContext exceptionContext;
DVDCommandBlock dvdCmd;
DVDCommandBlock dvdCmd2;
u32 numBytes;
u32 offset;
OSDisableInterrupts();
UNK_817FFFFC = 0;
UNK_817FFFF8 = 0;
OS_REBOOT_BOOL = TRUE;
BOOT_REGION_START = (u32)SaveStart;
BOOT_REGION_END = (u32)SaveEnd;
OSClearContext(&exceptionContext);
OSSetCurrentContext(&exceptionContext);
DVDInit();
DVDSetAutoInvalidation(TRUE);
__DVDPrepareResetAsync(Callback);
if (!DVDCheckDisk()) {
__OSDoHotReset(UNK_817FFFFC);
}
__OSMaskInterrupts(0xffffffe0);
__OSUnmaskInterrupts(0x400);
OSEnableInterrupts();
offset = 0;
numBytes = 32;
ReadApploader(&dvdCmd, (void*)&Header, offset, numBytes);
offset = Header.size + 0x20;
numBytes = OSRoundUp32B(Header.rebootSize);
ReadApploader(&dvdCmd2, (void*)(OS_BOOTROM_ADDR), offset, numBytes);
ICInvalidateRange((void*)(OS_BOOTROM_ADDR), numBytes);
OSDisableInterrupts();
ICFlashInvalidate();
Run(OS_BOOTROM_ADDR);
}
void OSSetSaveRegion(void* start, void* end) {
SaveStart = start;
SaveEnd = end;
}
|