Compare commits

...

17 Commits
v0.2.0 ... main

Author SHA1 Message Date
Maschell 7c987b5b9d Add option to (un)block updates from within the boot selector and update block warning 2024-05-06 13:36:40 +02:00
Maschell 8f495d213f Remove the Tiramisu Icon from the boot selector menu 2024-05-05 18:39:58 +02:00
Maschell 713f2a3aed Abort the quick start menu after ~120 seconds 2024-05-05 17:51:07 +02:00
Maschell e6cfed9da8 Compile with latest wut version 2024-05-05 17:51:07 +02:00
Maschell d8b2f36cf0 Fix quick starting into System Settings as regular title 2024-05-05 02:45:55 +02:00
Maschell 083998faab QuickStartMenu: Actually jump to the quick start settings 2024-05-05 02:23:51 +02:00
Maschell b5c007d921 Fix loading the Transfer App 2024-05-05 02:23:51 +02:00
Maschell b2ae87ae1f Try to mount WFS drives once even if now USBStorageDevice is connected 2024-05-03 22:32:10 +02:00
Maschell 67dfdd1fc8 Rename getQuickBoot to launchQuickStartTitle 2024-04-26 10:35:50 +02:00
Maschell 4cc08d82e2 Make sure to librpxloader before checking for quick start 2024-04-26 10:35:50 +02:00
Maschell f80e83dff9 Bump version 2024-04-25 17:59:25 +02:00
Maschell b245a71cdb Update github actions 2024-04-25 17:59:25 +02:00
Maschell 688b834d2a Improve LaunchInfoDatabase reading code 2024-04-25 17:59:25 +02:00
Maschell bf8d1a974d Add support for quick starting into homebrew titles 2024-04-25 17:59:25 +02:00
Maschell f313152874 Fix launching the system settings 2024-04-25 17:59:25 +02:00
Maschell f1a240ddbc Update .gitignore to ignore .zip files 2024-04-25 17:59:25 +02:00
Maschell ed1e612602 Create dependabot.yml 2023-07-23 10:31:17 +02:00
17 changed files with 298 additions and 60 deletions

10
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

View File

@ -9,7 +9,7 @@ jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source
@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: create version.h
run: |
git_hash=$(git rev-parse --short "$GITHUB_SHA")
@ -48,7 +48,7 @@ jobs:
- name: zip artifact
run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip *.rpx
- name: Create Release
uses: "softprops/action-gh-release@v1"
uses: "softprops/action-gh-release@v2"
with:
tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
draft: false

View File

@ -6,7 +6,7 @@ jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source
@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: build binary with logging
run: |
docker build . -t builder
@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: create version.h
run: |
git_hash=$(git rev-parse --short "${{ github.event.pull_request.head.sha }}")

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ build/
.vscode/
cmake-build-debug/
CMakeLists.txt
*.zip

View File

@ -1,5 +1,6 @@
FROM ghcr.io/wiiu-env/devkitppc:20230621
FROM ghcr.io/wiiu-env/devkitppc:20240505
COPY --from=ghcr.io/wiiu-env/libmocha:20230621 /artifacts $DEVKITPRO
COPY --from=ghcr.io/wiiu-env/librpxloader:20240425 /artifacts $DEVKITPRO
WORKDIR project

View File

