work in progress

This commit is contained in:
Naim2000 2025-02-12 21:28:36 -05:00
parent 62205f9ab5
commit c86808e911
30 changed files with 993 additions and 1586 deletions

View File

@ -28,7 +28,7 @@ INCLUDES :=
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS = -Os -Wall $(MACHDEP) $(INCLUDE)
CFLAGS = -g -Os -Wall $(MACHDEP) $(INCLUDE)
CXXFLAGS = $(CFLAGS)
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map
@ -128,9 +128,9 @@ $(OUTPUT).dol: $(OUTPUT).elf
$(OUTPUT).elf: $(OFILES)
#---------------------------------------------------------------------------------
# This rule links in binary data with the .jpg extension
# This rule links in binary data with the .png extension
#---------------------------------------------------------------------------------
%.jpg.o : %.jpg
%.png.o : %.png
#---------------------------------------------------------------------------------
@echo $(notdir $<)
$(bin2o)

View File

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

@ -1,3 +1,6 @@
#define WII_LIGHT_OFF 0
#define WII_LIGHT_ON 1
void WIILIGHT_Init();
void WIILIGHT_TurnOn();
int WIILIGHT_GetLevel();

View File

@ -1,23 +1,25 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "fileops.h"
#include "malloc.h"
static struct stat st;
#include "utils.h"
bool FSOPFileExists(const char* file)
{
struct stat st;
return !stat(file, &st) && !S_ISDIR(st.st_mode);
}
bool FSOPFolderExists(const char* path)
{
struct stat st;
return !stat(path, &st) && S_ISDIR(st.st_mode);
}
size_t FSOPGetFileSizeBytes(const char* path)
{
struct stat st;
if (stat(path, &st) < 0) return 0;
return st.st_size;
@ -56,17 +58,20 @@ void FSOPMakeFolder(const char* path)
s32 FSOPReadOpenFile(FILE* fp, void* buffer, u32 offset, u32 length)
{
fseek(fp, offset, SEEK_SET);
return fread(buffer, length, 1, fp);
if (!fread(buffer, length, 1, fp))
return -errno ?: -1;
return 0;
}
s32 FSOPReadOpenFileA(FILE* fp, void** buffer, u32 offset, u32 length)
{
*buffer = memalign32(length);
if (!*buffer)
return -1;
return -ENOMEM;
s32 ret = FSOPReadOpenFile(fp, *buffer, offset, length);
if (ret <= 0)
if (ret < 0)
{
free(*buffer);
*buffer = NULL;

View File

@ -3,12 +3,10 @@
// Constants
#define CIOS_VERSION 249
#define ENTRIES_PER_PAGE 12
#define MAX_FILE_PATH_LEN 1024
#define WAD_DIRECTORY "/"
#define WAD_ROOT_DIRECTORY "/wad/"
#define DEFAULT_WAD_DIRECTORY "/wad/"
#define MAX_PASSWORD_LENGTH 10
#define MAX_PASSWORD_LENGTH 16
#define MAX_FAT_DEVICE_LENGTH 10
#define MAX_NAND_DEVICE_LENGTH 10
@ -19,27 +17,23 @@
#define NAND_DEVICE_INDEX_INVALID -1
#define CIOS_VERSION_INVALID -1
// For the WiiLight
#define WII_LIGHT_OFF 0
#define WII_LIGHT_ON 1
typedef struct
typedef struct wm_config
{
char password[MAX_PASSWORD_LENGTH];
char startupPath [256];
int cIOSVersion;
int fatDeviceIndex;
int nandDeviceIndex;
char startupPath[256];
int cIOSVersion;
int fatDeviceIndex;
int nandDeviceIndex;
/*
const char *smbuser;
const char *smbpassword;
const char *share;
const char *ip;
} CONFIG;
*/
} CONFIG, wm_config_t;
extern CONFIG gConfig;
extern nandDevice ndevList[];
//extern fatDevice fdevList[];
extern wm_config_t gConfig;
#endif

View File

@ -2,80 +2,61 @@
#include <stdlib.h>
#include <ogcsys.h>
#include "gui.h"
#include "video.h"
#include "fat.h"
#include "menu.h"
#include "nand.h"
#include "pngu.h"
#include "globals.h"
#include "fileops.h"
#include "background_png.h"
/* Constants */
#define CONSOLE_XCOORD 70
#define CONSOLE_YCOORD 114
#define CONSOLE_WIDTH 502
#define CONSOLE_HEIGHT 300
static const GuiWindow s_defaultBackgroundData = {
.pngData = background_png,
.pngTarget = { 0, 0 },
s32 __Gui_DrawPng(void *img, u32 x, u32 y)
.consoleTarget = { 70, 114 },
.consoleWidth = 502,
.consoleHeight = 300,
// .consoleTarget = { 32, 32 },
// .consoleWidth = 640 - 64,
// .consoleHeight = 480 - 64,
};
s32 Gui_InitConsole(const GuiWindow *window)
{
s32 ret = 0;
IMGCTX ctx = NULL;
PNGUPROP imgProp;
char path[1024];
s32 ret = -1;
s32 i;
for (i = 0; i < FatGetDeviceCount(); i++)
{
snprintf(path, sizeof(path), "%s:%s", FatGetDevicePrefix(i), WM_BACKGROUND_PATH);
if (FSOPFileExists(path))
{
ctx = PNGU_SelectImageFromDevice(path);
break;
}
}
if (!window)
window = &s_defaultBackgroundData;
if(!ctx)
if (window->pngData)
{
/* Select PNG data */
ctx = PNGU_SelectImageFromBuffer(img);
if (!ctx) {
ret = -1;
ctx = PNGU_SelectImageFromBuffer(window->pngData);
if (!ctx)
return -12;
/* Get image properties */
ret = PNGU_GetImageProperties(ctx, &imgProp);
if (ret != PNGU_OK)
goto out;
}
}
/* Get image properties */
ret = PNGU_GetImageProperties(ctx, &imgProp);
if (ret != PNGU_OK) {
ret = -1;
goto out;
/* Draw image */
Video_DrawPng(ctx, imgProp, window->pngTarget.x, window->pngTarget.y);
}
/* Draw image */
Video_DrawPng(ctx, imgProp, x, y);
/* Success */
ret = 0;
/* Initialize console */
Con_Init(window->consoleTarget.x, window->consoleTarget.y, window->consoleWidth, window->consoleHeight);
// Con_Init(32, 32, 640 - 64, 480 - 64);
out:
/* Free memory */
if (ctx)
PNGU_ReleaseImageContext(ctx);
return ret;
return -ret;
}
void Gui_InitConsole(void)
{
/* Initialize console */
Con_Init(CONSOLE_XCOORD, CONSOLE_YCOORD, CONSOLE_WIDTH, CONSOLE_HEIGHT);
}
void Gui_DrawBackground(void)
{
extern char bgData[];
/* Draw background */
__Gui_DrawPng(bgData, 0, 0);
}

View File

@ -1,8 +1,15 @@
#ifndef _GUI_H_
#define _GUI_H_
typedef struct { u16 x, y; } point;
typedef struct GuiWindow {
const void *pngData;
point pngTarget;
point consoleTarget; // top left
u16 consoleWidth, consoleHeight;
} GuiWindow;
/* Prototypes */
void Gui_InitConsole(void);
void Gui_DrawBackground(void);
s32 Gui_InitConsole(const GuiWindow *);
#endif

View File

@ -10,71 +10,89 @@
// Copyright 2010 Joseph Jordan <joe.ftpii@psychlaw.com.au>
// Wii U vWii patches Copyright 2012/2013 damysteryman
#include <stdio.h>
#include <gccore.h>
#include <ogc/machine/processor.h>
/* memmem says hi */
#define _GNU_SOURCE
#include <string.h>
#include <unistd.h>
#include <ogc/ipc.h>
#include "iospatch.h"
#include "sys.h"
#define MEM_REG_BASE 0xd8b4000
#define MEM_PROT (MEM_REG_BASE + 0x20a)
static void disable_memory_protection() {
write32(MEM_PROT, read32(MEM_PROT) & 0x0000FFFF);
// I don't like hardcoding binary blobs like this either. We'll get serious later okay
static const u32 armCode[] = {
0xE3A00536, /* mov r0, #0x0D800000 */
0xE5901060, /* ldr r1, [r0, #0x60] */
0xE3811008, /* orr r1, #0x08 */
0xE5801060, /* str r1, [r0, #0x60] */
0xE5901064, /* ldr r1, [r0, #0x64] */
0xE381113A, /* orr r1, #0x8000000E */
0xE3811EDF, /* orr r1, #0x00000DF0 */
0xE5801064, /* str r1, [r0, #0x64] */
0xE12FFF1E, /* bx lr */
};
/*
* https://github.com/WiiLink24/wfc-patcher-wii/blob/main/launcher/source/IOS.cpp#L168-L171
*/
int do_sha_exploit(u32 addr) {
int ret;
int fd = 0x10001;
ioctlv vecs[3] ATTRIBUTE_ALIGN(0x20) = {};
vecs[0].data = NULL;
vecs[0].len = 0;
vecs[1].data = (void *)0xFFFE0028;
vecs[1].len = 0;
u32 *mem1 = (u32 *)0x80000000;
*mem1++ = 0x4903468D;
*mem1++ = 0x49034788;
*mem1++ = 0x49036209;
*mem1++ = 0x47080000;
*mem1++ = 0x10100000;
*mem1++ = MEM_VIRTUAL_TO_PHYSICAL(addr);
*mem1++ = 0xFFFF0014;
vecs[2].data = mem1;
vecs[2].len = 0x20;
ret = IOS_Ioctlv(fd, 0, 1, 2, vecs);
return ret;
}
static u32 apply_patch(char *name, const u8 *old, u32 old_size, const u8 *patch, u32 patch_size, u32 patch_offset) {
u8 *ptr_start = (u8*)*((u32*)0x80003134), *ptr_end = (u8*)0x94000000;
u32 found = 0;
// printf(" Patching %-30s", name);
u8 *location = NULL;
while (ptr_start < (ptr_end - patch_size)) {
if (!memcmp(ptr_start, old, old_size)) {
found++;
location = ptr_start + patch_offset;
u8 *start = location;
u32 i;
for (i = 0; i < patch_size; i++) {
*location++ = patch[i];
}
DCFlushRange((u8 *)(((u32)start) >> 5 << 5), (patch_size >> 5 << 5) + 64);
ICInvalidateRange((u8 *)(((u32)start) >> 5 << 5), (patch_size >> 5 << 5) + 64);
}
ptr_start++;
static u32 apply_patch(const void *old, u32 old_size, const void *patch, u32 patch_size, u32 patch_offset) {
void *ptr_start = (void *)0x933E0000;
void *ptr_end = (void *)0x94000000;
u32 found;
for (found = 0; ptr_start < ptr_end; found++) {
ptr_start = memmem(ptr_start, ptr_end - ptr_start, old, old_size);
if (!ptr_start)
break;
memcpy(ptr_start + patch_offset, patch, patch_size);
DCFlushRange(ptr_start + patch_offset, patch_size);
ptr_start += patch_offset + patch_size;
}
// if (found)
// printf(" patched\n");
// else
// printf(" not patched\n");
return found;
}
/*
static const u8 di_readlimit_old[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0A, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
0x7E, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08
};
static const u8 di_readlimit_patch[] = { 0x7e, 0xd4 };
const u8 isfs_permissions_old[] = { 0x42, 0x8B, 0xD0, 0x01, 0x25, 0x66 };
const u8 isfs_permissions_patch[] = { 0x42, 0x8B, 0xE0, 0x01, 0x25, 0x66 };
static const u8 setuid_old[] = { 0xD1, 0x2A, 0x1C, 0x39 };
static const u8 setuid_patch[] = { 0x46, 0xC0 };
const u8 es_identify_old[] = { 0x28, 0x03, 0xD1, 0x23 };
const u8 es_identify_patch[] = { 0x00, 0x00 };*/
const u8 hash_old[] = { 0x20, 0x07, 0x23, 0xA2 };
const u8 hash_patch[] = { 0x00 };
const u8 new_hash_old[] = { 0x20, 0x07, 0x4B, 0x0B };
const u8 es_set_ahbprot_old[] = { 0x68, 0x5B, 0x22, 0xEC, 0x00, 0x52, 0x18, 0x9B, 0x68, 0x1B, 0x46, 0x98, 0x07, 0xDB };
const u8 es_set_ahbprot_patch[] = { 0x01 };
const u8 ES_TitleVersionCheck_old[] = { 0xD2, 0x01, 0x4E, 0x56 };
const u8 ES_TitleVersionCheck_old[] = { 0xD2, 0x01, 0x4E, 0x56 };
const u8 ES_TitleVersionCheck_patch[] = { 0xE0, 0x01, 0x4E, 0x56 };
const u8 ES_TitleDeleteCheck_old[] = { 0xD8, 0x00, 0x4A, 0x04 };
const u8 ES_TitleDeleteCheck_old[] = { 0xD8, 0x00, 0x4A, 0x04 };
const u8 ES_TitleDeleteCheck_patch[] = { 0xE0, 0x00, 0x4A, 0x04 };
const u8 isfs_permissions_old[] = { 0x9B, 0x05, 0x40, 0x03, 0x99, 0x05, 0x42, 0x8B, };
const u16 ES_KeyslotPermissionCheck_old[] = { 0x2d06, 0xd000, 0x4803 };
const u16 ES_KeyslotPermissionCheck_patch[] = { 0x2d06, 0xe000, 0x4803 };
const u8 isfs_permissions_old[] = { 0x9B, 0x05, 0x40, 0x03, 0x99, 0x05, 0x42, 0x8B, };
const u8 isfs_permissions_patch[] = { 0x9B, 0x05, 0x40, 0x03, 0x1C, 0x0B, 0x42, 0x8B, };
//Following patches made my damysteryman for use with Wii U's vWii
@ -85,34 +103,102 @@ const u8 Kill_AntiSysTitleInstallv3_pt2_patch[] = { 0x46, 0xC0, 0x33, 0x06, 0x42
const u8 Kill_AntiSysTitleInstallv3_pt3_old[] = { 0x68, 0xFB, 0x2B, 0x00, 0xDB, 0x01 };
const u8 Kill_AntiSysTitleInstallv3_pt3_patch[] = { 0x68, 0xFB, 0x2B, 0x00, 0xDB, 0x10 };
u32 IOSPATCH_AHBPROT() {
if (AHBPROT_DISABLED) {
write32(MEM_PROT, read32(MEM_PROT) & 0x0000FFFF);
//return apply_patch("set_ahbprot", check_tmd_old, sizeof(check_tmd_old), check_tmd_patch, sizeof(check_tmd_patch), 6);
return apply_patch("es_set_ahbprot", es_set_ahbprot_old, sizeof(es_set_ahbprot_old), es_set_ahbprot_patch, sizeof(es_set_ahbprot_patch), 25);
static inline bool validJumptablePtr(uint32_t x) {
return (x >= 0xFFFF0040) && (x < 0xFFFFF000) && ((x & 3) == 0);
}
#define SRAMNOMIRR(x) (x - 0xF2B00000)
static u32 findTheSyscallTable(void) {
u32 undfInstruction = read32(0xD4F0004);
if ((undfInstruction & 0xFFFFF000) != 0xE59FF000 /* ldr pc, [pc, something] */)
// SRNPROT is probably on
return 0;
u32 undfHandler = read32(0xD4F0004 + 8 /* pc is 2 steps ahead */ + (undfInstruction & 0xFFF));
if (!validJumptablePtr(undfHandler))
// Eh?
return 0;
undfHandler = SRAMNOMIRR(undfHandler);
// arbitrary number. don't plan to go far
for (int i = 0; i < 0x80; i += 4) {
undfInstruction = read32(undfHandler + i);
if ((undfInstruction & 0xFFFF0000) == 0xE59F0000) { // find the first thing loaded relative to PC
u32 addr = undfHandler + i + 8 + (undfInstruction & 0xFFF);
// syscall instr mask stack args cnt map the actual syscall table (they are right next to each other)
if (read32(addr) == 0xE6000010 && (read32(addr + 4) - read32(addr + 8)) < 0x400) { // this 0x400 (1024) is from the & 0xFF applied to the syscall # after it gets unmasked
return SRAMNOMIRR(read32(addr + 8)); // the actual syscall table wooooooooo yeahh babyy
}
}
}
return 0;
}
u32 IOSPATCH_Apply() {
u32 count = 0;
if (AHBPROT_DISABLED) {
disable_memory_protection();
//count += apply_patch("di_readlimit", di_readlimit_old, sizeof(di_readlimit_old), di_readlimit_patch, sizeof(di_readlimit_patch), 12);
count += apply_patch("isfs_permissions", isfs_permissions_old, sizeof(isfs_permissions_old), isfs_permissions_patch, sizeof(isfs_permissions_patch), 0);
//count += apply_patch("es_setuid", setuid_old, sizeof(setuid_old), setuid_patch, sizeof(setuid_patch), 0);
//count += apply_patch("es_identify", es_identify_old, sizeof(es_identify_old), es_identify_patch, sizeof(es_identify_patch), 2);
count += apply_patch("hash_check", hash_old, sizeof(hash_old), hash_patch, sizeof(hash_patch), 1);
count += apply_patch("new_hash_check", new_hash_old, sizeof(new_hash_old), hash_patch, sizeof(hash_patch), 1);
count += apply_patch("ES_TitleVersionCheck", ES_TitleVersionCheck_old, sizeof(ES_TitleVersionCheck_old), ES_TitleVersionCheck_patch, sizeof(ES_TitleVersionCheck_patch), 0);
count += apply_patch("ES_TitleDeleteCheck", ES_TitleDeleteCheck_old, sizeof(ES_TitleDeleteCheck_old), ES_TitleDeleteCheck_patch, sizeof(ES_TitleDeleteCheck_patch), 0);
u32 *ptr_syscallTable = NULL;
u32 ptr_IOSC_VerifyPublicKeySign = 0;
static const u16 return0[] = {
0x2000, // mov r0, #0
0x4770, // bx lr
};
if((*(vu16*)0xCD8005A0 == 0xCAFE))
{
count += apply_patch("Kill_AntiSysTitleInstallv3_pt1", Kill_AntiSysTitleInstallv3_pt1_old, sizeof(Kill_AntiSysTitleInstallv3_pt1_old), Kill_AntiSysTitleInstallv3_pt1_patch, sizeof(Kill_AntiSysTitleInstallv3_pt1_patch), 0);
count += apply_patch("Kill_AntiSysTitleInstallv3_pt2", Kill_AntiSysTitleInstallv3_pt2_old, sizeof(Kill_AntiSysTitleInstallv3_pt2_old), Kill_AntiSysTitleInstallv3_pt2_patch, sizeof(Kill_AntiSysTitleInstallv3_pt2_patch), 0);
count += apply_patch("Kill_AntiSysTitleInstallv3_pt3", Kill_AntiSysTitleInstallv3_pt3_old, sizeof(Kill_AntiSysTitleInstallv3_pt3_old), Kill_AntiSysTitleInstallv3_pt3_patch, sizeof(Kill_AntiSysTitleInstallv3_pt3_patch), 0);
}
int IOSPATCH_Apply(void) {
int fd = IOS_Open("/dev/dolphin", 0);
IOS_Close(fd);
if (fd >= 0)
return 0;
int ret = fd = IOS_Open("/dev/sha", 0);
IOS_Close(fd);
if (ret < 0)
return (ret == IPC_ENOENT) ? 0 : ret;
ret = do_sha_exploit((u32)armCode);
if (ret < 0)
return ret;
int clock = 1000;
while (!AHBPROT_DISABLED) {
if (clock-- == 0)
return -0x123;
usleep(1000);
}
return count;
ptr_syscallTable = (u32 *)findTheSyscallTable();
if (!ptr_syscallTable)
return -0x105C;
ptr_IOSC_VerifyPublicKeySign = read32((u32)&ptr_syscallTable[0x6C]);
write16(MEM_PROT, 0);
IOSPATCH_SetSignatureChecks(false);
// apply_patch(hash_old, sizeof(hash_old), hash_patch, sizeof(hash_patch), 1);
// apply_patch(new_hash_old, sizeof(new_hash_old), hash_patch, sizeof(hash_patch), 1);
apply_patch(isfs_permissions_old, sizeof(isfs_permissions_old), isfs_permissions_patch, sizeof(isfs_permissions_patch), 0);
apply_patch(ES_TitleVersionCheck_old, sizeof(ES_TitleVersionCheck_old), ES_TitleVersionCheck_patch, sizeof(ES_TitleVersionCheck_patch), 0);
apply_patch(ES_TitleDeleteCheck_old, sizeof(ES_TitleDeleteCheck_old), ES_TitleDeleteCheck_patch, sizeof(ES_TitleDeleteCheck_patch), 0);
apply_patch(ES_KeyslotPermissionCheck_old, sizeof(ES_KeyslotPermissionCheck_old), ES_KeyslotPermissionCheck_patch, sizeof(ES_KeyslotPermissionCheck_patch), 0);
if (IS_WIIU)
{
apply_patch(Kill_AntiSysTitleInstallv3_pt1_old, sizeof(Kill_AntiSysTitleInstallv3_pt1_old), Kill_AntiSysTitleInstallv3_pt1_patch, sizeof(Kill_AntiSysTitleInstallv3_pt1_patch), 0);
apply_patch(Kill_AntiSysTitleInstallv3_pt2_old, sizeof(Kill_AntiSysTitleInstallv3_pt2_old), Kill_AntiSysTitleInstallv3_pt2_patch, sizeof(Kill_AntiSysTitleInstallv3_pt2_patch), 0);
apply_patch(Kill_AntiSysTitleInstallv3_pt3_old, sizeof(Kill_AntiSysTitleInstallv3_pt3_old), Kill_AntiSysTitleInstallv3_pt3_patch, sizeof(Kill_AntiSysTitleInstallv3_pt3_patch), 0);
}
return 0;
}
void IOSPATCH_SetSignatureChecks(bool enable)
{
if (!ptr_syscallTable)
return;
u32 new = enable ? ptr_IOSC_VerifyPublicKeySign : (MEM_VIRTUAL_TO_PHYSICAL(return0) | 0x1);
write32((u32)&ptr_syscallTable[0x6C], new);
}

View File

@ -13,20 +13,12 @@
#ifndef _IOSPATCH_H
#define _IOSPATCH_H
#ifdef __cplusplus
extern "C" {
#endif
/* __cplusplus */
#include <gccore.h>
#include <ogc/machine/processor.h>
#define AHBPROT_DISABLED ((*(vu32*)0xcd800064 == 0xFFFFFFFF) ? 1 : 0)
#define AHBPROT_DISABLED (read32(0xcd800064) != 0)
u32 IOSPATCH_AHBPROT();
u32 IOSPATCH_Apply();
#ifdef __cplusplus
}
#endif /* __cplusplus */
int IOSPATCH_Apply();
void IOSPATCH_SetSignatureChecks(bool);
#endif /* _IOSPATCH_H */

View File

@ -1,11 +0,0 @@
#include <stdlib.h>
static inline void *memalign32(size_t size)
{
return aligned_alloc(0x20, (size + 0x1F) & ~0x1F);
}
static inline void *memalign64(size_t size)
{
return aligned_alloc(0x40, (size + 0x3F) & ~0x3F);
}

View File

@ -25,28 +25,13 @@
#include "fileops.h"
#include "menu.h"
/* NAND device list */
nandDevice ndevList[] =
{
{ "Disable", 0, 0x00, 0x00 },
{ "SD/SDHC Card", 1, 0xF0, 0xF1 },
{ "USB 2.0 Mass Storage Device", 2, 0xF2, 0xF3 },
};
static nandDevice *ndev = NULL;
static int gSelected;
static bool gNeedPriiloaderOption = false;
/* Macros */
#define NB_NAND_DEVICES (sizeof(ndevList) / sizeof(nandDevice))
// Local prototypes: wiiNinja
void WaitPrompt (char *prompt);
u32 WaitButtons(void);
u32 Pad_GetButtons(void);
void WiiLightControl (int state);
#define ENTRIES_PER_PAGE (g_consoleHeight - 5)
void PriiloaderRetainedPrompt(void);
@ -68,10 +53,8 @@ static int __Menu_EntryCmp(const void *p1, const void *p2)
fatFile *f2 = (fatFile *)p2;
/* Compare entries */ // wiiNinja: Include directory
if ((f1->isdir) && !(f2->isdir))
return (-1);
else if (!(f1->isdir) && (f2->isdir))
return (1);
if (f1->isdir ^ f2->isdir)
return f2->isdir - f1->isdir;
else
return strcasecmp(f1->filename, f2->filename);
}
@ -104,7 +87,7 @@ static s32 __Menu_RetrieveList(char *inPath, fatFile **outbuf, u32 *outlen)
bool iswad = false;
size_t fsize = 0;
/* Hide entries that start with "._". I hate macOS */
/* Hide entries that start with "._". I hate macOS. */
if (!strncmp(ent->d_name, "._", 2))
continue;
@ -187,7 +170,7 @@ static s32 __Menu_RetrieveList(char *inPath, fatFile **outbuf, u32 *outlen)
void Menu_SelectIOS(void)
{
u8 *iosVersion = NULL;
u8 iosVersions[255] = {};
u32 iosCnt;
u8 tmpVersion;
@ -196,12 +179,12 @@ void Menu_SelectIOS(void)
bool found = false;
/* Get IOS versions */
ret = Title_GetIOSVersions(&iosVersion, &iosCnt);
ret = Title_GetIOSVersions(iosVersions, &iosCnt);
if (ret < 0)
return;
/* Sort list */
qsort(iosVersion, iosCnt, sizeof(u8), __Menu_IsGreater);
qsort(iosVersions, iosCnt, sizeof(u8), __Menu_IsGreater);
if (gConfig.cIOSVersion < 0)
{
@ -218,7 +201,7 @@ void Menu_SelectIOS(void)
/* Set default version */
for (cnt = 0; cnt < iosCnt; cnt++)
{
u8 version = iosVersion[cnt];
u8 version = iosVersions[cnt];
/* Custom IOS available */
//if (version == CIOS_VERSION)
@ -242,7 +225,7 @@ void Menu_SelectIOS(void)
/* Clear console */
Con_Clear();
printf("\t>> Select IOS version to use: < IOS%d >\n\n", iosVersion[selected]);
printf("\t>> Select IOS version to use: < IOS%d >\n\n", iosVersions[selected]);
printf("\t Press LEFT/RIGHT to change IOS version.\n\n");
@ -271,7 +254,7 @@ void Menu_SelectIOS(void)
}
}
u8 version = iosVersion[selected];
u8 version = iosVersions[selected];
if (IOS_GetVersion() != version) {
/* Shutdown subsystems */
@ -280,7 +263,7 @@ void Menu_SelectIOS(void)
/* Load IOS */
if (!loadIOS(version))
if (Sys_LoadIOS(version) != 0)
{
Wpad_Init();
Menu_SelectIOS();
@ -337,14 +320,18 @@ void Menu_FatDevice(void)
* 0xcc - vertical conjuction to right
*/
char horizontal[60];
char horizontal[80];
memset(horizontal, 0xcd, sizeof(horizontal));
printf(" \xc9%.59s\xbb", horizontal);
printf(" \xcc%.14sWelcome to YAWM ModMii Edition!%.14s\xb9", horizontal, horizontal);
printf(" \xc8%.59s\xbc", horizontal);
/*
printf("\xc9%.*s\xbb", g_consoleWidth - 2, horizontal);
//31
printf("\xcc%.*sWelcome to YAWM ModMii Edition!%.*s\xb9", (g_consoleWidth - 33) / 2, horizontal, (g_consoleWidth - 32) / 2, horizontal);
printf("\xc8%.*s\xbc", g_consoleWidth - 2, horizontal);
*/
printf(" Running on IOS%u v%u (AHB access %s)\n\n", iosVersion, iosRevision, AHBPROT_DISABLED ? "enabled" : "disabled");
printf(" -== Welcome to YAWM ModMii Edition! ==-\n");
printf(" Running on IOS%u v%u (%u.%u)\n\n", iosVersion, iosRevision, iosRevision >> 8, iosRevision & 0xFF);
if (VersionIsOriginal(version))
printf(" System menu: %s%c %s\n", GetSysMenuVersionString(version), region ?: '?', GetSysMenuRegionString(region)); // The ? should not appear any more, but, in any case.
@ -476,10 +463,10 @@ void Menu_NandDevice(void)
/* LEFT/RIGHT buttons */
if (buttons & WPAD_BUTTON_LEFT) {
if ((--selected) <= -1)
selected = (NB_NAND_DEVICES - 1);
selected = (ndevCount - 1);
}
if (buttons & WPAD_BUTTON_RIGHT) {
if ((++selected) >= NB_NAND_DEVICES)
if ((++selected) >= ndevCount)
selected = 0;
}
@ -533,20 +520,30 @@ err:
char gTmpFilePath[MAX_FILE_PATH_LEN];
/* Install and/or Uninstall multiple WADs - Leathl */
int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath)
int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath, bool delete)
{
int installCnt = 0;
int uninstallCnt = 0;
int count;
int wadcnt = 0;
int ret = 0;
fatFile* wads[fileCount];
for (fatFile* f = files; f < files + fileCount; f++) {
if (f->install == 1) installCnt++; else
if (f->install == 2) uninstallCnt++;
switch (f->install) {
case 1:
wads[wadcnt++] = f;
installCnt++;
break;
case 2:
wads[wadcnt++] = f;
uninstallCnt++;
break;
}
}
if (!(installCnt || uninstallCnt))
return 0;
/*
for (;;)
{
Con_Clear();
@ -678,6 +675,139 @@ int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath)
}
}
}
*/
char *ptr_fname = gTmpFilePath + sprintf(gTmpFilePath, "%s/", inFilePath);
int start = 0; // No cursor here so we just need start
while (true)
{
Con_Clear();
printf("[+] List of WADs to %sinstall%s:\n\n", uninstallCnt ? "(un)" : "", delete ? " and delete" : "");
for (int i = 0; i < ENTRIES_PER_PAGE; i++)
{
int index = start + i;
if (index >= wadcnt) // Data store interrupt safety!!
putchar('\n');
else
printf(" %c %.50s\n", " +-"[wads[index]->install], wads[index]->filename);
}
putchar('\n');
puts("[+] A: Continue UP/DOWN: Move list");
puts(" B: Cancel -/R: Toggle deletion");
u32 buttons = WaitButtons();
if (buttons & WPAD_BUTTON_UP)
{
if (start) start--;
}
else if (buttons & WPAD_BUTTON_DOWN)
{
if (wadcnt - start > ENTRIES_PER_PAGE) start++;
}
else if (buttons & WPAD_BUTTON_A)
{
break;
}
else if (buttons & WPAD_BUTTON_B)
{
return 0;
}
else if (buttons & WPAD_BUTTON_MINUS)
{
delete ^= true;
}
}
WiiLightControl(WII_LIGHT_ON);
for (int i = 0; i < wadcnt; i++)
{
fatFile *f = wads[i];
FILE *fp = NULL;
Con_Clear();
printf("[+] Processing WAD %i/%i...\n\n", i + 1, wadcnt);
printf("[+] Opening \"%s\", please wait... ", f->filename);
strcpy(ptr_fname, f->filename);
fp = fopen(gTmpFilePath, "rb");
if (!fp)
{
printf("ERROR!\n");
perror(" ");
f->installstate = ret = -996;
}
else
{
puts("OK!");
printf(" >> %s WAD...\n", f->install == 1 ? "Installing" : "Uninstalling");
f->installstate = ret = (f->install == 1 ? Wad_Install : Wad_Uninstall)(fp);
fclose(fp);
if (!ret)
{
if (delete)
{
printf(" >> Deleting WAD... ");
// ret = FSOPDeleteFile(gTmpFilePath);
ret = remove(gTmpFilePath);
if (!ret)
puts("OK!");
else
printf("ERROR! (errno=%i)\n", errno);
}
} else
if (ret == -1010)
{
do { wads[i++]->installstate = -1010; } while (i < wadcnt);
WaitPrompt("Wii System Memory is full. Installation terminated...\n");
break;
}
}
usleep((!ret) ? 500000 : 4000000);
continue;
}
start = 0;
while (true)
{
Con_Clear();
printf("[+] End results:\n\n");
for (int i = 0; i < ENTRIES_PER_PAGE; i++)
{
int index = start + i;
if (index >= wadcnt) // Data store interrupt safety!!
putchar('\n');
else
printf(" %-.32s: %s\n", wads[index]->filename, wad_strerror(wads[index]->installstate));
}
putchar('\n');
puts("[+] A: Continue UP/DOWN: Move list");
u32 buttons = WaitButtons();
if (buttons & WPAD_BUTTON_UP)
{
if (start) start--;
}
else if (buttons & WPAD_BUTTON_DOWN)
{
if (wadcnt - start > ENTRIES_PER_PAGE) start++;
}
else if (buttons & WPAD_BUTTON_A)
{
break;
}
}
if (gNeedPriiloaderOption)
{
@ -685,11 +815,6 @@ int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath)
gNeedPriiloaderOption = false;
}
else
{
printf("\n Press any button to continue...\n");
WaitButtons();
}
return 1;
}
@ -761,15 +886,11 @@ int Menu_FolderOperations(fatFile* file, char* path)
{
int ret;
char workpath[MAX_FILE_PATH_LEN];
fatFile *flist = NULL;
unsigned int fcnt = 0;
unsigned int wadcnt = 0;
char* ptr_fname = workpath + sprintf(workpath, "%s%s/", path, file->filename);
ret = __Menu_RetrieveList(workpath, &flist, &fcnt);
ret = __Menu_RetrieveList(path, &flist, &fcnt);
if (ret != 0)
{
WaitPrompt("__Menu_RetrieveList failed");
@ -802,6 +923,7 @@ int Menu_FolderOperations(fatFile* file, char* path)
if (buttons & (WPAD_BUTTON_LEFT | WPAD_BUTTON_RIGHT))
mode ^= 1;
if (buttons & WPAD_BUTTON_A)
break;
@ -815,128 +937,10 @@ int Menu_FolderOperations(fatFile* file, char* path)
goto finish;
}
int start = 0; // No cursor here so we just need start
while (true)
{
Con_Clear();
printf("[+] List of WADs to %s:\n\n", mode ? "install and delete" : "install");
for (int i = 0; i < ENTRIES_PER_PAGE; i++)
{
int index = start + i;
if (index >= wadcnt) // Data store interrupt safety!!
putchar('\n');
else
printf(" %.50s\n", wads[index]->filename);
}
putchar('\n');
printf("[+] Press UP/DOWN to move list.\n");
printf(" Press A to continue.\n");
printf(" Press B to cancel.");
u32 buttons = WaitButtons();
if (buttons & WPAD_BUTTON_UP)
{
if (start) start--;
}
else if (buttons & WPAD_BUTTON_DOWN)
{
if (wadcnt - start > ENTRIES_PER_PAGE) start++;
}
else if (buttons & WPAD_BUTTON_A)
{
break;
}
else if (buttons & WPAD_BUTTON_B)
{
goto finish;
}
}
for (int i = 0; i < wadcnt; i++)
{
fatFile *f = wads[i];
FILE *fp = NULL;
wads[i]->install = 1;
Con_Clear();
printf("[+] Processing WAD %i/%i...\n\n", i + 1, wadcnt);
printf("[+] Opening \"%s\", please wait...\n", f->filename);
strcpy(ptr_fname, f->filename);
fp = fopen(workpath, "rb");
if (!fp)
{
printf(" ERROR! (errno=%i)\n", errno);
}
else
{
// puts(">> Installing WAD...");
f->installstate = ret = Wad_Install(fp);
fclose(fp);
if (!ret)
{
if (mode == 1)
{
printf(">> Deleting WAD... ");
// ret = FSOPDeleteFile(workpath);
ret = remove(workpath);
if (!ret)
puts("OK!");
else
printf("ERROR! (errno=%i)\n", errno);
}
}
else if (ret == -1010)
{
do { wads[i++]->installstate = -1010; } while (i < wadcnt);
WaitPrompt("Wii System Memory is full to the brim. Installation terminated...\n");
break;
}
}
usleep((!ret) ? 500000 : 4000000);
continue;
}
start = 0;
while (true)
{
Con_Clear();
printf("[+] End results:\n\n");
for (int i = 0; i < ENTRIES_PER_PAGE; i++)
{
int index = start + i;
if (index >= wadcnt) // Data store interrupt safety!!
putchar('\n');
else
printf(" %-.32s: %s\n", wads[index]->filename, wad_strerror(wads[index]->installstate));
}
putchar('\n');
printf("[+] Press UP/DOWN to move list.\n");
printf(" Press A to continue.");
u32 buttons = WaitButtons();
if (buttons & WPAD_BUTTON_UP)
{
if (start) start--;
}
else if (buttons & WPAD_BUTTON_DOWN)
{
if (wadcnt - start > ENTRIES_PER_PAGE) start++;
}
else if (buttons & WPAD_BUTTON_A)
{
break;
}
}
Menu_BatchProcessWads(flist, fcnt, path, mode == 1);
finish:
free(flist);
@ -1085,7 +1089,7 @@ void Menu_WadList(void)
fflush(stdout);
// if user provides startup directory, try it out first
if (strcmp(gConfig.startupPath, WAD_DIRECTORY) != 0)
if (*gConfig.startupPath != '\0')
{
// replace root dir with provided startup directory
sprintf(tmpPath, "%s:%s", FatGetDevicePrefix(gSelected), gConfig.startupPath);
@ -1098,7 +1102,7 @@ void Menu_WadList(void)
goto getList;
}
sprintf(tmpPath, "%s:%s", FatGetDevicePrefix(gSelected), WAD_DIRECTORY);
sprintf(tmpPath, "%s:/", FatGetDevicePrefix(gSelected));
/* Retrieve filelist */
getList:
@ -1155,23 +1159,25 @@ getList:
if ((cnt - start) >= ENTRIES_PER_PAGE)
break;
/* Print filename */
//printf("\t%2s %s (%.2f MB)\n", (cnt == selected) ? ">>" : " ", file->filename, filesize);
if (file->isdir) // wiiNinja
{
printf("\t%2s [%.40s]\n", (cnt == selected) ? ">>" : " ", file->filename);
printf("\t%2s [%.*s]\n", (cnt == selected) ? ">>" : " ", g_consoleWidth - 7, file->filename);
}
else
{
if(file->iswad)
printf("\t%2s%c%.40s (%.2f MB)\n", (cnt == selected) ? ">>" : " ", " +-"[file->install], file->filename, filesize);
printf("\t%2s%c%.*s (%.2f MB)\n", (cnt == selected) ? ">>" : " ", " +-"[file->install], g_consoleWidth - 7, file->filename, filesize);
else
printf("\t%2s %.40s (%.2f MB)\n", (cnt == selected) ? ">>" : " ", file->filename, filesize);
printf("\t%2s %.*s (%.2f MB)\n", (cnt == selected) ? ">>" : " ", g_consoleWidth - 7, file->filename, filesize);
}
}
putchar('\n');
while ((cnt++ - start) < ENTRIES_PER_PAGE)
putchar('\n');
putchar('\n'); // One more newline!
fatFile *file = &fileList[selected];
// There is only one occurence of /, likely because we are at the root!
bool atRoot = (strchr(tmpPath, '/') == strrchr(tmpPath, '/'));
@ -1197,8 +1203,9 @@ getList:
operationA = "Enter directory";
// "[+] A: Install/Uninstall WAD"
printf("[+] A: %-23s" "B: %s\n", operationA, operationB);
printf(" 1/R: %-23s" "2/L: Enable batch mode", operationR);
unsigned somewidth = g_consoleWidth / 2;
printf("[+] A: %-*s" "B: %-*s\n", somewidth - 9, operationA, somewidth - 6, operationB);
printf(" 1/R: %-*s" "2/L: Enable batch mode", somewidth - 9, operationR);
}
@ -1299,7 +1306,7 @@ getList:
{
if (batchMode)
{
int res = Menu_BatchProcessWads(fileList, fileCnt, tmpPath);
int res = Menu_BatchProcessWads(fileList, fileCnt, tmpPath, false);
if (res == 1)
{
@ -1374,15 +1381,6 @@ err:
void Menu_Loop(void)
{
u8 iosVersion;
if (AHBPROT_DISABLED)
{
IOSPATCH_Apply();
}
else
{
/* Select IOS menu */
Menu_SelectIOS();
}
/* Retrieve IOS version */
iosVersion = IOS_GetVersion();
@ -1463,10 +1461,12 @@ char *PeekCurrentDir (void)
}
#endif
void WaitPrompt (char *prompt)
void WaitPrompt (const char *prompt)
{
printf("\n%s", prompt);
printf(" Press any button to continue...\n");
if (prompt)
printf("\n%s", prompt);
printf(" Press any button to continue...\n");
/* Wait for button */
WaitButtons();
@ -1633,10 +1633,10 @@ void WiiLightControl (int state)
void PriiloaderRetainedPrompt(void)
{
puts(" Priiloader has been retained, but all hacks were reset.\n");
puts(" Priiloader has been retained, but all hacks were reset.\n");
puts(" Press A launch Priiloader now.");
puts(" Press any other button to continue...");
puts(" Press A launch Priiloader now.");
puts(" Press any other button to continue...");
u32 buttons = WaitButtons();

View File

@ -2,6 +2,9 @@
#define _MENU_H_
/* Prototypes */
void WaitPrompt(const char *prompt);
u32 WaitButtons(void);
void WiiLightControl (int state);
void Menu_Loop(void);
void SetPriiloaderOption(bool enabled);
bool MenuTestDevice();

View File

@ -1,267 +0,0 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
SEEPROM support
Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
Copyright (C) 2008, 2009 Haxx Enterprises <bushing@gmail.com>
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
Copyright (C) 2008, 2009 John Kelley <wiidev@kelley.ca>
Copyright (C) 2020 Pablo Curiel "DarkMatterCore" <pabloacurielz@gmail.com>
# This code is licensed to you under the terms of the GNU GPL, version 2;
# see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#include <ogc/machine/processor.h>
#include <unistd.h>
#include <string.h>
#include "mini_seeprom.h"
#define HW_REG_BASE 0xd800000
#define HW_GPIO1OUT (HW_REG_BASE + 0x0e0)
#define HW_GPIO1IN (HW_REG_BASE + 0x0e8)
#define HW_SEEPROM_BLK_SIZE 2
#define HW_SEEPROM_BLK_CNT (SEEPROM_SIZE / HW_SEEPROM_BLK_SIZE)
#define eeprom_delay() usleep(5)
enum {
GP_EEP_CS = 0x000400,
GP_EEP_CLK = 0x000800,
GP_EEP_MOSI = 0x001000,
GP_EEP_MISO = 0x002000
};
static void seeprom_send_bits(u16 value, u8 bits)
{
if (!bits || bits > 16) return;
while(bits--)
{
if (value & (1 << bits))
{
mask32(HW_GPIO1OUT, 0, GP_EEP_MOSI);
} else {
mask32(HW_GPIO1OUT, GP_EEP_MOSI, 0);
}
eeprom_delay();
mask32(HW_GPIO1OUT, 0, GP_EEP_CLK);
eeprom_delay();
mask32(HW_GPIO1OUT, GP_EEP_CLK, 0);
eeprom_delay();
}
}
static u16 seeprom_recv_bits(u8 bits)
{
if (!bits || bits > 16) return 0;
int res = 0;
while(bits--)
{
res <<= 1;
mask32(HW_GPIO1OUT, 0, GP_EEP_CLK);
eeprom_delay();
mask32(HW_GPIO1OUT, GP_EEP_CLK, 0);
eeprom_delay();
res |= !!(read32(HW_GPIO1IN) & GP_EEP_MISO);
}
return (u16)res;
}
u16 seeprom_read(void *dst, u16 offset, u16 size)
{
/*
* WiiUBrew told me that you interact with the SEEPROM the exact same way you do on Wii.
* However the contents are way different. Like there's absolutely no vWii stuff here.
*/
if (read16(0xCD8005A0) == 0xCAFE) return 0;
if (!dst || offset >= SEEPROM_SIZE || !size || (offset + size) > SEEPROM_SIZE) return 0;
u16 cur_offset = 0;
u8 *ptr = (u8*)dst;
u8 val[HW_SEEPROM_BLK_SIZE] = {0};
// Calculate block offsets and sizes
u8 start_addr = (u8)(offset / HW_SEEPROM_BLK_SIZE);
u8 start_addr_offset = (u8)(offset % HW_SEEPROM_BLK_SIZE);
u8 end_addr = (u8)((offset + size) / HW_SEEPROM_BLK_SIZE);
u8 end_addr_size = (u8)((offset + size) % HW_SEEPROM_BLK_SIZE);
if (!end_addr_size)
{
end_addr--;
end_addr_size = HW_SEEPROM_BLK_SIZE;
}
if (end_addr == start_addr) end_addr_size -= start_addr_offset;
mask32(HW_GPIO1OUT, GP_EEP_CLK, 0);
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
for(u16 i = start_addr; i <= end_addr; i++)
{
if (cur_offset >= size) break;
// Start command cycle
mask32(HW_GPIO1OUT, 0, GP_EEP_CS);
// Send read command + address
seeprom_send_bits(0x600 | i, 11);
// Receive data
*((u16*)val) = seeprom_recv_bits(16);
// End of command cycle
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
// Copy read data to destination buffer
if (i == start_addr && start_addr_offset != 0)
{
// Handle unaligned read at start address
memcpy(ptr + cur_offset, val + start_addr_offset, HW_SEEPROM_BLK_SIZE - start_addr_offset);
cur_offset += (HW_SEEPROM_BLK_SIZE - start_addr_offset);
} else
if (i == end_addr && end_addr_size != HW_SEEPROM_BLK_SIZE)
{
// Handle unaligned read at end address
memcpy(ptr + cur_offset, val, end_addr_size);
cur_offset += end_addr_size;
} else {
// Normal read
memcpy(ptr + cur_offset, val, HW_SEEPROM_BLK_SIZE);
cur_offset += HW_SEEPROM_BLK_SIZE;
}
}
return cur_offset;
}
#if 0
u16 seeprom_write(const void *src, u16 offset, u16 size)
{
if (!src || offset >= SEEPROM_SIZE || !size || (offset + size) > SEEPROM_SIZE) return 0;
u32 level = 0;
u16 cur_offset = 0;
const u8 *ptr = (const u8*)src;
u8 val[HW_SEEPROM_BLK_SIZE] = {0};
// Calculate block offsets and sizes
u8 start_addr = (u8)(offset / HW_SEEPROM_BLK_SIZE);
u8 start_addr_offset = (u8)(offset % HW_SEEPROM_BLK_SIZE);
u8 end_addr = (u8)((offset + size) / HW_SEEPROM_BLK_SIZE);
u8 end_addr_size = (u8)((offset + size) % HW_SEEPROM_BLK_SIZE);
if (!end_addr_size)
{
end_addr--;
end_addr_size = HW_SEEPROM_BLK_SIZE;
}
if (end_addr == start_addr) end_addr_size -= start_addr_offset;
// Disable CPU interruptions
_CPU_ISR_Disable(level);
mask32(HW_GPIO1OUT, GP_EEP_CLK, 0);
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
// EWEN - Enable programming commands
mask32(HW_GPIO1OUT, 0, GP_EEP_CS);
seeprom_send_bits(0x4FF, 11);
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
for(u16 i = start_addr; i <= end_addr; i++)
{
if (cur_offset >= size) break;
// Copy data to write from source buffer
if ((i == start_addr && start_addr_offset != 0) || (i == end_addr && end_addr_size != HW_SEEPROM_BLK_SIZE))
{
// Read data from SEEPROM to handle unaligned writes
// Start command cycle
mask32(HW_GPIO1OUT, 0, GP_EEP_CS);
// Send read command + address
seeprom_send_bits(0x600 | i, 11);
// Receive data
*((u16*)val) = seeprom_recv_bits(16);
// End of command cycle
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
if (i == start_addr && start_addr_offset != 0)
{
// Handle unaligned write at start address
memcpy(val + start_addr_offset, ptr + cur_offset, HW_SEEPROM_BLK_SIZE - start_addr_offset);
cur_offset += (HW_SEEPROM_BLK_SIZE - start_addr_offset);
} else {
// Handle unaligned write at end address
memcpy(val, ptr + cur_offset, end_addr_size);
cur_offset += end_addr_size;
}
} else {
// Normal write
memcpy(val, ptr + cur_offset, HW_SEEPROM_BLK_SIZE);
cur_offset += HW_SEEPROM_BLK_SIZE;
}
// Start command cycle
mask32(HW_GPIO1OUT, 0, GP_EEP_CS);
// Send write command + address
seeprom_send_bits(0x500 | i, 11);
// Send data
seeprom_send_bits(*((u16*)val), 16);
// End of command cycle
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
// Wait until SEEPROM is ready (write cycle is self-timed so no clocking needed)
mask32(HW_GPIO1OUT, 0, GP_EEP_CS);
do {
eeprom_delay();
} while(!(read32(HW_GPIO1IN) & GP_EEP_MISO));
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
}
// EWDS - Disable programming commands
mask32(HW_GPIO1OUT, 0, GP_EEP_CS);
seeprom_send_bits(0x400, 11);
mask32(HW_GPIO1OUT, GP_EEP_CS, 0);
eeprom_delay();
// Enable CPU interruptions
_CPU_ISR_Restore(level);
return cur_offset;
}
#endif

View File

@ -1,59 +0,0 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
SEEPROM support
Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
# This code is licensed to you under the terms of the GNU GPL, version 2;
# see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
#ifndef __MINI_SEEPROM_H__
#define __MINI_SEEPROM_H__
#define SEEPROM_SIZE 0x100
typedef struct
{
union {
struct {
u8 boot2version;
u8 unknown1;
u8 unknown2;
u8 pad;
u32 update_tag;
};
u8 data[8];
};
u16 checksum; // sum of data[] elements?
} __attribute__((packed)) eep_boot2_ctr_t;
typedef struct
{
union {
u32 nand_gen; // matches offset 0x8 in nand SFFS blocks
u8 data[4];
};
u16 checksum; // sum of data[] elements?
} __attribute__((packed)) eep_nand_ctr_t;
struct SEEPROM
{
u32 ms_id; // 0x00000002
u32 ca_id; // 0x00000001
u32 ng_key_id;
u8 ng_sig[60];
eep_boot2_ctr_t boot2_counters[2];
eep_nand_ctr_t nand_counters[3]; // current slot rotates on each write
u8 pad0[6];
u8 korean_key[16];
u8 pad1[116];
u16 prng_seed[2]; // u32 with lo word stored first, incremented every time IOS starts. Used with the PRNG key to setup IOS's PRNG (syscalls 73/74 etc.)
u8 pad2[4];
};
_Static_assert(sizeof(struct SEEPROM) == SEEPROM_SIZE, "SEEPROM struct size incorrect!");
u16 seeprom_read(void *dst, u16 offset, u16 size);
// u16 seeprom_write(const void *src, u16 offset, u16 size);
#endif /* __MINI_SEEPROM_H__ */

View File

@ -4,13 +4,21 @@
#include <string.h>
#include "nand.h"
#include "malloc.h"
#include "utils.h"
#include "fileops.h"
/* Buffer */
static u32 inbuf[8] ATTRIBUTE_ALIGN(32);
static bool gNandInitialized = false;
/* NAND device list */
nandDevice ndevList[] =
{
{ "Disable", 0, 0x00, 0x00 },
{ "SD/SDHC Card", 1, 0xF0, 0xF1 },
{ "USB 2.0 Mass Storage Device", 2, 0xF2, 0xF3 },
};
const int ndevCount = (sizeof(ndevList) / sizeof(nandDevice));
s32 Nand_Mount(nandDevice *dev)
{

View File

@ -20,6 +20,8 @@ typedef struct
int type;
} NameList;
extern nandDevice ndevList[];
extern const int ndevCount;
/* Prototypes */
s32 Nand_Mount(nandDevice *);

View File

@ -1,67 +0,0 @@
#include <ogc/machine/processor.h>
#include <unistd.h>
#include <string.h>
#include "otp.h"
#define HW_OTP_COMMAND (*(vu32*)0xCD8001EC)
#define HW_OTP_DATA (*(vu32*)0xCD8001F0)
#define HW_OTP_BLK_SIZE 4
#define HW_OTP_BLK_CNT (OTP_SIZE / HW_OTP_BLK_SIZE)
u8 otp_read(void *dst, u8 offset, u8 size)
{
if (!dst || offset >= OTP_SIZE || !size || (offset + size) > OTP_SIZE) return 0;
u8 cur_offset = 0;
u8 *ptr = (u8*)dst;
u8 val[HW_OTP_BLK_SIZE] = {0};
// Calculate block offsets and sizes
u8 start_addr = (offset / HW_OTP_BLK_SIZE);
u8 start_addr_offset = (offset % HW_OTP_BLK_SIZE);
u8 end_addr = ((offset + size) / HW_OTP_BLK_SIZE);
u8 end_addr_size = ((offset + size) % HW_OTP_BLK_SIZE);
if (!end_addr_size)
{
end_addr--;
end_addr_size = HW_OTP_BLK_SIZE;
}
if (end_addr == start_addr) end_addr_size -= start_addr_offset;
for(u8 i = start_addr; i <= end_addr; i++)
{
if (cur_offset >= size) break;
// Send command + address
HW_OTP_COMMAND = (0x80000000 | i);
// Receive data
*((u32*)val) = HW_OTP_DATA;
// Copy read data to destination buffer
if (i == start_addr && start_addr_offset != 0)
{
// Handle unaligned read at start address
memcpy(ptr + cur_offset, val + start_addr_offset, HW_OTP_BLK_SIZE - start_addr_offset);
cur_offset += (HW_OTP_BLK_SIZE - start_addr_offset);
} else
if (i == end_addr && end_addr_size != HW_OTP_BLK_SIZE)
{
// Handle unaligned read at end address
memcpy(ptr + cur_offset, val, end_addr_size);
cur_offset += end_addr_size;
} else {
// Normal read
memcpy(ptr + cur_offset, val, HW_OTP_BLK_SIZE);
cur_offset += HW_OTP_BLK_SIZE;
}
}
return cur_offset;
}

View File

@ -1,29 +0,0 @@
#ifndef __OTP_H__
#define __OTP_H__
#define OTP_SIZE 0x80
typedef struct
{
u8 boot1_hash[20];
u8 common_key[16];
u8 ng_id[4];
union { // first two bytes of nand_hmac overlap last two bytes of ng_priv
struct {
u8 ng_priv[30];
u8 _wtf1[18];
};
struct {
u8 _wtf2[28];
u8 nand_hmac[20];
};
};
u8 nand_key[16];
u8 rng_key[16];
u32 unk1;
u32 unk2; // 0x00000007
} otp_t;
u8 otp_read(void *dst, u8 offset, u8 size);
#endif /* __OTP_H__ */

View File

@ -1,6 +0,0 @@
.rodata
.globl bgData
.balign 32
bgData:
.incbin "../data/background"

View File

@ -6,17 +6,11 @@
#include "sys.h"
#include "nand.h"
#include "mini_seeprom.h"
#include "malloc.h"
#include "utils.h"
#include "mload.h"
#include "ehcmodule_elf.h"
/* Constants */
#define CERTS_LEN 0x280
/* Variables */
static const char certs_fs[] ATTRIBUTE_ALIGN(32) = "/sys/cert.sys";
u32 boot2version;
static bool gDisablePRButtons = false;
void __Sys_ResetCallback(__attribute__((unused)) u32 irq, __attribute__((unused)) void *ctx)
@ -33,57 +27,46 @@ void __Sys_PowerCallback(void)
Sys_Shutdown();
}
bool tmdIsStubIOS(tmd* p_tmd)
{
return
p_tmd->sys_version >> 32 == 0
&& p_tmd->num_contents == 3
&& p_tmd->contents[0].type == 0x0001
&& p_tmd->contents[1].type == 0x8001
&& p_tmd->contents[2].type == 0x8001;
}
// we should be gangster and call the real ioctlv 69
// (in all honesty I really don't like the blind copies of otp.c and mini_seeprom.c I added)
bool ES_CheckHasKoreanKey(void)
{
aeskey korean_key;
unsigned char iv[16] = {};
__attribute__ ((__aligned__(0x10)))
unsigned char data[16] = {0x56, 0x52, 0x6f, 0x63, 0xa1, 0x2c, 0xd1, 0x32, 0x07, 0x99, 0x82, 0x3b, 0x1b, 0x08, 0x17, 0xd0};
ATTRIBUTE_ALIGN(0x20)
unsigned char data[16] = { 0x56, 0x52, 0x6f, 0x63, 0xa1, 0x2c, 0xd1, 0x32, 0x07, 0x99, 0x82, 0x3b, 0x1b, 0x08, 0x17, 0xd0 };
u32 iv[4] = {};
if (seeprom_read(korean_key, offsetof(struct SEEPROM, korean_key), sizeof(korean_key)) != sizeof(korean_key))
return false;
AES_Decrypt(korean_key, 0x10, iv, 0x10, data, data, sizeof(data));
int ret = ES_Decrypt(11, iv, data, sizeof(data), data);
// return (!strcmp((char*) data, "thepikachugamer")) Just remembered that this is how the Trucha bug came to be
return (!memcmp(data, "thepikachugamer", sizeof(data)));
return (ret == 0) && (!memcmp(data, "thepikachugamer", sizeof(data)));
}
bool isIOSstub(u8 ios_number)
bool Sys_CanLoadIOS(int ios)
{
int ret;
u32 tmd_size = 0;
tmd_view *ios_tmd;
u32 boot2version = 0;
tmd_view *view;
if ((boot2version >= 5) && (ios_number == 202 || ios_number == 222 || ios_number == 223 || ios_number == 224))
ES_GetBoot2Version(&boot2version);
if ((boot2version >= 5) && (ios == 202 || ios == 222 || ios == 223 || ios == 224))
return true;
ES_GetTMDViewSize(0x0000000100000000ULL | ios_number, &tmd_size);
if (!tmd_size)
ret = ES_GetTMDViewSize(0x0000000100000000ULL | ios, &tmd_size);
if (ret < 0)
return true;
view = memalign32(tmd_size);
if (!view)
return true;
ret = ES_GetTMDView(0x0000000100000000ULL | ios, (u8 *)view, tmd_size);
if (ret < 0)
{
// getting size failed. invalid or fake tmd for sure!
// gprintf("failed to get tmd for ios %d\n",ios_number);
free(view);
return true;
}
ios_tmd = memalign32(tmd_size);
if (!ios_tmd)
{
// gprintf("failed to mem align the TMD struct!\n");
return true;
}
memset(ios_tmd, 0, tmd_size);
ES_GetTMDView(0x0000000100000000ULL | ios_number, (u8 *)ios_tmd, tmd_size);
// gprintf("IOS %d is rev %d(0x%x) with tmd size of %u and %u contents\n",ios_number,ios_tmd->title_version,ios_tmd->title_version,tmd_size,ios_tmd->num_contents);
/*Stubs have a few things in common:
- title version : it is mostly 65280 , or even better : in hex the last 2 digits are 0.
example : IOS 60 rev 6400 = 0x1900 = 00 = stub
@ -91,59 +74,49 @@ bool isIOSstub(u8 ios_number)
- the stub ios' have 1 app of their own (type 0x1) and 2 shared apps (type 0x8001).
eventho the 00 check seems to work fine , we'll only use other knowledge as well cause some
people/applications install an ios with a stub rev >_> ...*/
u8 Version = ios_tmd->title_version;
if ((boot2version >= 5) && (ios_number == 249 || ios_number == 250) && (Version < 18))
u16 title_version = view->title_version;
free(view);
if ((boot2version >= 5) && (ios == 249 || ios == 250) && (title_version < 18))
return true;
if ((ios_number == 202 || ios_number == 222 || ios_number == 223 || ios_number == 224) && (Version < 4))
if ((ios == 202 || ios == 222 || ios == 223 || ios == 224) && (title_version < 4))
return true;
// version now contains the last 2 bytes. as said above, if this is 00, its a stub
if (Version == 0)
{
if ((ios_tmd->num_contents == 3) && (ios_tmd->contents[0].type == 1 && ios_tmd->contents[1].type == 0x8001 && ios_tmd->contents[2].type == 0x8001))
{
// gprintf("IOS %d is a stub\n",ios_number);
free(ios_tmd);
return true;
}
else
{
// gprintf("IOS %d is active\n",ios_number);
free(ios_tmd);
return false;
}
}
// gprintf("IOS %d is active\n",ios_number);
free(ios_tmd);
if ((title_version & 0xFF) == 0 && (ios < 200 || title_version == 0xFF00))
return true;
return false;
}
bool loadIOS(int ios)
int Sys_LoadIOS(int ios)
{
if (isIOSstub(ios))
return false;
if (Sys_CanLoadIOS(ios))
return -1;
mload_close();
if (IOS_ReloadIOS(ios) >= 0)
int ret = IOS_ReloadIOS(ios);
if (ret < 0)
return ret;
usleep(100000); // there should be a more professional way to do this
if (IOS_GetVersion() != 249 && IOS_GetVersion() != 250)
{
if (IOS_GetVersion() != 249 && IOS_GetVersion() != 250)
if (mload_init() >= 0)
{
if (mload_init() >= 0)
{
data_elf my_data_elf;
mload_elf((void *)ehcmodule_elf, &my_data_elf);
mload_run_thread(my_data_elf.start, my_data_elf.stack, my_data_elf.size_stack, 0x47);
}
data_elf my_data_elf;
mload_elf((void *)ehcmodule_elf, &my_data_elf);
mload_run_thread(my_data_elf.start, my_data_elf.stack, my_data_elf.size_stack, 0x47);
}
return true;
}
return false;
return ret;
}
void Sys_Init(void)
{
/* Initialize video subsytem */
VIDEO_Init();
/* Set RESET/POWER button callback */
SYS_SetResetCallback(__Sys_ResetCallback);
SYS_SetPowerCallback(__Sys_PowerCallback);
@ -186,6 +159,9 @@ void Sys_Shutdown(void)
}
#if 0
// this is a title.c thing
// also we're a wad manager we don't need to be reading the system certificate store
s32 Sys_GetCerts(signed_blob **certs, u32 *len)
{
static signed_blob certificates[CERTS_LEN] ATTRIBUTE_ALIGN(32);
@ -212,6 +188,7 @@ s32 Sys_GetCerts(signed_blob **certs, u32 *len)
return ret;
}
#endif
void SetPRButtons(bool enabled)
{

View File

@ -3,17 +3,13 @@
#define IS_WIIU (*(vu16*)0xCD8005A0 == 0xCAFE)
extern u32 boot2version;
/* Prototypes */
bool isIOSstub(u8 ios_number);
bool tmdIsStubIOS(tmd*);
bool loadIOS(int ios);
bool ES_CheckHasKoreanKey(void);
void Sys_Init(void);
void Sys_Reboot(void);
void Sys_Shutdown(void);
s32 Sys_GetCerts(signed_blob **, u32 *);
bool Sys_CanLoadIOS(int ios);
int Sys_LoadIOS(int ios);
bool ES_CheckHasKoreanKey(void);
void SetPRButtons(bool enabled);
#endif

View File

@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <ogcsys.h>
@ -10,7 +11,6 @@
#include "nand.h"
#include "sha1.h"
#include "utils.h"
#include "otp.h"
#include "malloc.h"
s32 Title_ZeroSignature(signed_blob *p_sig)
@ -185,14 +185,33 @@ err:
return ret;
}
s32 Title_GetTMDContents(signed_blob *s_tmd, u32 **contents, u32 *num_contents)
{
s32 ret;
ret = ES_GetNumStoredTMDContents(s_tmd, SIGNED_TMD_SIZE(s_tmd), num_contents);
if (ret < 0)
return ret;
*contents = memalign32(*num_contents * sizeof(u32));
if (!*contents)
return -1;
ret = ES_GetStoredTMDContents(s_tmd, SIGNED_TMD_SIZE(s_tmd), *contents, *num_contents);
if (ret >= 0)
return ret;
free(*contents);
*contents = NULL;
*num_contents = 0;
return ret;
}
s32 Title_GetTMDView(u64 tid, tmd_view** outbuf, u32* outlen)
{
s32 ret;
u32 view_sz = 0;
*outbuf = NULL;
*outlen = 0;
ret = ES_GetTMDViewSize(tid, &view_sz);
if (ret < 0)
return ret;
@ -210,79 +229,66 @@ s32 Title_GetTMDView(u64 tid, tmd_view** outbuf, u32* outlen)
return 0;
fail:
*outbuf = NULL;
*outlen = 0;
free(view);
return ret;
}
s32 Title_GetVersion(u64 tid, u16 *outbuf)
{
signed_blob *p_tmd = NULL;
tmd *tmd_data = NULL;
u32 len;
s32 ret;
tmd_view *view = NULL;
u32 len;
/* Get title TMD */
ret = Title_GetTMD(tid, &p_tmd, &len);
ret = Title_GetTMDView(tid, &view, &len);
if (ret < 0)
return ret;
/* Retrieve TMD info */
tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd);
/* Set values */
*outbuf = tmd_data->title_version;
*outbuf = view->title_version;
/* Free memory */
free(p_tmd);
free(view);
return 0;
}
s32 Title_GetSysVersion(u64 tid, u64 *outbuf)
{
signed_blob *p_tmd = NULL;
tmd *tmd_data = NULL;
u32 len;
s32 ret;
tmd_view *view = NULL;
u32 len;
/* Get title TMD */
ret = Title_GetTMD(tid, &p_tmd, &len);
ret = Title_GetTMDView(tid, &view, &len);
if (ret < 0)
return ret;
/* Retrieve TMD info */
tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd);
/* Set values */
*outbuf = tmd_data->sys_version;
*outbuf = view->sys_version;
/* Free memory */
free(p_tmd);
free(view);
return 0;
}
s32 Title_GetSize(u64 tid, u32 *outbuf)
{
signed_blob *p_tmd = NULL;
tmd *tmd_data = NULL;
u32 cnt, len, size = 0;
s32 ret;
tmd_view *view = NULL;
u32 len, size = 0;
/* Get title TMD */
ret = Title_GetTMD(tid, &p_tmd, &len);
ret = Title_GetTMDView(tid, &view, &len);
if (ret < 0)
return ret;
/* Retrieve TMD info */
tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd);
/* Calculate title size */
for (cnt = 0; cnt < tmd_data->num_contents; cnt++) {
tmd_content *content = &tmd_data->contents[cnt];
for (int cnt = 0; cnt < view->num_contents; cnt++) {
tmd_view_content *content = &view->contents[cnt];
/* Add content size */
size += content->size;
@ -297,7 +303,7 @@ s32 Title_GetSize(u64 tid, u32 *outbuf)
return 0;
}
s32 Title_GetIOSVersions(u8 **outbuf, u32 *outlen)
s32 Title_GetIOSVersions(u8 *outbuf, u32 *outlen)
{
u8 *buffer = NULL;
u64 *list = NULL;
@ -310,23 +316,6 @@ s32 Title_GetIOSVersions(u8 **outbuf, u32 *outlen)
if (ret < 0)
return ret;
/* Count IOS */
for (cnt = idx = 0; idx < count; idx++) {
u32 tidh = (list[idx] >> 32);
u32 tidl = (list[idx] & 0xFFFFFFFF);
/* Title is IOS */
if ((tidh == 0x1) && (tidl >= 3) && (tidl <= 255))
cnt++;
}
/* Allocate memory */
buffer = memalign32(cnt);
if (!buffer) {
ret = -1;
goto out;
}
/* Copy IOS */
for (cnt = idx = 0; idx < count; idx++) {
u32 tidh = (list[idx] >> 32);
@ -338,63 +327,24 @@ s32 Title_GetIOSVersions(u8 **outbuf, u32 *outlen)
}
/* Set values */
*outbuf = buffer;
*outlen = cnt;
goto out;
out:
/* Free memory */
free(list);
return ret;
}
s32 Title_GetSharedContents(SharedContent** out, u32* count)
s32 Title_GetcIOSInfo(int ios, cIOSInfo* out)
{
if (!out || !count) return false;
u32 size;
SharedContent* buf = (SharedContent*)NANDLoadFile("/shared1/content.map", &size);
if (!buf)
return (s32)size;
else if (size % sizeof(SharedContent) != 0) {
free(buf);
return -996;
}
*out = buf;
*count = size / sizeof(SharedContent);
return 0;
}
bool Title_SharedContentPresent(tmd_content* content, SharedContent shared[], u32 count)
{
if (!shared || !content || !count)
return false;
if (!(content->type & 0x8000))
return false;
for (SharedContent* s_content = shared; s_content < shared + count; s_content++)
{
if (memcmp(s_content->hash, content->hash, sizeof(sha1)) == 0)
return true;
}
return false;
}
bool Title_GetcIOSInfo(int IOS, cIOSInfo* out)
{
u64 titleID = 0x0000000100000000ULL | IOS;
u64 titleID = 0x100000000ULL | ios;
tmd_view* view = NULL;
u32 view_size = 0;
int i;
char path[ISFS_MAXPATH];
u32 size;
u32 size = 0;
cIOSInfo* buf = NULL;
s32 ret = Title_GetTMDView(titleID, &view, &view_size);
@ -402,7 +352,7 @@ bool Title_GetcIOSInfo(int IOS, cIOSInfo* out)
return ret;
u32 content0 = 0;
for (int i = 0; i < view->num_contents; i++)
for (i = 0; i < view->num_contents; i++)
{
if (view->contents[i].index == 0) {
content0 = view->contents[i].cid;
@ -411,19 +361,20 @@ bool Title_GetcIOSInfo(int IOS, cIOSInfo* out)
}
free(view);
sprintf(path, "/title/00000001/%08x/content/%08x.app", IOS, content0);
// insert ES_OpenTitleContent here
sprintf(path, "/title/00000001/%08x/content/%08x.app", ios, content0);
buf = (cIOSInfo*)NANDLoadFile(path, &size);
if (!buf || size != 0x40 || buf->hdr_magic != CIOS_INFO_MAGIC || buf->hdr_version != CIOS_INFO_VERSION)
goto fail;
if (buf && size == 0x40 && buf->hdr_magic == CIOS_INFO_MAGIC && buf->hdr_version == CIOS_INFO_VERSION) {
*out = *buf;
ret = 0;
}
else {
ret = -1;
}
*out = *buf;
free(buf);
return true;
fail:
free(buf);
return false;
return ret;
}
#if 0
@ -461,8 +412,7 @@ void Title_GetFreeSpace(u32* free, s32* user_free)
*user_free = user_clusters_free * cluster_size;
}
#endif
__attribute__((aligned(0x10)))
aeskey WiiCommonKey, vWiiCommonKey;
u32 vWiiCommonKey[4] ATTRIBUTE_ALIGN(0x20);
void Title_SetupCommonKeys(void)
{
@ -470,16 +420,17 @@ void Title_SetupCommonKeys(void)
if (keys_ok)
return;
// Grab the Wii common key...
otp_read(WiiCommonKey, offsetof(otp_t, common_key), sizeof(aeskey));
ATTRIBUTE_ALIGN(0x20)
static const u32 vWiiCommonKey_enc[4] = { 0x6E18DB23, 0x847CBA6C, 0x1931A417, 0x9BAF8E09 };
u32 iv[4] = {};
// ...and decrypt the vWii common key with it.
static const unsigned char vwii_key_enc_bin[0x10] = { 0x6e, 0x18, 0xdb, 0x23, 0x84, 0x7c, 0xba, 0x6c, 0x19, 0x31, 0xa4, 0x17, 0x9b, 0xaf, 0x8e, 0x09 };
unsigned char iv[0x10] = {};
s32 ret = ES_Decrypt(ES_KEY_COMMON, iv, vWiiCommonKey_enc, sizeof(vWiiCommonKey_enc), vWiiCommonKey);
memcpy(vWiiCommonKey, vwii_key_enc_bin, sizeof(vwii_key_enc_bin));
AES_Decrypt(WiiCommonKey, sizeof(aeskey), iv, sizeof(iv), vWiiCommonKey, vWiiCommonKey, sizeof(aeskey));
if (ret != 0) {
printf("ES_Encrypt -> %i\n", ret);
sleep(10);
}
keys_ok = true;
keys_ok = (ret == 0);
return;
};

View File

@ -3,16 +3,6 @@
#include <ogc/es.h>
/* Constants */
#define BLOCK_SIZE 0x4000
/* /shared1/content.map entry */
typedef struct
{
char filename[8];
sha1 hash;
} ATTRIBUTE_PACKED SharedContent;
/* "cIOS build tag" */
enum
{
@ -35,7 +25,7 @@ typedef struct
_Static_assert(sizeof(cIOSInfo) == 0x40, "cIOSInfo struct size wrong");
/* Variables */
extern aeskey WiiCommonKey, vWiiCommonKey;
extern u32 vWiiCommonKey[4];
/* Prototypes */
s32 Title_ZeroSignature(signed_blob *);
@ -45,13 +35,12 @@ s32 Title_GetList(u64 **, u32 *);
s32 Title_GetTicketViews(u64, tikview **, u32 *);
s32 Title_GetTMDView(u64, tmd_view **, u32 *);
s32 Title_GetTMD(u64, signed_blob **, u32 *);
s32 Title_GetTMDContents(signed_blob *, u32**, u32*);
s32 Title_GetVersion(u64, u16 *);
s32 Title_GetSysVersion(u64, u64 *);
s32 Title_GetSize(u64, u32 *);
s32 Title_GetIOSVersions(u8 **, u32 *);
s32 Title_GetSharedContents(SharedContent** out, u32* count);
bool Title_SharedContentPresent(tmd_content* content, SharedContent shared[], u32 count);
bool Title_GetcIOSInfo(int IOS, cIOSInfo*);
s32 Title_GetIOSVersions(u8 *, u32 *);
s32 Title_GetcIOSInfo(int IOS, cIOSInfo*);
void Title_SetupCommonKeys(void);

View File

@ -1,15 +1,30 @@
#ifndef _UTILS_H_
#define _UTILS_H_
#include <stdlib.h>
/* Constants */
#define KB_SIZE 1024.0
#define MB_SIZE 1048576.0
#define GB_SIZE 1073741824.0
/* Macros */
#define round_up(x,n) (-(-(x) & -(n)))
#ifdef __builtin_align_up
# define round_up(x,n) __builtin_align_up(x, n)
#else
# define round_up(x,n) ((x + n - 1) & ~(n - 1))
#endif
/* Prototypes */
u32 swap32(u32);
static inline void *memalign32(size_t size)
{
return aligned_alloc(0x20, (size + 0x1F) & ~0x1F);
}
static inline void *memalign64(size_t size)
{
return aligned_alloc(0x40, (size + 0x3F) & ~0x3F);
}
#endif

View File

@ -8,11 +8,15 @@
static void *framebuffer = NULL;
static GXRModeObj *vmode = NULL;
/* Console Variables */
int g_consoleWidth, g_consoleHeight;
void Con_Init(u32 x, u32 y, u32 w, u32 h)
{
/* Create console in the framebuffer */
CON_InitEx(vmode, x, y, w, h);
CON_GetMetrics(&g_consoleWidth, &g_consoleHeight);
}
void Con_Clear(void)
@ -24,17 +28,13 @@ void Con_Clear(void)
void Con_ClearLine(void)
{
int cols, rows;
u32 cnt;
printf("\r");
fflush(stdout);
/* Get console metrics */
CON_GetMetrics(&cols, &rows);
/* Erase line */
for (cnt = 1; cnt < cols; cnt++) {
for (cnt = 1; cnt < g_consoleWidth; cnt++) {
printf(" ");
fflush(stdout);
}
@ -59,16 +59,12 @@ void Con_BgColor(u32 color, u8 bold)
void Con_FillRow(u32 row, u32 color, u8 bold)
{
int cols, rows;
u32 cnt;
/* Set color */
printf("\x1b[%u;%um", color + 40, bold);
fflush(stdout);
/* Get console metrics */
CON_GetMetrics(&cols, &rows);
/* Save current row and col */
printf("\x1b[s");
fflush(stdout);
@ -78,7 +74,7 @@ void Con_FillRow(u32 row, u32 color, u8 bold)
fflush(stdout);
/* Fill row */
for (cnt = 0; cnt < cols; cnt++) {
for (cnt = 0; cnt < g_consoleWidth; cnt++) {
printf(" ");
fflush(stdout);
}
@ -92,22 +88,10 @@ void Con_FillRow(u32 row, u32 color, u8 bold)
Con_FgColor(7, 1);
}
void Video_Configure(GXRModeObj *rmode)
void Video_Init(void)
{
/* Configure the video subsystem */
VIDEO_Configure(rmode);
VIDEO_Init();
/* Setup video */
VIDEO_SetBlack(FALSE);
VIDEO_Flush();
VIDEO_WaitVSync();
if (rmode->viTVMode & VI_NON_INTERLACE)
VIDEO_WaitVSync();
}
void Video_SetMode(void)
{
/* Select preferred video mode */
vmode = VIDEO_GetPreferredMode(NULL);
@ -127,7 +111,7 @@ void Video_SetMode(void)
VIDEO_WaitVSync();
/* Clear the screen */
Video_Clear(COLOR_BLACK);
Video_Clear(COLOR_RED);
}
void Video_Clear(s32 color)

View File

@ -3,7 +3,14 @@
#include "libpng/pngu/pngu.h"
/* Variables */
extern int g_consoleWidth, g_consoleHeight;
/* Prototypes */
void Video_Init(void);
void Video_Clear(s32);
void Video_DrawPng(IMGCTX, PNGUPROP, u16, u16);
void Con_Init(u32, u32, u32, u32);
void Con_Clear(void);
void Con_ClearLine(void);
@ -11,9 +18,4 @@ void Con_FgColor(u32, u8);
void Con_BgColor(u32, u8);
void Con_FillRow(u32, u32, u8);
void Video_Configure(GXRModeObj *);
void Video_SetMode(void);
void Video_Clear(s32);
void Video_DrawPng(IMGCTX, PNGUPROP, u16, u16);
#endif

View File

@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>
#include <ctype.h>
@ -23,19 +24,17 @@
#include "iospatch.h"
#include "fileops.h"
// Globals
CONFIG gConfig;
// Prototypes
extern void __exception_setreload(int t);
extern u32 WaitButtons (void);
extern void __exception_setreload(unsigned sec);
void CheckPassword (void);
void SetDefaultConfig (void);
int ReadConfigFile (void);
int GetIntParam (char *inputStr);
int GetStartupPath (char *startupPath, char *inputStr);
int GetStringParam (char *outParam, char *inputStr, int maxChars);
int LaunchApp(const char* path, bool external);
wm_config_t gConfig;
// Default password Up-Down-Left-Right-Up-Down
//#define PASSWORD "UDLRUD"
@ -151,38 +150,27 @@ void Disclaimer(void)
int main(int argc, char **argv)
{
__exception_setreload(10);
__exception_setreload(15);
Sys_LoadIOS(IOS_GetVersion());
ES_GetBoot2Version(&boot2version);
if (!AHBPROT_DISABLED)
/*
We should just enable it tbh.
Like, look at https://github.com/WiiLink24/wfc-patcher-wii/blob/main/launcher/source/IOS.cpp
Awesome stuff.
*/
{
if (boot2version < 5)
{
if (!loadIOS(202)) if (!loadIOS(222)) if (!loadIOS(223)) if (!loadIOS(224)) if (!loadIOS(249)) loadIOS(36);
} else {
if (!loadIOS(249)) loadIOS(36);
}
/* Initialize display */
Video_Init();
/* Initialize console */
Gui_InitConsole(NULL); // todo: custom background & console config ?
printf("hello\n");
s32 ret = IOSPATCH_Apply();
if (ret != 0) {
printf("We goofed up.... (%#X)\n", ret);
sleep(15);
return ret;
}
/* Initialize subsystems */
Sys_Init();
/* Set video mode */
Video_SetMode();
FatMount();
/* Initialize console */
Gui_InitConsole();
/* Draw background */
Gui_DrawBackground();
/* Initialize Wiimote and GC Controller */
Wpad_Init();
PAD_Init();
@ -190,7 +178,8 @@ int main(int argc, char **argv)
WKB_Initialize();
WIILIGHT_Init();
AES_Init();
FatMount();
Title_SetupCommonKeys();
/* Print disclaimer */
@ -219,96 +208,144 @@ int main(int argc, char **argv)
int ReadConfigFile()
{
FILE* fptr;
char tmpStr[MAX_FILE_PATH_LEN];
char tmpOutStr[40], path[128];
s32 i;
bool found = false;
char tmpStr[256];
char path[128];
for (i = 0; i < FatGetDeviceCount(); i++)
if (__system_argv->argvMagic == ARGV_MAGIC) {
strncpy(path, __system_argv->argv[0], sizeof(path));
char *fpath = strrchr(path, '/');
if (fpath)
{
strcpy(fpath, "/config.txt");
if (FSOPFileExists(path))
goto found_the_file;
}
}
for (int i = 0; i < FatGetDeviceCount(); i++)
{
snprintf(path, sizeof(path), "%s:%s", FatGetDevicePrefix(i), WM_CONFIG_FILE_PATH);
if (FSOPFileExists(path))
{
found = true;
break;
}
goto found_the_file;
}
if (!found)
return -1;
return -1;
found_the_file:
// Read the file
// fptr = fopen(path, "rb"); // umm, why are we opening with mode rb and then using fgets?
fptr = fopen(path, "r");
if (!fptr) {
// perror(path);
perror(path);
return -1;
}
// Read the options
while (true)
{
if (!fgets(tmpStr, MAX_FILE_PATH_LEN, fptr))
char *option, *value;
unsigned valueLen;
if (!fgets(tmpStr, sizeof(tmpStr), fptr))
break;
else if (isalpha((int)tmpStr[0]))
option = tmpStr;
while (isspace((int)*option))
option++;
if (*option == ';' || *option == '#' || *option == '\0')
continue;
value = strchr(tmpStr, '=');
if (!value)
continue;
while (isspace((int)*++value))
;
if (!*value)
continue;
valueLen = (strpbrk(value, "#;\r\n") ?: strchr(value, 0)) - value;
while (isspace((int)value[valueLen]))
valueLen--;
// Get the password
if (strncasecmp(option, "password", 8) == 0)
{
// Get the password
if (strncmp (tmpStr, "Password", 8) == 0)
{
// Get password
// GetPassword (gConfig.password, tmpStr);
GetStringParam (gConfig.password, tmpStr, MAX_PASSWORD_LENGTH);
int i;
// If password is too long, ignore it
if (strlen (gConfig.password) > 10)
{
gConfig.password [0] = 0;
puts("Password longer than 10 characters; will be ignored. Press a button...");
WaitButtons ();
}
}
// Get startup path
else if (strncmp (tmpStr, "StartupPath", 11) == 0)
// Validate the length
if (valueLen >= MAX_PASSWORD_LENGTH)
{
// Get startup Path
GetStartupPath (gConfig.startupPath, tmpStr);
WaitPrompt("Password is too long....\n");
continue;
}
// cIOS
else if (strncmp (tmpStr, "cIOSVersion", 11) == 0)
{
// Get cIOSVersion
gConfig.cIOSVersion = GetIntParam(tmpStr);
// Validate the characters
const char* const validPasswordChars = "UDLR12";
for (i = 0; i < valueLen; i++) {
if (!strchr(validPasswordChars, value[i]))
break;
}
// FatDevice
else if (strncmp (tmpStr, "FatDevice", 9) == 0)
if (i != valueLen)
{
// Get fatDevice
GetStringParam (tmpOutStr, tmpStr, MAX_FAT_DEVICE_LENGTH);
for (i = 0; i < 5; i++)
{
if (strncmp(FatGetDevicePrefix(i), tmpOutStr, 4) == 0)
{
gConfig.fatDeviceIndex = i;
}
}
printf("Password has invalid characters! (?)\n");
printf(" Valid characters: %s\n", validPasswordChars);
printf(" Provided password: %s\n", value);
printf(" %.*s^\n\n", i, "");
WaitPrompt(NULL);
continue;
}
// NandDevice
else if (strncmp (tmpStr, "NANDDevice", 10) == 0)
strncpy(gConfig.password, value, i);
}
// Get startup path
else if (strncasecmp(option, "startupPath", 11) == 0)
{
value[valueLen] = '\0';
if (FSOPFolderExists(value))
strncpy(gConfig.startupPath, value, sizeof(gConfig.startupPath));
}
// cIOS
else if (strncasecmp(option, "cIOSVersion", 11) == 0)
{
char *endPtr;
long num = strtol(value, &endPtr, 10);
if (num < 3 || num >= 256)
{
// Get fatDevice
GetStringParam (tmpOutStr, tmpStr, MAX_NAND_DEVICE_LENGTH);
for (i = 0; i < 3; i++)
{
if (strncmp (ndevList[i].name, tmpOutStr, 2) == 0)
{
gConfig.nandDeviceIndex = i;
}
}
printf("Invalid cIOSVersion %lu (%s)\n", num, value);
WaitPrompt(NULL);
}
// Get cIOSVersion
gConfig.cIOSVersion = num;
}
// FatDevice
else if (strncasecmp(option, "fatDevice", 9) == 0)
{
// Get fatDevice
for (int i = 0; i < FatGetDeviceCount(); i++)
{
if (strcmp(FatGetDevicePrefix(i), value) == 0)
gConfig.fatDeviceIndex = i;
}
}
// NandDevice
else if (strncasecmp(tmpStr, "NANDDevice", 10) == 0)
{
for (int i = 0; i < 3; i++)
{
if (strcmp(ndevList[i].name, value) == 0)
gConfig.nandDeviceIndex = i;
}
}
} // EndWhile
@ -322,107 +359,13 @@ int ReadConfigFile()
void SetDefaultConfig (void)
{
// Default password is NULL or no password
gConfig.password [0] = 0;
memset(&gConfig, 0, sizeof(gConfig));
// Default startup folder
strcpy (gConfig.startupPath, WAD_ROOT_DIRECTORY);
strcpy (gConfig.startupPath, DEFAULT_WAD_DIRECTORY);
gConfig.cIOSVersion = CIOS_VERSION_INVALID; // Means that user has to select later
gConfig.fatDeviceIndex = FAT_DEVICE_INDEX_INVALID; // Means that user has to select
gConfig.nandDeviceIndex = NAND_DEVICE_INDEX_INVALID; // Means that user has to select
} // SetDefaultConfig
int GetStartupPath (char *startupPath, char *inputStr)
{
int i = 0;
int len = strlen (inputStr);
// Find the "="
while ((inputStr [i] != '=') && (i < len))
{
i++;
}
i++;
// Get to the "/"
while ((inputStr [i] != '/') && (i < len))
{
i++;
}
// Get the startup Path
int count = 0;
while (isascii(inputStr [i]) && (i < len) && (inputStr [i] != '\n') &&
(inputStr [i] != '\r') && (inputStr [i] != ' '))
{
startupPath [count++] = inputStr [i++];
}
startupPath [count] = 0; // NULL terminate
return (0);
} // GetStartupPath
int GetIntParam (char *inputStr)
{
int retval = 0;
int i = 0;
int len = strlen (inputStr);
char outParam [40];
// Find the "="
while ((inputStr [i] != '=') && (i < len))
{
i++;
}
i++;
// Get to the first alpha numeric character
while ((isdigit((int)inputStr[i]) == 0) && (i < len))
{
i++;
}
// Get the string param
int outCount = 0;
while ((isdigit((int)inputStr[i])) && (i < len) && (outCount < 40))
{
outParam [outCount++] = inputStr [i++];
}
outParam [outCount] = 0; // NULL terminate
retval = atoi (outParam);
return (retval);
} // GetIntParam
int GetStringParam (char *outParam, char *inputStr, int maxChars)
{
int i = 0;
int len = strlen (inputStr);
// Find the "="
while ((inputStr [i] != '=') && (i < len))
{
i++;
}
i++;
// Get to the first alpha character
while ((isalpha((int)inputStr[i]) == 0) && (i < len))
{
i++;
}
// Get the string param
int outCount = 0;
while ((isalnum((int)inputStr[i])) && (i < len) && (outCount < maxChars))
{
outParam [outCount++] = inputStr [i++];
}
outParam [outCount] = 0; // NULL terminate
return (0);
} // GetStringParam

View File

@ -9,8 +9,6 @@
#include "sys.h"
#include "title.h"
#include "utils.h"
#include "mini_seeprom.h"
#include "otp.h"
#include "video.h"
#include "wad.h"
#include "wpad.h"
@ -95,76 +93,6 @@ static void DecEncTxtBuffer(char* buffer)
}
}
u64 get_title_ios(u64 title) {
s32 ret, fd;
static char filepath[256] ATTRIBUTE_ALIGN(32);
// Check to see if title exists
if (ES_GetDataDir(title, filepath) >= 0 ) {
u32 tmd_size = 0;
static u8 tmd_buf[MAX_SIGNED_TMD_SIZE] ATTRIBUTE_ALIGN(32);
ret = ES_GetStoredTMDSize(title, &tmd_size);
if (ret < 0){
// If we fail to use the ES function, try reading manually
// This is a workaround added since some IOS (like 21) don't like our
// call to ES_GetStoredTMDSize
//printf("Error! ES_GetStoredTMDSize: %d\n", ret);
sprintf(filepath, "/title/%08x/%08x/content/title.tmd", TITLE_UPPER(title), TITLE_LOWER(title));
ret = ISFS_Open(filepath, ISFS_OPEN_READ);
if (ret <= 0)
{
//printf("Error! ISFS_Open (ret = %d)\n", ret);
return 0;
}
fd = ret;
ret = ISFS_Seek(fd, 0x184, 0);
if (ret < 0)
{
//printf("Error! ISFS_Seek (ret = %d)\n", ret);
return 0;
}
ret = ISFS_Read(fd,tmd_buf,8);
if (ret < 0)
{
//printf("Error! ISFS_Read (ret = %d)\n", ret);
return 0;
}
ret = ISFS_Close(fd);
if (ret < 0)
{
//printf("Error! ISFS_Close (ret = %d)\n", ret);
return 0;
}
return be64(tmd_buf);
} else {
// Normal versions of IOS won't have a problem, so we do things the "right" way.
// Some of this code adapted from bushing's title_lister.c
signed_blob *s_tmd = (signed_blob *)tmd_buf;
ret = ES_GetStoredTMD(title, s_tmd, tmd_size);
if (ret < 0){
//printf("Error! ES_GetStoredTMD: %d\n", ret);
return -1;
}
tmd *t = SIGNATURE_PAYLOAD(s_tmd);
return t->sys_version;
}
}
return 0;
}
static bool GetRegionFromTXT(char* region)
{
u32 size = 0;
@ -324,7 +252,9 @@ bool GetSysMenuExecPath(char path[ISFS_MAXPATH], bool mainDOL)
u32 cid = GetSysMenuBootContent();
if (!cid) return false;
if (mainDOL) cid |= 0x10000000;
if (mainDOL)
cid = (cid & ~0xF00000000) | 0x10000000;
sprintf(path, "/title/00000001/00000002/content/%08x.app", cid);
return true;
@ -506,56 +436,20 @@ static bool CompareHashes(bool priiloader)
/* 'WAD Header' structure */
typedef struct {
/* Header length */
u32 header_len;
/* WAD type */
u16 type;
u16 padding;
/* Data length */
u16 version;
u32 certs_len;
u32 crl_len;
u32 tik_len;
u32 tmd_len;
u32 data_len;
u32 footer_len;
} ATTRIBUTE_PACKED wadHeader;
} wadHeader;
/* Variables */
static u8 wadBuffer[BLOCK_SIZE] ATTRIBUTE_ALIGN(32);
s32 __Wad_GetTitleID(FILE *fp, wadHeader *header, u64 *tid)
{
signed_blob *p_tik = NULL;
tik *tik_data = NULL;
u32 offset = 0;
s32 ret;
/* Ticket offset */
offset += round_up(header->header_len, 64);
offset += round_up(header->certs_len, 64);
offset += round_up(header->crl_len, 64);
/* Read ticket */
ret = FSOPReadOpenFileA(fp, (void*)&p_tik, offset, header->tik_len);
if (ret != 1)
goto out;
/* Ticket data */
tik_data = (tik *)SIGNATURE_PAYLOAD(p_tik);
/* Copy title ID */
*tid = tik_data->titleid;
out:
/* Free memory */
free(p_tik);
return ret;
}
ATTRIBUTE_ALIGN(0x40)
static u8 wadBuffer[16 << 10];
bool __Wad_FixTicket(signed_blob *s_tik)
{
@ -583,7 +477,7 @@ bool __Wad_FixTicket(signed_blob *s_tik)
iv[0] = p_tik->titleid;
iv[1] = 0;
AES_Encrypt(WiiCommonKey, 0x10, iv, 0x10, tkeybuf, tkeybuf, sizeof(tkeybuf));
ES_Encrypt(ES_KEY_COMMON, (u32 *)iv, tkeybuf, sizeof(tkeybuf), tkeybuf);
memcpy(p_tik->cipher_title_key, tkeybuf, sizeof(tkeybuf));
}
@ -597,10 +491,7 @@ bool __Wad_FixTicket(signed_blob *s_tik)
bool __Wad_VerifyHeader(wadHeader* header)
{
return
header->header_len == 0x20
&& header->type == ('I' << 8 | 's')
&& header->padding == 0x00;
return (header->header_len == 0x20 && header->type == 0x4973 && header->version == 0x0000);
}
const char* wad_strerror(int ec)
@ -614,10 +505,14 @@ const char* wad_strerror(int ec)
case -999: return "BRICK BLOCKED";
case -1010: return "Wii System memory full!";
case -1017: return "Invalid argument";
case -1020: return "Device ID mismatch";
case -1022: return "Content hash mismatch";
case -1027: return "Issuer not found in the certificate chain";
case -1028: return "Ticket not found";
case -1029: return "Invalid Ticket";
case -1035: return "Newer version already installed";
case -1036: return "Needed IOS missing!";
case -2011: return "No trucha bug?";
case -2011: return "No signature check patch?";
/*
* from libogc.
* This rarely happens unless the WAD had an invalid ticket/tmd size
@ -629,6 +524,12 @@ const char* wad_strerror(int ec)
}
}
// Convenience purposes
u32 hbcList[] = { 0x48415858, 0x4A4F4449, 0xAF1BF516, 0x4C554C5A, 0x4F484243 };
u32 eulaList[] = { 0x48414B45, 0x48414B50, 0x48414B4A, 0x48414B4B };
u32 rgnselList[] = { 0x48414C45, 0x48414C50, 0x48414C4A, 0x48414C4B };
// Some of the safety checks can block region changing
// Entering the Konami code turns this true, so it will
// skip the problematic checks for region changing.
@ -636,26 +537,26 @@ bool skipRegionSafetyCheck = false;
s32 Wad_Install(FILE *fp)
{
SetPRButtons(false);
wadHeader *header = NULL;
s32 ret;
wadHeader *header = {};
signed_blob *p_certs = NULL, *p_crl = NULL, *p_tik = NULL, *p_tmd = NULL;
tmd *tmd_data = NULL;
u64 tid;
tmd_view *view = NULL;
u32 view_size = 0;
u32 boot2version;
u32 cnt, offset = 0;
u32 *installedContents = NULL;
u32 installedContentsCount = 0;
SharedContent* sharedContents = NULL;
tmd *tmd_data = NULL;
u32 cnt, offset = 0;
u32 sharedContentsCount = 0;
int ret;
u64 tid;
bool retainPriiloader = false;
bool cleanupPriiloader = false;
printf("\t\t>> Reading WAD data...");
fflush(stdout);
SetPRButtons(false);
printf("\t\t>> Reading WAD data...\n\n");
ret = FSOPReadOpenFileA(fp, (void*)&header, offset, sizeof(wadHeader));
if (ret != 1)
if (ret < 0)
goto err;
if (!__Wad_VerifyHeader(header))
@ -665,7 +566,9 @@ s32 Wad_Install(FILE *fp)
}
offset += round_up(header->header_len, 64);
/*
* IOS won't let you do this unless you actually call ES_ImportBoot
//Don't try to install boot2
__Wad_GetTitleID(fp, header, &tid);
@ -675,10 +578,10 @@ s32 Wad_Install(FILE *fp)
ret = -999;
goto out;
}
*/
/* WAD certificates */
ret = FSOPReadOpenFileA(fp, (void*)&p_certs, offset, header->certs_len);
if (ret != 1)
if (ret < 0)
goto err;
offset += round_up(header->certs_len, 64);
@ -686,7 +589,7 @@ s32 Wad_Install(FILE *fp)
/* WAD crl */
if (header->crl_len) {
ret = FSOPReadOpenFileA(fp, (void*)&p_crl, offset, header->crl_len);
if (ret != 1)
if (ret < 0)
goto err;
offset += round_up(header->crl_len, 64);
@ -694,140 +597,159 @@ s32 Wad_Install(FILE *fp)
/* WAD ticket */
ret = FSOPReadOpenFileA(fp, (void*)&p_tik, offset, header->tik_len);
if (ret != 1)
if (ret < 0)
goto err;
bool isvWiiTitle = __Wad_FixTicket(p_tik);
offset += round_up(header->tik_len, 64);
/* WAD TMD */
ret = FSOPReadOpenFileA(fp, (void*)&p_tmd, offset, header->tmd_len);
if (ret != 1)
if (ret < 0)
goto err;
offset += round_up(header->tmd_len, 64);
Con_ClearLine();
bool isvWiiTitle = __Wad_FixTicket(p_tik);
/* Get TMD info */
tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd);
tid = tmd_data->title_id;
if (TITLE_UPPER(tmd_data->sys_version) == 0) // IOS
{
if ((isvWiiTitle || tmd_data->vwii_title) ^ IS_WIIU) // xor is one of my favourite binary operators of all time
bool stubbed = (tmd_data->title_version & 0xFF) == 0 || tmd_data->title_version == 404;
bool isCrossPlatformIOS = (isvWiiTitle || tmd_data->vwii_title) ^ IS_WIIU; // xor is one of my favourite binary operators of all time
if (isCrossPlatformIOS && !skipRegionSafetyCheck)
{
printf("\n Cannot install vWii IOS on Wii\n or Wii IOS on vWii.\n");
printf(" Cannot install vWii IOS on Wii\n");
printf(" or Wii IOS on vWii.\n");
printf(" I mean maybe you can. I'm not going to find out though\n");
ret = -999;
goto err;
}
if(tid == get_title_ios(TITLE_ID(1, 2)))
ret = Title_GetTMDView(0x100000002LL, &view, &view_size);
if (ret < 0)
{
if (tmdIsStubIOS(tmd_data))
printf(" Hey, where's Perry?\n\n");
printf(" (No really, where is your Wii System Menu?)\n");
goto err;
}
if (view->sys_version == tmd_data->title_id)
{
if (isCrossPlatformIOS)
{
printf("\n I won't install a stub System Menu IOS\n");
printf(" Anything but the System menu's IOS...!!!!\n");
ret = -999;
goto err;
}
// this code feels like a MESS
else if (!IS_WIIU && (tid == TITLE_ID(1, 70) || tid == TITLE_ID(1, 80)))
if (stubbed) {
printf(" I won't install a stub System Menu IOS\n");
ret = -999;
goto err;
}
if (!IS_WIIU && (view->title_version >> 5) >= 15) // 4.2 or later. Again.
{
tik* ticket = (tik*)SIGNATURE_PAYLOAD(p_tik);
__aligned(0x10)
__aligned(0x20)
aeskey titlekey;
u64 iv[2] = { tid };
memcpy(titlekey, ticket->cipher_title_key, sizeof(aeskey));
AES_Decrypt(WiiCommonKey, sizeof(aeskey), iv, sizeof(iv), titlekey, titlekey, sizeof(aeskey));
ES_Decrypt(ES_KEY_COMMON, (u32 *)iv, titlekey, sizeof(aeskey), titlekey);
u32 content0_offset = offset;
for (tmd_content* con = tmd_data->contents; con < tmd_data->contents + tmd_data->num_contents; con++)
for (int i = 0; i < tmd_data->num_contents; i++)
{
if (con->index == 0) break;
content0_offset += round_up(con->size, 0x40);
if (tmd_data->contents[i].index == 0) break;
content0_offset += round_up(tmd_data->contents[i].size, 0x40);
}
__aligned(0x20)
cIOSInfo build_tag = {};
ret = FSOPReadOpenFile(fp, (void*)&build_tag, content0_offset, sizeof(cIOSInfo));
if (ret != 1)
ret = FSOPReadOpenFile(fp, (void*)&build_tag, content0_offset, sizeof(build_tag));
if (ret < 0)
goto err;
iv[0] = 0;
iv[1] = 0;
AES_Decrypt(titlekey, sizeof(aeskey), iv, sizeof(iv), &build_tag, &build_tag, sizeof(cIOSInfo));
AES_Decrypt(titlekey, sizeof(aeskey), iv, sizeof(iv), &build_tag, &build_tag, sizeof(build_tag));
if ((build_tag.hdr_magic != CIOS_INFO_MAGIC ||
build_tag.hdr_version != CIOS_INFO_VERSION ||
build_tag.ios_base != 60) && ES_CheckHasKoreanKey())
{
printf("\n"
" Installing this System menu IOS will brick your Wii.\n"
" Please remove the Korean key via KoreanKii,\n"
" then try again.\n\n"
);
printf(" Installing this System menu IOS will brick your Wii.\n\n");
printf(" Please remove the Korean key via KoreanKii,\n");
printf(" then try again.\n");
ret = -999;
goto err;
}
}
}
if(tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | 'E'))
|| tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | 'P'))
|| tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | 'J'))
|| tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | 'K')))
if (stubbed)
{
if (tmdIsStubIOS(tmd_data))
u64 sysvers = 0;
for (int i = 0; i < 4; i++)
{
printf("\n I won't install a stub EULA IOS\n");
ret = -999;
goto err;
if ((Title_GetSysVersion(TITLE_ID(0x00010008, eulaList[i]), &sysvers) == 0) && tid == sysvers)
{
printf(" I won't install a stub EULA IOS\n");
ret = -999;
goto err;
}
if ((Title_GetSysVersion(TITLE_ID(0x00010008, rgnselList[i]), &sysvers) == 0) && tid == sysvers)
{
printf(" I won't install a stub Region select IOS\n");
ret = -999;
goto err;
}
}
}
if(tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | 'E'))
|| tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | 'P'))
|| tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | 'J'))
|| tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | 'K')))
{
if (tmdIsStubIOS(tmd_data))
for (int i = 0; i < 5; i++)
{
printf("\n I won't install a stub rgnsel IOS\n");
ret = -999;
goto err;
}
}
if(tid == get_title_ios(TITLE_ID(0x10001, 0x48415858))
|| tid == get_title_ios(TITLE_ID(0x10001, 0x4A4F4449))
|| tid == get_title_ios(TITLE_ID(0x10001, 0xAF1BF516))
|| tid == get_title_ios(TITLE_ID(0x10001, 0x4C554C5A))
|| tid == get_title_ios(TITLE_ID(0x10001, 0x4F484243)))
{
if (tmdIsStubIOS(tmd_data))
{
printf("\n I won't stub Homebrew Channel's IOS\n");
ret = -999;
goto err;
if ((Title_GetSysVersion(TITLE_ID(0x00010001, hbcList[i]), &sysvers) == 0) && tid == sysvers)
{
printf(" I won't stub The Homebrew Channel's IOS\n");
ret = -999;
goto err;
}
}
}
}
else // not IOS
{
if (isIOSstub(TITLE_LOWER(tmd_data->sys_version)))
ret = Title_GetTMDView(tmd_data->sys_version, &view, &view_size);
if (ret < 0)
{
printf("\n This Title wants IOS%i but the installed version\n is a stub.\n", TITLE_LOWER(tmd_data->sys_version));
printf(" This title wants IOS%i, but the installed ver-...\n", TITLE_LOWER(tmd_data->sys_version));
printf(" ...is it even installed?\n");
goto err;
}
if ((view->title_version & 0xFF) == 0 || view->title_version == 404)
{
printf(" This title wants IOS%i, but the installed version\n", TITLE_LOWER(tmd_data->sys_version));
printf(" is a stub.\n");
ret = -1036;
goto err;
}
if (tid == TITLE_ID(1, 2))
if (tid == 0x100000002LL)
{
if (skipRegionSafetyCheck || gForcedInstall)
goto skipChecks;
@ -839,17 +761,18 @@ s32 Wad_Install(FILE *fp)
if (isvWiiTitle || tmd_data->vwii_title) // && !IS_WIIU ? :thinking:
{
printf("\n I won't install a vWii SM by default.\n\n");
printf("\n If you're really sure what you're doing, next time\n");
printf(" select your device using Konami...\n\n");
printf(" I won't install a vWii SM by default.\n\n");
printf(" If you're really sure about what you're doing, next time\n");
printf(" select your device using Konami...\n");
ret = -999;
goto err;
}
if(region == 0)
if (region == '\0')
{
printf("\n Unknown System menu region\n Please check the site for updates\n");
printf(" Unknown System menu region. What's up with setting.txt?\n");
ret = -999;
goto err;
@ -857,10 +780,11 @@ s32 Wad_Install(FILE *fp)
if (!VersionIsOriginal(tmd_data->title_version))
{
printf("\n I won't install an unknown SM versions by default.\n\n");
printf("\n Are you installing a tweaked system menu?\n");
printf("\n If you're really sure what you're doing, next time\n");
printf(" select your device using Konami...\n\n");
printf(" I won't install an unknown SM versions by default.\n\n");
printf(" Are you installing a tweaked system menu?\n");
printf(" If you're really sure what you're doing, next time\n");
printf(" select your device using Konami...\n");
ret = -999;
goto err;
@ -869,9 +793,10 @@ s32 Wad_Install(FILE *fp)
if(region != RegionLookupTable[(tmd_data->title_version & 0x0F)])
{
printf("\n I won't install the wrong regions SM by default.\n\n");
printf("\n Are you region changing?\n");
printf("\n If you're really sure what you're doing, next time\n");
printf(" select your device using Konami...\n\n");
printf(" select your device using Konami...\n");
ret = -999;
goto err;
@ -882,15 +807,12 @@ s32 Wad_Install(FILE *fp)
{
cIOSInfo ios_info;
if (ES_CheckHasKoreanKey() &&
(!Title_GetcIOSInfo(TITLE_LOWER(tmd_data->sys_version), &ios_info) ||
ios_info.ios_base != 60))
if ((Title_GetcIOSInfo(TITLE_LOWER(tmd_data->sys_version), &ios_info) != 0 ||
ios_info.ios_base != 60) && ES_CheckHasKoreanKey())
{
printf("\n"
" Installing this System menu will brick your Wii.\n"
" Please remove the Korean key via KoreanKii,\n"
" then try again.\n\n"
);
printf(" Installing this System menu will brick your Wii.\n");
printf(" Please remove the Korean key via KoreanKii,\n");
printf(" then try again.\n");
ret = -999;
goto err;
@ -900,21 +822,25 @@ s32 Wad_Install(FILE *fp)
skipChecks:
if (tmd_data->title_version < 416)
{
ES_GetBoot2Version(&boot2version);
if(boot2version == 4)
{
printf("\n This version of the System Menu\n is not compatible with your Wii\n");
printf(" This version of the System Menu\n");
printf(" is not compatible with your Wii\n");
ret = -999;
goto err;
}
}
if (!gForcedInstall && AHBPROT_DISABLED && IsPriiloaderInstalled())
if (!gForcedInstall && IsPriiloaderInstalled())
{
cleanupPriiloader = true;
printf("\n Priiloader is installed next to the system menu.\n\n");
printf(" It is recommended to retain Priiloader as it can\n");
printf(" protect your console from being bricked.\n\n");
printf(" Press A to retain Priiloader or B to remove.");
printf(" Priiloader is installed next to the system menu.\n\n");
printf(" It is recommended to retain Priiloader as it can\n");
printf(" protect your console from being bricked.\n\n");
printf(" Press A to retain Priiloader or B to remove.");
u32 buttons = WaitButtons();
@ -989,26 +915,22 @@ skipChecks:
}
#endif
printf("\t\t>> Installing ticket...");
fflush(stdout);
printf("\t\t>> Installing ticket...\n");
/* Install ticket */
ret = ES_AddTicket(p_tik, header->tik_len, p_certs, header->certs_len, p_crl, header->crl_len);
if (ret < 0)
goto err;
Con_ClearLine();
printf("\r\t\t>> Installing title...");
fflush(stdout);
printf("\t\t>> Installing title...\n");
/* Install title */
ret = ES_AddTitleStart(p_tmd, header->tmd_len, p_certs, header->certs_len, p_crl, header->crl_len);
if (ret < 0)
goto err;
/* Get list of currently installed shared contents */
Title_GetSharedContents(&sharedContents, &sharedContentsCount);
/* Get list of currently installed contents */
Title_GetTMDContents(p_tmd, &installedContents, &installedContentsCount);
/* Install contents */
for (cnt = 0; cnt < tmd_data->num_contents; cnt++)
@ -1021,23 +943,21 @@ skipChecks:
/* Encrypted content size */
len = round_up(content->size, 64);
if (Title_SharedContentPresent(content, sharedContents, sharedContentsCount))
{
offset += len;
continue;
}
if (content->type & 0x8000) // We're only doing shared. Unless we're going to genuinely read the non-shared contents and check the hash against what we're installing
for (int i = 0; i < installedContentsCount; i++)
if (installedContents[i] == content->cid)
{
offset += len;
continue;
}
Con_ClearLine();
printf("\r\t\t>> Installing content #%02d...", content->cid);
fflush(stdout);
printf("\r\t\t>> Installing content #%02d...", content->index);
/* Install content */
cfd = ES_AddContentStart(tmd_data->title_id, content->cid);
if (cfd < 0)
{
ret = cfd;
ret = cfd = ES_AddContentStart(tmd_data->title_id, content->cid);
if (ret < 0)
goto err;
}
/* Install content data */
while (idx < len)
@ -1046,12 +966,12 @@ skipChecks:
/* Data length */
size = (len - idx);
if (size > BLOCK_SIZE)
size = BLOCK_SIZE;
if (size > sizeof(wadBuffer))
size = sizeof(wadBuffer);
/* Read data */
ret = FSOPReadOpenFile(fp, &wadBuffer, offset, size);
if (ret != 1)
ret = FSOPReadOpenFile(fp, wadBuffer, offset, size);
if (ret < 0)
{
ES_AddContentFinish(cfd);
goto err;
@ -1183,7 +1103,7 @@ skipChecks:
}
err:
printf("\n ERROR! (ret = %d)\n", ret);
printf("\n ERROR! (ret = %d)\n", ret);
if (retainPriiloader)
SetPriiloaderOption(false);
@ -1200,7 +1120,8 @@ out:
free(p_crl);
free(p_tik);
free(p_tmd);
free(sharedContents);
free(installedContents);
free(view);
if (gForcedInstall)
return Wad_Install(fp);
@ -1211,30 +1132,30 @@ out:
s32 Wad_Uninstall(FILE *fp)
{
SetPRButtons(false);
wadHeader *header = NULL;
tikview *viewData = NULL;
wadHeader *header = {};
tikview *tikviews = NULL;
signed_blob *s_tik = NULL;
signed_blob *s_tmd = NULL;
u64 tid;
u64 tid, sysvers;
u32 viewCnt;
int ret;
printf("\t\t>> Reading WAD data...");
fflush(stdout);
SetPRButtons(false);
printf("\t\t>> Reading WAD data...\n");
/* WAD header */
ret = FSOPReadOpenFileA(fp, (void*)&header, 0, sizeof(wadHeader));
if (ret != 1)
if (ret < 0)
{
printf(" ERROR! (ret = %d)\n", ret);
printf(" ERROR! (ret = %d)\n", ret);
goto out;
}
if (!__Wad_VerifyHeader(header))
{
puts("\t\tInvalid WAD file?");
puts(" Invalid WAD file?");
ret = ES_EINVAL;
goto out;
}
@ -1246,8 +1167,8 @@ s32 Wad_Uninstall(FILE *fp)
offset += round_up(header->crl_len, 0x40);
ret = FSOPReadOpenFileA(fp, (void*)&s_tik, offset, header->tik_len);
if (ret != 1) {
printf(" ERROR! (ret = %d)\n", ret);
if (ret < 0) {
printf(" ERROR! (ret = %d)\n", ret);
goto out;
}
@ -1257,8 +1178,8 @@ s32 Wad_Uninstall(FILE *fp)
offset += round_up(header->tik_len, 0x40);
ret = FSOPReadOpenFileA(fp, (void*)&s_tmd, offset, header->tmd_len);
if (ret != 1) {
printf(" ERROR! (ret = %d)\n", ret);
if (ret < 0) {
printf(" ERROR! (ret = %d)\n", ret);
goto out;
}
@ -1267,134 +1188,91 @@ s32 Wad_Uninstall(FILE *fp)
//Assorted Checks
if (TITLE_UPPER(tid) == 0x1)
{
if (!get_title_ios(TITLE_ID(1, 2)))
if ((ret = Title_GetSysVersion(0x100000002LL, &sysvers)) != 0)
{
printf("\n I can't determine the System Menus IOS\nDeleting system titles is disabled\n");
ret = -999;
printf(" I can't determine the System Menus IOS\n");
printf(" Deleting system titles is disabled\n");
goto out;
}
if (((isvWiiTitle || tmd_data->vwii_title) ^ IS_WIIU) && !skipRegionSafetyCheck) // Only this way around this time // Ehh nvm
{
printf("\n"
" Attempting to uninstall a Wii IOS WAD on vWii.\n"
" or a vWii IOS WAD on Wii.\n\n"
printf(
" Attempting to uninstall a Wii IOS WAD on vWii.\n"
" or a vWii IOS WAD on Wii.\n\n"
" Maybe you installed one on accident before?\n\n"
" Maybe you installed one on accident before?\n\n"
" If you're sure about what you're doing, input\n"
" the Konami code on the device screen. Have fun.\n");
" If you're sure about what you're doing, input\n"
" the Konami code on the device screen. Have fun.\n");
ret = -999;
goto out;
}
if (tid == TITLE_ID(1, 1))
if (tid == 0x100000001LL)
{
printf("\n I won't try to uninstall boot2\n");
printf(" I won't try to uninstall boot2\n");
ret = -999;
goto out;
}
if (tid == TITLE_ID(1, 2))
if (tid == 0x100000002LL)
{
printf("\n I won't uninstall the System Menu\n");
printf(" I won't uninstall the System Menu\n");
ret = -999;
goto out;
}
if (tid == get_title_ios(TITLE_ID(1, 2)))
if (tid == sysvers)
{
printf("\n I won't uninstall the System Menus IOS\n");
printf(" I won't uninstall the System Menu's IOS\n");
ret = -999;
goto out;
}
if (tid == get_title_ios(TITLE_ID(0x10001, 0x48415858))
|| tid == get_title_ios(TITLE_ID(0x10001, 0x4A4F4449))
|| tid == get_title_ios(TITLE_ID(0x10001, 0xAF1BF516))
|| tid == get_title_ios(TITLE_ID(0x10001, 0x4C554C5A))
|| tid == get_title_ios(TITLE_ID(0x10001, 0x4F484243)))
for (int i = 0; i < 5; i++)
{
printf("\n I won't uninstall the Homebrew Channel's IOS!\n");
ret = -999;
goto out;
if ((Title_GetSysVersion(TITLE_ID(0x00010001, hbcList[5 - i]), &sysvers) == 0) && tid == sysvers)
{
printf(" I won't uninstall the Homebrew Channel's IOS!\n");
ret = -999;
goto out;
}
}
}
char region = 0;
GetSysMenuRegion(NULL, &region);
if((tid == TITLE_ID(0x10008, 0x48414B00 | 'E') || tid == TITLE_ID(0x10008, 0x48414B00 | 'P') || tid == TITLE_ID(0x10008, 0x48414B00 | 'J') || tid == TITLE_ID(0x10008, 0x48414B00 | 'K')
|| (tid == TITLE_ID(0x10008, 0x48414C00 | 'E') || tid == TITLE_ID(0x10008, 0x48414C00 | 'P') || tid == TITLE_ID(0x10008, 0x48414C00 | 'J') || tid == TITLE_ID(0x10008, 0x48414C00 | 'K')))
&& region == 0)
if (((tid | 0xFF) == 0x0001000848414CFFLL || (tid | 0xFF) == 0x0001000848414BFFLL) && strchr("JEPK", (char)tid) && region == 0)
{
printf("\n Unknown SM region\n Please check the site for updates\n");
printf(" Unknown System Menu region\n Please check the site for updates\n");
ret = -999;
goto out;
}
if(tid == TITLE_ID(0x10008, 0x48414B00 | region))
if (tid == TITLE_ID(0x10008, 0x48414B00 | region))
{
printf("\n I won't uninstall the EULA\n");
printf(" I won't uninstall the EULA\n");
ret = -999;
goto out;
}
if(tid == TITLE_ID(0x10008, 0x48414C00 | region))
if (tid == TITLE_ID(0x10008, 0x48414C00 | region))
{
printf("\n I won't uninstall rgnsel\n");
printf(" I won't uninstall rgnsel\n");
ret = -999;
goto out;
}
if(tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | region)))
if (Title_GetSysVersion(0x0001000848414B00LL | region, &sysvers) == 0 && tid == sysvers)
{
printf("\n I won't uninstall the EULAs IOS\n");
printf(" I won't uninstall the EULAs IOS\n");
ret = -999;
goto out;
}
if(tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | region)))
}
if (Title_GetSysVersion(0x0001000848414C00LL | region, &sysvers) == 0 && tid == sysvers)
{
printf("\n I won't uninstall the rgnsel IOS\n");
printf(" I won't uninstall rgnsel's IOS\n");
ret = -999;
goto out;
}
Con_ClearLine();
/* Why don't we do this the other way around? Delete title contents, delete TMD, delete ticket. Seems more natural. */
printf("\t\t>> Deleting tickets...");
fflush(stdout);
/* Get ticket views */
ret = Title_GetTicketViews(tid, &viewData, &viewCnt);
if (ret < 0)
printf(" ERROR! (ret = %d)\n", ret);
/* Delete tickets */
else {
u32 cnt;
static tikview view ATTRIBUTE_ALIGN(0x20);
/* Delete all tickets */
for (cnt = 0; cnt < viewCnt; cnt++) {
memcpy(&view, viewData + cnt, sizeof(tikview));
if (view.devicetype)
{
u32 deviceID = 0;
/* If we failed to get the ID or it actually matches, skip this */
if (ES_GetDeviceID(&deviceID) || view.devicetype == deviceID) continue;
}
ret = ES_DeleteTicket(&view);
if (ret < 0)
break;
}
if (ret < 0)
printf(" ERROR! (ret = %d)\n", ret);
else
printf(" OK!\n");
}
free(viewData);
printf("\t\t>> Deleting title contents...");
fflush(stdout);
printf("\t\t>> Deleting title contents... ");
/* Delete title contents */
ret = ES_DeleteTitleContent(tid);
@ -1405,7 +1283,6 @@ s32 Wad_Uninstall(FILE *fp)
printf("\t\t>> Deleting title...");
fflush(stdout);
/* Delete title */
ret = ES_DeleteTitle(tid);
@ -1414,6 +1291,39 @@ s32 Wad_Uninstall(FILE *fp)
else
printf(" OK!\n");
printf("\t\t>> Deleting tickets...");
/* Get ticket views */
ret = Title_GetTicketViews(tid, &tikviews, &viewCnt);
if (ret < 0)
printf(" ERROR! (ret = %d)\n", ret);
/* Delete tickets */
else
{
u32 cnt;
/* Delete all tickets */
for (cnt = 0; cnt < viewCnt; cnt++) {
#if 0
if (view.devicetype)
{
u32 deviceID = 0;
/* If we failed to get the ID or it actually matches, skip this */
if (ES_GetDeviceID(&deviceID) || view.devicetype == deviceID) continue;
}
#endif
ret = ES_DeleteTicket(&tikviews[cnt]);
if (ret < 0)
break;
}
if (ret < 0)
printf(" ERROR! (ret = %d)\n", ret);
else
printf(" OK!\n");
}
free(tikviews);
out:
/* Free memory */
free(header);

View File

@ -86,6 +86,8 @@ static void WKBEventHandler(USBKeyboard_event evt)
static void* WKBThread(__attribute__((unused)) void* arg)
{
sleep(10); // HACK: IOS totally bricks up if I initialize this too early(??)
while (WKBThreadActive)
{
/*

View File

@ -1,10 +1,6 @@
#ifndef _WKB_H_
#define _WKB_H_
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//#include <malloc.h>
#include <gctypes.h> // u8, u16, etc...
#include <wiikeyboard/keyboard.h>