Nn cmpt.rpl
Jump to navigation
Jump to search
nn_cmpt.rpl is used to coordinate the MCP when entering vWii mode. It generates a full config file and plays with the system config (via UCWriteSysConfig).
Reverse Engineering
/* As set by CMPTExSetWorkBuffer(void* workBuffer, size_t workBufferSz)
Any time I have pointer + x; I mean add x *bytes*, not x datatypes */
extern unsigned int* workBuffer;
extern size_t workBufferSz;
void CMPTExPrepareLaunch(int mode, int* cmd_buffer, size_t cmd_buffer_sz) {
unsigned int cmd[0x20]; //stack, 0x80 bytes
/* oh bdnz, oh bdnz, thy decrements unchanging
This isn't quite how it's done in code, but hey, same diff */
for (int i = 0x20; i != 0; i--) {
cmd[i] = 0;
}
if (!workBuffer || !workBufferSz) {
return -0x200;
}
*workBuffer = 0;
/* This isn't actually a jumptable.
It's a complex hierachy of comparisons, sorta like a
binary tree.
The code itself has also undergone a fair amount of
refactoring. */
switch (mode) {
case 0:
break;
case 1:
cmd[2] = 1; //actually mode, probably a compiler thing
break;
case 2:
if (!cmd_buffer || cmd_buffer_sz != 8) return -1;
cmd[2] = 0x10;
cmd[3] = cmd_buffer[0];
cmd[4] = cmd_buffer[1]; //aka cmd_buffer+4 or 4(cmd_buffer)
break;
case 3:
*workBuffer = 1;
if (!cmd_buffer || cmd_buffer_sz > 5) return -1;
memcpy(workBuffer + 4, cmd_buffer, cmd_buffer_sz);
if (cmd_buffer_sz < 5) {
/* cmd_buffer is too small, zero out the remaining
space in the output buffer.
Possible + 1 on this next line?
See docs for "subfic" instruction. */
size_t sz = 5 - cmd_buffer_sz;
memset(workBuffer + 4 + cmd_buffer_sz, 0, sz);
}
break;
case 4:
cmd[2] = 2;
break;
default:
return -1;
}
return makeConfigFile(cmd + 4, workBuffer, 0, workBuffer + 0x84, workBufferSz - 0x84);
}
int makeConfigFile(unsigned int* cmd, unsigned int* workBuffer, int b, unsigned int* buffer, size_t bufferSz) {
memset(buffer, 0, 0x20C4);
COSWarn(1, "CMPT: Conf: %08X (%d bytes)\n", buffer, 0x20C4);
int mcpFd = MCP_Open();
if (mcpFd < 0) {
COSWarn(1, "CMPT: failed: %s:%d: ", "compat.c", 374);
COSWarn(1, "MCP_Open: %d\n", mcpFd);
return -0x200;
}
int ret = updateAVConfIfAppropriate(mcpFd, buffer, cmd);
if (b && ret) {
COSWarn(1, "CMPT: CONF_ERROR: Use Preset\n");
sub_0580(buffer);
ret = 0;
}
COSWarn(1, "\n");
sub_01B0(buffer);
/* Not a bug, sub_01B0 does not return a value. This is a check
on updateAVConfIfAppropriate's return value.
This can *only* be true where b == 0. */
if (ret) {
COSWarn(1, "CMPT: CONF_ERROR\n");
MCP_Close(mcpFd); //haven't actually checked if this is mcpFd, but c'mon
}
sub_3FCC(buffer);
/* INCOMPLETE; REVERSE-ENGINEERING STOPPED HERE
0x02000BCC on 5.5.1.
I want to really hone in on some specific functions for now. */
}
//Down the rabbit hole...
int updateAVConfIfAppropriate(int fd, unsigned int* buffer, unsigned int* cmd) {
int ret;
/* clrlwi. 31... possibly & 0x0?
If not, this is a check for mode (from before) being 1. */
if (cmd[2] & 0x1) {
ret = sub_3C98(fd, buffer);
} else { //All other modes
sub_0580(buffer);
ret = updateAVConf(fd, buffer);
}
if (ret != -0x400) {
COSWarn(1, "CMPT: NG: translate UC to SC: %d\n", ret);
return (ret == -0x408) ? -8 : -0x200;
}
memcpy(buffer, cmd, 0x80);
return 0;
}
int updateAVConf(int fd, unsigned int* buffer) {
if (fd < 0 || !buffer) {
return -0x401;
}
unsigned int prodInfo, prodInfo2;
if (!_CMPTGetProdInfo(fd, &prodInfo, &prodInfo2)) {
COSWarn(1, "CMPT: failed: %s:%d: ", "compat_config.c", 655);
COSWarn(1, "NG: cmptGetProdInfo\n");
return -0x480;
}
int ret = _CMPTUpdateAVConf(prodInfo2, 0, buffer + 0xA8);
if (ret != -0x400) {
COSWarn(1, "CMPT: NG: cmptUpdateAvConf: %d\n", ret);
}
return ret;
}
//VERY incomplete look at nn_cmpt's work buffer...
struct workBuffer {
/* +0x1*/ unsigned int mode; //0 or 1
/* +0x4*/ unsigned char cmd_buffer[5]; //Only used in mode 3
/* Actual sizing is "whatever's left of the buffer"
0x3C is minimum as enforced by ExSetWorkBuffer, although
0x80 bytes are copied here at one point. */
/* +0x84*/ char cmd[0x80]; //"cmd" from start of PrepareLaunch
/*+0x12C*/ char AVConf[/*?*/];
}
sizeof(workBuffer) = 0x20C4