Added dual emuNAND support, multi-payload loader with built-in screen init (inspired by arm9select, thanks Fix94)
This commit is contained in:
parent
8ce395caa5
commit
dcb09a9472
14
loader/source/buttons.h
Normal file
14
loader/source/buttons.h
Normal file
@ -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)
|
@ -1,15 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include "../../types.h"
|
||||||
//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;
|
|
149
loader/source/i2c.c
Normal file
149
loader/source/i2c.c
Normal file
@ -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;
|
||||||
|
}
|
35
loader/source/i2c.h
Normal file
35
loader/source/i2c.h
Normal file
@ -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);
|
@ -1,17 +1,42 @@
|
|||||||
|
#include "types.h"
|
||||||
|
#include "buttons.h"
|
||||||
|
#include "screeninit.h"
|
||||||
#include "fatfs/ff.h"
|
#include "fatfs/ff.h"
|
||||||
|
|
||||||
#define PAYLOAD_ADDRESS 0x23F00000
|
#define PAYLOAD_ADDRESS 0x23F00000
|
||||||
|
|
||||||
void main()
|
u32 loadPayload(const char *path){
|
||||||
{
|
|
||||||
FATFS fs;
|
|
||||||
FIL payload;
|
FIL payload;
|
||||||
unsigned int br;
|
unsigned int br;
|
||||||
|
if(f_open(&payload, path, FA_READ) == FR_OK)
|
||||||
f_mount(&fs, "0:", 1);
|
|
||||||
if(f_open(&payload, "rei/arm9payload.bin", 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)();
|
((void (*)())PAYLOAD_ADDRESS)();
|
||||||
}
|
}
|
||||||
}
|
}
|
118
loader/source/screeninit.c
Normal file
118
loader/source/screeninit.c
Normal file
@ -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);
|
||||||
|
}
|
5
loader/source/screeninit.h
Normal file
5
loader/source/screeninit.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
void initLCD();
|
20
loader/source/types.h
Normal file
20
loader/source/types.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* types.h
|
||||||
|
* by Reisyukaku
|
||||||
|
* Copyright (c) 2015 All Rights Reserved
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
//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;
|
@ -26,7 +26,7 @@ void __attribute__((naked)) shutdownLCD(void){
|
|||||||
*(vu32 *)0x10202244 = 0;
|
*(vu32 *)0x10202244 = 0;
|
||||||
*(vu32 *)0x10202014 = 0;
|
*(vu32 *)0x10202014 = 0;
|
||||||
|
|
||||||
//Wait for the ARM11 entrypoint to be set
|
//Wait for the entry to be set
|
||||||
while(!*arm11);
|
while(!*arm11);
|
||||||
//Jump to it
|
//Jump to it
|
||||||
((void (*)())*arm11)();
|
((void (*)())*arm11)();
|
||||||
|
@ -8,15 +8,20 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "fatfs/sdmmc/sdmmc.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;
|
u8 *const temp = (u8 *)0x24300000;
|
||||||
|
|
||||||
u32 nandSize = getMMCDevice(0)->total_size;
|
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){
|
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){
|
||||||
*off = 0;
|
*off = nandOffset;
|
||||||
*head = nandSize;
|
*head = nandOffset + nandSize;
|
||||||
}
|
}
|
||||||
|
//Fallback to the first emuNAND if there's no second one
|
||||||
|
else if(emuNAND == 2) getEmunandSect(off, head, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#define NCSD_MAGIC (0x4453434E)
|
#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 getSDMMC(void *pos, u32 *off, u32 size);
|
||||||
void getEmuRW(void *pos, u32 size, u32 *readOff, u32 *writeOff);
|
void getEmuRW(void *pos, u32 size, u32 *readOff, u32 *writeOff);
|
||||||
void getMPU(void *pos, u32 *off, u32 size);
|
void getMPU(void *pos, u32 *off, u32 size);
|
@ -53,11 +53,11 @@ void setupCFW(void){
|
|||||||
fileRead(&tempConfig, lastConfigPath, 1);
|
fileRead(&tempConfig, lastConfigPath, 1);
|
||||||
|
|
||||||
//Always force a sysNAND boot when quitting AGB_FIRM
|
//Always force a sysNAND boot when quitting AGB_FIRM
|
||||||
if(previousFirm == 0x7) {
|
if(previousFirm == 0x7){
|
||||||
if(!updatedSys) mode = tempConfig & 0x1;
|
if(!updatedSys) mode = tempConfig & 0x1;
|
||||||
overrideConfig = 1;
|
overrideConfig = 1;
|
||||||
//Else, force the last used boot options unless A is pressed
|
//Else, force the last used boot options unless A is pressed
|
||||||
} else if(!(pressed & BUTTON_A)) {
|
} else if(!(pressed & BUTTON_A)){
|
||||||
mode = tempConfig & 0x1;
|
mode = tempConfig & 0x1;
|
||||||
emuNAND = (tempConfig >> 1) & 0x1;
|
emuNAND = (tempConfig >> 1) & 0x1;
|
||||||
overrideConfig = 1;
|
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
|
/* 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 */
|
or R is pressed on a > 9.2 SysNAND, boot emuNAND */
|
||||||
if((updatedSys && (!mode || ((pressed & BUTTON_R1) && pressed != SAFEMODE))) ||
|
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
|
//Write the current boot options on A9LH
|
||||||
if(a9lhBoot){
|
if(a9lhBoot){
|
||||||
@ -88,8 +92,9 @@ void setupCFW(void){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mode) firmPathPatched = emuNAND ? "/rei/patched_firmware_emu.bin" :
|
if(mode) firmPathPatched = emuNAND ? (emuNAND == 1 ? "/rei/patched_firmware_emu.bin" :
|
||||||
"/rei/patched_firmware_sys.bin";
|
"/rei/patched_firmware_em2.bin") :
|
||||||
|
"/rei/patched_firmware_sys.bin";
|
||||||
|
|
||||||
//Skip decrypting and patching FIRM
|
//Skip decrypting and patching FIRM
|
||||||
if(fileExists("/rei/usepatchedfw")){
|
if(fileExists("/rei/usepatchedfw")){
|
||||||
@ -156,7 +161,7 @@ static u32 loadEmu(void){
|
|||||||
u32 *pos_offset = (u32 *)memsearch((void *)emuCodeOffset, "NAND", size, 4);
|
u32 *pos_offset = (u32 *)memsearch((void *)emuCodeOffset, "NAND", size, 4);
|
||||||
u32 *pos_header = (u32 *)memsearch((void *)emuCodeOffset, "NCSD", size, 4);
|
u32 *pos_header = (u32 *)memsearch((void *)emuCodeOffset, "NCSD", size, 4);
|
||||||
getSDMMC(firmLocation, &sdmmcOffset, firmSize);
|
getSDMMC(firmLocation, &sdmmcOffset, firmSize);
|
||||||
getEmunandSect(&emuOffset, &emuHeader);
|
getEmunandSect(&emuOffset, &emuHeader, emuNAND);
|
||||||
getEmuRW(firmLocation, firmSize, &emuRead, &emuWrite);
|
getEmuRW(firmLocation, firmSize, &emuRead, &emuWrite);
|
||||||
getMPU(firmLocation, &mpuOffset, firmSize);
|
getMPU(firmLocation, &mpuOffset, firmSize);
|
||||||
*pos_sdmmc = sdmmcOffset;
|
*pos_sdmmc = sdmmcOffset;
|
||||||
@ -228,7 +233,8 @@ u32 patchFirm(void){
|
|||||||
//Patch path for emuNAND-patched FIRM
|
//Patch path for emuNAND-patched FIRM
|
||||||
if(emuNAND){
|
if(emuNAND){
|
||||||
void *pos_path = memsearch((void *)rebootOffset, L"sy", size, 4);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#define BUTTON_L1 (1 << 9)
|
#define BUTTON_L1 (1 << 9)
|
||||||
#define BUTTON_L1R1 (BUTTON_R1 | BUTTON_L1)
|
#define BUTTON_L1R1 (BUTTON_R1 | BUTTON_L1)
|
||||||
#define BUTTON_A 1
|
#define BUTTON_A 1
|
||||||
|
#define BUTTON_B (1 << 1)
|
||||||
#define SAFEMODE (BUTTON_L1R1 | BUTTON_A | (1 << 6))
|
#define SAFEMODE (BUTTON_L1R1 | BUTTON_A | (1 << 6))
|
||||||
|
|
||||||
//FIRM Header layout
|
//FIRM Header layout
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#define PAYLOAD_ADDRESS 0x24F00000
|
#define PAYLOAD_ADDRESS 0x24F00000
|
||||||
|
|
||||||
void loadPayload(void){
|
void loadPayload(void){
|
||||||
if(fileExists("rei/arm9payload.bin") &&
|
if(fileExists("rei/payloads/default.bin") &&
|
||||||
fileRead((u8 *)PAYLOAD_ADDRESS, "rei/loader.bin", 0))
|
fileRead((u8 *)PAYLOAD_ADDRESS, "rei/loader.bin", 0))
|
||||||
((void (*)())PAYLOAD_ADDRESS)();
|
((void (*)())PAYLOAD_ADDRESS)();
|
||||||
}
|
}
|
Reference in New Issue
Block a user