Skip to content
2 changes: 1 addition & 1 deletion ios_kernel/source/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ int _main(void* arg)

map_info.paddr = 0x05116000 - 0x05100000 + 0x13d80000;
map_info.vaddr = 0x05116000;
map_info.size = 0xa000;
map_info.size = 0xf000;
map_info.domain = 1; // MCP
map_info.type = 3;
map_info.cached = 0xffffffff;
Expand Down
2 changes: 1 addition & 1 deletion ios_mcp/link.ld
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ SECTIONS {
}
}

ASSERT(SIZEOF(.text) < 0xa000, "ios_mcp text is too big");
ASSERT(SIZEOF(.text) < 0xf000, "ios_mcp text is too big");
ASSERT(SIZEOF(.bss) < 0x3000, "ios_mcp bss is too big");
200 changes: 200 additions & 0 deletions ios_mcp/source/file_check.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
#include <string.h>

#include "file_check.h"
#include "gfx.h"
#include "fsa.h"
#include "utils.h"
#include "menu.h"



#define COPY_BUFFER_SIZE 1024
#define MAX_PATH_LENGHT 0x27F
#define MAX_DIRECTORY_DEPTH 60
#define LOG_INFO 1

#define printf_fs_error(error_cnt, fmt, ...) ({\
gfx_set_font_color(COLOR_ERROR); \
gfx_printf(16, 120, GfxPrintFlag_ClearBG, "Total Errors: %u", error_cnt); \
gfx_printf(16, 100, GfxPrintFlag_ClearBG, fmt, ##__VA_ARGS__); \
gfx_set_font_color(COLOR_PRIMARY); })

static void* malloc_e(size_t sz){
void *buff = IOS_HeapAlloc(LOCAL_PROCESS_HEAP_ID, sz);
if(!buff)
print_error(16 + 8 + 2 + 50, "Out of memory!");
return buff;
}

static int error_count = 0;

static int write_log(int fsaHandle, int logHandle, void *dataBuffer){
int res = FSA_WriteFile(fsaHandle, dataBuffer, strnlen(dataBuffer, COPY_BUFFER_SIZE), 1, logHandle, 0);
if(res == 1)
res = FSA_FlushFile(fsaHandle, logHandle);
if(res<0){
printf_error(6 + 8 + 2 + 8, "Error writing log: -%08X", -res);
return -1;
}
return 0;
}

static int log_error(int fsaHandle, int logHandle, const char *operation, const char *path, int error, void *dataBuffer){
error_count++;
printf_fs_error(error_count, "Error %s %s: -%08X", operation, path, error);
snprintf(dataBuffer, COPY_BUFFER_SIZE, "ERROR;%s;%s;-%08X\n", operation, path, -error);
return write_log(fsaHandle, logHandle, dataBuffer);
}

static int log_info(int fsaHandle, int logHandle, const char *operation, const char *path, void *dataBuffer){
#if LOGINFO
snprintf(dataBuffer, COPY_BUFFER_SIZE, "INFO;%s;%s;00000000\n", operation, path);
return write_log(fsaHandle, logHandle, dataBuffer);
#else
return 0;
#endif
}


static int tryToReadFile(int fsaHandle, const char *path, int logHandle, char *dataBuffer, int *in_out_error_cnt){
int ret = 0;
int readHandle = 0;

static uint8_t color = 0;
SMC_SetNotificationLED(color?NOTIF_LED_BLUE:NOTIF_LED_ORANGE);
color=!color;

log_info(fsaHandle, logHandle, "StartOpenFile", path, dataBuffer);
int res = FSA_OpenFile(fsaHandle, path, "r", &readHandle);
if (res < 0) {
log_error(fsaHandle, logHandle, "OpenFile", path, res, dataBuffer);
return 1;
}

log_info(fsaHandle, logHandle, "StartReadFile", path, dataBuffer);
do{
res = FSA_ReadFile(fsaHandle, dataBuffer, 1, COPY_BUFFER_SIZE, readHandle, 0);
} while (res > 0);

if (res < 0) {
log_error(fsaHandle, logHandle, "ReadFile", path, res, dataBuffer);
ret = 2;
}
log_info(fsaHandle, logHandle, "StartCloseFile", path, dataBuffer);
FSA_CloseFile(fsaHandle, readHandle);

return ret;
}

static int open_dir_e(int fsaHandle, const char *path, int *dir_handle, int logHandle, void *dataBuffer, int *in_out_error_cnt){
log_info(fsaHandle, logHandle, "StartOpenDir", path, dataBuffer);
int res = FSA_OpenDir(fsaHandle, path, dir_handle);
if (res < 0) {
log_error(fsaHandle, logHandle, "OpenDir", path, res, dataBuffer);
return 1;
}
return 0;
}