@ -10,6 +10,8 @@ TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/wut/share/wut_rules
WUMS_ROOT := $(DEVKITPRO)/wums
#-------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
@ -36,7 +38,7 @@ CXXFLAGS := $(CFLAGS) -std=c++20 -fno-rtti
ASFLAGS := -g $(ARCH)
LDFLAGS = -g $(ARCH) $(RPXSPECS) --entry=_start -Wl,-Map,$(notdir $*.map)
LIBS := -lpng -lmocha -lwut -lz
LIBS := -lrpxloader -lpng -lmocha -lwut -lz
ifeq ($(DEBUG),1)
CXXFLAGS += -DDEBUG -g
@ -52,7 +54,7 @@ endif
# list of directories containing libraries, this must be the top level
# containing include and lib
#-------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUT_ROOT)/usr
LIBDIRS := $(PORTLIBS) $(WUMS_ROOT) $(WUT_ROOT) $(WUT_ROOT)/usr
#-------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -3,22 +3,24 @@
#include "DrawUtils.h"
#include "InputUtils.h"
#include "PairUtils.h"
#include "icon_png.h"
#include "logger.h"
#include "main.h"
#include "utils.h"
#include "version.h"
#include <coreinit/debug.h>
#include <coreinit/filesystem_fsa.h>
#include <coreinit/screen.h>
#include <coreinit/thread.h>
#include <cstring>
#include <gx2/state.h>
#include <malloc.h>
#include <memory>
#include <mocha/mocha.h>
#include <string>
#include <sysapp/title.h>
#include <vector>
#define AUTOBOOT_MODULE_VERSION "v0.2.0"
#define AUTOBOOT_MODULE_VERSION "v0.2.1"
const char *autoboot_config_strings[] = {
"wiiu_menu",
@ -56,7 +58,7 @@ void writeAutobootOption(std::string &configPath, int32_t autobootOption) {
}
}
void drawMenuScreen(const std::map<uint32_t, std::string> &menu, uint32_t selectedIndex, uint32_t autobootIndex) {
void drawMenuScreen(const std::map<uint32_t, std::string> &menu, uint32_t selectedIndex, uint32_t autobootIndex, bool updatesBlocked) {
DrawUtils::beginDraw();
DrawUtils::clear(COLOR_BACKGROUND);
@ -81,8 +83,7 @@ void drawMenuScreen(const std::map<uint32_t, std::string> &menu, uint32_t select
// draw top bar
DrawUtils::setFontSize(24);
DrawUtils::drawPNG(16, 2, icon_png);
DrawUtils::print(64 + 2, 6 + 24, "Boot Selector");
DrawUtils::print(16, 6 + 24, "Boot Selector");
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_WHITE);
DrawUtils::setFontSize(16);
DrawUtils::print(SCREEN_WIDTH - 16, 6 + 24, AUTOBOOT_MODULE_VERSION AUTOBOOT_MODULE_VERSION_EXTRA, true);
@ -95,6 +96,14 @@ void drawMenuScreen(const std::map<uint32_t, std::string> &menu, uint32_t select
const char *autobootHints = "\ue002/\ue046 Clear Autoboot / \ue003/\ue045 Select Autoboot";
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(autobootHints) / 2, SCREEN_HEIGHT - 8, autobootHints, true);
if (updatesBlocked) {
DrawUtils::setFontSize(10);
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 24 - 8 - 4 - 10, "Updates blocked! Hold \ue045 + \ue046 to restore Update folder", true);
} else {
DrawUtils::setFontSize(10);
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 24 - 8 - 4 - 10, "Updates not blocked! Hold \ue045 + \ue046 to delete Update folder", true);
}
DrawUtils::endDraw();
}
@ -135,16 +144,18 @@ int32_t handleMenuScreen(std::string &configPath, int32_t autobootOptionInput, c
}
}
{
PairMenu pairMenu;
int32_t holdUpdateBlockedForFrames = 0;
while (true) {
if (pairMenu.ProcessPairScreen()) {
continue;
}
InputUtils::InputData input = InputUtils::getControllerInput();
if (input.trigger & VPAD_BUTTON_UP) {
selectedIndex--;
@ -166,10 +177,20 @@ int32_t handleMenuScreen(std::string &configPath, int32_t autobootOptionInput, c
autobootIndex = -1;
} else if (input.trigger & (VPAD_BUTTON_Y | VPAD_BUTTON_PLUS)) {
autobootIndex = selectedIndex;
} else if ((input.hold & (VPAD_BUTTON_PLUS | VPAD_BUTTON_MINUS)) == (VPAD_BUTTON_PLUS | VPAD_BUTTON_MINUS)) {
if (holdUpdateBlockedForFrames++ > 50) {
if (gUpdatesBlocked) {
gUpdatesBlocked = !RestoreMLCUpdateDirectory();
} else {
gUpdatesBlocked = DeleteMLCUpdateDirectory();
}
holdUpdateBlockedForFrames = 0;
}
} else {
holdUpdateBlockedForFrames = 0;
}
drawMenuScreen(menu, selectedIndex, autobootIndex);
drawMenuScreen(menu, selectedIndex, autobootIndex, gUpdatesBlocked);
}
}
@ -337,7 +358,7 @@ void drawUpdateWarningScreen() {
DrawUtils::beginDraw();
DrawUtils::clear(COLOR_BACKGROUND_WARN);
DrawUtils::setFontColor(COLOR_TEXT);
DrawUtils::setFontColor(COLOR_WARNING);
// draw top bar
DrawUtils::setFontSize(48);
@ -351,8 +372,12 @@ void drawUpdateWarningScreen() {
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(message) / 2, SCREEN_HEIGHT / 2 - 48, message, true);
message = "Your system might not be blocking updates properly!";
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(message) / 2, SCREEN_HEIGHT / 2 - 24, message, true);
message = "Press \ue002 to block the updates! This can be reverted in the Boot Selector.";
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(message) / 2, SCREEN_HEIGHT / 2 + 24, message, true);
message = "See https://wiiu.hacks.guide/#/block-updates for more information.";
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(message) / 2, SCREEN_HEIGHT / 2 + 0, message, true);
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(message) / 2, SCREEN_HEIGHT / 2 + 64 + 24, message, true);
DrawUtils::setFontSize(16);
@ -362,7 +387,7 @@ void drawUpdateWarningScreen() {
// draw bottom bar
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_WHITE);
DrawUtils::setFontSize(18);
const char *exitHints = "\ue000 Continue / \ue001 Don't show this again";
const char *exitHints = "\ue000 Continue without blocking / \ue001 Don't show this again";
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHints) / 2, SCREEN_HEIGHT - 8, exitHints, true);
DrawUtils::endDraw();
@ -402,6 +427,9 @@ void handleUpdateWarningScreen() {
InputUtils::InputData input = InputUtils::getControllerInput();
if (input.trigger & VPAD_BUTTON_A) {
break;
} else if (input.trigger & VPAD_BUTTON_X) {
gUpdatesBlocked = DeleteMLCUpdateDirectory();
break;
} else if (input.trigger & VPAD_BUTTON_B) {
f = fopen(UPDATE_SKIP_PATH, "w");
if (f) {

View File

@ -13,8 +13,9 @@
#define COLOR_WHITE Color(0xffffffff)
#define COLOR_BLACK Color(0, 0, 0, 255)
#define COLOR_BACKGROUND COLOR_BLACK
#define COLOR_BACKGROUND_WARN Color(255, 40, 0, 255)
#define COLOR_BACKGROUND_WARN Color(255, 251, 4, 255)
#define COLOR_TEXT COLOR_WHITE
#define COLOR_WARNING COLOR_BLACK
#define COLOR_TEXT2 Color(0xB3ffffff)
#define COLOR_AUTOBOOT Color(0xaeea00ff)
#define COLOR_BORDER Color(204, 204, 204, 255)

View File

@ -7,17 +7,25 @@
#include <coreinit/exit.h>
#include <coreinit/foreground.h>
#include <coreinit/launch.h>
#include <coreinit/memdefaultheap.h>
#include <coreinit/thread.h>
#include <nn/acp/title.h>
#include <nn/act/client_cpp.h>
#include <nn/ccr/sys_caffeine.h>
#include <nn/sl.h>
#include <nsysccr/cdc.h>
#include <optional>
#include <proc_ui/procui.h>
#include <rpxloader/rpxloader.h>
#include <sysapp/launch.h>
#include <sysapp/title.h>
extern "C" void __fini_wut();
extern "C" void CCRSysCaffeineBootCheckAbort();
#define UPPER_TITLE_ID_HOMEBREW 0x0005000F
#define TITLE_ID_HOMEBREW_MASK (((uint64_t) UPPER_TITLE_ID_HOMEBREW) << 32)
static void StartAppletAndExit() {
DEBUG_FUNCTION_LINE("Wait for applet");
@ -79,44 +87,131 @@ void loadConsoleAccount(const char *data_uuid) {
nn::act::Finalize();
}
bool getQuickBoot() {
class FileStreamWrapper {
public:
static std::unique_ptr<FileStreamWrapper> CreateFromPath(std::string_view path, std::string_view mode = "r") {
return std::unique_ptr<FileStreamWrapper>(new FileStreamWrapper(path, mode));
}
~FileStreamWrapper() {
mFileStream.reset();
FSDelClient(&mFsClient, FS_ERROR_FLAG_NONE);
}
nn::sl::details::IStreamBase &GetStream() {
return *mFileStream;
}
private:
explicit FileStreamWrapper(std::string_view path, std::string_view mode) {
FSAddClient(&mFsClient, FS_ERROR_FLAG_NONE);
FSInitCmdBlock(&mCmdBlock);
mFileStream = std::make_unique<nn::sl::FileStream>();
mFileStream->Initialize(&mFsClient, &mCmdBlock, path.data(), mode.data());
}
std::unique_ptr<nn::sl::FileStream> mFileStream{};
FSClient mFsClient{};
FSCmdBlock mCmdBlock{};
};
class QuickStartAutoAbort {
public:
QuickStartAutoAbort() {
OSCreateAlarm(&mAlarm);
OSSetPeriodicAlarm(&mDRCConnectedAlarm,
OSSecondsToTicks(10),
OSSecondsToTicks(1),
&AbortOnDRCDisconnect);
OSSetAlarm(&mAlarm, OSSecondsToTicks(120), AbortQuickStartTitle);
mDRCConnected = IsDRCConnected();
}
~QuickStartAutoAbort() {
OSCancelAlarm(&mDRCConnectedAlarm);
OSCancelAlarm(&mAlarm);
// Reconnect the DRC if it was connected at launch but then disconnected;
if (mDRCConnected && !IsDRCConnected()) {
DEBUG_FUNCTION_LINE_VERBOSE("Wake up GamePad");
CCRCDCWowlWakeDrcArg args = {.state = 1};
CCRCDCWowlWakeDrc(&args);
}
}
static bool IsDRCConnected() {
CCRCDCDrcState state = {};
CCRCDCSysGetDrcState(CCR_CDC_DESTINATION_DRC0, &state);
return state.state != 0;
}
static void AbortQuickStartTitle(OSAlarm *alarm, OSContext *) {
DEBUG_FUNCTION_LINE_VERBOSE("Selecting a title takes too long, lets abort the quick start menu");
CCRSysCaffeineBootCheckAbort();
}
static void AbortOnDRCDisconnect(OSAlarm *alarm, OSContext *) {
if (!IsDRCConnected()) {
DEBUG_FUNCTION_LINE_VERBOSE("GamePad was disconnected, lets abort the quick start menu");
CCRSysCaffeineBootCheckAbort();
}
}
private:
OSAlarm mDRCConnectedAlarm{};
OSAlarm mAlarm{};
bool mDRCConnected = false;
};
bool launchQuickStartTitle() {
// Automatically abort quick start if selecting takes longer than 120 seconds or the DRC disconnects
QuickStartAutoAbort quickStartAutoAbort;
// Waits until the quick start menu has been closed.
auto bootCheck = CCRSysCaffeineBootCheck();
if (bootCheck == 0) {
nn::sl::Initialize(MEMAllocFromDefaultHeapEx, MEMFreeToDefaultHeap);
char path[0x80];
nn::sl::GetDefaultDatabasePath(path, 0x80, 0x0005001010066000); // ECO process
FSCmdBlock cmdBlock;
FSInitCmdBlock(&cmdBlock);
auto fileStream = new nn::sl::FileStream;
auto *fsClient = (FSClient *) memalign(0x40, sizeof(FSClient));
if (!fsClient) {
DEBUG_FUNCTION_LINE("Couldn't alloc memory for fsClient.");
return false;
nn::sl::LaunchInfoDatabase launchInfoDatabase;
nn::sl::LaunchInfo info;
{
// In theory the region doesn't even matter.
// The region is to load a "system table" into the LaunchInfoDatabase which provides the LaunchInfos for
// the Wii U Menu and System Settings. In the code below we check for all possible System Settings title id and
// have a fallback to the Wii U Menu... This means we could get away a wrong region, but let's use the correct one
// anyway
const auto region = []() {
if (SYSCheckTitleExists(0x0005001010047000L)) { // JPN System Settings
return nn::sl::REGION_JPN;
} else if (SYSCheckTitleExists(0x0005001010047100L)) { // USA System Settings
return nn::sl::REGION_USA;
} else if (SYSCheckTitleExists(0x0005001010047200L)) { // EUR System Settings
return nn::sl::REGION_EUR;
}
return nn::sl::REGION_EUR;
}();
auto fileStream = FileStreamWrapper::CreateFromPath(path);
if (launchInfoDatabase.Load(fileStream->GetStream(), region).IsFailure()) {
DEBUG_FUNCTION_LINE_ERR("Failed to load LaunchInfoDatabase");
return false;
}
}
memset(fsClient, 0, sizeof(*fsClient));
FSAddClient(fsClient, FS_ERROR_FLAG_NONE);
fileStream->Initialize(fsClient, &cmdBlock, path, "r");
auto database = new nn::sl::LaunchInfoDatabase;
database->Load(fileStream, nn::sl::REGION_EUR);
CCRAppLaunchParam data; // load sys caffeine data
// load app launch param
CCRSysCaffeineGetAppLaunchParam(&data);
if (data.launchInfoDatabaseEntryId == 1) { // This id is hardcoded into the nn_sl.rpl
DEBUG_FUNCTION_LINE("Launch Quick Start Settings");
SysAppSettingsArgs args{};
args.jumpTo = SYS_SETTINGS_JUMP_TO_QUICK_START_SETTINGS; // quick start settings
_SYSLaunchSettings(&args);
return true;
}
loadConsoleAccount(data.uuid);
// get launch info for id
nn::sl::LaunchInfo info;
auto result = database->GetLaunchInfoById(&info, data.titleId);
delete database;
delete fileStream;
FSDelClient(fsClient, FS_ERROR_FLAG_NONE);
free(fsClient);
auto result = launchInfoDatabase.GetLaunchInfoById(&info, data.launchInfoDatabaseEntryId);
nn::sl::Finalize();
@ -125,6 +220,17 @@ bool getQuickBoot() {
return false;
}
if ((info.titleId & TITLE_ID_HOMEBREW_MASK) == TITLE_ID_HOMEBREW_MASK) {
std::string homebrewPath = info.parameter;
DEBUG_FUNCTION_LINE("Trying to launch homebrew title: \"%s\"", homebrewPath.c_str());
if (auto err = RPXLoader_LaunchHomebrew(homebrewPath.c_str()); err != RPX_LOADER_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_WARN("Failed to launch homebrew title: %s (%d)", RPXLoader_GetStatusStr(err), err);
return false;
}
return true;
}
if (info.titleId == 0x0005001010040000L ||
info.titleId == 0x0005001010040100L ||
info.titleId == 0x0005001010040200L) {
@ -132,6 +238,14 @@ bool getQuickBoot() {
return false;
}
if (info.titleId == 0x0005001010047000L ||
info.titleId == 0x0005001010047100L ||
info.titleId == 0x0005001010047200L) {
DEBUG_FUNCTION_LINE("Launch System Settings");
_SYSLaunchSettings(nullptr);
return true;
}
if (info.titleId == 0x000500301001220AL ||
info.titleId == 0x000500301001210AL ||
info.titleId == 0x000500301001200AL) {

View File

@ -1,3 +1,3 @@
#pragma once
bool getQuickBoot();
bool launchQuickStartTitle();

View File

@ -90,23 +90,21 @@ void initExternalStorage() {
// the lib before actually using it.
return;
}
int connectedStorage = 0;
if ((connectedStorage = numberUSBStorageDevicesConnected()) <= 0) {
nn::spm::Initialize();
InitEmptyExternalStorage();
nn::spm::Finalize();
return;
int numConnectedStorage;
int maxTries = 1200; // Wait up to 20 seconds, like the Wii U Menu
if ((numConnectedStorage = numberUSBStorageDevicesConnected()) <= 0) {
maxTries = 1; // Only try once if no USBStorageDrive is connected
} else {
DEBUG_FUNCTION_LINE("Connected StorageDevices = %d", numConnectedStorage);
}
DEBUG_FUNCTION_LINE("Connected StorageDevices = %d", connectedStorage);
nn::spm::Initialize();
nn::spm::StorageListItem items[0x20];
int tries = 0;
bool found = false;
while (tries < 1200) { // Wait up to 20 seconds, like the Wii U Menu
while (tries < maxTries) {
int32_t numItems = nn::spm::GetStorageList(items, 0x20);
DEBUG_FUNCTION_LINE("Number of items: %d", numItems);
@ -127,7 +125,7 @@ void initExternalStorage() {
}
}
}
if (found || (connectedStorage == numItems)) {
if (found || (numConnectedStorage == numItems)) {
DEBUG_FUNCTION_LINE("Found all expected items, breaking.");
break;
}
@ -135,7 +133,9 @@ void initExternalStorage() {
tries++;
}
if (!found) {
DEBUG_FUNCTION_LINE("USB Storage is connected but either it doesn't have a WFS partition or we ran into a timeout.");
if (numConnectedStorage > 0) {
DEBUG_FUNCTION_LINE("USB Storage is connected but either it doesn't have a WFS partition or we ran into a timeout.");
}
InitEmptyExternalStorage();
}

View File

@ -41,6 +41,7 @@ extern "C" {
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "## WARN## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "## INFO## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS);
@ -58,6 +59,7 @@ extern "C" {
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "## WARN## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "## INFO## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS);

View File

@ -7,12 +7,15 @@
#include "logger.h"
#include <coreinit/debug.h>
#include <coreinit/filesystem_fsa.h>
#include <coreinit/title.h>
#include <gx2/state.h>
#include <malloc.h>
#include <mocha/mocha.h>
#include <rpxloader/rpxloader.h>
#include <sndcore2/core.h>
#include <string>
#include <sys/stat.h>
#include <sysapp/launch.h>
#include <vpad/input.h>
void clearScreen() {
@ -28,6 +31,8 @@ void clearScreen() {
free(buffer);
}
bool gUpdatesBlocked = false;
int32_t main(int32_t argc, char **argv) {
initLogging();
DEBUG_FUNCTION_LINE("Hello from Autoboot Module");
@ -41,7 +46,20 @@ int32_t main(int32_t argc, char **argv) {
initExternalStorage();
if (getQuickBoot()) {
// Use librpxloader.
RPXLoaderStatus error3;
if ((error3 = RPXLoader_InitLibrary()) != RPX_LOADER_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("AutobootModule: Failed to init RPXLoader. This can be ignored when not running Aroma. Error %s [%d]", RPXLoader_GetStatusStr(error3), error3);
}
// If we are in System Transfer context we need to restart the app to actually
if (OSGetTitleID() == 0x0005001010062000L || OSGetTitleID() == 0x0005001010062100L || OSGetTitleID() == 0x0005001010062200L) {
_SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), nullptr);
deinitLogging();
return 0;
}
if (launchQuickStartTitle()) {
deinitLogging();
return 0;
}
@ -60,7 +78,16 @@ int32_t main(int32_t argc, char **argv) {
FSADirectoryHandle dirHandle{};
if (FSAOpenDir(client, "/vol/storage_mlc01/sys/update", &dirHandle) >= 0) {
FSACloseDir(client, dirHandle);
gUpdatesBlocked = false;
handleUpdateWarningScreen();
} else {
FSAStat st{};
if (FSAGetStat(client, "/vol/storage_mlc01/sys/update", &st) != FS_ERROR_OK) {
DEBUG_FUNCTION_LINE_INFO("Created \"/vol/storage_mlc01/sys/update\" as file");
FSAFileHandle fd;
FSAOpenFileEx(client, "/vol/storage_mlc01/sys/update", "w", static_cast<FSMode>(0x666), FS_OPEN_FLAG_NONE, 0, &fd);
}
gUpdatesBlocked = true;
}
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to unlock FSA Client");

View File

@ -1 +1,3 @@
#pragma once
extern bool gUpdatesBlocked;

View File

@ -1,5 +1,7 @@
#include "logger.h"
#include <coreinit/filesystem_fsa.h>
#include <coreinit/mcp.h>
#include <mocha/mocha.h>
bool GetTitleIdOfDisc(uint64_t *titleId, bool *discPresent) {
if (discPresent) {
@ -30,4 +32,48 @@ bool GetTitleIdOfDisc(uint64_t *titleId, bool *discPresent) {
}
}
return false;
}
bool DeleteMLCUpdateDirectory() {
bool result = false;
auto client = FSAAddClient(nullptr);
if (client > 0) {
if (Mocha_UnlockFSClientEx(client) == MOCHA_RESULT_SUCCESS) {
if (FSARemove(client, "/vol/storage_mlc01/sys/update") != FS_ERROR_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to remove update directory");
} else {
FSAFileHandle fd;
if (FSAOpenFileEx(client, "/vol/storage_mlc01/sys/update", "w", static_cast<FSMode>(0x666), FS_OPEN_FLAG_NONE, 0, &fd) != FS_ERROR_OK) {
DEBUG_FUNCTION_LINE_WARN("Failed to create update file");
}
result = true;
}
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to unlock FSA Client");
}
FSADelClient(client);
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to create FSA Client");
}
return result;
}
bool RestoreMLCUpdateDirectory() {
bool result = false;
auto client = FSAAddClient(nullptr);
if (client > 0) {
if (Mocha_UnlockFSClientEx(client) == MOCHA_RESULT_SUCCESS) {
FSARemove(client, "/vol/storage_mlc01/sys/update"); // Remove any existing files
if (FSAMakeDir(client, "/vol/storage_mlc01/sys/update", static_cast<FSMode>(0x666)) != FS_ERROR_OK) {
DEBUG_FUNCTION_LINE_WARN("Failed to restore update directory");
}
result = true;
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to unlock FSA Client");
}
FSADelClient(client);
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to create FSA Client");
}
return result;
}

View File

@ -28,4 +28,8 @@ std::string string_format(const std::string &format, Args... args) {
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}
bool GetTitleIdOfDisc(uint64_t *titleId, bool *discPresent);
bool GetTitleIdOfDisc(uint64_t *titleId, bool *discPresent);
bool DeleteMLCUpdateDirectory();
bool RestoreMLCUpdateDirectory();