Nn hai.rpl
Jump to navigation
Jump to search
nn_hai.rpl is used by Wii VC titles to handle getting into vWii mode.
Reverse Engineering
typedef struct _CMPTMode3CMDBuffer {
char enableDisableFlag;
unsigned int apdParam;
} CMPTMode3CMDBuffer;
/* workBuffer must be at least 0xC0 in size, and aligned so that
a clrlwi 26 on it results in 0 */
void nn::hai::launch::PrepareLaunch(unsigned int* out, void* workBuffer, size_t workBufferSz) {
nn::hai::error::Error errorInstance; //stack
nn::hai::error::Init(&errorInstance);
if (errorInstance) goto quit; //will skip StopIfRequired call
if (!workBuffer) {
//much nn::hai::error::Error handling ensues; "Invalid buffer"
goto quit;
}
int slotno = 0; //register
unsigned int nn_act_status; //also on stack
nn_act_status = nn::act::Initialize();
if (nn_act_status & /*who knows? clrrwi. RA, RS, 31... 31?*/) {
slotno = nn::act::GetSlotNo();
}
nn::act::Finalize();
if (!(nn_act_status & /*same again*/)) {
//Error handling; "failed to initialize nn::act"
goto quit;
}
unsigned int nn_pdm_status; //register
nn_pdm_status = nn::pdm::Initialize();
if (!(nn_pdm_status & /*again*/)) {
//Error handling; "failed to initialize nn::pdm"
goto quit;
}
nn::pdm::NotifyEnterHaiModeEvent();
nn::pdm::Finalize();
unsigned int screenState = CMPTCheckScreenState(); //register
if (!screenState) {
//Error handling
if (screenState == -9) {
//"HDMI seems not beeing linked to TV\n" [sic]
//Unlike the other error handlers, this does *not* set a fatal error
goto quit;
} else {
//"failed to check screen state"
goto quit;
}
}
if (!CMPTAcctSetEulaBySlotNo(slotno)) {
//Error handling: "failed to set EULA for current account"
goto quit;
}
CMPTMode3CMDBuffer cmd_buffer = {0, 0};
if (getSysConfig(&cmd_buffer.enableDisableFlag) != 1) {
//Error handling: "failed to get enable/disable flag of US"
goto quit;
}
unsigned int apd_param = 0; //stack
if (IM_GetNVParameterWithoutHandleAndItb(3, &apd_param)) {
//Error handling: "failed to get APD params"
goto quit;
}
unsigned int apd_param2 = 0; //stack
if (apd_param) {
if (IM_GetNVParameterWithoutHandleAndItb(4, &apd_param2)) {
//Error handling; as above
goto quit;
}
}
cmd_buffer.apdParam = apd_param2;
if (CMPTExSetWorkBuffer(workBuffer, workBufferSz)) {
//Error handling: "failed to set work workBuffer for prepare l" [sic]
goto quit;
}
if (CMPTExPrepareLaunch(3, &cmd_buffer, 5)) {
//Error handling: "failed to prepare compat mode launch"
//not fatal if return code was -0xA
goto quit;
}
quit:
nn::hai::error::StopIfRequired(&errorInstance);
unsigned int* mystery_stack_ptr; //completely random place on stack, see for yourself
for (int i = 5; i != 0; i--) { //praise bdnz
*out = *mystery_stack_ptr;
out += 4; //add 4 bytes, not 4 ints
mystery_stack_ptr += 4;
}
}
void nn::hai::launch::Launch() {
nn::hai::error::Error errorInstance; //stack
nn::hai::error::Init(&errorInstance);
if (errorInstance != 0 /* wtf C++ */) {
//Error handling; SetFatalError etc.
}
int ret = CMPTExLaunch();
if (ret) {
COSWarn(1, "[launch.cpp:%d] Err:", 237);
COSWarn(1, "failed to launch compat mode: %d\n", ret);
//Error handling
}
nn::hai::error::StopIfRequired(&errorInstance);
}