int checkDirRecursive(int fsaHandle, const char *base_path, int logHandle){
void* dataBuffer = NULL;
char *path = NULL;
int ret = -1;
error_count = 0;


dataBuffer = IOS_HeapAllocAligned(CROSS_PROCESS_HEAP_ID, COPY_BUFFER_SIZE, 0x40);
if (!dataBuffer) {
print_error(16 + 8 + 2 + 8, "Out of IO memory!");
goto error;
}

path = (char*) malloc_e(MAX_PATH_LENGHT + 1);
if (!path) {
goto error;
}
strncpy(path, base_path, MAX_DIRECTORY_DEPTH);

int depth = -1;
int dir_stack[MAX_DIRECTORY_DEPTH] = { 0 };
int res=open_dir_e(fsaHandle, path, dir_stack, logHandle, dataBuffer, &ret);
if(res)
goto error;
depth = 0;
uint32_t dir_path_len = strnlen(path, MAX_PATH_LENGHT);
path[dir_path_len] = '/';
dir_path_len++;
path[dir_path_len] ='\0';

ret = 0;
while(depth >= 0){
FSDirectoryEntry dir_entry;
log_info(fsaHandle, logHandle, "StartReadDir", path, dataBuffer);
res = FSA_ReadDir(fsaHandle, dir_stack[depth], &dir_entry);
if(res < 0){
if(res != END_OF_DIR){
ret++;
log_error(fsaHandle, logHandle, "ReadDir", path, res, dataBuffer);
}
log_info(fsaHandle, logHandle, "StartCloseDir", path, dataBuffer);
FSA_CloseDir(fsaHandle, dir_stack[depth]);
dir_stack[depth] = 0;
depth--;
do {
dir_path_len--;
} while((dir_path_len > 0) && (path[dir_path_len - 1] != '/'));
path[dir_path_len] = '\0';
continue;
}
if(dir_entry.stat.flags & DIR_ENTRY_IS_LINK)
continue; //skip symlinks
strncpy(path + dir_path_len, dir_entry.name, MAX_PATH_LENGHT);
gfx_print(16, 16 + 8 + 2 + 15, GfxPrintFlag_ClearBG, path);
if(!(dir_entry.stat.flags & DIR_ENTRY_IS_DIRECTORY)){
strncpy(path+dir_path_len, dir_entry.name, MAX_PATH_LENGHT - (dir_path_len + 1));
res = tryToReadFile(fsaHandle, path, logHandle, dataBuffer, &ret);
if(res < 0){
ret = res;
break;
}
} else { // Directory
if(depth >= MAX_DIRECTORY_DEPTH){
gfx_set_font_color(COLOR_ERROR);
gfx_printf(16, 200, GfxPrintFlag_ClearBG, "Exceeded max dir depth %u. Skipping:", depth);
gfx_print(16, 200, GfxPrintFlag_ClearBG, path);
gfx_set_font_color(COLOR_PRIMARY);
log_error(fsaHandle, logHandle, "ExceedDepth", path, -depth, dataBuffer);
continue;
}
res = open_dir_e(fsaHandle, path, dir_stack + depth + 1, logHandle, dataBuffer, &ret);
if(res < 0){
ret = res;
break;
}
if(res){
path[dir_path_len] = '\0';
continue;
}
depth++;
dir_path_len = strnlen(path, MAX_PATH_LENGHT);
path[dir_path_len] = '/';
dir_path_len++;
path[dir_path_len] = '\0';
}
}

error:
//TODO: close remaining directories in error case
for(; depth >= 0; depth--){
if(dir_stack[depth])
FSA_CloseDir(fsaHandle, dir_stack[depth]);
}
snprintf(dataBuffer, COPY_BUFFER_SIZE, "INFO;finished;%s;%d\n", base_path, error_count);
return write_log(fsaHandle, logHandle, dataBuffer);

if(path)
IOS_HeapFree(LOCAL_PROCESS_HEAP_ID, path);
if(dataBuffer)
IOS_HeapFree(CROSS_PROCESS_HEAP_ID, dataBuffer);
return ret?ret:error_count;
}
8 changes: 8 additions & 0 deletions ios_mcp/source/file_check.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef FILE_CHECK_H
#define FILE_CHECK_H


int checkDirRecursive(int fsaHandle, const char *base_path, int logHandle);


#endif //FILE_CHECK_H
14 changes: 14 additions & 0 deletions ios_mcp/source/fsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,20 @@ int FSA_StatFile(int fd, int handle, FSStat* out_data)
return ret;
}

int FSA_FlushFile(int fd, int fileHandle)
{
uint8_t* iobuf = allocIobuf();
uint32_t* inbuf = (uint32_t*)iobuf;
uint32_t* outbuf = (uint32_t*)&iobuf[0x520];

inbuf[1] = fileHandle;

int ret = IOS_Ioctl(fd, 0x17, inbuf, 0x520, outbuf, 0x293);

freeIobuf(iobuf);
return ret;
}

