Over the past few years I've written a lot of wii code that has been kept private for various reasons. I think it might be time to show some of it off and give somebody else the chance to do something useful with it. Having said that, all code posted here falls under the following licence:
Code:
If the function returns 1 it succeeded, you should be able to communicate with your IOS module using regular IPC calls - you did make it register a device name, right?
Code:
Code:
/* Copyright 2013 tueidj All Rights Reserved * This code may not be used in any project * without explicit permission from the author. */ Lesson 1: Loading your own IOS module into the currently running IOS Most people know IOS runs on its own dedicated CPU - an ARM926EJ-S commonly known as Starlet. For the majority of the time, Starlet sits in an idle loop waiting for interrupts - why not give it some real work to do by making IOS run some custom code? First you need to be able to modify the existing IOS code. This requires the MEM2 protection to be disabled, which needs AHBPROT disabled. HBC can take of AHBPROT and the rest is fairly trivial. Since the ES module is the only part of IOS that is "allowed" to load a new module, we're going to modify one of its ioctls. Choosing which one is pretty simple; it should be one that isn't used under normal conditions, it should have uniquely identifiable code (so we can find where it is in memory) and there should be plenty of space for us to overwrite with our own code. ES_ImportBoot2 fits these requirements - it's used to upgrade boot2 which no regular application will want to do. After deciding which ioctl to overwrite all we need to do is write our custom IOS module to the wii's NAND (the /tmp directory is a good choice) and use the following function: Code: #define ES_MODULE_START ((u8*)0x939F0000) #define ES_MODULE_SIZE 0x20000 static int load_module_file(s32 es_fd, const char *filename) { // this is the original code for the ES_ImportBoot2 ioctl const u8 old_es_code[24] = { 0x68, 0x4B, 0x2B, 0x06, 0xD1, 0x0C, 0x68, 0x8B, 0x2B, 0x00, 0xD1, 0x09, 0x68, 0xC8, 0x68, 0x42, 0x23, 0xA9, 0x00, 0x9B, 0x42, 0x9A, 0xD1, 0x03}; // this is the code that will overwrite it const u16 load_module[12] = { 0x68CE, // ldr r6, [r1, #0x0c] ; ipcmessage.vec 0x6830, // ldr r0, [r6] ; vec[0].data (filename of module) 0x4778, // thumb->arm (BX PC) 0x46C0, // nop (for alignment, assumes this block starts 4-byte aligned) 0xE600, 0x0B50, // syscall_5a (load_ios_module) 0xE28D, 0xD020, // ADD SP, SP, #0x20 0xE8BD, 0x4070, // LDMFD SP!,{R4-R6,LR} 0xE12F, 0xFF1E, // BX LR }; u8 *addr; s32 ret=1; ioctlv vec; for (addr=ES_MODULE_START;addr < ES_MODULE_START+ES_MODULE_SIZE-sizeof(old_es_code);addr++) { if (!memcmp(addr, old_es_code, sizeof(old_es_code))) { memcpy(addr, load_module, sizeof(load_module)); DCFlushRange((void*)((u32)addr&~0x1F), 32); vec.data = (void*)filename; vec.len = strlen(filename)+1; // call ES_ImportBoot2 with the module filename as a parameter ret = IOS_Ioctlv(es_fd, 0x1F, 1, 0, &vec); // restore the old code and flush memcpy(addr, old_es_code, sizeof(load_module)); DCFlushRange((void*)((u32)addr&~0x1F), 32); break; } } return !ret; }
If the function returns 1 it succeeded, you should be able to communicate with your IOS module using regular IPC calls - you did make it register a device name, right?