Document CIC6105 (#2739)

* Document CIC6105

* Changes, AUDIOMGR_DEBUG_LEVEL -> AUDIOMGR_ACTIVITY_LEVEL
This commit is contained in:
Tharo
2026-05-06 08:25:34 +01:00
committed by GitHub
parent 5625f1826e
commit 18d73ff374
10 changed files with 86 additions and 52 deletions
+1 -1
View File
@@ -12,7 +12,7 @@
/* RSP code for cic6105.c, used only in N64 versions. */
glabel cic6105TextStart
.word 0xE80C2001 # sqv $v12[0], 0x10($zero)
.word 0x34014000 # li $1, 0x4000
.word 0x34014000 # li $1, SP_SET_SIG2
.word 0x40812000 # mtc0 $1, SP_STATUS
.word 0x0000000D # break
.word 0x00000000 # nop
+5 -5
View File
@@ -4,11 +4,11 @@
#include "sched.h"
#include "audio.h"
typedef enum AudioMgrDebugLevel {
/* 0 */ AUDIOMGR_DEBUG_LEVEL_NONE,
/* 1 */ AUDIOMGR_DEBUG_LEVEL_NO_RSP,
/* 2 */ AUDIOMGR_DEBUG_LEVEL_NO_UPDATE
} AudioMgrDebugLevel;
typedef enum AudioMgrActivityLevel {
/* 0 */ AUDIOMGR_ACTIVITY_LEVEL_ALL,
/* 1 */ AUDIOMGR_ACTIVITY_LEVEL_NO_RSP,
/* 2 */ AUDIOMGR_ACTIVITY_LEVEL_NO_UPDATE
} AudioMgrActivityLevel;
typedef struct AudioMgr {
/* 0x0000 */ IrqMgr* irqMgr;
+6 -4
View File
@@ -3,12 +3,14 @@
#include "ultra64.h"
extern u32 B_80008EE0;
extern u32 gCICBootMagic0;
void func_800014E8(void);
#define CIC_BOOT_MAGIC0_IS_CORRECT() (gCICBootMagic0 == 0xAD090010)
void CIC6105_EnableAudio(void);
void CIC6105_AddFaultClient(void);
void CIC6105_RemoveFaultClient(void);
void func_80001640(void);
void func_80001720(void);
void CIC6105_RunBootTask(void);
void CIC6105_SaveBootMagicValues(void);
#endif
+1 -1
View File
@@ -54,7 +54,7 @@ struct PlayState;
#define R_DECELERATE_RATE REG(43)
#define R_RUN_SPEED_LIMIT REG(45)
#define R_ENABLE_ARENA_DBG SREG(0)
#define R_AUDIOMGR_DEBUG_LEVEL SREG(20)
#define R_AUDIOMGR_ACTIVITY_LEVEL SREG(20)
#define R_ROOM_IMAGE_NODRAW_FLAGS SREG(25)
#define R_ROOM_BG2D_FORCE_SCALEBG SREG(26)
#define R_UPDATE_RATE SREG(30)
+1 -1
View File
@@ -29,7 +29,7 @@ void bootproc(void) {
osMemSize = osGetMemSize();
#if PLATFORM_N64
func_80001720();
CIC6105_SaveBootMagicValues();
#endif
bootclear();
osInitialize();
+66 -34
View File
@@ -1,5 +1,19 @@
/**
* @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"
@@ -7,35 +21,47 @@
#include "regs.h"
#include "sched.h"
s32 func_80001714(void);
s32 CIC6105_Stub(void);
OSTask D_800067C0_unknown = {
4, 0, rspbootTextStart, 0x3E8, cic6105TextStart, 0x20, (u64*)gBuildCreator, 8, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
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 B_80008EE0;
u32 B_80008EE4;
u32 gCICBootMagic0;
u32 gCICBootMagic1;
FaultClient sCIC6105FaultClient;
u32 B_80008EF8;
u32 B_80008EFC;
u32 sCICTaskResult0;
u32 sCICTaskResult1;
void func_800014D0(void) {
R_AUDIOMGR_DEBUG_LEVEL = AUDIOMGR_DEBUG_LEVEL_NO_RSP;
void CIC6105_DisableAudio(void) {
R_AUDIOMGR_ACTIVITY_LEVEL = AUDIOMGR_ACTIVITY_LEVEL_NO_RSP;
}
void func_800014E8(void) {
R_AUDIOMGR_DEBUG_LEVEL = AUDIOMGR_DEBUG_LEVEL_NONE;
void CIC6105_EnableAudio(void) {
R_AUDIOMGR_ACTIVITY_LEVEL = AUDIOMGR_ACTIVITY_LEVEL_ALL;
}
void CIC6105_FaultClient(void) {
s32 spStatus;
u32 spStatus = IO_READ(SP_STATUS_REG);
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", B_80008EF8, B_80008EFC);
Fault_Printf("OCARINA %08x %08x", sCICTaskResult0, sCICTaskResult1);
} else {
Fault_Printf("LEGEND %08x %08x", B_80008EF8, B_80008EFC);
Fault_Printf("LEGEND %08x %08x", sCICTaskResult0, sCICTaskResult1);
}
Fault_SetCursor(40, 184);
Fault_Printf("ROM_F");
@@ -47,7 +73,7 @@ void CIC6105_FaultClient(void) {
#else
Fault_SetCursor(96, 32);
#endif
Fault_Printf("I LOVE YOU %08x", func_80001714());
Fault_Printf("I LOVE YOU %08x", CIC6105_Stub());
}
void CIC6105_AddFaultClient(void) {
@@ -58,31 +84,37 @@ void CIC6105_RemoveFaultClient(void) {
Fault_RemoveClient(&sCIC6105FaultClient);
}
void func_80001640(void) {
OSScTask sp38;
void CIC6105_RunBootTask(void) {
OSScTask scTask;
OSMesgQueue queue;
OSMesg msg;
// Prepare the CIC6105 task
osCreateMesgQueue(&queue, &msg, 1);
sp38.next = NULL;
sp38.flags = OS_SC_NEEDS_RSP;
sp38.msgQueue = &queue;
sp38.msg = (OSMesg)0;
sp38.framebuffer = 0;
sp38.list = D_800067C0_unknown;
osSendMesg(&gScheduler.cmdQueue, &sp38, OS_MESG_BLOCK);
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);
osRecvMesg(&queue, NULL, 1);
B_80008EF8 = IO_READ(SP_DMEM_START + 0xFF4);
B_80008EFC = IO_READ(SP_DMEM_START + 0xFFC);
func_80001714();
// 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 func_80001714(void) {
s32 CIC6105_Stub(void) {
return 0;
}
void func_80001720(void) {
B_80008EE0 = IO_READ(0x002FB1F4);
B_80008EE4 = IO_READ(0x002FE1C0);
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);
}
+3 -3
View File
@@ -29,7 +29,7 @@ void AudioMgr_NotifyTaskDone(AudioMgr* audioMgr) {
void AudioMgr_HandleRetrace(AudioMgr* audioMgr) {
AudioTask* rspTask;
if (R_AUDIOMGR_DEBUG_LEVEL > AUDIOMGR_DEBUG_LEVEL_NONE) {
if (R_AUDIOMGR_ACTIVITY_LEVEL > AUDIOMGR_ACTIVITY_LEVEL_ALL) {
// Inhibit audio rsp task processing
audioMgr->rspTask = NULL;
}
@@ -53,7 +53,7 @@ void AudioMgr_HandleRetrace(AudioMgr* audioMgr) {
gAudioThreadUpdateTimeStart = osGetTime();
if (R_AUDIOMGR_DEBUG_LEVEL >= AUDIOMGR_DEBUG_LEVEL_NO_UPDATE) {
if (R_AUDIOMGR_ACTIVITY_LEVEL >= AUDIOMGR_ACTIVITY_LEVEL_NO_UPDATE) {
// Skip update, no rsp task produced
rspTask = NULL;
} else {
@@ -160,7 +160,7 @@ void AudioMgr_Init(AudioMgr* audioMgr, void* stack, OSPri pri, OSId id, Schedule
audioMgr->rspTask = NULL;
#if PLATFORM_N64
R_AUDIOMGR_DEBUG_LEVEL = AUDIOMGR_DEBUG_LEVEL_NO_RSP;
R_AUDIOMGR_ACTIVITY_LEVEL = AUDIOMGR_ACTIVITY_LEVEL_NO_RSP;
#endif
osCreateMesgQueue(&audioMgr->taskDoneQueue, &audioMgr->taskDoneMsg, 1);
+1 -1
View File
@@ -159,7 +159,7 @@ void Main(void* arg) {
#if PLATFORM_N64
CIC6105_AddFaultClient();
func_80001640();
CIC6105_RunBootTask();
#endif
IrqMgr_AddClient(&gIrqMgr, &irqClient, &irqMgrMsgQueue);
+1 -1
View File
@@ -869,7 +869,7 @@ void Fishing_Init(Actor* thisx, PlayState* play2) {
#if PLATFORM_N64
// Anti-piracy check, if the check fails the line can't be reeled in if
// a fish is caught and the fish will always let go after 50 frames.
sReelLock = !(B_80008EE0 == 0xAD090010);
sReelLock = !CIC_BOOT_MAGIC0_IS_CORRECT();
#else
sReelLock = 0;
#endif
+1 -1
View File
@@ -212,7 +212,7 @@ void ConsoleLogo_Destroy(GameState* thisx) {
Sram_InitSram(&this->state, &this->sramCtx);
#if PLATFORM_N64
func_800014E8();
CIC6105_EnableAudio();
#endif
}