diff --git a/include/mocha/mocha.h b/include/mocha/mocha.h index 984a31b..695620e 100644 --- a/include/mocha/mocha.h +++ b/include/mocha/mocha.h @@ -1,7 +1,7 @@ #pragma once - #include #include +#include #include #ifdef __cplusplus @@ -12,6 +12,7 @@ typedef enum MochaUtilsStatus { MOCHA_RESULT_SUCCESS = 0, MOCHA_RESULT_INVALID_ARGUMENT = -0x01, MOCHA_RESULT_MAX_CLIENT = -0x02, + MOCHA_RESULT_OUT_OF_MEMORY = -0x03, MOCHA_RESULT_NOT_FOUND = -0x06, MOCHA_RESULT_UNSUPPORTED_API_VERSION = -0x10, MOCHA_RESULT_UNSUPPORTED_COMMAND = -0x11, @@ -26,7 +27,11 @@ typedef enum MochaUtilsStatus { */ MochaUtilsStatus Mocha_InitLibrary(); -MochaUtilsStatus Mocha_DeInitLibrary(); +/** + * Deinitializes the mocha lib + * @return + */ +MochaUtilsStatus Mocha_DeinitLibrary(); /** * Retrieves the API Version of the running mocha. @@ -39,6 +44,87 @@ MochaUtilsStatus Mocha_DeInitLibrary(); */ MochaUtilsStatus Mocha_CheckAPIVersion(uint32_t *outVersion); +/** + * Copies data within IOSU with kernel permission. + * @param dst - Destination address + * @param src - Source address + * @param size - Bytes to copy. + * @return MOCHA_RESULT_SUCCESS: The data has been copied successfully
+ * MOCHA_RESULT_INVALID_ARGUMENT: invalid version pointer
+ * MOCHA_RESULT_UNKNOWN_ERROR: Unknown error
+ * MOCHA_RESULT_UNSUPPORTED_API_VERSION: Failed to get the API version caused by an outdated mocha version. + */ +MochaUtilsStatus Mocha_IOSUKernelMemcpy(uint32_t dst, uint32_t src, uint32_t size); + +/** + * Writes data to a given address with kernel permission. + * @param address - Address where the data will be written to. + * @param buffer - Pointer to the data which should be written. + * @param size - Bytes to write. + * @return MOCHA_RESULT_SUCCESS: The data has been written successfully
+ * MOCHA_RESULT_INVALID_ARGUMENT: invalid version pointer
+ * MOCHA_RESULT_UNKNOWN_ERROR: Unknown error
+ * MOCHA_RESULT_UNSUPPORTED_API_VERSION: Failed to get the API version caused by an outdated mocha version. + */ +MochaUtilsStatus Mocha_IOSUKernelWrite(uint32_t address, const uint8_t *buffer, uint32_t size); + +/** + * Reads data from a given address with kernel permission. + * @param address - Address where the data will be read from. + * @param buffer - Pointer to the buffer where the read will be stored + * @param size - Bytes to read. + * @return MOCHA_RESULT_SUCCESS: The data has been read successfully
+ * MOCHA_RESULT_INVALID_ARGUMENT: invalid version pointer
+ * MOCHA_RESULT_UNKNOWN_ERROR: Unknown error
+ * MOCHA_RESULT_UNSUPPORTED_API_VERSION: Failed to get the API version caused by an outdated mocha version. + */ +MochaUtilsStatus Mocha_IOSUKernelRead(uint32_t address, uint8_t *out_buffer, uint32_t size); + +/** + * Write 4 bytes with IOSU kernel permission + * @param address Address where the value will be written. + * @param value Value that will be written to address. + * @return MOCHA_RESULT_SUCCESS: The data has been written successfully
+ * MOCHA_RESULT_INVALID_ARGUMENT: invalid version pointer
+ * MOCHA_RESULT_UNKNOWN_ERROR: Unknown error
+ * MOCHA_RESULT_UNSUPPORTED_API_VERSION: Failed to get the API version caused by an outdated mocha version. + */ +MochaUtilsStatus Mocha_IOSUKernelWrite32(uint32_t address, uint32_t value); + +/** + * Reads 4 bytes with IOSU kernel permission + * @param address Address from which the data will be read. + * @param out_buffer Pointer where the result will be stored + * @return MOCHA_RESULT_SUCCESS: The data has been read successfully
+ * MOCHA_RESULT_INVALID_ARGUMENT: invalid version pointer
+ * MOCHA_RESULT_UNKNOWN_ERROR: Unknown error
+ * MOCHA_RESULT_UNSUPPORTED_API_VERSION: Failed to get the API version caused by an outdated mocha version. + */ +MochaUtilsStatus Mocha_IOSUKernelRead32(uint32_t address, uint32_t *out_buffer); + +/** + * Read the consoles OTP into the given buffer. + * + * @param out_buffer Buffer where the result will be stored. + * @return MOCHA_RESULT_SUCCESS: The OTP has been read into the buffer
+ * MOCHA_RESULT_INVALID_ARGUMENT: invalid environmentPathBuffer pointer or bufferLen \< 0x100
+ * MOCHA_RESULT_LIB_UNINITIALIZED: Library was not initialized. Call Mocha_InitLibrary() before using this function.
+ * MOCHA_RESULT_UNKNOWN_ERROR: Failed to retrieve the environment path. + */ +MochaUtilsStatus Mocha_ReadOTP(WiiUConsoleOTP *out_buffer); + +/** + * Calls an iosu SVC. + * @param svc_id + * @param args array of argument with the length arg_cnt + * @param arg_cnt number of arguments + * @param outResult + * @return MOCHA_RESULT_SUCCESS: The SVC has been called successfully, the result has been stored in outResult.
+ * MOCHA_RESULT_LIB_UNINITIALIZED: Library was not initialized. Call Mocha_InitLibrary() before using this function.
+ * MOCHA_RESULT_UNKNOWN_ERROR + */ +int Mocha_IOSUCallSVC(uint32_t svc_id, uint32_t *args, uint32_t arg_cnt, int32_t *outResult); + /** * Returns the path of the currently loaded environment * @param environmentPathBuffer: buffer where the result will be stored diff --git a/include/mocha/otp.h b/include/mocha/otp.h new file mode 100644 index 0000000..a876b84 --- /dev/null +++ b/include/mocha/otp.h @@ -0,0 +1,193 @@ +#pragma once +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct WiiUConsoleOTP WiiUConsoleOTP; +typedef struct OTPWiiBank OTPWiiBank; +typedef struct OTPWiiUBank OTPWiiUBank; +typedef struct OTPWiiUNGBank OTPWiiUNGBank; +typedef struct OTPWiiUCertBank OTPWiiUCertBank; +typedef struct OTPWiiCertBank OTPWiiCertBank; +typedef struct OTPMiscBank OTPMiscBank; + +typedef uint32_t OTPJTAGStatus; +typedef uint32_t OTPSecurityLevel; + +typedef enum OTPSecurityLevelFlags { + SECURITY_FLAG_UNKNOWN = 0x40000000, // Unknown, causes error in boot0 + SECURITY_FLAG_CONSOLE_PROGRAMMED = 0x80000000, // Console type has been programmed + SECURITY_FLAG_USE_DEBUG_KEY_IMAGE = 0x08000000, // Use first RSA key and debug ancast images in boot0 + SECURITY_FLAG_USE_RETAIL_KEY_IMAGE = 0x10000000 // Use second RSA key and retail ancast images in boot0 +} OTPSecurityLevelFlags; + +typedef enum OTPIOStrength { + IO_HW_IOSTRCTRL0 = 0x00008000, + IO_HW_IOSTRCTRL1_3 = 0x00002000, + IO_HW_IOSTRCTRL1_2 = 0x00000800, + IO_HW_IOSTRCTRL1_1 = 0x00000080, + IO_HW_IOSTRCTRL1_0 = 0x00000008, + IO_NONE = 0x00000000 +} OTPIOStrength; + +typedef enum OTPPulseLength { + PULSE_BOOT0 = 0x0000002F, + PULSE_NONE = 0x00000000 +} OTPPulseLength; + +typedef enum OTPJTAGMask { + JTAG_MASK_DISABLED = 0x80 +} OTPJTAGMask; + +struct OTPWiiBank { + uint8_t boot1SHA1Hash[0x14]; + uint8_t commonKey[0x10]; + uint32_t ngId; + uint8_t ngPrivateKey[0x1C]; + uint8_t nandHMAC[0x14]; + uint8_t nandKey[0x10]; + uint8_t rngKey[0x10]; + WUT_UNKNOWN_BYTES(0x08); +}; +WUT_CHECK_SIZE(OTPWiiBank, 0x80); +WUT_CHECK_OFFSET(OTPWiiBank, 0x00, boot1SHA1Hash); +WUT_CHECK_OFFSET(OTPWiiBank, 0x14, commonKey); +WUT_CHECK_OFFSET(OTPWiiBank, 0x24, ngId); +WUT_CHECK_OFFSET(OTPWiiBank, 0x28, ngPrivateKey); +WUT_CHECK_OFFSET(OTPWiiBank, 0x44, nandHMAC); +WUT_CHECK_OFFSET(OTPWiiBank, 0x58, nandKey); +WUT_CHECK_OFFSET(OTPWiiBank, 0x68, rngKey); + +struct OTPWiiUBank { + OTPSecurityLevel securityLevel; + OTPIOStrength ioStrength; + OTPPulseLength pulseLength; + uint32_t signature; + uint8_t starbuckAncastKey[0x10]; + uint8_t seepromKey[0x10]; + WUT_UNKNOWN_BYTES(0x10); + WUT_UNKNOWN_BYTES(0x10); + uint8_t vWiiCommonKey[0x10]; + uint8_t wiiUCommonKey[0x10]; + WUT_UNKNOWN_BYTES(0x10); + WUT_UNKNOWN_BYTES(0x10); + WUT_UNKNOWN_BYTES(0x10); + uint8_t sslRSAKey[0x10]; + uint8_t usbStorageSeedsKey[0x10]; + WUT_UNKNOWN_BYTES(0x10); + uint8_t xorKey[0x10]; + uint8_t rngKey[0x10]; + uint8_t slcKey[0x10]; + uint8_t mlcKey[0x10]; + uint8_t sshdKey[0x10]; + uint8_t drhWLAN[0x10]; + WUT_UNKNOWN_BYTES(0x30); + uint8_t slcHmac[0x14]; + WUT_UNKNOWN_BYTES(0x0C); +}; +WUT_CHECK_SIZE(OTPWiiUBank, 0x180); +WUT_CHECK_OFFSET(OTPWiiUBank, 0x00, securityLevel); +WUT_CHECK_OFFSET(OTPWiiUBank, 0x04, ioStrength); +WUT_CHECK_OFFSET(OTPWiiUBank, 0x08, pulseLength); +WUT_CHECK_OFFSET(OTPWiiUBank, 0x10, starbuckAncastKey); +WUT_CHECK_OFFSET(OTPWiiUBank, 0x20, seepromKey); +WUT_CHECK_OFFSET(OTPWiiUBank, 0x50, vWiiCommonKey); +WUT_CHECK_OFFSET(OTPWiiUBank, 0x60, wiiUCommonKey); +WUT_CHECK_OFFSET(OTPWiiUBank, 0xA0, sslRSAKey); +WUT_CHECK_OFFSET(OTPWiiUBank, 0xB0, usbStorageSeedsKey); +WUT_CHECK_OFFSET(OTPWiiUBank, 0xD0, xorKey); +WUT_CHECK_OFFSET(OTPWiiUBank, 0xE0, rngKey); +WUT_CHECK_OFFSET(OTPWiiUBank, 0xF0, slcKey); +WUT_CHECK_OFFSET(OTPWiiUBank, 0x100, mlcKey); +WUT_CHECK_OFFSET(OTPWiiUBank, 0x110, sshdKey); +WUT_CHECK_OFFSET(OTPWiiUBank, 0x120, drhWLAN); +WUT_CHECK_OFFSET(OTPWiiUBank, 0x160, slcHmac); + +struct OTPWiiUNGBank { + WUT_UNKNOWN_BYTES(0x10); + WUT_UNKNOWN_BYTES(0x0C); + uint32_t ngId; + uint8_t ngPrivateKey[0x20]; + uint8_t privateNSSDeviceCertKey[0x20]; + uint8_t otpRNGSeed[0x10]; + WUT_UNKNOWN_BYTES(0x10); +}; +WUT_CHECK_SIZE(OTPWiiUNGBank, 0x80); +WUT_CHECK_OFFSET(OTPWiiUNGBank, 0x1C, ngId); +WUT_CHECK_OFFSET(OTPWiiUNGBank, 0x20, ngPrivateKey); +WUT_CHECK_OFFSET(OTPWiiUNGBank, 0x40, privateNSSDeviceCertKey); +WUT_CHECK_OFFSET(OTPWiiUNGBank, 0x60, otpRNGSeed); + +struct OTPWiiUCertBank { + uint32_t rootCertMSId; + uint32_t rootCertCAId; + uint32_t rootCertNGKeyId; + uint8_t rootCertNGSignature[0x3C]; + WUT_UNKNOWN_BYTES(0x18); + WUT_UNKNOWN_BYTES(0x20); +}; +WUT_CHECK_SIZE(OTPWiiUCertBank, 0x80); +WUT_CHECK_OFFSET(OTPWiiUCertBank, 0x00, rootCertMSId); +WUT_CHECK_OFFSET(OTPWiiUCertBank, 0x04, rootCertCAId); +WUT_CHECK_OFFSET(OTPWiiUCertBank, 0x08, rootCertNGKeyId); +WUT_CHECK_OFFSET(OTPWiiUCertBank, 0x0C, rootCertNGSignature); + +struct OTPWiiCertBank { + uint32_t rootCertMSId; + uint32_t rootCertCAId; + uint32_t rootCertNGKeyId; + uint8_t rootCertNGSignature[0x3C]; + uint8_t koreanKey[0x10]; + WUT_UNKNOWN_BYTES(0x08); + uint8_t privateNSSDeviceCertKey[0x20]; +}; +WUT_CHECK_SIZE(OTPWiiCertBank, 0x80); +WUT_CHECK_OFFSET(OTPWiiCertBank, 0x00, rootCertMSId); +WUT_CHECK_OFFSET(OTPWiiCertBank, 0x04, rootCertCAId); +WUT_CHECK_OFFSET(OTPWiiCertBank, 0x08, rootCertNGKeyId); +WUT_CHECK_OFFSET(OTPWiiCertBank, 0x0C, rootCertNGSignature); +WUT_CHECK_OFFSET(OTPWiiCertBank, 0x48, koreanKey); +WUT_CHECK_OFFSET(OTPWiiCertBank, 0x60, privateNSSDeviceCertKey); + +struct OTPMiscBank { + WUT_UNKNOWN_BYTES(0x20); + uint8_t boot1Key_protected[0x10]; + WUT_UNKNOWN_BYTES(0x10); + WUT_UNKNOWN_BYTES(0x20); + WUT_UNKNOWN_BYTES(0x04); + uint32_t otpVersionAndRevision; + uint64_t otpDateCode; + char otpVersionName[0x08]; + WUT_UNKNOWN_BYTES(0x04); + OTPJTAGStatus jtagStatus; +}; +WUT_CHECK_SIZE(OTPMiscBank, 0x80); +WUT_CHECK_OFFSET(OTPMiscBank, 0x20, boot1Key_protected); +WUT_CHECK_OFFSET(OTPMiscBank, 0x64, otpVersionAndRevision); +WUT_CHECK_OFFSET(OTPMiscBank, 0x68, otpDateCode); +WUT_CHECK_OFFSET(OTPMiscBank, 0x70, otpVersionName); +WUT_CHECK_OFFSET(OTPMiscBank, 0x7C, jtagStatus); + +struct WiiUConsoleOTP { + OTPWiiBank wiiBank; + OTPWiiUBank wiiUBank; + OTPWiiUNGBank wiiUNGBank; + OTPWiiUCertBank wiiUCertBank; + OTPWiiCertBank wiiCertBank; + OTPMiscBank miscBank; +}; +WUT_CHECK_SIZE(WiiUConsoleOTP, 0x400); +WUT_CHECK_OFFSET(WiiUConsoleOTP, 0x00, wiiBank); +WUT_CHECK_OFFSET(WiiUConsoleOTP, 0x80, wiiUBank); +WUT_CHECK_OFFSET(WiiUConsoleOTP, 0x200, wiiUNGBank); +WUT_CHECK_OFFSET(WiiUConsoleOTP, 0x280, wiiUCertBank); +WUT_CHECK_OFFSET(WiiUConsoleOTP, 0x300, wiiCertBank); +WUT_CHECK_OFFSET(WiiUConsoleOTP, 0x380, miscBank); + +#ifdef __cplusplus +} // extern "C" +#endif \ No newline at end of file diff --git a/source/logger.h b/source/logger.h new file mode 100644 index 0000000..ffa747e --- /dev/null +++ b/source/logger.h @@ -0,0 +1,23 @@ +#pragma once +#include +#include + +#define __FILENAME__ ({ \ + const char *__filename = __FILE__; \ + const char *__pos = strrchr(__filename, '/'); \ + if (!__pos) __pos = strrchr(__filename, '\\'); \ + __pos ? __pos + 1 : __filename; \ +}) + +#define LOG_APP_TYPE "L" +#define LOG_APP_NAME "libmocha" + +#define LOG_EX(FILENAME, FUNCTION, LINE, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \ + do { \ + LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, FILENAME, FUNCTION, LINE, ##ARGS); \ + } while (0) + +#define LOG_EX_DEFAULT(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) LOG_EX(__FILENAME__, __FUNCTION__, __LINE__, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ##ARGS) + +#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS) +#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##WARNING## ", "\n", FMT, ##ARGS) diff --git a/source/utils.cpp b/source/utils.cpp index ae77858..1f86f39 100644 --- a/source/utils.cpp +++ b/source/utils.cpp @@ -1,21 +1,48 @@ #include "utils.h" +#include "logger.h" #include "mocha/commands.h" #include "mocha/mocha.h" +#include "mocha/otp.h" #include #include +#include #include #include #include +int iosuhaxHandle = -1; int mochaInitDone = 0; uint32_t mochaApiVersion = 0; +#define IOCTL_MEM_WRITE 0x00 +#define IOCTL_MEM_READ 0x01 +#define IOCTL_SVC 0x02 +#define IOCTL_MEMCPY 0x04 +#define IOCTL_REPEATED_WRITE 0x05 +#define IOCTL_KERN_READ32 0x06 +#define IOCTL_KERN_WRITE32 0x07 +#define IOCTL_READ_OTP 0x08 MochaUtilsStatus Mocha_InitLibrary() { + if (mochaInitDone) { + return MOCHA_RESULT_SUCCESS; + } + + if (iosuhaxHandle < 0) { + int haxHandle = IOS_Open((char *) ("/dev/iosuhax"), static_cast(0)); + if (haxHandle < 0) { + DEBUG_FUNCTION_LINE_ERR("Failed to open /dev/iosuhax"); + return MOCHA_RESULT_UNSUPPORTED_COMMAND; + } + iosuhaxHandle = haxHandle; + } + mochaInitDone = 1; mochaApiVersion = 0; uint32_t version = 0; if (Mocha_CheckAPIVersion(&version) != MOCHA_RESULT_SUCCESS) { - return MOCHA_RESULT_SUCCESS; + IOS_Close(iosuhaxHandle); + iosuhaxHandle = -1; + return MOCHA_RESULT_UNSUPPORTED_COMMAND; } mochaApiVersion = version; @@ -23,10 +50,14 @@ MochaUtilsStatus Mocha_InitLibrary() { return MOCHA_RESULT_SUCCESS; } -MochaUtilsStatus Mocha_DeInitLibrary() { +MochaUtilsStatus Mocha_DeinitLibrary() { mochaInitDone = 0; mochaApiVersion = 0; + if (iosuhaxHandle >= 0) { + IOS_Close(iosuhaxHandle); + } + return MOCHA_RESULT_SUCCESS; } @@ -37,11 +68,11 @@ MochaUtilsStatus Mocha_CheckAPIVersion(uint32_t *version) { MochaUtilsStatus res = MOCHA_RESULT_UNKNOWN_ERROR; int mcpFd = IOS_Open("/dev/mcp", IOS_OPEN_READ); if (mcpFd >= 0) { - ALIGN_0x40 uint32_t io_buffer[0x100 / 4]; + ALIGN_0x40 uint32_t io_buffer[0x40 / 4]; io_buffer[0] = IPC_CUSTOM_GET_MOCHA_API_VERSION; - if (IOS_Ioctl(mcpFd, 100, io_buffer, 4, io_buffer, 4) == IOS_ERROR_OK) { - *version = io_buffer[0]; + if (IOS_Ioctl(mcpFd, 100, io_buffer, 4, io_buffer, 8) == IOS_ERROR_OK && io_buffer[0] == 0xCAFEBABE) { + *version = io_buffer[1]; res = MOCHA_RESULT_SUCCESS; } else { res = MOCHA_RESULT_UNSUPPORTED_API_VERSION; @@ -55,6 +86,138 @@ MochaUtilsStatus Mocha_CheckAPIVersion(uint32_t *version) { return res; } +MochaUtilsStatus Mocha_IOSUKernelMemcpy(uint32_t dst, uint32_t src, uint32_t size) { + if (size == 0) { + return MOCHA_RESULT_SUCCESS; + } + if (dst == 0 || src == 0) { + return MOCHA_RESULT_INVALID_ARGUMENT; + } + if (!mochaInitDone || iosuhaxHandle < 0) { + return MOCHA_RESULT_LIB_UNINITIALIZED; + } + + ALIGN_0x40 uint32_t io_buf[0x40 >> 2]; + io_buf[0] = dst; + io_buf[1] = src; + io_buf[2] = size; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_MEMCPY, io_buf, 3 * sizeof(uint32_t), nullptr, 0); + return res >= 0 ? MOCHA_RESULT_SUCCESS : MOCHA_RESULT_UNKNOWN_ERROR; +} + +MochaUtilsStatus Mocha_IOSUKernelWrite(uint32_t address, const uint8_t *buffer, uint32_t size) { + if (size == 0) { + return MOCHA_RESULT_SUCCESS; + } + if (address == 0 || buffer == nullptr) { + return MOCHA_RESULT_INVALID_ARGUMENT; + } + if (!mochaInitDone || iosuhaxHandle < 0) { + return MOCHA_RESULT_LIB_UNINITIALIZED; + } + + auto *io_buf = (uint32_t *) memalign(0x40, ROUNDUP(size + 4, 0x40)); + if (!io_buf) { + return MOCHA_RESULT_OUT_OF_MEMORY; + } + + io_buf[0] = address; + memcpy(io_buf + 1, buffer, size); + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_MEM_WRITE, io_buf, size + 4, nullptr, 0); + + free(io_buf); + return res >= 0 ? MOCHA_RESULT_SUCCESS : MOCHA_RESULT_UNKNOWN_ERROR; +} + +MochaUtilsStatus Mocha_IOSUKernelRead(uint32_t address, uint8_t *out_buffer, uint32_t size) { + if (size == 0) { + return MOCHA_RESULT_SUCCESS; + } + if (address == 0 || out_buffer == nullptr) { + return MOCHA_RESULT_INVALID_ARGUMENT; + } + if (!mochaInitDone || iosuhaxHandle < 0) { + return MOCHA_RESULT_LIB_UNINITIALIZED; + } + + ALIGN_0x40 uint32_t io_buf[0x40 >> 2]; + io_buf[0] = address; + + void *tmp_buf = nullptr; + + if (((uintptr_t) out_buffer & 0x3F) || (size & 0x3F)) { + tmp_buf = (uint32_t *) memalign(0x40, ROUNDUP(size, 0x40)); + if (!tmp_buf) { + return MOCHA_RESULT_OUT_OF_MEMORY; + } + } + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_MEM_READ, io_buf, sizeof(address), tmp_buf ? tmp_buf : out_buffer, size); + + if (res >= 0 && tmp_buf) { + memcpy(out_buffer, tmp_buf, size); + } + + free(tmp_buf); + return res >= 0 ? MOCHA_RESULT_SUCCESS : MOCHA_RESULT_UNKNOWN_ERROR; +} + +MochaUtilsStatus Mocha_IOSUKernelWrite32(uint32_t address, uint32_t value) { + return Mocha_IOSUKernelWrite(address, reinterpret_cast(&value), 4); +} + +MochaUtilsStatus Mocha_IOSUKernelRead32(uint32_t address, uint32_t *out_buffer) { + return Mocha_IOSUKernelRead(address, reinterpret_cast(out_buffer), 4); +} + +MochaUtilsStatus Mocha_ReadOTP(WiiUConsoleOTP *out_buffer) { + if (out_buffer == nullptr) { + return MOCHA_RESULT_INVALID_ARGUMENT; + } + if (!mochaInitDone || iosuhaxHandle < 0) { + return MOCHA_RESULT_LIB_UNINITIALIZED; + } + + ALIGN_0x40 uint32_t io_buf[0x400 >> 2]; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_READ_OTP, nullptr, 0, io_buf, 0x400); + + if (res < 0) { + return MOCHA_RESULT_UNKNOWN_ERROR; + } + memcpy(out_buffer, io_buf, 0x400); + + return MOCHA_RESULT_SUCCESS; +} + +int Mocha_IOSUCallSVC(uint32_t svc_id, uint32_t *args, uint32_t arg_cnt, int32_t *outResult) { + if (!mochaInitDone || iosuhaxHandle < 0) { + return MOCHA_RESULT_LIB_UNINITIALIZED; + } + + ALIGN_0x40 uint32_t arguments[0x40 >> 2]; + arguments[0] = svc_id; + + if (args && arg_cnt) { + if (arg_cnt > 8) { + arg_cnt = 8; + } + + memcpy(arguments + 1, args, arg_cnt * 4); + } + + ALIGN_0x40 int result[0x40 >> 2]; + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_SVC, arguments, (1 + arg_cnt) * 4, result, 4); + + if (res >= 0 && outResult) { + *outResult = *result; + } + + return res >= 0 ? MOCHA_RESULT_SUCCESS : MOCHA_RESULT_UNKNOWN_ERROR; +} + MochaUtilsStatus Mocha_GetEnvironmentPath(char *environmentPathBuffer, uint32_t bufferLen) { if (!mochaInitDone) { return MOCHA_RESULT_LIB_UNINITIALIZED; @@ -73,7 +236,8 @@ MochaUtilsStatus Mocha_GetEnvironmentPath(char *environmentPathBuffer, uint32_t if (IOS_Ioctl(mcpFd, 100, io_buffer, 4, io_buffer, 0x100) == IOS_ERROR_OK) { memcpy(environmentPathBuffer, reinterpret_cast(io_buffer), 0xFF); - res = MOCHA_RESULT_SUCCESS; + environmentPathBuffer[bufferLen - 1] = 0; + res = MOCHA_RESULT_SUCCESS; } IOS_Close(mcpFd);