From 4a8dbfff5cf699d5a2295014cf6cf1ac6582d137 Mon Sep 17 00:00:00 2001 From: GaryOderNichts <12049776+GaryOderNichts@users.noreply.github.com> Date: Sun, 3 Mar 2024 16:13:48 +0100 Subject: [PATCH] Implement basic async WUP install --- ios_mcp/source/imports.h | 58 ++++++++++++++++++++++++++ ios_mcp/source/mcp_install.c | 14 ++++--- ios_mcp/source/mcp_install.h | 8 +++- ios_mcp/source/options/InstallWUP.c | 64 +++++++++++++++++++++++++++-- ios_mcp/source/utils.c | 2 +- 5 files changed, 136 insertions(+), 10 deletions(-) diff --git a/ios_mcp/source/imports.h b/ios_mcp/source/imports.h index 2550ea1..402fe12 100644 --- a/ios_mcp/source/imports.h +++ b/ios_mcp/source/imports.h @@ -2,6 +2,7 @@ #include #include +#include #define LOCAL_PROCESS_HEAP_ID 0xcafe #define CROSS_PROCESS_HEAP_ID 0xcaff @@ -12,6 +13,63 @@ typedef struct { uint32_t paddr; } IOSVec_t; +typedef struct __attribute__((__packed__)) { + uint32_t command; + int32_t result; + int32_t handle; + uint32_t flags; + uint32_t cpuId; + uint32_t processId; + uint64_t titleId; + uint32_t groupId; + + union { + uint32_t args[5]; + + struct __attribute__((__packed__)) { + const char* device; + uint32_t nameLen; + uint32_t mode; + uint64_t caps; + } open; + + struct { + uint32_t unknown; + } close; + + struct { + void* data; + uint32_t length; + } read; + + struct { + const void* data; + uint32_t length; + } write; + + struct { + uint32_t offset; + uint32_t origin; + } seek; + + struct { + uint32_t request; + const void* inputData; + uint32_t inputLength; + void* outputData; + uint32_t outputLength; + } ioctl; + + struct { + uint32_t request; + uint32_t numVecIn; + uint32_t numVecOut; + IOSVec_t* vecs; + } ioctlv; + }; +} IOSIpcRequest_t; +static_assert(sizeof(IOSIpcRequest_t) == 0x38); + enum { UC_DATA_TYPE_U8 = 1, UC_DATA_TYPE_U16 = 2, diff --git a/ios_mcp/source/mcp_install.c b/ios_mcp/source/mcp_install.c index e3a0c8a..e2004be 100644 --- a/ios_mcp/source/mcp_install.c +++ b/ios_mcp/source/mcp_install.c @@ -82,20 +82,24 @@ int MCP_InstallTitle(int handle, const char* path) return res; } -int MCP_InstallTitleAsync(int handle, const char* path, int callbackQueue, void* msg) +int MCP_InstallTitleAsync(int handle, const char* path, int callbackQueue) { - uint8_t* buf = allocIoBuf(0x27f + sizeof(IOSVec_t)); + uint8_t* buf = allocIoBuf(0x27f + sizeof(IOSVec_t) + sizeof(MCPAsyncReply)); - char* path_buf = (char*) buf + sizeof(IOSVec_t); + char* path_buf = (char*) buf + sizeof(IOSVec_t) + sizeof(MCPAsyncReply); strncpy(path_buf, path, 0x27f); IOSVec_t* vecs = (IOSVec_t*) buf; vecs[0].ptr = path_buf; vecs[0].len = 0x27f; - int res = IOS_IoctlvAsync(handle, 0x81, 1, 0, vecs, callbackQueue, msg); + MCPAsyncReply* reply = (MCPAsyncReply*) (buf + sizeof(IOSVec_t)); + reply->ioBuf = buf; - freeIoBuf(buf); + int res = IOS_IoctlvAsync(handle, 0x81, 1, 0, vecs, callbackQueue, &reply->reply); + if (res < 0) { + freeIoBuf(buf); + } return res; } diff --git a/ios_mcp/source/mcp_install.h b/ios_mcp/source/mcp_install.h index ae65950..55a812e 100644 --- a/ios_mcp/source/mcp_install.h +++ b/ios_mcp/source/mcp_install.h @@ -1,5 +1,6 @@ #pragma once +#include "imports.h" #include typedef struct __attribute__((packed)) { @@ -16,6 +17,11 @@ typedef struct __attribute__((packed)) { uint32_t contentsProgress; } MCPInstallProgress; +typedef struct __attribute__((packed)) { + IOSIpcRequest_t reply; + void* ioBuf; +} MCPAsyncReply; + int MCP_InstallGetInfo(int handle, const char* path, MCPInstallInfo* out_info); int MCP_InstallSetTargetUsb(int handle, int target); @@ -24,6 +30,6 @@ int MCP_InstallSetTargetDevice(int handle, int device); int MCP_InstallTitle(int handle, const char* path); -int MCP_InstallTitleAsync(int handle, const char* path, int callbackQueue, void* msg); +int MCP_InstallTitleAsync(int handle, const char* path, int callbackQueue); int MCP_InstallGetProgress(int handle, MCPInstallProgress* progress); diff --git a/ios_mcp/source/options/InstallWUP.c b/ios_mcp/source/options/InstallWUP.c index 300af73..7f58bb6 100644 --- a/ios_mcp/source/options/InstallWUP.c +++ b/ios_mcp/source/options/InstallWUP.c @@ -5,6 +5,27 @@ #include "mcp_install.h" #include "imports.h" #include "utils.h" +#include + +static int callbackQueue = -1; +static uint8_t callbackThreadStack[0x200] __attribute__((aligned(0x20))); +static int asyncPending = 0; +static int asyncResult = -1; + +static int callbackThread(void* arg) +{ + MCPAsyncReply* reply = NULL; + int ret = IOS_ReceiveMessage(callbackQueue, (uint32_t*)&reply, IOS_MESSAGE_FLAGS_NONE); + if (ret >= 0 && reply) { + asyncResult = reply->reply.result; + asyncPending = 0; + + // Free original request + IOS_HeapFree(CROSS_PROCESS_HEAP_ID, reply->ioBuf); + } + + return 0; +} void option_InstallWUP(void) { @@ -51,18 +72,55 @@ void option_InstallWUP(void) return; } - // TODO: async installations - res = MCP_InstallTitle(mcpHandle, "/vol/storage_recovsd/install"); + int callbackThreadId = IOS_CreateThread(callbackThread, NULL, callbackThreadStack + sizeof(callbackThreadStack), sizeof(callbackThreadStack), IOS_GetThreadPriority(0), IOS_THREAD_FLAGS_NONE); + if (callbackThreadId < 0) { + IOS_Close(mcpHandle); + printf_error(index, "IOS_CreateThread: %x", res); + return; + } + + if (IOS_StartThread(callbackThreadId) < 0) { + IOS_Close(mcpHandle); + printf_error(index, "IOS_StartThread failed"); + return; + } + + uint32_t messages[5]; + callbackQueue = IOS_CreateMessageQueue(messages, sizeof(messages) / sizeof(uint32_t)); + if (callbackQueue < 0) { + IOS_Close(mcpHandle); + printf_error(index, "IOS_CreateThread: %x", res); + return; + } + + asyncResult = -1; + asyncPending = 1; + res = MCP_InstallTitleAsync(mcpHandle, "/vol/storage_recovsd/install", callbackQueue); if (res < 0) { IOS_Close(mcpHandle); printf_error(index, "Failed to install: %x", res); return; } + while (asyncPending) { + MCPInstallProgress progress; + res = MCP_InstallGetProgress(mcpHandle, &progress); + if (res < 0) { + // Uh oh + } + + gfx_printf(16, index, GfxPrintFlag_ClearBG, "Installing (%ld)... (%lu KiB / %lu KiB)", progress.inProgress, (uint32_t) (progress.sizeProgress / 1024llu), (uint32_t) (progress.sizeTotal / 1024llu)); + usleep(50 * 1000); + } + index += CHAR_SIZE_DRC_Y + 4; + setNotificationLED(NOTIF_LED_PURPLE, 0); gfx_set_font_color(COLOR_SUCCESS); - gfx_print(16, index, 0, "Done!"); + gfx_printf(16, index, 0, "Done (with result %d)!", asyncResult); waitButtonInput(); + IOS_JoinThread(callbackThreadId, NULL); + IOS_DestroyMessageQueue(callbackQueue); + IOS_Close(mcpHandle); } diff --git a/ios_mcp/source/utils.c b/ios_mcp/source/utils.c index 07d93ad..a8c498f 100644 --- a/ios_mcp/source/utils.c +++ b/ios_mcp/source/utils.c @@ -12,7 +12,7 @@ enum { }; static int asyncThreadHandle = -1; -static uint8_t asyncThreadStack[0x400] __attribute__((aligned(0x20))); +static uint8_t asyncThreadStack[0x200] __attribute__((aligned(0x20))); static uint32_t asyncMessageQueueBuf[0x20]; static int asyncMessageQueue = -1; static int ledTimer = -1;