int FSA_CloseFile(int fd, int fileHandle)
{
uint8_t* iobuf = allocIobuf();
Expand Down
3 changes: 3 additions & 0 deletions ios_mcp/source/fsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ typedef struct {
} FSDirectoryEntry;

#define DIR_ENTRY_IS_DIRECTORY 0x80000000
#define DIR_ENTRY_IS_LINK 0x10000
#define END_OF_DIR -0x30004

#define FSA_MOUNTFLAGS_BINDMOUNT (1 << 0)
#define FSA_MOUNTFLAGS_GLOBAL (1 << 1)
Expand All @@ -42,6 +44,7 @@ int FSA_OpenFile(int fd, const char* path, const char* mode, int* outHandle);
int FSA_ReadFile(int fd, void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags);
int FSA_WriteFile(int fd, void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags);
int FSA_StatFile(int fd, int handle, FSStat* out_data);
int FSA_FlushFile(int fd, int fileHandle);
int FSA_CloseFile(int fd, int fileHandle);
int FSA_SetPosFile(int fd, int fileHandle, uint32_t position);
int FSA_GetStat(int fd, const char* path, FSStat* out_data);
Expand Down
55 changes: 55 additions & 0 deletions ios_mcp/source/menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@

#include <string.h>
#include <unistd.h>
#include <stdarg.h>

#include "StartWupserver.h"
#include "PairDRC.h"
#include "DebugSystemRegion.h"
#include "SystemInformation.h"
#include "SubmitSystemData.h"
#include "file_check.h"

static void option_SetColdbootTitle(void);
static void option_DumpSyslogs(void);
Expand All @@ -43,6 +45,7 @@ static void option_LoadNetConf(void);
static void option_InstallWUP(void);
static void option_EditParental(void);
static void option_Shutdown(void);
static void option_checkMLC(void);

extern int ppcHeartBeatThreadId;
extern uint64_t currentColdbootOS;
Expand All @@ -60,6 +63,7 @@ static const Menu mainMenuOptions[] = {
{"Install WUP", {.callback = option_InstallWUP}},
{"Edit Parental Controls", {.callback = option_EditParental}},
{"Debug System Region", {.callback = option_DebugSystemRegion}},
{"Check MLC", {.callback = option_checkMLC}},
{"System Information", {.callback = option_SystemInformation}},
{"Submit System Data", {.callback = option_SubmitSystemData}},
{"Shutdown", {.callback = option_Shutdown}},
Expand Down Expand Up @@ -223,6 +227,28 @@ void waitButtonInput(void)
}
}

void print_error(int index, const char *msg)
{
gfx_set_font_color(COLOR_ERROR);
gfx_print(16, index, GfxPrintFlag_ClearBG, msg);
SMC_SetNotificationLED(NOTIF_LED_RED);
waitButtonInput();
SMC_SetNotificationLED(NOTIF_LED_PURPLE);
}

void printf_error(int index, const char *format, ...)
{
va_list args;
va_start(args, format);

char buffer[0x100];

vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);

print_error(index, buffer);
}

static void option_SetColdbootTitle(void)
{
static const Menu coldbootTitleOptions[] = {
Expand Down Expand Up @@ -932,6 +958,35 @@ static void option_Shutdown(void)
IOS_Shutdown(0);
}

static void option_checkMLC(void)
{
gfx_clear(COLOR_BACKGROUND);

drawTopBar("Checking MLC...");
SMC_SetNotificationLED(NOTIF_LED_ORANGE_BLINKING);

int fileHandle;
int res = FSA_OpenFile(fsaHandle, "/vol/storage_recovsd/mlc_checker.txt", "w", &fileHandle);
if (res < 0) {
printf_error(16 + 8 + 2 + 8, "Failed to create mlc_checker.txt: %x", res);
return;
}

int result = checkDirRecursive(fsaHandle, "/vol/storage_mlc01", fileHandle);
if (result<0) {
print_error(16 + 8 + 2 + 15, "ERROR!");
goto close;
}

gfx_draw_rect_filled(0, 16 + 8 + 2 + 15, 1280, 16 + 8 + 2 + 8, COLOR_BACKGROUND);
gfx_set_font_color(COLOR_SUCCESS);
gfx_printf(16, 16 + 8 + 2 + 15, 0, "Done! %u errors", result);

close:
FSA_CloseFile(fsaHandle, fileHandle);
SMC_SetNotificationLED(NOTIF_LED_PURPLE);
}

int menuThread(void* arg)
{
printf("menuThread running\n");
Expand Down
4 changes: 4 additions & 0 deletions ios_mcp/source/menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ int drawMenu(const char* title, const Menu* menu, size_t count,
*/
void waitButtonInput(void);

void print_error(int index, const char *msg);

void printf_error(int index, const char *format, ...);

/**
* Initialize the network configuration.
* @param index [in/out] Starting (and ending) Y position.
Expand Down
2 changes: 1 addition & 1 deletion ios_mcp/source/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,4 @@ int SMC_SetNotificationLED(uint8_t mask)
int SMC_SetODDPower(int power)
{
return bspWrite("SMC", 0, "ODDPower", 4, &power);
}
}
1 change: 1 addition & 0 deletions ios_mcp/source/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ enum {
NOTIF_LED_RED = 1 << 3,
NOTIF_LED_BLUE_BLINKING = 1 << 4,
NOTIF_LED_BLUE = 1 << 5,
NOTIF_LED_PURPLE = NOTIF_LED_RED | NOTIF_LED_BLUE,
};

uint32_t kernRead32(uint32_t address);
Expand Down