mirror of
https://github.com/modmii/YAWM-ModMii-Edition.git
synced 2024-06-02 23:48:46 +02:00
Compare commits
25 Commits
1.0
...
modmii-edi
Author | SHA1 | Date | |
---|---|---|---|
|
d9ba968f90 | ||
|
e49d9a8850 | ||
|
7cc66cc0a1 | ||
|
7e86d9ce5f | ||
|
4875edf350 | ||
|
66a8fb1440 | ||
|
7b47e2800e | ||
|
60c42a760c | ||
|
d18498361e | ||
|
34aae016b9 | ||
|
d5a817b680 | ||
|
1a825dcfce | ||
|
608d954afe | ||
|
13dd003f3d | ||
|
bc99919c45 | ||
|
53072c83fe | ||
|
289a1cee79 | ||
|
18f2e3f07f | ||
|
5283493c4e | ||
|
1d0f7d6f67 | ||
|
cb2351b877 | ||
|
abd5f48be9 | ||
|
8c0269a8bc | ||
|
b520bc7f88 | ||
|
596fa16162 |
4
Makefile
4
Makefile
|
@ -21,7 +21,7 @@ include $(DEVKITPPC)/wii_rules
|
||||||
TARGET := boot
|
TARGET := boot
|
||||||
BUILD := build
|
BUILD := build
|
||||||
SOURCES := source include source/libtinysmb source/libpng source/libpng/pngu
|
SOURCES := source include source/libtinysmb source/libpng source/libpng/pngu
|
||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES :=
|
INCLUDES :=
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
|
@ -36,7 +36,7 @@ LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# any extra libraries we wish to link with the project
|
# any extra libraries we wish to link with the project
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
LIBS := -lmxml -ltinysmb -lpng -lfat -lwiidrc -lwiiuse -lbte -logc -lm -lz -lwiilight
|
LIBS := -lmxml -ltinysmb -lpng -lfat -lwiikeyboard -lwiidrc -lwiiuse -lbte -logc -lm -lz -lwiilight
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# list of directories containing libraries, this must be the top level containing
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
|
125
source/aes.c
Normal file
125
source/aes.c
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/*-------------------------------------------------------------
|
||||||
|
|
||||||
|
aes.c -- AES Engine
|
||||||
|
|
||||||
|
Copyright (C) 2022
|
||||||
|
GaryOderNichts
|
||||||
|
Joris 'DacoTaco' Vermeylen info@dacotaco.com
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you
|
||||||
|
must not claim that you wrote the original software. If you use
|
||||||
|
this software in a product, an acknowledgment in the product
|
||||||
|
documentation would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
-------------------------------------------------------------*/
|
||||||
|
#if defined(HW_RVL)
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <gctypes.h>
|
||||||
|
#include <gcutil.h>
|
||||||
|
#include <ogc/ipc.h>
|
||||||
|
|
||||||
|
#include "aes.h"
|
||||||
|
|
||||||
|
#define AES_HEAPSIZE 0x200
|
||||||
|
|
||||||
|
#define AES_IOCTLV_ENCRYPT 2
|
||||||
|
#define AES_IOCTLV_DECRYPT 3
|
||||||
|
|
||||||
|
static s32 __aes_fd = -1;
|
||||||
|
static s32 __aes_hid = -1;
|
||||||
|
|
||||||
|
static s32 AES_ExecuteCommand(s32 command, const void* key, u32 key_size, void* iv, u32 iv_size, const void* in_data, void* out_data, u32 data_size)
|
||||||
|
{
|
||||||
|
if ((((u32)in_data | (u32)out_data) & 0xF) != 0)
|
||||||
|
return -4;
|
||||||
|
|
||||||
|
if (key_size != 16 || iv_size != 16 || (data_size & 15) != 0)
|
||||||
|
return -4;
|
||||||
|
|
||||||
|
ioctlv* params = (ioctlv*)iosAlloc(__aes_hid, sizeof(ioctlv) * 4);
|
||||||
|
if (!params)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
s32 ret = -1;
|
||||||
|
for (u32 i = 0; i < data_size; i += AES_BLOCK_SIZE) {
|
||||||
|
u32 size = i+AES_BLOCK_SIZE >= data_size
|
||||||
|
? data_size - i
|
||||||
|
: AES_BLOCK_SIZE;
|
||||||
|
|
||||||
|
params[0].data = (void*)((u32)in_data + i);
|
||||||
|
params[0].len = size;
|
||||||
|
params[1].data = (void*) key;
|
||||||
|
params[1].len = key_size;
|
||||||
|
params[2].data = (void*)((u32)out_data + i);
|
||||||
|
params[2].len = size;
|
||||||
|
params[3].data = iv;
|
||||||
|
params[3].len = iv_size;
|
||||||
|
|
||||||
|
ret = IOS_Ioctlv(__aes_fd, command, 2, 2, params);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
iosFree(__aes_hid, params);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 AES_Init(void)
|
||||||
|
{
|
||||||
|
if (__aes_fd >= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
__aes_fd = IOS_Open("/dev/aes", 0);
|
||||||
|
if (__aes_fd < 0)
|
||||||
|
return __aes_fd;
|
||||||
|
|
||||||
|
//only create heap if it wasn't created yet.
|
||||||
|
//its never disposed, so only create once.
|
||||||
|
if(__aes_hid < 0)
|
||||||
|
__aes_hid = iosCreateHeap(AES_HEAPSIZE);
|
||||||
|
|
||||||
|
if (__aes_hid < 0) {
|
||||||
|
AES_Close();
|
||||||
|
return __aes_hid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 AES_Close(void)
|
||||||
|
{
|
||||||
|
if (__aes_fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
IOS_Close(__aes_fd);
|
||||||
|
__aes_fd = -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 AES_Encrypt(const void* key, u32 key_size, void* iv, u32 iv_size, const void* in_data, void* out_data, u32 data_size)
|
||||||
|
{
|
||||||
|
return AES_ExecuteCommand(AES_IOCTLV_ENCRYPT, key, key_size, iv, iv_size, in_data, out_data, data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 AES_Decrypt(const void* key, u32 key_size, void* iv, u32 iv_size, const void* in_data, void* out_data, u32 data_size)
|
||||||
|
{
|
||||||
|
return AES_ExecuteCommand(AES_IOCTLV_DECRYPT, key, key_size, iv, iv_size, in_data, out_data, data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
53
source/aes.h
Normal file
53
source/aes.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*-------------------------------------------------------------
|
||||||
|
|
||||||
|
aes.h -- AES Engine
|
||||||
|
|
||||||
|
Copyright (C) 2022
|
||||||
|
GaryOderNichts
|
||||||
|
Joris 'DacoTaco' Vermeylen info@dacotaco.com
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you
|
||||||
|
must not claim that you wrote the original software. If you use
|
||||||
|
this software in a product, an acknowledgment in the product
|
||||||
|
documentation would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
-------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __AES_H___
|
||||||
|
#define __AES_H___
|
||||||
|
|
||||||
|
#if defined(HW_RVL)
|
||||||
|
#include <gctypes.h>
|
||||||
|
#include <gcutil.h>
|
||||||
|
|
||||||
|
#define AES_BLOCK_SIZE 0x10000
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
s32 AES_Init(void);
|
||||||
|
s32 AES_Close(void);
|
||||||
|
s32 AES_Decrypt(const void* key, u32 key_size, void* iv, u32 iv_size, const void* in_data, void* out_data, u32 data_size);
|
||||||
|
s32 AES_Encrypt(const void* key, u32 key_size, void* iv, u32 iv_size, const void* in_data, void* out_data, u32 data_size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -1,56 +1,32 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <malloc.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "fileops.h"
|
#include "fileops.h"
|
||||||
|
#include "malloc.h"
|
||||||
|
|
||||||
|
static struct stat st;
|
||||||
|
|
||||||
bool FSOPFileExists(const char* file)
|
bool FSOPFileExists(const char* file)
|
||||||
{
|
{
|
||||||
FILE* f;
|
return !stat(file, &st) && !S_ISDIR(st.st_mode);
|
||||||
f = fopen(file, "rb");
|
|
||||||
if (f)
|
|
||||||
{
|
|
||||||
fclose(f);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FSOPFolderExists(const char* path)
|
bool FSOPFolderExists(const char* path)
|
||||||
{
|
{
|
||||||
DIR* dir;
|
return !stat(path, &st) && S_ISDIR(st.st_mode);
|
||||||
dir = opendir(path);
|
|
||||||
if (dir)
|
|
||||||
{
|
|
||||||
closedir(dir);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t FSOPGetFileSizeBytes(const char* path)
|
size_t FSOPGetFileSizeBytes(const char* path)
|
||||||
{
|
{
|
||||||
FILE* f;
|
if (stat(path, &st) < 0) return 0;
|
||||||
size_t size = 0;
|
|
||||||
|
|
||||||
f = fopen(path, "rb");
|
return st.st_size;
|
||||||
if (!f)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fseek(f, 0, SEEK_END);
|
|
||||||
size = ftell(f);
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSOPDeleteFile(const char* file)
|
void FSOPDeleteFile(const char* file)
|
||||||
{
|
{
|
||||||
if (!FSOPFileExists(file))
|
if (FSOPFileExists(file))
|
||||||
return;
|
remove(file);
|
||||||
|
|
||||||
remove(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSOPMakeFolder(const char* path)
|
void FSOPMakeFolder(const char* path)
|
||||||
|
@ -85,13 +61,16 @@ s32 FSOPReadOpenFile(FILE* fp, void* buffer, u32 offset, u32 length)
|
||||||
|
|
||||||
s32 FSOPReadOpenFileA(FILE* fp, void** buffer, u32 offset, u32 length)
|
s32 FSOPReadOpenFileA(FILE* fp, void** buffer, u32 offset, u32 length)
|
||||||
{
|
{
|
||||||
*buffer = memalign(32, length);
|
*buffer = memalign32(length);
|
||||||
if (!*buffer)
|
if (!*buffer)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
s32 ret = FSOPReadOpenFile(fp, *buffer, offset, length);
|
s32 ret = FSOPReadOpenFile(fp, *buffer, offset, length);
|
||||||
if (ret < 0)
|
if (ret <= 0)
|
||||||
|
{
|
||||||
free(*buffer);
|
free(*buffer);
|
||||||
|
*buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef __FILEOPS_H__
|
#ifndef __FILEOPS_H__
|
||||||
#define __FILEOPS_H__
|
#define __FILEOPS_H__
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <ogcsys.h>
|
#include <ogcsys.h>
|
||||||
|
|
||||||
|
@ -14,4 +15,4 @@ void FSOPMakeFolder(const char* path);
|
||||||
s32 FSOPReadOpenFile(FILE* fp, void* buffer, u32 offset, u32 length);
|
s32 FSOPReadOpenFile(FILE* fp, void* buffer, u32 offset, u32 length);
|
||||||
s32 FSOPReadOpenFileA(FILE* fp, void** buffer, u32 offset, u32 length);
|
s32 FSOPReadOpenFileA(FILE* fp, void** buffer, u32 offset, u32 length);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
11
source/malloc.h
Normal file
11
source/malloc.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#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);
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <ogcsys.h>
|
#include <ogcsys.h>
|
||||||
|
#include <ogc/pad.h>
|
||||||
#include <wiilight.h>
|
#include <wiilight.h>
|
||||||
#include <wiidrc/wiidrc.h>
|
#include <wiidrc/wiidrc.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -16,7 +17,7 @@
|
||||||
#include "video.h"
|
#include "video.h"
|
||||||
#include "wad.h"
|
#include "wad.h"
|
||||||
#include "wpad.h"
|
#include "wpad.h"
|
||||||
#include <ogc/pad.h>
|
#include "wkb.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "iospatch.h"
|
#include "iospatch.h"
|
||||||
#include "appboot.h"
|
#include "appboot.h"
|
||||||
|
@ -646,42 +647,29 @@ int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath, int i
|
||||||
|
|
||||||
if (thisFile->installstate < 0)
|
if (thisFile->installstate < 0)
|
||||||
{
|
{
|
||||||
char str[41];
|
printf(" %.40s: ", thisFile->filename);
|
||||||
strncpy(str, thisFile->filename, 40); //Only 40 chars to fit the screen
|
|
||||||
str[40]=0;
|
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
|
|
||||||
switch (thisFile->installstate)
|
switch (thisFile->installstate)
|
||||||
{
|
{
|
||||||
case -106:
|
case -106: puts("Not installed?"); break;
|
||||||
{
|
case -996: puts("Read error"); break;
|
||||||
printf(" %s Not installed?\n", str);
|
case -998: puts("Skipped"); break;
|
||||||
} break;
|
case -999: puts("BRICK BLOCKED"); break;
|
||||||
case -996:
|
case -1010: puts("Wii System memory full!");
|
||||||
{
|
case -1022: puts("Content hash mismatch"); break;
|
||||||
printf(" %s Read error\n", str);
|
case -1035: puts("Newer version already installed"); break;
|
||||||
} break;
|
case -1036: puts("Needed IOS missing!"); break;
|
||||||
case -998:
|
case -2011: puts("No trucha bug?"); break;
|
||||||
{
|
/*
|
||||||
printf(" %s Skipped\n", str);
|
* from libogc.
|
||||||
} break;
|
* This rarely happens unless the WAD had an invalid ticket/tmd size
|
||||||
case -999:
|
* (certs were not stripped after downloading from NUS maybe?)
|
||||||
{
|
*/
|
||||||
printf(" %s BRICK BLOCKED\n", str);
|
case ES_EINVAL: puts("Invalid WAD?"); break;
|
||||||
} break;
|
|
||||||
case -1036:
|
default: printf("error %d\n", thisFile->installstate); break;
|
||||||
{
|
|
||||||
printf(" %s Needed IOS missing\n", str);
|
|
||||||
} break;
|
|
||||||
case -4100:
|
|
||||||
{
|
|
||||||
printf(" %s No trucha bug?\n", str);
|
|
||||||
} break;
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
printf(" %s error %d\n", str, thisFile->installstate);
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(i == 17)
|
if(i == 17)
|
||||||
|
@ -1084,24 +1072,34 @@ getList:
|
||||||
if (--selected < 0)
|
if (--selected < 0)
|
||||||
selected = (fileCnt - 1);
|
selected = (fileCnt - 1);
|
||||||
}
|
}
|
||||||
else if (buttons & WPAD_BUTTON_LEFT)
|
else if (buttons & WPAD_BUTTON_RIGHT)
|
||||||
{
|
{
|
||||||
selected += ENTRIES_PER_PAGE;
|
if (fileCnt - start > ENTRIES_PER_PAGE) {
|
||||||
|
start += ENTRIES_PER_PAGE;
|
||||||
if (selected >= fileCnt)
|
selected += ENTRIES_PER_PAGE;
|
||||||
selected = 0;
|
if (selected >= fileCnt)
|
||||||
|
selected = fileCnt - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selected = fileCnt - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (buttons & WPAD_BUTTON_DOWN)
|
else if (buttons & WPAD_BUTTON_DOWN)
|
||||||
{
|
{
|
||||||
if (++selected >= fileCnt)
|
if (++selected >= fileCnt)
|
||||||
selected = 0;
|
selected = 0;
|
||||||
}
|
}
|
||||||
else if (buttons & WPAD_BUTTON_RIGHT)
|
else if (buttons & WPAD_BUTTON_LEFT)
|
||||||
{
|
{
|
||||||
selected -= ENTRIES_PER_PAGE;
|
if (start >= ENTRIES_PER_PAGE) {
|
||||||
|
start -= ENTRIES_PER_PAGE;
|
||||||
if (selected < 0)
|
selected -= ENTRIES_PER_PAGE;
|
||||||
selected = (fileCnt - 1);
|
if (selected < 0)
|
||||||
|
selected = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selected = start = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (buttons & WPAD_BUTTON_HOME)
|
else if (buttons & WPAD_BUTTON_HOME)
|
||||||
{
|
{
|
||||||
|
@ -1496,9 +1494,10 @@ u32 WaitButtons(void)
|
||||||
u32 buttons = 0;
|
u32 buttons = 0;
|
||||||
u32 buttonsGC = 0;
|
u32 buttonsGC = 0;
|
||||||
u32 buttonsDRC = 0;
|
u32 buttonsDRC = 0;
|
||||||
|
u16 buttonsWKB = 0;
|
||||||
|
|
||||||
/* Wait for button pressing */
|
/* Wait for button pressing */
|
||||||
while (!buttons && !buttonsGC && !buttonsDRC)
|
while (!(buttons | buttonsGC | buttonsDRC | buttonsWKB))
|
||||||
{
|
{
|
||||||
// Wii buttons
|
// Wii buttons
|
||||||
buttons = Wpad_GetButtons();
|
buttons = Wpad_GetButtons();
|
||||||
|
@ -1509,6 +1508,9 @@ u32 WaitButtons(void)
|
||||||
// DRC buttons
|
// DRC buttons
|
||||||
buttonsDRC = WiiDRC_GetButtons();
|
buttonsDRC = WiiDRC_GetButtons();
|
||||||
|
|
||||||
|
// USB Keyboard buttons
|
||||||
|
buttonsWKB = WKB_GetButtons();
|
||||||
|
|
||||||
VIDEO_WaitVSync();
|
VIDEO_WaitVSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1581,6 +1583,9 @@ u32 WaitButtons(void)
|
||||||
buttons |= WPAD_BUTTON_1;
|
buttons |= WPAD_BUTTON_1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (buttonsWKB)
|
||||||
|
buttons |= buttonsWKB;
|
||||||
|
|
||||||
return buttons;
|
return buttons;
|
||||||
} // WaitButtons
|
} // WaitButtons
|
||||||
|
|
||||||
|
|
267
source/mini_seeprom.c
Normal file
267
source/mini_seeprom.c
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
/*
|
||||||
|
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
|
59
source/mini_seeprom.h
Normal file
59
source/mini_seeprom.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
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__ */
|
|
@ -1,10 +1,10 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <ogcsys.h>
|
#include <ogcsys.h>
|
||||||
#include <malloc.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "nand.h"
|
#include "nand.h"
|
||||||
|
#include "malloc.h"
|
||||||
#include "fileops.h"
|
#include "fileops.h"
|
||||||
|
|
||||||
/* Buffer */
|
/* Buffer */
|
||||||
|
@ -118,7 +118,7 @@ u8* NANDReadFromFile(const char* path, u32 offset, u32 length, u32* size)
|
||||||
if (!length)
|
if (!length)
|
||||||
length = IOS_Seek(fd, 0, SEEK_END);
|
length = IOS_Seek(fd, 0, SEEK_END);
|
||||||
|
|
||||||
u8* data = (u8*)memalign(0x40, length);
|
u8* data = memalign64(length);
|
||||||
if (!data)
|
if (!data)
|
||||||
{
|
{
|
||||||
*size = 0;
|
*size = 0;
|
||||||
|
@ -155,9 +155,10 @@ u8* NANDLoadFile(const char* path, u32* size)
|
||||||
|
|
||||||
s32 NANDWriteFileSafe(const char* path, u8* data, u32 size)
|
s32 NANDWriteFileSafe(const char* path, u8* data, u32 size)
|
||||||
{
|
{
|
||||||
|
char tmpPath[ISFS_MAXPATH] ATTRIBUTE_ALIGN(64);
|
||||||
|
|
||||||
NANDInitialize();
|
NANDInitialize();
|
||||||
|
|
||||||
char* tmpPath = (char*)memalign(0x40, ISFS_MAXPATH);
|
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
for (i = strlen(path); i > 0; --i)
|
for (i = strlen(path); i > 0; --i)
|
||||||
|
@ -175,43 +176,29 @@ s32 NANDWriteFileSafe(const char* path, u8* data, u32 size)
|
||||||
ret = ISFS_CreateFile(tmpPath, 0, 3, 3, 3);
|
ret = ISFS_CreateFile(tmpPath, 0, 3, 3, 3);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
|
||||||
free(tmpPath);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else if (ret < 0)
|
||||||
{
|
{
|
||||||
if (ret < 0)
|
return ret;
|
||||||
{
|
|
||||||
free(tmpPath);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 fd = IOS_Open(tmpPath, 2);
|
s32 fd = IOS_Open(tmpPath, 2);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
|
||||||
free(tmpPath);
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
|
||||||
|
|
||||||
ret = IOS_Write(fd, data, size);
|
ret = IOS_Write(fd, data, size);
|
||||||
|
|
||||||
|
|
||||||
IOS_Close(fd);
|
IOS_Close(fd);
|
||||||
if (ret != size)
|
if (ret != size)
|
||||||
{
|
|
||||||
free(tmpPath);
|
|
||||||
return ret - 3;
|
return ret - 3;
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(tmpPath, path))
|
if (strcmp(tmpPath, path))
|
||||||
ret = ISFS_Rename(tmpPath, path);
|
ret = ISFS_Rename(tmpPath, path);
|
||||||
else
|
else
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
free(tmpPath);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
67
source/otp.c
Normal file
67
source/otp.c
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#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;
|
||||||
|
}
|
29
source/otp.h
Normal file
29
source/otp.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#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__ */
|
284
source/sys.c
284
source/sys.c
|
@ -1,14 +1,18 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <malloc.h>
|
|
||||||
#include <ogcsys.h>
|
#include <ogcsys.h>
|
||||||
|
#include <ogc/es.h>
|
||||||
|
|
||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
|
#include "aes.h"
|
||||||
|
#include "nand.h"
|
||||||
|
#include "mini_seeprom.h"
|
||||||
|
#include "malloc.h"
|
||||||
#include "mload.h"
|
#include "mload.h"
|
||||||
#include "ehcmodule_elf.h"
|
#include "ehcmodule_elf.h"
|
||||||
|
|
||||||
/* Constants */
|
/* Constants */
|
||||||
#define CERTS_LEN 0x280
|
#define CERTS_LEN 0x280
|
||||||
|
|
||||||
/* Variables */
|
/* Variables */
|
||||||
static const char certs_fs[] ATTRIBUTE_ALIGN(32) = "/sys/cert.sys";
|
static const char certs_fs[] ATTRIBUTE_ALIGN(32) = "/sys/cert.sys";
|
||||||
|
@ -29,75 +33,104 @@ void __Sys_PowerCallback(void)
|
||||||
Sys_Shutdown();
|
Sys_Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isIOSstub(u8 ios_number)
|
bool tmdIsStubIOS(tmd* p_tmd)
|
||||||
{
|
{
|
||||||
u32 tmd_size;
|
return
|
||||||
tmd_view *ios_tmd;
|
p_tmd->sys_version >> 32 == 0
|
||||||
|
&& p_tmd->num_contents == 3
|
||||||
|
&& p_tmd->contents[0].type == 0x0001
|
||||||
if((boot2version >= 5) && ( ios_number == 202 || ios_number == 222 || ios_number == 223 || ios_number == 224)) return true;
|
&& p_tmd->contents[1].type == 0x8001
|
||||||
|
&& p_tmd->contents[2].type == 0x8001;
|
||||||
ES_GetTMDViewSize(0x0000000100000000ULL | ios_number, &tmd_size);
|
}
|
||||||
if (!tmd_size)
|
|
||||||
{
|
bool ES_CheckHasKoreanKey(void)
|
||||||
//getting size failed. invalid or fake tmd for sure!
|
{
|
||||||
//gprintf("failed to get tmd for ios %d\n",ios_number);
|
aeskey korean_key;
|
||||||
return true;
|
unsigned char iv[16] = {};
|
||||||
}
|
|
||||||
ios_tmd = (tmd_view *)memalign( 32, (tmd_size+31)&(~31) );
|
__attribute__ ((__aligned__(0x10)))
|
||||||
if(!ios_tmd)
|
unsigned char data[16] = {0x56, 0x52, 0x6f, 0x63, 0xa1, 0x2c, 0xd1, 0x32, 0x07, 0x99, 0x82, 0x3b, 0x1b, 0x08, 0x17, 0xd0};
|
||||||
{
|
|
||||||
//gprintf("failed to mem align the TMD struct!\n");
|
if (seeprom_read(korean_key, offsetof(struct SEEPROM, korean_key), sizeof(korean_key)) != sizeof(korean_key))
|
||||||
return true;
|
return false;
|
||||||
}
|
|
||||||
memset(ios_tmd , 0, tmd_size);
|
AES_Decrypt(korean_key, 0x10, iv, 0x10, data, data, sizeof(data));
|
||||||
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);
|
// return (!strcmp((char*) data, "thepikachugamer")) Just remembered that this is how the Trucha bug came to be
|
||||||
/*Stubs have a few things in common:
|
return (!memcmp(data, "thepikachugamer", sizeof(data)));
|
||||||
- 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
|
|
||||||
- exception for IOS21 which is active, the tmd size is 592 bytes (or 140 with the views)
|
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
|
u32 tmd_size = 0;
|
||||||
people/applications install an ios with a stub rev >_> ...*/
|
tmd_view *ios_tmd;
|
||||||
u8 Version = ios_tmd->title_version;
|
|
||||||
|
if ((boot2version >= 5) && (ios_number == 202 || ios_number == 222 || ios_number == 223 || ios_number == 224))
|
||||||
if((boot2version >= 5) && (ios_number == 249 || ios_number == 250) && (Version < 18)) return true;
|
return true;
|
||||||
if(( ios_number == 202 || ios_number == 222 || ios_number == 223 || ios_number == 224) && (Version < 4)) return true;
|
|
||||||
//version now contains the last 2 bytes. as said above, if this is 00, its a stub
|
ES_GetTMDViewSize(0x0000000100000000ULL | ios_number, &tmd_size);
|
||||||
if ( Version == 0 )
|
if (!tmd_size)
|
||||||
{
|
{
|
||||||
if ( ( ios_tmd->num_contents == 3) && (ios_tmd->contents[0].type == 1 && ios_tmd->contents[1].type == 0x8001 && ios_tmd->contents[2].type == 0x8001) )
|
// getting size failed. invalid or fake tmd for sure!
|
||||||
{
|
// gprintf("failed to get tmd for ios %d\n",ios_number);
|
||||||
//gprintf("IOS %d is a stub\n",ios_number);
|
return true;
|
||||||
free(ios_tmd);
|
}
|
||||||
return true;
|
ios_tmd = memalign32(tmd_size);
|
||||||
}
|
if (!ios_tmd)
|
||||||
else
|
{
|
||||||
{
|
// gprintf("failed to mem align the TMD struct!\n");
|
||||||
//gprintf("IOS %d is active\n",ios_number);
|
return true;
|
||||||
free(ios_tmd);
|
}
|
||||||
return false;
|
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);
|
||||||
//gprintf("IOS %d is active\n",ios_number);
|
/*Stubs have a few things in common:
|
||||||
free(ios_tmd);
|
- title version : it is mostly 65280 , or even better : in hex the last 2 digits are 0.
|
||||||
return false;
|
example : IOS 60 rev 6400 = 0x1900 = 00 = stub
|
||||||
}
|
- exception for IOS21 which is active, the tmd size is 592 bytes (or 140 with the views)
|
||||||
|
- 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))
|
||||||
|
return true;
|
||||||
|
if ((ios_number == 202 || ios_number == 222 || ios_number == 223 || ios_number == 224) && (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);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool loadIOS(int ios)
|
bool loadIOS(int ios)
|
||||||
{
|
{
|
||||||
if(isIOSstub(ios)) return false;
|
if (isIOSstub(ios))
|
||||||
|
return false;
|
||||||
mload_close();
|
mload_close();
|
||||||
if(IOS_ReloadIOS(ios)>=0)
|
if (IOS_ReloadIOS(ios) >= 0)
|
||||||
{
|
{
|
||||||
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;
|
data_elf my_data_elf;
|
||||||
mload_elf((void *) ehcmodule_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);
|
mload_run_thread(my_data_elf.start, my_data_elf.stack, my_data_elf.size_stack, 0x47);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,17 +158,20 @@ void Sys_Reboot(void)
|
||||||
void Sys_Shutdown(void)
|
void Sys_Shutdown(void)
|
||||||
{
|
{
|
||||||
/* Poweroff console */
|
/* Poweroff console */
|
||||||
if(CONF_GetShutdownMode() == CONF_SHUTDOWN_IDLE) {
|
if (CONF_GetShutdownMode() == CONF_SHUTDOWN_IDLE)
|
||||||
|
{
|
||||||
s32 ret;
|
s32 ret;
|
||||||
|
|
||||||
/* Set LED mode */
|
/* Set LED mode */
|
||||||
ret = CONF_GetIdleLedMode();
|
ret = CONF_GetIdleLedMode();
|
||||||
if(ret >= 0 && ret <= 2)
|
if (ret >= 0 && ret <= 2)
|
||||||
STM_SetLedMode(ret);
|
STM_SetLedMode(ret);
|
||||||
|
|
||||||
/* Shutdown to idle */
|
/* Shutdown to idle */
|
||||||
STM_ShutdownToIdle();
|
STM_ShutdownToIdle();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* Shutdown to standby */
|
/* Shutdown to standby */
|
||||||
STM_ShutdownToStandby();
|
STM_ShutdownToStandby();
|
||||||
}
|
}
|
||||||
|
@ -143,26 +179,33 @@ void Sys_Shutdown(void)
|
||||||
|
|
||||||
void Sys_LoadMenu(void)
|
void Sys_LoadMenu(void)
|
||||||
{
|
{
|
||||||
|
/* SYSCALL(exit) does all of this already */
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
/* Also the code gcc generated for this looks really painful */
|
||||||
|
#if 0
|
||||||
int HBC = 0;
|
int HBC = 0;
|
||||||
char * sig = (char *)0x80001804;
|
char *sig = (char *)0x80001804;
|
||||||
if( sig[0] == 'S' &&
|
if (sig[0] == 'S' &&
|
||||||
sig[1] == 'T' &&
|
sig[1] == 'T' &&
|
||||||
sig[2] == 'U' &&
|
sig[2] == 'U' &&
|
||||||
sig[3] == 'B' &&
|
sig[3] == 'B' &&
|
||||||
sig[4] == 'H' &&
|
sig[4] == 'H' &&
|
||||||
sig[5] == 'A' &&
|
sig[5] == 'A' &&
|
||||||
sig[6] == 'X' &&
|
sig[6] == 'X' &&
|
||||||
sig[7] == 'X')
|
sig[7] == 'X')
|
||||||
{
|
{
|
||||||
HBC=1; // Exit to HBC
|
HBC = 1; // Exit to HBC
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Homebrew Channel stub */
|
/* Homebrew Channel stub */
|
||||||
if (HBC == 1) {
|
if (HBC == 1)
|
||||||
|
{
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
/* Return to the Wii system menu */
|
/* Return to the Wii system menu */
|
||||||
SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0);
|
SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 Sys_GetCerts(signed_blob **certs, u32 *len)
|
s32 Sys_GetCerts(signed_blob **certs, u32 *len)
|
||||||
|
@ -183,14 +226,101 @@ s32 Sys_GetCerts(signed_blob **certs, u32 *len)
|
||||||
IOS_Close(fd);
|
IOS_Close(fd);
|
||||||
|
|
||||||
/* Set values */
|
/* Set values */
|
||||||
if (ret > 0) {
|
if (ret > 0)
|
||||||
|
{
|
||||||
*certs = certificates;
|
*certs = certificates;
|
||||||
*len = sizeof(certificates);
|
*len = sizeof(certificates);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s32 Sys_GetSharedContents(SharedContent** out, u32* count)
|
||||||
|
{
|
||||||
|
if (!out || !count) return false;
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
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 Sys_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 Sys_GetcIOSInfo(int IOS, cIOSInfo* out)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u64 titleID = 0x0000000100000000ULL | IOS;
|
||||||
|
ATTRIBUTE_ALIGN(0x20) char path[ISFS_MAXPATH];
|
||||||
|
u32 size;
|
||||||
|
cIOSInfo* buf = NULL;
|
||||||
|
|
||||||
|
u32 view_size = 0;
|
||||||
|
if (ES_GetTMDViewSize(titleID, &view_size) < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
tmd_view* view = memalign32(view_size);
|
||||||
|
if (!view)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ES_GetTMDView(titleID, (u8*)view, view_size) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
tmd_view_content* content0 = NULL;
|
||||||
|
|
||||||
|
for (tmd_view_content* con = view->contents; con < view->contents + view->num_contents; con++)
|
||||||
|
{
|
||||||
|
if (con->index == 0)
|
||||||
|
content0 = con;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!content0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
sprintf(path, "/title/00000001/%08x/content/%08x.app", IOS, content0->cid);
|
||||||
|
buf = (cIOSInfo*)NANDLoadFile(path, &size);
|
||||||
|
|
||||||
|
if (!buf || size != 0x40 || buf->hdr_magic != CIOS_INFO_MAGIC || buf->hdr_version != CIOS_INFO_VERSION)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
*out = *buf;
|
||||||
|
free(view);
|
||||||
|
free(buf);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
free(view);
|
||||||
|
free(buf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void SetPRButtons(bool enabled)
|
void SetPRButtons(bool enabled)
|
||||||
{
|
{
|
||||||
gDisablePRButtons = !enabled;
|
gDisablePRButtons = !enabled;
|
||||||
|
|
36
source/sys.h
36
source/sys.h
|
@ -1,15 +1,51 @@
|
||||||
#ifndef _SYS_H_
|
#ifndef _SYS_H_
|
||||||
#define _SYS_H_
|
#define _SYS_H_
|
||||||
|
|
||||||
|
/* /shared1/content.map entry */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char filename[8];
|
||||||
|
sha1 hash;
|
||||||
|
} ATTRIBUTE_PACKED SharedContent;
|
||||||
|
|
||||||
|
/* "cIOS build tag" */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CIOS_INFO_MAGIC = 0x1EE7C105,
|
||||||
|
CIOS_INFO_VERSION = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 hdr_magic; // 0x1EE7C105
|
||||||
|
u32 hdr_version; // 1
|
||||||
|
u32 cios_version; // Eg. 11
|
||||||
|
u32 ios_base; // Eg. 60
|
||||||
|
|
||||||
|
char name[16];
|
||||||
|
char cios_version_str[16];
|
||||||
|
|
||||||
|
char _padding[16];
|
||||||
|
} cIOSInfo;
|
||||||
|
// _Static_assert(sizeof(cIOSInfo) == 0x40, "Incorrect cIOSInfo struct size, do i really need to pack this..?");
|
||||||
|
|
||||||
|
#define IS_WIIU (*(vu16*)0xCD8005A0 == 0xCAFE)
|
||||||
|
|
||||||
extern u32 boot2version;
|
extern u32 boot2version;
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
bool isIOSstub(u8 ios_number);
|
bool isIOSstub(u8 ios_number);
|
||||||
|
bool tmdIsStubIOS(tmd*);
|
||||||
bool loadIOS(int ios);
|
bool loadIOS(int ios);
|
||||||
|
bool ES_CheckHasKoreanKey(void);
|
||||||
void Sys_Init(void);
|
void Sys_Init(void);
|
||||||
void Sys_Reboot(void);
|
void Sys_Reboot(void);
|
||||||
void Sys_Shutdown(void);
|
void Sys_Shutdown(void);
|
||||||
void Sys_LoadMenu(void);
|
void Sys_LoadMenu(void);
|
||||||
s32 Sys_GetCerts(signed_blob **, u32 *);
|
s32 Sys_GetCerts(signed_blob **, u32 *);
|
||||||
|
bool Sys_GetcIOSInfo(int IOS, cIOSInfo*);
|
||||||
|
s32 Sys_GetSharedContents(SharedContent** out, u32* count);
|
||||||
|
bool Sys_SharedContentPresent(tmd_content* content, SharedContent shared[], u32 count);
|
||||||
void SetPRButtons(bool enabled);
|
void SetPRButtons(bool enabled);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2,12 +2,14 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <malloc.h>
|
|
||||||
#include <ogcsys.h>
|
#include <ogcsys.h>
|
||||||
|
#include <ogc/es.h>
|
||||||
|
|
||||||
#include "sha1.h"
|
#include "sha1.h"
|
||||||
|
#include "aes.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "otp.h"
|
||||||
|
#include "malloc.h"
|
||||||
|
|
||||||
s32 Title_ZeroSignature(signed_blob *p_sig)
|
s32 Title_ZeroSignature(signed_blob *p_sig)
|
||||||
{
|
{
|
||||||
|
@ -79,7 +81,7 @@ s32 Title_GetList(u64 **outbuf, u32 *outlen)
|
||||||
{
|
{
|
||||||
u64 *titles = NULL;
|
u64 *titles = NULL;
|
||||||
|
|
||||||
u32 len, nb_titles;
|
u32 nb_titles;
|
||||||
s32 ret;
|
s32 ret;
|
||||||
|
|
||||||
/* Get number of titles */
|
/* Get number of titles */
|
||||||
|
@ -87,11 +89,9 @@ s32 Title_GetList(u64 **outbuf, u32 *outlen)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Calculate buffer lenght */
|
|
||||||
len = round_up(sizeof(u64) * nb_titles, 32);
|
|
||||||
|
|
||||||
/* Allocate memory */
|
/* Allocate memory */
|
||||||
titles = memalign(32, len);
|
titles = memalign32(nb_titles * sizeof(u64));
|
||||||
if (!titles)
|
if (!titles)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ s32 Title_GetTicketViews(u64 tid, tikview **outbuf, u32 *outlen)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Allocate memory */
|
/* Allocate memory */
|
||||||
views = (tikview *)memalign(32, sizeof(tikview) * nb_views);
|
views = memalign32(sizeof(tikview) * nb_views);
|
||||||
if (!views)
|
if (!views)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ s32 Title_GetTMD(u64 tid, signed_blob **outbuf, u32 *outlen)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Allocate memory */
|
/* Allocate memory */
|
||||||
p_tmd = memalign(32, round_up(len, 32));
|
p_tmd = memalign32(len);
|
||||||
if (!p_tmd)
|
if (!p_tmd)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -290,7 +290,7 @@ s32 Title_GetIOSVersions(u8 **outbuf, u32 *outlen)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate memory */
|
/* Allocate memory */
|
||||||
buffer = (u8 *)memalign(32, cnt);
|
buffer = memalign32(cnt);
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -318,3 +318,26 @@ out:
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((aligned(0x10)))
|
||||||
|
aeskey WiiCommonKey, vWiiCommonKey;
|
||||||
|
|
||||||
|
void Title_SetupCommonKeys(void)
|
||||||
|
{
|
||||||
|
static bool keys_ok = false;
|
||||||
|
if (keys_ok)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Grab the Wii common key...
|
||||||
|
otp_read(WiiCommonKey, offsetof(otp_t, common_key), sizeof(aeskey));
|
||||||
|
|
||||||
|
// ...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] = {};
|
||||||
|
|
||||||
|
memcpy(vWiiCommonKey, vwii_key_enc_bin, sizeof(vwii_key_enc_bin));
|
||||||
|
AES_Decrypt(WiiCommonKey, sizeof(aeskey), iv, sizeof(iv), vWiiCommonKey, vWiiCommonKey, sizeof(aeskey));
|
||||||
|
|
||||||
|
keys_ok = true;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
#ifndef _TITLE_H_
|
#ifndef _TITLE_H_
|
||||||
#define _TITLE_H_
|
#define _TITLE_H_
|
||||||
|
|
||||||
|
#include <ogc/es.h>
|
||||||
|
|
||||||
/* Constants */
|
/* Constants */
|
||||||
#define BLOCK_SIZE 1024
|
#define BLOCK_SIZE 0x4000
|
||||||
|
|
||||||
|
/* Variables */
|
||||||
|
extern aeskey WiiCommonKey, vWiiCommonKey;
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
s32 Title_ZeroSignature(signed_blob *);
|
s32 Title_ZeroSignature(signed_blob *);
|
||||||
|
@ -15,5 +20,6 @@ s32 Title_GetVersion(u64, u16 *);
|
||||||
s32 Title_GetSysVersion(u64, u64 *);
|
s32 Title_GetSysVersion(u64, u64 *);
|
||||||
s32 Title_GetSize(u64, u32 *);
|
s32 Title_GetSize(u64, u32 *);
|
||||||
s32 Title_GetIOSVersions(u8 **, u32 *);
|
s32 Title_GetIOSVersions(u8 **, u32 *);
|
||||||
|
void Title_SetupCommonKeys(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,12 +8,15 @@
|
||||||
#include <wiidrc/wiidrc.h>
|
#include <wiidrc/wiidrc.h>
|
||||||
|
|
||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
|
#include "title.h"
|
||||||
|
#include "aes.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
#include "restart.h"
|
#include "restart.h"
|
||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
#include "video.h"
|
#include "video.h"
|
||||||
#include "wpad.h"
|
#include "wpad.h"
|
||||||
|
#include "wkb.h"
|
||||||
#include "fat.h"
|
#include "fat.h"
|
||||||
#include "nand.h"
|
#include "nand.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
@ -179,8 +182,12 @@ int main(int argc, char **argv)
|
||||||
Wpad_Init();
|
Wpad_Init();
|
||||||
PAD_Init();
|
PAD_Init();
|
||||||
WiiDRC_Init();
|
WiiDRC_Init();
|
||||||
|
WKB_Initialize();
|
||||||
WIILIGHT_Init();
|
WIILIGHT_Init();
|
||||||
|
|
||||||
|
AES_Init();
|
||||||
|
Title_SetupCommonKeys();
|
||||||
|
|
||||||
/* Print disclaimer */
|
/* Print disclaimer */
|
||||||
//Disclaimer();
|
//Disclaimer();
|
||||||
|
|
||||||
|
|
874
source/wad.c
874
source/wad.c
File diff suppressed because it is too large
Load Diff
161
source/wkb.c
161
source/wkb.c
|
@ -1,47 +1,150 @@
|
||||||
|
/*
|
||||||
|
* Most of this code was adapted from Priiloader.
|
||||||
|
* https://github.com/DacoTaco/priiloader/blob/master/tools/DacosLove/source/Input.cpp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <ogc/lwp.h>
|
||||||
|
#include <wiiuse/wpad.h>
|
||||||
|
|
||||||
#include "wkb.h"
|
#include "wkb.h"
|
||||||
|
|
||||||
/*
|
enum
|
||||||
|
|
||||||
s32 USBKeyboard_Open(const eventcallback cb);
|
|
||||||
void USBKeyboard_Close(void);
|
|
||||||
|
|
||||||
bool USBKeyboard_IsConnected(void);
|
|
||||||
s32 USBKeyboard_Scan(void);
|
|
||||||
|
|
||||||
s32 USBKeyboard_SetLed(const USBKeyboard_led led, bool on);
|
|
||||||
s32 USBKeyboard_ToggleLed(const USBKeyboard_led led);
|
|
||||||
*/
|
|
||||||
|
|
||||||
s32 WkbInit(void)
|
|
||||||
{
|
{
|
||||||
s32 retval = 0;
|
/* Configuration i guess */
|
||||||
|
WKB_THREAD_PRIORITY = 0x7F,
|
||||||
|
WKB_THREAD_STACK = 0x4000,
|
||||||
|
WKB_THREAD_UDELAY = 400,
|
||||||
|
WKB_ANIMATION_UDELAY= 250000,
|
||||||
|
|
||||||
retval = USBKeyboard_Initialize();
|
/* The keys themselves */
|
||||||
|
WKB_ARROW_UP = 0x52,
|
||||||
|
WKB_ARROW_DOWN = 0x51,
|
||||||
|
WKB_ARROW_LEFT = 0x50,
|
||||||
|
WKB_ARROW_RIGHT = 0x4F,
|
||||||
|
|
||||||
return (retval);
|
WKB_SPACEBAR = 0x2C,
|
||||||
|
WKB_ENTER = 0x28,
|
||||||
|
WKB_NUMPAD_ENTER = 0x58,
|
||||||
|
WKB_BACKSPACE = 0x2A,
|
||||||
|
WKB_DELETE = 0x4C,
|
||||||
|
WKB_ESCAPE = 0x29,
|
||||||
|
WKB_HOME = 0x4A,
|
||||||
|
|
||||||
} // WkbInit
|
WKB_KEY_PLUS = 0x2E,
|
||||||
|
WKB_KEY_MINUS = 0x2D,
|
||||||
|
|
||||||
s32 WkbDeInit(void)
|
WKB_KEY_X = 0x1B,
|
||||||
|
WKB_KEY_Y = 0x1C,
|
||||||
|
WKB_KEY_1 = 0x1E,
|
||||||
|
WKB_KEY_2 = 0x1F,
|
||||||
|
};
|
||||||
|
|
||||||
|
static lwp_t WKBThreadHandle = LWP_THREAD_NULL;
|
||||||
|
static volatile bool WKBThreadActive;
|
||||||
|
static u16 WKBButtonsPressed;
|
||||||
|
|
||||||
|
static void WKBEventHandler(USBKeyboard_event evt)
|
||||||
{
|
{
|
||||||
s32 retval = 0;
|
// OSReport("Keyboard event: {%i, 0x%02hhx}", evt.type, evt.keyCode);
|
||||||
|
|
||||||
retval = USBKeyboard_Deinitialize();
|
if (!(evt.type == USBKEYBOARD_PRESSED || evt.type == USBKEYBOARD_RELEASED))
|
||||||
|
return;
|
||||||
|
|
||||||
return (retval);
|
u16 button;
|
||||||
|
switch (evt.keyCode)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Maybe I should create an array with a map of keycodes to the corresponding WPAD buttons.
|
||||||
|
* Like there's just this u16 WKBKeyMap[0x100] somewhere here and I can just say button = WKBKeyMap[evt.keyCode];
|
||||||
|
*/
|
||||||
|
case WKB_ENTER:
|
||||||
|
case WKB_NUMPAD_ENTER: button = WPAD_BUTTON_A; break;
|
||||||
|
case WKB_BACKSPACE: button = WPAD_BUTTON_B; break;
|
||||||
|
|
||||||
} // WkbDeInit
|
case WKB_ARROW_UP: button = WPAD_BUTTON_UP; break;
|
||||||
|
case WKB_ARROW_DOWN: button = WPAD_BUTTON_DOWN; break;
|
||||||
|
case WKB_ARROW_LEFT: button = WPAD_BUTTON_LEFT; break;
|
||||||
|
case WKB_ARROW_RIGHT: button = WPAD_BUTTON_RIGHT; break;
|
||||||
|
|
||||||
u32 WkbWaitKey (void)
|
case WKB_ESCAPE:
|
||||||
|
case WKB_HOME: button = WPAD_BUTTON_HOME; break;
|
||||||
|
case WKB_KEY_PLUS: button = WPAD_BUTTON_PLUS; break;
|
||||||
|
case WKB_KEY_MINUS: button = WPAD_BUTTON_MINUS; break;
|
||||||
|
case WKB_KEY_1: button = WPAD_BUTTON_1; break;
|
||||||
|
case WKB_KEY_2: button = WPAD_BUTTON_2; break;
|
||||||
|
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt.type == USBKEYBOARD_PRESSED)
|
||||||
|
WKBButtonsPressed |= button;
|
||||||
|
else
|
||||||
|
WKBButtonsPressed &= ~button;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* WKBThread(__attribute__((unused)) void* arg)
|
||||||
{
|
{
|
||||||
u32 retval = 0;
|
while (WKBThreadActive)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Despite having a return type of s32, USBKeyboard_Open() returns 1 if it was successful, rather than 0.
|
||||||
|
* So this statement right here will check if a USB keyboard was detected, and if not, try open it again.
|
||||||
|
*/
|
||||||
|
if (!USBKeyboard_IsConnected() && USBKeyboard_Open(WKBEventHandler) == true)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* And once it does open it successfully:
|
||||||
|
*
|
||||||
|
* "wake up the keyboard by sending it a command.
|
||||||
|
* im looking at you, bastard LINQ keyboard."
|
||||||
|
* - https://github.com/DacoTaco/priiloader/blob/master/tools/DacosLove/source/Input.cpp#L93-L94
|
||||||
|
*
|
||||||
|
* Just thought i would make this a fun lil animation :)
|
||||||
|
*/
|
||||||
|
for (int led = 0; led < 3; led++) { USBKeyboard_SetLed(led, true); usleep(WKB_ANIMATION_UDELAY); }
|
||||||
|
}
|
||||||
|
|
||||||
// Stub
|
USBKeyboard_Scan();
|
||||||
return (retval);
|
usleep(WKB_THREAD_UDELAY);
|
||||||
|
}
|
||||||
|
|
||||||
} // WkbWaitKey
|
// for (int led = 3; led; led--) { USBKeyboard_SetLed(led, false); usleep(WKB_ANIMATION_UDELAY); }
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WKB_Initialize(void)
|
||||||
|
{
|
||||||
|
USB_Initialize();
|
||||||
|
USBKeyboard_Initialize();
|
||||||
|
|
||||||
|
WKBThreadActive = true;
|
||||||
|
LWP_CreateThread(&WKBThreadHandle, WKBThread, NULL, NULL, WKB_THREAD_STACK, WKB_THREAD_PRIORITY);
|
||||||
|
atexit(WKB_Deinitialize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WKB_Deinitialize(void)
|
||||||
|
{
|
||||||
|
WKBThreadActive = false;
|
||||||
|
usleep(WKB_THREAD_UDELAY);
|
||||||
|
|
||||||
|
USBKeyboard_Close();
|
||||||
|
USBKeyboard_Deinitialize();
|
||||||
|
|
||||||
|
if (WKBThreadHandle != LWP_THREAD_NULL)
|
||||||
|
LWP_JoinThread(WKBThreadHandle, NULL);
|
||||||
|
|
||||||
|
WKBThreadHandle = LWP_THREAD_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 WKB_GetButtons(void)
|
||||||
|
{
|
||||||
|
u16 buttons = WKBButtonsPressed;
|
||||||
|
WKBButtonsPressed = 0;
|
||||||
|
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
|
||||||
//void Wpad_Disconnect(void);
|
|
||||||
//u32 Wpad_GetButtons(void);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,15 +5,14 @@
|
||||||
//#include <stdlib.h>
|
//#include <stdlib.h>
|
||||||
//#include <string.h>
|
//#include <string.h>
|
||||||
//#include <malloc.h>
|
//#include <malloc.h>
|
||||||
#include <ogcsys.h> // u8, u16, etc...
|
#include <gctypes.h> // u8, u16, etc...
|
||||||
|
|
||||||
#include <wiikeyboard/keyboard.h>
|
#include <wiikeyboard/keyboard.h>
|
||||||
#include <wiikeyboard/usbkeyboard.h>
|
#include <wiikeyboard/usbkeyboard.h>
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
s32 WkbInit(void);
|
void WKB_Initialize(void);
|
||||||
u32 WkbWaitKey (void);
|
void WKB_Deinitialize(void);
|
||||||
//void Wpad_Disconnect(void);
|
u16 WKB_GetButtons(void);
|
||||||
//u32 Wpad_GetButtons(void);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<app version="1">
|
<app version="1">
|
||||||
<name>YAWM ModMii Edition</name>
|
<name>YAWM ModMii Edition</name>
|
||||||
<version>1.0</version>
|
<version>1.1</version>
|
||||||
<coder>Various</coder>
|
<coder>Various</coder>
|
||||||
<short_description>Manage WADs and Launch Apps</short_description>
|
<short_description>Manage WADs and Launch Apps</short_description>
|
||||||
<long_description>Yet Another Wad Manager ModMii Edition (yawmME)
|
<long_description>Yet Another Wad Manager ModMii Edition (yawmME)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user