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
117
118
119
120
|
/**
* @file cic6105.c
*
* This file implements routines relating to the CIC X105 anti-piracy measures present in N64 releases.
*
* The "authentication" chain begins in IPL3, which deposits specific expected values into RAM and runs an RSP task in
* parallel with loading the boot segment into RAM. This RSP task leaves data in the RSP's registers which rspboot and
* the CIC6105 RSP task later read according to routines in this file. Their security model relied on CICs being
* uncloneable with scarcely many donor CIC options from other games available at the time, in which case IPL3 would be
* unmodifiable. The rest of the chain is designed with a "security through obscurity" mindset, storing later antipiracy
* checks intermixed with other game code or RSP code that was expected to be non-trivial to analyze in a timely
* fashion. Notably this effort did little to curb emulation, almost wholly due to early emulators being insufficiently
* accurate to run RSP code or even IPL3 at a low level, sidestepping much of the early setup in favor of providing a
* known-good post-boot state to begin emulation from.
*/
#pragma increment_block_number "ntsc-1.0:132 ntsc-1.1:132 ntsc-1.2:132 pal-1.0:132 pal-1.1:132"
#include "audiomgr.h"
#include "build.h"
#include "cic6105.h"
#include "fault.h"
#include "regs.h"
#include "sched.h"
s32 CIC6105_Stub(void);
OSTask sCIC6105Task = {
// clang-format off
4,
0,
rspbootTextStart, 0x3E8,
cic6105TextStart, 0x20,
(u64*)gBuildCreator, 8,
NULL, 0,
NULL, NULL,
NULL, 0,
NULL, 0,
// clang-format on
};
u32 gCICBootMagic0;
u32 gCICBootMagic1;
FaultClient sCIC6105FaultClient;
u32 sCICTaskResult0;
u32 sCICTaskResult1;
void CIC6105_DisableAudio(void) {
R_AUDIOMGR_ACTIVITY_LEVEL = AUDIOMGR_ACTIVITY_LEVEL_NO_RSP;
}
void CIC6105_EnableAudio(void) {
R_AUDIOMGR_ACTIVITY_LEVEL = AUDIOMGR_ACTIVITY_LEVEL_ALL;
}
void CIC6105_FaultClient(void) {
u32 spStatus = IO_READ(SP_STATUS_REG);
Fault_SetCursor(48, 200);
// Signal 7 is set by rspboot when it is first executed, corresponding to
// whether rspboot's antipiracy checks passed. Signal 7 is expected to
// stay set for the entire duration of the game running.
if (spStatus & SP_STATUS_SIG7) {
Fault_Printf("OCARINA %08x %08x", sCICTaskResult0, sCICTaskResult1);
} else {
Fault_Printf("LEGEND %08x %08x", sCICTaskResult0, sCICTaskResult1);
}
Fault_SetCursor(40, 184);
Fault_Printf("ROM_F");
Fault_Printf(" [Creator:%s]", gBuildCreator);
Fault_SetCursor(56, 192);
Fault_Printf("[Date:%s]", gBuildDate);
#if OOT_VERSION < PAL_1_0
Fault_SetCursor(128, 24);
#else
Fault_SetCursor(96, 32);
#endif
Fault_Printf("I LOVE YOU %08x", CIC6105_Stub());
}
void CIC6105_AddFaultClient(void) {
Fault_AddClient(&sCIC6105FaultClient, CIC6105_FaultClient, NULL, NULL);
}
void CIC6105_RemoveFaultClient(void) {
Fault_RemoveClient(&sCIC6105FaultClient);
}
void CIC6105_RunBootTask(void) {
OSScTask scTask;
OSMesgQueue queue;
OSMesg msg;
// Prepare the CIC6105 task
osCreateMesgQueue(&queue, &msg, 1);
scTask.next = NULL;
scTask.flags = OS_SC_NEEDS_RSP;
scTask.msgQueue = &queue;
scTask.msg = (OSMesg)0;
scTask.framebuffer = NULL;
scTask.list = sCIC6105Task;
// Send it to the scheduler for execution
osSendMesg(&gScheduler.cmdQueue, &scTask, OS_MESG_BLOCK);
Sched_Notify(&gScheduler);
// Blocking wait until completion
osRecvMesg(&queue, NULL, OS_MESG_BLOCK);
// Retrieve results from RSP DMEM, it is assumed no other RSP task is running
sCICTaskResult0 = IO_READ(SP_DMEM_START + 0xFF4);
sCICTaskResult1 = IO_READ(SP_DMEM_START + 0xFFC);
CIC6105_Stub();
}
s32 CIC6105_Stub(void) {
return 0;
}
void CIC6105_SaveBootMagicValues(void) {
// IPL3 writes two magic values into RDRAM during the boot process into fixed locations.
// These must be retrieved early before memory is claimed by game memory management systems.
gCICBootMagic0 = IO_READ(0x002FB1F4);
gCICBootMagic1 = IO_READ(0x002FE1C0);
}
|