Nn cmpt.rpl

From WiiUBrew
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