From dcb09a9472263e1e1787039f05765dd6b757ad2e Mon Sep 17 00:00:00 2001 From: Aurora Date: Thu, 17 Mar 2016 00:08:13 +0100 Subject: [PATCH] Added dual emuNAND support, multi-payload loader with built-in screen init (inspired by arm9select, thanks Fix94) --- loader/source/buttons.h | 14 +++ loader/source/fatfs/sdmmc/common.h | 13 +-- loader/source/i2c.c | 149 +++++++++++++++++++++++++++++ loader/source/i2c.h | 35 +++++++ loader/source/main.c | 39 ++++++-- loader/source/screeninit.c | 118 +++++++++++++++++++++++ loader/source/screeninit.h | 5 + loader/source/types.h | 20 ++++ source/draw.c | 2 +- source/emunand.c | 13 ++- source/emunand.h | 2 +- source/firm.c | 20 ++-- source/firm.h | 1 + source/loader.c | 2 +- 14 files changed, 400 insertions(+), 33 deletions(-) create mode 100644 loader/source/buttons.h create mode 100644 loader/source/i2c.c create mode 100644 loader/source/i2c.h create mode 100644 loader/source/screeninit.c create mode 100644 loader/source/screeninit.h create mode 100644 loader/source/types.h diff --git a/loader/source/buttons.h b/loader/source/buttons.h new file mode 100644 index 000000000..1d42c9af6 --- /dev/null +++ b/loader/source/buttons.h @@ -0,0 +1,14 @@ +#pragma once + +#include "types.h" + +#define HID_PAD ((~*(vu16 *)0x10146000) & 0xFFF) +#define BUTTON_B (1 << 1) +#define BUTTON_X (1 << 10) +#define BUTTON_Y (1 << 11) +#define BUTTON_SELECT (1 << 2) +#define BUTTON_START (1 << 3) +#define BUTTON_RIGHT (1 << 4) +#define BUTTON_LEFT (1 << 5) +#define BUTTON_UP (1 << 6) +#define BUTTON_DOWN (1 << 7) \ No newline at end of file diff --git a/loader/source/fatfs/sdmmc/common.h b/loader/source/fatfs/sdmmc/common.h index 64cf63220..90a327e1a 100644 --- a/loader/source/fatfs/sdmmc/common.h +++ b/loader/source/fatfs/sdmmc/common.h @@ -1,15 +1,4 @@ #pragma once -#include -#include #include - -//Common data types -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; -typedef volatile u8 vu8; -typedef volatile u16 vu16; -typedef volatile u32 vu32; -typedef volatile u64 vu64; \ No newline at end of file +#include "../../types.h" \ No newline at end of file diff --git a/loader/source/i2c.c b/loader/source/i2c.c new file mode 100644 index 000000000..f0beefdf9 --- /dev/null +++ b/loader/source/i2c.c @@ -0,0 +1,149 @@ +#include "i2c.h" + +//----------------------------------------------------------------------------- + +static const struct { u8 bus_id, reg_addr; } dev_data[] = { + {0, 0x4A}, {0, 0x7A}, {0, 0x78}, + {1, 0x4A}, {1, 0x78}, {1, 0x2C}, + {1, 0x2E}, {1, 0x40}, {1, 0x44}, + {2, 0xD6}, {2, 0xD0}, {2, 0xD2}, + {2, 0xA4}, {2, 0x9A}, {2, 0xA0}, +}; + +inline u8 i2cGetDeviceBusId(u8 device_id) { + return dev_data[device_id].bus_id; +} + +inline u8 i2cGetDeviceRegAddr(u8 device_id) { + return dev_data[device_id].reg_addr; +} + +//----------------------------------------------------------------------------- + +static vu8* reg_data_addrs[] = { + (vu8*)(I2C1_REG_OFF + I2C_REG_DATA), + (vu8*)(I2C2_REG_OFF + I2C_REG_DATA), + (vu8*)(I2C3_REG_OFF + I2C_REG_DATA), +}; + +inline vu8* i2cGetDataReg(u8 bus_id) { + return reg_data_addrs[bus_id]; +} + +//----------------------------------------------------------------------------- + +static vu8* reg_cnt_addrs[] = { + (vu8*)(I2C1_REG_OFF + I2C_REG_CNT), + (vu8*)(I2C2_REG_OFF + I2C_REG_CNT), + (vu8*)(I2C3_REG_OFF + I2C_REG_CNT), +}; + +inline vu8* i2cGetCntReg(u8 bus_id) { + return reg_cnt_addrs[bus_id]; +} + +//----------------------------------------------------------------------------- + +inline void i2cWaitBusy(u8 bus_id) { + while (*i2cGetCntReg(bus_id) & 0x80); +} + +inline bool i2cGetResult(u8 bus_id) { + i2cWaitBusy(bus_id); + return (*i2cGetCntReg(bus_id) >> 4) & 1; +} + +void i2cStop(u8 bus_id, u8 arg0) { + *i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0; + i2cWaitBusy(bus_id); + *i2cGetCntReg(bus_id) = 0xC5; +} + +//----------------------------------------------------------------------------- + +bool i2cSelectDevice(u8 bus_id, u8 dev_reg) { + i2cWaitBusy(bus_id); + *i2cGetDataReg(bus_id) = dev_reg; + *i2cGetCntReg(bus_id) = 0xC2; + return i2cGetResult(bus_id); +} + +bool i2cSelectRegister(u8 bus_id, u8 reg) { + i2cWaitBusy(bus_id); + *i2cGetDataReg(bus_id) = reg; + *i2cGetCntReg(bus_id) = 0xC0; + return i2cGetResult(bus_id); +} + +//----------------------------------------------------------------------------- + +u8 i2cReadRegister(u8 dev_id, u8 reg) { + u8 bus_id = i2cGetDeviceBusId(dev_id); + u8 dev_addr = i2cGetDeviceRegAddr(dev_id); + + for (size_t i = 0; i < 8; i++) { + if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) { + if (i2cSelectDevice(bus_id, dev_addr | 1)) { + i2cWaitBusy(bus_id); + i2cStop(bus_id, 1); + i2cWaitBusy(bus_id); + return *i2cGetDataReg(bus_id); + } + } + *i2cGetCntReg(bus_id) = 0xC5; + i2cWaitBusy(bus_id); + } + return 0xff; +} + +bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size) { + u8 bus_id = i2cGetDeviceBusId(dev_id); + u8 dev_addr = i2cGetDeviceRegAddr(dev_id); + + size_t j = 0; + while (!i2cSelectDevice(bus_id, dev_addr) + || !i2cSelectRegister(bus_id, reg) + || !i2cSelectDevice(bus_id, dev_addr | 1)) + { + i2cWaitBusy(bus_id); + *i2cGetCntReg(bus_id) = 0xC5; + i2cWaitBusy(bus_id); + if (++j >= 8) + return false; + } + + if (buf_size != 1) { + for (size_t i = 0; i < buf_size - 1; i++) { + i2cWaitBusy(bus_id); + *i2cGetCntReg(bus_id) = 0xF0; + i2cWaitBusy(bus_id); + buffer[i] = *i2cGetDataReg(bus_id); + } + } + + i2cWaitBusy(bus_id); + *i2cGetCntReg(bus_id) = 0xE1; + i2cWaitBusy(bus_id); + *buffer = *i2cGetDataReg(bus_id); + return true; +} + +bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data) { + u8 bus_id = i2cGetDeviceBusId(dev_id); + u8 dev_addr = i2cGetDeviceRegAddr(dev_id); + + for (int i = 0; i < 8; i++) { + if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) { + i2cWaitBusy(bus_id); + *i2cGetDataReg(bus_id) = data; + *i2cGetCntReg(bus_id) = 0xC1; + i2cStop(bus_id, 0); + if (i2cGetResult(bus_id)) + return true; + } + *i2cGetCntReg(bus_id) = 0xC5; + i2cWaitBusy(bus_id); + } + + return false; +} diff --git a/loader/source/i2c.h b/loader/source/i2c.h new file mode 100644 index 000000000..f047c17d3 --- /dev/null +++ b/loader/source/i2c.h @@ -0,0 +1,35 @@ +#pragma once + +#include "common.h" + +#define I2C1_REG_OFF 0x10161000 +#define I2C2_REG_OFF 0x10144000 +#define I2C3_REG_OFF 0x10148000 + +#define I2C_REG_DATA 0 +#define I2C_REG_CNT 1 +#define I2C_REG_CNTEX 2 +#define I2C_REG_SCL 4 + +#define I2C_DEV_MCU 3 +#define I2C_DEV_GYRO 10 +#define I2C_DEV_IR 13 + +u8 i2cGetDeviceBusId(u8 device_id); +u8 i2cGetDeviceRegAddr(u8 device_id); + +vu8* i2cGetDataReg(u8 bus_id); +vu8* i2cGetCntReg(u8 bus_id); + +void i2cWaitBusy(u8 bus_id); +bool i2cGetResult(u8 bus_id); +u8 i2cGetData(u8 bus_id); +void i2cStop(u8 bus_id, u8 arg0); + +bool i2cSelectDevice(u8 bus_id, u8 dev_reg); +bool i2cSelectRegister(u8 bus_id, u8 reg); + +u8 i2cReadRegister(u8 dev_id, u8 reg); +bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data); + +bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size); diff --git a/loader/source/main.c b/loader/source/main.c index b3ddb9b5a..f55a6b6bc 100644 --- a/loader/source/main.c +++ b/loader/source/main.c @@ -1,17 +1,42 @@ +#include "types.h" +#include "buttons.h" +#include "screeninit.h" #include "fatfs/ff.h" #define PAYLOAD_ADDRESS 0x23F00000 -void main() -{ - FATFS fs; +u32 loadPayload(const char *path){ FIL payload; unsigned int br; - - f_mount(&fs, "0:", 1); - if(f_open(&payload, "rei/arm9payload.bin", FA_READ) == FR_OK) + if(f_open(&payload, path, FA_READ) == FR_OK) { - f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br); + f_read(&payload, (void*)PAYLOAD_ADDRESS, f_size(&payload), &br); + f_close(&payload); + + return 1; + } + + return 0; +} + +void main(){ + FATFS fs; + f_mount(&fs, "0:", 1); + + //Get pressed buttons + u16 pressed = HID_PAD; + + if(((pressed & BUTTON_B) && loadPayload("/rei/payloads/b.bin")) || + ((pressed & BUTTON_X) && loadPayload("/rei/payloads/x.bin")) || + ((pressed & BUTTON_Y) && loadPayload("/rei/payloads/y.bin")) || + ((pressed & BUTTON_SELECT) && loadPayload("/rei/payloads/select.bin")) || + ((pressed & BUTTON_START) && loadPayload("/rei/payloads/start.bin")) || + ((pressed & BUTTON_RIGHT) && loadPayload("/rei/payloads/right.bin")) || + ((pressed & BUTTON_LEFT) && loadPayload("/rei/payloads/left.bin")) || + ((pressed & BUTTON_UP) && loadPayload("/rei/payloads/up.bin")) || + ((pressed & BUTTON_DOWN) && loadPayload("/rei/payloads/down.bin")) || + loadPayload("/rei/payloads/default.bin")){ + initLCD(); ((void (*)())PAYLOAD_ADDRESS)(); } } \ No newline at end of file diff --git a/loader/source/screeninit.c b/loader/source/screeninit.c new file mode 100644 index 000000000..793c9d13f --- /dev/null +++ b/loader/source/screeninit.c @@ -0,0 +1,118 @@ +#include "screeninit.h" +#include "i2c.h" + +void initLCD() +{ + vu32 *const arm11 = (u32 *)0x1FFFFFF8; + + void __attribute__((naked)) ARM11() + { + *(vu32 *)0x10141200 = 0x1007F; + *(vu32 *)0x10202014 = 0x00000001; + *(vu32 *)0x1020200C &= 0xFFFEFFFE; + *(vu32 *)0x10202240 = 0x39; + *(vu32 *)0x10202A40 = 0x39; + *(vu32 *)0x10202244 = 0x1023E; + *(vu32 *)0x10202A44 = 0x1023E; + + // Top screen + *(vu32 *)0x10400400 = 0x000001c2; + *(vu32 *)0x10400404 = 0x000000d1; + *(vu32 *)0x10400408 = 0x000001c1; + *(vu32 *)0x1040040c = 0x000001c1; + *(vu32 *)0x10400410 = 0x00000000; + *(vu32 *)0x10400414 = 0x000000cf; + *(vu32 *)0x10400418 = 0x000000d1; + *(vu32 *)0x1040041c = 0x01c501c1; + *(vu32 *)0x10400420 = 0x00010000; + *(vu32 *)0x10400424 = 0x0000019d; + *(vu32 *)0x10400428 = 0x00000002; + *(vu32 *)0x1040042c = 0x00000192; + *(vu32 *)0x10400430 = 0x00000192; + *(vu32 *)0x10400434 = 0x00000192; + *(vu32 *)0x10400438 = 0x00000001; + *(vu32 *)0x1040043c = 0x00000002; + *(vu32 *)0x10400440 = 0x01960192; + *(vu32 *)0x10400444 = 0x00000000; + *(vu32 *)0x10400448 = 0x00000000; + *(vu32 *)0x1040045C = 0x00f00190; + *(vu32 *)0x10400460 = 0x01c100d1; + *(vu32 *)0x10400464 = 0x01920002; + *(vu32 *)0x10400468 = 0x18300000; + *(vu32 *)0x10400470 = 0x80341; + *(vu32 *)0x10400474 = 0x00010501; + *(vu32 *)0x10400478 = 0; + *(vu32 *)0x10400490 = 0x000002D0; + *(vu32 *)0x1040049C = 0x00000000; + + // Disco register + for(vu32 i = 0; i < 256; i++) + *(vu32 *)0x10400484 = 0x10101 * i; + + // Bottom screen + *(vu32 *)0x10400500 = 0x000001c2; + *(vu32 *)0x10400504 = 0x000000d1; + *(vu32 *)0x10400508 = 0x000001c1; + *(vu32 *)0x1040050c = 0x000001c1; + *(vu32 *)0x10400510 = 0x000000cd; + *(vu32 *)0x10400514 = 0x000000cf; + *(vu32 *)0x10400518 = 0x000000d1; + *(vu32 *)0x1040051c = 0x01c501c1; + *(vu32 *)0x10400520 = 0x00010000; + *(vu32 *)0x10400524 = 0x0000019d; + *(vu32 *)0x10400528 = 0x00000052; + *(vu32 *)0x1040052c = 0x00000192; + *(vu32 *)0x10400530 = 0x00000192; + *(vu32 *)0x10400534 = 0x0000004f; + *(vu32 *)0x10400538 = 0x00000050; + *(vu32 *)0x1040053c = 0x00000052; + *(vu32 *)0x10400540 = 0x01980194; + *(vu32 *)0x10400544 = 0x00000000; + *(vu32 *)0x10400548 = 0x00000011; + *(vu32 *)0x1040055C = 0x00f00140; + *(vu32 *)0x10400560 = 0x01c100d1; + *(vu32 *)0x10400564 = 0x01920052; + *(vu32 *)0x10400568 = 0x18300000 + 0x46500; + *(vu32 *)0x10400570 = 0x80301; + *(vu32 *)0x10400574 = 0x00010501; + *(vu32 *)0x10400578 = 0; + *(vu32 *)0x10400590 = 0x000002D0; + *(vu32 *)0x1040059C = 0x00000000; + + // Disco register + for(vu32 i = 0; i < 256; i++) + *(vu32 *)0x10400584 = 0x10101 * i; + + // Enable backlight + i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); + + *(vu32 *)0x10400468 = 0x18300000; + *(vu32 *)0x1040046c = 0x18300000; + *(vu32 *)0x10400494 = 0x18300000; + *(vu32 *)0x10400498 = 0x18300000; + *(vu32 *)0x10400568 = 0x18346500; + *(vu32 *)0x1040056c = 0x18346500; + + //Clear ARM11 entry offset + *arm11 = 0; + + //Wait for the entry to be set + while(!*arm11); + //Jump to it + ((void (*)())*arm11)(); + } + + //Determine if screen was already inited + if(*(vu8 *)0x10141200 != 0x1) return; + + //Set CakeBrah framebuffers + *(vu32 *)0x23FFFE00 = 0x18300000; + *(vu32 *)0x23FFFE04 = 0x18300000; + *(vu32 *)0x23FFFE08 = 0x18346500; + + *arm11 = (u32)ARM11; + + //This delay is needed for some reason + for(vu32 i = 0; i < 0x2000; ++i); + while(*arm11); +} \ No newline at end of file diff --git a/loader/source/screeninit.h b/loader/source/screeninit.h new file mode 100644 index 000000000..95311a3c7 --- /dev/null +++ b/loader/source/screeninit.h @@ -0,0 +1,5 @@ +#pragma once + +#include "types.h" + +void initLCD(); \ No newline at end of file diff --git a/loader/source/types.h b/loader/source/types.h new file mode 100644 index 000000000..56d82bb94 --- /dev/null +++ b/loader/source/types.h @@ -0,0 +1,20 @@ +/* +* types.h +* by Reisyukaku +* Copyright (c) 2015 All Rights Reserved +*/ + +#pragma once + +#include +#include + +//Common data types +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef volatile u8 vu8; +typedef volatile u16 vu16; +typedef volatile u32 vu32; +typedef volatile u64 vu64; \ No newline at end of file diff --git a/source/draw.c b/source/draw.c index cabe8fdc6..e3acdc0ca 100644 --- a/source/draw.c +++ b/source/draw.c @@ -26,7 +26,7 @@ void __attribute__((naked)) shutdownLCD(void){ *(vu32 *)0x10202244 = 0; *(vu32 *)0x10202014 = 0; - //Wait for the ARM11 entrypoint to be set + //Wait for the entry to be set while(!*arm11); //Jump to it ((void (*)())*arm11)(); diff --git a/source/emunand.c b/source/emunand.c index 697f5a36c..f38017248 100644 --- a/source/emunand.c +++ b/source/emunand.c @@ -8,15 +8,20 @@ #include "memory.h" #include "fatfs/sdmmc/sdmmc.h" -void getEmunandSect(u32 *off, u32 *head){ +void getEmunandSect(u32 *off, u32 *head, u32 emuNAND){ u8 *const temp = (u8 *)0x24300000; u32 nandSize = getMMCDevice(0)->total_size; - if(sdmmc_sdcard_readsectors(nandSize, 1, temp) == 0){ + u32 nandOffset = emuNAND == 1 ? 0 : + (nandSize > 0x200000 ? 0x400000 : 0x200000); + + if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0){ if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){ - *off = 0; - *head = nandSize; + *off = nandOffset; + *head = nandOffset + nandSize; } + //Fallback to the first emuNAND if there's no second one + else if(emuNAND == 2) getEmunandSect(off, head, 1); } } diff --git a/source/emunand.h b/source/emunand.h index 1fbb2fb11..6ccd34179 100644 --- a/source/emunand.h +++ b/source/emunand.h @@ -10,7 +10,7 @@ #define NCSD_MAGIC (0x4453434E) -void getEmunandSect(u32 *off, u32 *head); +void getEmunandSect(u32 *off, u32 *head, u32 emuNAND); void getSDMMC(void *pos, u32 *off, u32 size); void getEmuRW(void *pos, u32 size, u32 *readOff, u32 *writeOff); void getMPU(void *pos, u32 *off, u32 size); \ No newline at end of file diff --git a/source/firm.c b/source/firm.c index c9785ebfa..65a9bfda1 100755 --- a/source/firm.c +++ b/source/firm.c @@ -53,11 +53,11 @@ void setupCFW(void){ fileRead(&tempConfig, lastConfigPath, 1); //Always force a sysNAND boot when quitting AGB_FIRM - if(previousFirm == 0x7) { + if(previousFirm == 0x7){ if(!updatedSys) mode = tempConfig & 0x1; overrideConfig = 1; //Else, force the last used boot options unless A is pressed - } else if(!(pressed & BUTTON_A)) { + } else if(!(pressed & BUTTON_A)){ mode = tempConfig & 0x1; emuNAND = (tempConfig >> 1) & 0x1; overrideConfig = 1; @@ -79,7 +79,11 @@ void setupCFW(void){ /* If L or R aren't pressed on a 9.0/9.2 SysNAND, or the 9.0 FIRM is selected or R is pressed on a > 9.2 SysNAND, boot emuNAND */ if((updatedSys && (!mode || ((pressed & BUTTON_R1) && pressed != SAFEMODE))) || - (!updatedSys && mode && !(pressed & BUTTON_R1))) emuNAND = 1; + (!updatedSys && mode && !(pressed & BUTTON_R1))){ + //If not 9.0 FIRM and B is pressed, attempt booting the second emuNAND + if(mode && (pressed & BUTTON_B)) emuNAND = 2; + else emuNAND = 1; + } //Write the current boot options on A9LH if(a9lhBoot){ @@ -88,8 +92,9 @@ void setupCFW(void){ } } - if(mode) firmPathPatched = emuNAND ? "/rei/patched_firmware_emu.bin" : - "/rei/patched_firmware_sys.bin"; + if(mode) firmPathPatched = emuNAND ? (emuNAND == 1 ? "/rei/patched_firmware_emu.bin" : + "/rei/patched_firmware_em2.bin") : + "/rei/patched_firmware_sys.bin"; //Skip decrypting and patching FIRM if(fileExists("/rei/usepatchedfw")){ @@ -156,7 +161,7 @@ static u32 loadEmu(void){ u32 *pos_offset = (u32 *)memsearch((void *)emuCodeOffset, "NAND", size, 4); u32 *pos_header = (u32 *)memsearch((void *)emuCodeOffset, "NCSD", size, 4); getSDMMC(firmLocation, &sdmmcOffset, firmSize); - getEmunandSect(&emuOffset, &emuHeader); + getEmunandSect(&emuOffset, &emuHeader, emuNAND); getEmuRW(firmLocation, firmSize, &emuRead, &emuWrite); getMPU(firmLocation, &mpuOffset, firmSize); *pos_sdmmc = sdmmcOffset; @@ -228,7 +233,8 @@ u32 patchFirm(void){ //Patch path for emuNAND-patched FIRM if(emuNAND){ void *pos_path = memsearch((void *)rebootOffset, L"sy", size, 4); - memcpy(pos_path, L"emu", 5); + const wchar_t *path = emuNAND == 1 ? L"emu" : L"em2"; + memcpy(pos_path, path, 5); } } diff --git a/source/firm.h b/source/firm.h index 614e2b758..a700f07aa 100644 --- a/source/firm.h +++ b/source/firm.h @@ -17,6 +17,7 @@ #define BUTTON_L1 (1 << 9) #define BUTTON_L1R1 (BUTTON_R1 | BUTTON_L1) #define BUTTON_A 1 +#define BUTTON_B (1 << 1) #define SAFEMODE (BUTTON_L1R1 | BUTTON_A | (1 << 6)) //FIRM Header layout diff --git a/source/loader.c b/source/loader.c index e2ececc9f..d3dae58bb 100644 --- a/source/loader.c +++ b/source/loader.c @@ -8,7 +8,7 @@ #define PAYLOAD_ADDRESS 0x24F00000 void loadPayload(void){ - if(fileExists("rei/arm9payload.bin") && + if(fileExists("rei/payloads/default.bin") && fileRead((u8 *)PAYLOAD_ADDRESS, "rei/loader.bin", 0)) ((void (*)())PAYLOAD_ADDRESS)(); } \ No newline at end of file