Skip to content

Commit

Permalink
Improve "Install WUP" option (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
GaryOderNichts authored Aug 18, 2024
1 parent 02a554f commit c15c896
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 18 deletions.
58 changes: 58 additions & 0 deletions ios_mcp/source/imports.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <stdint.h>
#include <stdio.h>
#include <assert.h>

#define LONG_CALL __attribute__((long_call))

Expand All @@ -14,6 +15,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,
Expand Down
14 changes: 9 additions & 5 deletions ios_mcp/source/mcp_install.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
8 changes: 7 additions & 1 deletion ios_mcp/source/mcp_install.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "imports.h"
#include <stdint.h>

typedef struct __attribute__((packed)) {
Expand All @@ -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);
Expand All @@ -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);
110 changes: 99 additions & 11 deletions ios_mcp/source/options/InstallWUP.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,35 @@
#include "mcp_install.h"
#include "imports.h"
#include "utils.h"
#include <unistd.h>

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)
{
gfx_clear(COLOR_BACKGROUND);
drawTopBar("Installing WUP");
drawTopBar("Install WUP");
setNotificationLED(NOTIF_LED_RED_BLINKING, 0);

uint32_t index = 16 + 8 + 2 + 8;
gfx_print(16, index, 0, "Make sure to place a valid signed WUP directly in 'sd:/install'");
index += CHAR_SIZE_DRC_Y + 4;

int mcpHandle = IOS_Open("/dev/mcp", 0);
if (mcpHandle < 0) {
Expand All @@ -29,11 +48,33 @@ void option_InstallWUP(void)
int res = MCP_InstallGetInfo(mcpHandle, "/vol/storage_recovsd/install", &info);
if (res < 0) {
IOS_Close(mcpHandle);
gfx_print(16, index, 0, "Make sure to place a valid signed WUP directly in 'sd:/install'");
index += CHAR_SIZE_DRC_Y + 4;
printf_error(index, "Failed to get install info: %x", res);
return;
}

gfx_printf(16, index, 0, "Installing title: %08lx-%08lx...",
index = gfx_printf(16, index, 0, "Found title: %08lx-%08lx\nDo you want to install this title?",
(uint32_t)(info.titleId >> 32), (uint32_t)(info.titleId & 0xFFFFFFFFU));
index += CHAR_SIZE_DRC_Y + 4;

static const Menu installWupOptions[] = {
{"Cancel", {0} },
{"Install", {0} },
};
int selected = drawMenu("Install WUP",
installWupOptions, ARRAY_SIZE(installWupOptions), 0,
MenuFlag_NoClearScreen, 16, index);
if (selected == 0) {
IOS_Close(mcpHandle);
return;
}

gfx_clear(COLOR_BACKGROUND);
drawTopBar("Install WUP");
index = 16 + 8 + 2 + 8;

gfx_printf(16, index, 0, "Starting install for title: %08lx-%08lx",
(uint32_t)(info.titleId >> 32), (uint32_t)(info.titleId & 0xFFFFFFFFU));
index += CHAR_SIZE_DRC_Y + 4;

Expand All @@ -51,18 +92,65 @@ void option_InstallWUP(void)
return;
}

// TODO: async installations
res = MCP_InstallTitle(mcpHandle, "/vol/storage_recovsd/install");
uint32_t messages[5];
callbackQueue = IOS_CreateMessageQueue(messages, sizeof(messages) / sizeof(uint32_t));
if (callbackQueue < 0) {
IOS_Close(mcpHandle);
printf_error(index, "IOS_CreateMessageQueue: %x", res);
return;
}

int callbackThreadId = IOS_CreateThread(callbackThread, NULL, callbackThreadStack + sizeof(callbackThreadStack), sizeof(callbackThreadStack), IOS_GetThreadPriority(0), IOS_THREAD_FLAGS_NONE);
if (callbackThreadId < 0) {
IOS_DestroyMessageQueue(callbackQueue);
IOS_Close(mcpHandle);
printf_error(index, "IOS_CreateThread: %x", res);
return;
}

if (IOS_StartThread(callbackThreadId) < 0) {
IOS_DestroyMessageQueue(callbackQueue);
IOS_Close(mcpHandle);
printf_error(index, "IOS_StartThread failed");
return;
}

asyncResult = -1;
asyncPending = 1;
res = MCP_InstallTitleAsync(mcpHandle, "/vol/storage_recovsd/install", callbackQueue);
if (res < 0) {
// Send a NULL message and wait for the thread to stop
IOS_SendMessage(callbackQueue, 0, IOS_MESSAGE_FLAGS_NONE);
IOS_JoinThread(callbackThreadId, NULL);

IOS_DestroyMessageQueue(callbackQueue);
IOS_Close(mcpHandle);
printf_error(index, "Failed to install: %x", res);
printf_error(index, "Failed to start install: %x", res);
return;
}

setNotificationLED(NOTIF_LED_PURPLE, 0);
gfx_set_font_color(COLOR_SUCCESS);
gfx_print(16, index, 0, "Done!");
waitButtonInput();
while (asyncPending) {
MCPInstallProgress progress;
res = MCP_InstallGetProgress(mcpHandle, &progress);
if (res >= 0) {
gfx_printf(16, index, GfxPrintFlag_ClearBG, "Installing... (%lu KiB / %lu KiB)", (uint32_t) (progress.sizeProgress / 1024llu), (uint32_t) (progress.sizeTotal / 1024llu));
}

usleep(50 * 1000);
}
index += CHAR_SIZE_DRC_Y + 4;

if (asyncResult < 0) {
printf_error(index, "Failed to install: %x", asyncResult);
} else {
setNotificationLED(NOTIF_LED_PURPLE, 0);
gfx_set_font_color(COLOR_SUCCESS);
gfx_printf(16, index, 0, "Done!");
waitButtonInput();
}

IOS_JoinThread(callbackThreadId, NULL);
IOS_DestroyMessageQueue(callbackQueue);

IOS_Close(mcpHandle);
}
2 changes: 1 addition & 1 deletion ios_mcp/source/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit c15c896

Please sign in to comment.