Skip to content

Instantly share code, notes, and snippets.

@rw-r-r-0644
Created January 23, 2021 15:50
Show Gist options
  • Save rw-r-r-0644/48a81ad9a49adf1849f1846f0ea8c9a0 to your computer and use it in GitHub Desktop.
Save rw-r-r-0644/48a81ad9a49adf1849f1846f0ea8c9a0 to your computer and use it in GitHub Desktop.
dump boot1 without relying on boot1 functions
.text
@ this code runs at 0x00000048 after boot1 jumps to NULL
.global _start
_start:
@ Patch PRSH checksum (offsets replaced when writing payload)
ldr r2, =0xcafe0001 @ prsh_hdr_offset
ldr r0, =0xcafe0002 @ checksum_old
str r0, [r2]
@ Patch boot_info_ptr (offsets replaced when writing payload)
ldr r2, =0xcafe0003 @ boot_info_ptr_addr
ldr r0, =0x10008000 @ normal location at 0x10008000
str r0, [r2]
@ Dump OTP
ldr r2, =0x0d8001ec @ r2 is HW_OTPCMD reg address (0x0d8001ec)
add r0, r0, #0x1400 @ r0 is MEM2 OTP dump buffer + OTP dump size (0x10009400)
otp_dump_loop:
sub r0, r0, #4 @ get current index
mov r3, r0, lsr #4 @ r3 is banknum followed by 3 bits
and r3, r3, #0x38 @ clear last 3 bits
orr r3, r3, r0, lsl #25 @ load wordnum to highest 5 bits
movs r3, r3, ror #27 @ rotate to get banknum+3bit+wordnum
orr r3, r3, #0x80000000 @ set read flag
str r3, [r2] @ write cmd -> HW_OTPCMD
ldr r3, [r2, #4] @ load data from HW_OTPDATA
str r3, [r0] @ save data to pointer
bne otp_dump_loop @ loop until index zero done
@ Copy boot1
ldr r2, =0x0d40e200
add r0, r0, #0xf200
boot1_copy_loop:
ldr r3, [r2, #-4]!
str r3, [r0, #-4]!
movs r3, r2, lsl #16
bne 2b
@ Return to boot1
@ r1 contains set_boot_info_08 return address,
@ unchanged by this payload
mov pc, r1
#!/bin/python3
import struct
f = open("boot1_payload.bin", "rb")
addr = 0x00000048
while True:
b = f.read(4)
if not b:
break
i = struct.unpack('>I', b)
print(' kern_write(0x{:08X}, 0x{:08X});'.format(addr, i[0]))
addr += 4
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "imports.h"
#include "latte.h"
#include "net_ifmgr_ncl.h"
#include "socket.h"
#include "fsa.h"
#include "svc.h"
#include "text.h"
#define FG_COLOR_REGULAR (0x00000000)
#define BG_COLOR_REGULAR (0xFF0000FF)
#define BG_COLOR_HIGHLIGHT (0xFFFFFFFF)
bool server_done;
void init_screen()
{
clearScreen(0xFF0000FF);
print(0, 0, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Welcome to hexFW (v0.0.3) by hexkyz");
}
void print_credits()
{
// Clear the screen first
init_screen();
int t = 0x2710;
while (t > 0)
{
print(10, 10, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Thanks to:");
print(15, 20, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "fail0verflow");
print(15, 30, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "smealum");
print(15, 40, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "yellows8");
print(15, 50, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "hykem");
print(15, 60, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "naehrwert");
print(15, 70, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "plutoo");
print(15, 80, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "derrek");
print(15, 90, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "libwiiu team");
t--;
}
// Clear back the screen
init_screen();
}
int server_cmd(u32* command_buffer, u32 length)
{
if (!command_buffer || !length) return -1;
int out_length = 4;
switch (command_buffer[0])
{
case 0:
// write
// [cmd_id][addr]
{
void* dst = (void*)command_buffer[1];
memcpy(dst, &command_buffer[2], length - 8);
}
break;
case 1:
// read
// [cmd_id][addr][length]
{
void* src = (void*)command_buffer[1];
length = command_buffer[2];
memcpy(&command_buffer[1], src, length);
out_length = length + 4;
}
break;
case 2:
// svc
// [cmd_id][svc_id]
{
int svc_id = command_buffer[1];
int size_arguments = length - 8;
u32 arguments[8];
memset(arguments, 0x00, sizeof(arguments));
memcpy(arguments, &command_buffer[2], (size_arguments < 8 * 4) ? size_arguments : (8 * 4));
// return error code as data
out_length = 8;
command_buffer[1] = ((int (*const)(u32, u32, u32, u32, u32, u32, u32, u32))(MCP_SVC_BASE + svc_id * 8))(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7]);
}
break;
case 3:
// kill
// [cmd_id]
{
server_done = true;
}
break;
case 4:
// memcpy
// [dst][src][size]
{
void* dst = (void*)command_buffer[1];
void* src = (void*)command_buffer[2];
int size = command_buffer[3];
memcpy(dst, src, size);
}
break;
case 5:
// repeated-write
// [address][value][n]
{
u32* dst = (u32*)command_buffer[1];
u32* cache_range = (u32*)(command_buffer[1] & ~0xFF);
u32 value = command_buffer[2];
u32 n = command_buffer[3];
u32 old = *dst;
int i;
for (i = 0; i < n; i++)
{
if (*dst != old)
{
if (*dst == 0x0) old = *dst;
else
{
*dst = value;
svcFlushDCache(cache_range, 0x100);
break;
}
}
else
{
svcInvalidateDCache(cache_range, 0x100);
usleep(50);
}
}
}
break;
default:
// Unknown command
return -2;
break;
}
// No error
command_buffer[0] = 0x00000000;
return out_length;
}
void server_handler(int sock)
{
u32 command_buffer[0x180];
while (!server_done)
{
int ret = recv(sock, command_buffer, sizeof(command_buffer), 0);
if (ret <= 0) break;
ret = server_cmd(command_buffer, ret);
if (ret > 0)
{
send(sock, command_buffer, ret, 0);
}
else if (ret < 0)
{
send(sock, &ret, sizeof(int), 0);
}
}
closesocket(sock);
}
void server_listen()
{
server_done = false;
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in server;
memset(&server, 0x00, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = 1337;
server.sin_addr.s_addr = 0;
int ret = bind(sock, (struct sockaddr *)&server, sizeof(server));
while (!server_done)
{
ret = listen(sock, 1);
if (ret >= 0)
{
int csock = accept(sock, NULL, NULL);
server_handler(csock);
} else usleep(1000);
}
}
void mount_storage()
{
int fsa_handle = 0xFFFFFFFF;
int fsa_mount_res = 0xFFFFFFFF;
// Initialize /dev/fsa
while (fsa_handle < 0)
{
fsa_handle = fsaInit();
usleep(1000);
}
// Mount the SD card for storage
while (fsa_mount_res < 0)
{
fsa_mount_res = FSA_Mount("/dev/sdcard01", "/vol/storage_sdcard", 0x00000002, NULL, 0);
usleep(1000);
}
}
int file_write(char *path, void* data, int size, int count, bool append)
{
int fsa_file_handle = 0xFFFFFFFF;
int fsa_write_result = 0xFFFFFFFF;
// Open target file
if (append)
FSA_OpenFile(path, "a+", &fsa_file_handle);
else
FSA_OpenFile(path, "w", &fsa_file_handle);
// Write target file
fsa_write_result = FSA_WriteFile(data, size, count, fsa_file_handle, 0x00000002);
// Close target file
FSA_CloseFile(fsa_file_handle);
return fsa_write_result;
}
void dump_otp()
{
// Allocate buffer
void* otp_data = svcAlloc(0xCAFF, 0x400);
memset(otp_data, 0x00, 0x400);
// Read OTP data
svcReadOTP(0x00, otp_data, 0x400);
// Dump to SD card
file_write("/vol/storage_sdcard/otp.bin", otp_data, 0x01, 0x400, false);
// Free buffer
svcFree(0xCAFF, otp_data);
}
void dump_seeprom()
{
// Allocate buffer
void* seeprom_data = svcAlloc(0xCAFF, 0x200);
memset(seeprom_data, 0x00, 0x200);
// Read SEEPROM data
seeprom_read(0x00, 0xF8, seeprom_data);
// Dump to SD card
file_write("/vol/storage_sdcard/seeprom.bin", seeprom_data, 0x01, 0x200, false);
// Free buffer
svcFree(0xCAFF, seeprom_data);
}
void dump_slc()
{
int fsa_raw_handle = 0xFFFFFFFF;
int fsa_raw_open_result = 0xFFFFFFFF;
int fsa_read_result = 0xFFFFFFFF;
// Allocate temporary buffer
void* slc_buf = svcAlloc(0xCAFF, 0x1000);
memset(slc_buf, 0x00, 0x1000);
// Wait for SLC to be mounted
while (fsa_raw_open_result < 0)
{
// Open target device
fsa_raw_open_result = FSA_RawOpen("/dev/slc01", &fsa_raw_handle);
usleep(1000);
}
// Read raw sectors and dump to SD card
int slc_offset = 0;
while (slc_offset < 0x20000000)
{
// Lock PPC
ppc_reset();
// Clear buffer
memset(slc_buf, 0x00, 0x1000);
// Read from target device
fsa_read_result = FSA_RawRead(slc_buf, 0x01, 0x1000, slc_offset, fsa_raw_handle);
// We've reached the end of the device's memory
if (fsa_read_result == 0xFFFCFFD5)
break;
// Print
print(10, 20, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "SLC");
print(10, 30, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Result: 0x%08x Offset: 0x%08x", fsa_read_result, slc_offset);
// Sleep for a while
usleep(10);
// Write to SD card
file_write("/vol/storage_sdcard/slc.bin", slc_buf, 0x01, 0x1000, true);
// Increase offset
slc_offset += 0x1000;
}
// Close target device
FSA_RawClose(fsa_raw_handle);
// Free buffer
svcFree(0xCAFF, slc_buf);
}
void dump_slccmpt()
{
int fsa_raw_handle = 0xFFFFFFFF;
int fsa_raw_open_result = 0xFFFFFFFF;
int fsa_read_result = 0xFFFFFFFF;
// Allocate temporary buffer
void* slccmpt_buf = svcAlloc(0xCAFF, 0x1000);
memset(slccmpt_buf, 0x00, 0x1000);
// Wait for SLCCMPT to be mounted
while (fsa_raw_open_result < 0)
{
// Open target device
fsa_raw_open_result = FSA_RawOpen("/dev/slccmpt01", &fsa_raw_handle);
usleep(1000);
}
// Read raw sectors and dump to SD card
int slccmpt_offset = 0;
while (slccmpt_offset < 0x20000000)
{
// Lock PPC
ppc_reset();
// Clear buffer
memset(slccmpt_buf, 0x00, 0x1000);
// Read from target device
fsa_read_result = FSA_RawRead(slccmpt_buf, 0x01, 0x1000, slccmpt_offset, fsa_raw_handle);
// We've reached the end of the device's memory
if (fsa_read_result == 0xFFFCFFD5)
break;
// Print
print(10, 20, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "SLCCMPT");
print(10, 30, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Result: 0x%08x Offset: 0x%08x", fsa_read_result, slccmpt_offset);
// Sleep for a while
usleep(10);
// Write to SD card
file_write("/vol/storage_sdcard/slccmpt.bin", slccmpt_buf, 0x01, 0x1000, true);
// Increase offset
slccmpt_offset += 0x1000;
}
// Close target device
FSA_RawClose(fsa_raw_handle);
// Free buffer
svcFree(0xCAFF, slccmpt_buf);
}
void dump_mlc()
{
int fsa_raw_handle = 0xFFFFFFFF;
int fsa_raw_open_result = 0xFFFFFFFF;
int fsa_read_result = 0xFFFFFFFF;
// Allocate temporary buffer
void* mlc_buf = svcAlloc(0xCAFF, 0x10 * 0x1000);
memset(mlc_buf, 0x00, 0x10 * 0x1000);
// Wait for MLC to be mounted
while (fsa_raw_open_result < 0)
{
// Open target device
fsa_raw_open_result = FSA_RawOpen("/dev/mlc01", &fsa_raw_handle);
usleep(1000);
}
// Read raw sectors and dump to SD card
int mlc_offset = 0;
while (mlc_offset < 0x20000000)
{
// Lock PPC
ppc_reset();
// Clear buffer
memset(mlc_buf, 0x00, 0x10 * 0x1000);
// Read from target device
fsa_read_result = FSA_RawRead(mlc_buf, 0x10, 0x1000, mlc_offset, fsa_raw_handle);
// Print
print(10, 20, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "MLC");
print(10, 30, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Result: 0x%08x Offset: 0x%08x", fsa_read_result, mlc_offset);
// Sleep for a while
usleep(10);
// Write to SD card
file_write("/vol/storage_sdcard/mlc.bin", mlc_buf, 0x10, 0x1000, true);
// Increase offset
mlc_offset += 0x10 * 0x1000;
}
// Close target device
FSA_RawClose(fsa_raw_handle);
// Free buffer
svcFree(0xCAFF, mlc_buf);
}
void dump_ramdisk()
{
int fsa_raw_handle = 0xFFFFFFFF;
int fsa_raw_open_result = 0xFFFFFFFF;
int fsa_read_result = 0xFFFFFFFF;
// Allocate temporary buffer
void* ramdisk_buf = svcAlloc(0xCAFF, 0x10 * 0x1000);
memset(ramdisk_buf, 0x00, 0x10 * 0x1000);
// Wait for RAMDISK to be mounted
while (fsa_raw_open_result < 0)
{
// Open target device
fsa_raw_open_result = FSA_RawOpen("/dev/ramdisk01", &fsa_raw_handle);
usleep(1000);
}
// Read raw sectors and dump to SD card
int ramdisk_offset = 0;
while (ramdisk_offset < 0x20000000)
{
// Lock PPC
ppc_reset();
// Clear buffer
memset(ramdisk_buf, 0x00, 0x10 * 0x1000);
// Read from target device
fsa_read_result = FSA_RawRead(ramdisk_buf, 0x10, 0x1000, ramdisk_offset, fsa_raw_handle);
// Print
print(10, 20, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "RAMDISK");
print(10, 30, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Result: 0x%08x Offset: 0x%08x", fsa_read_result, ramdisk_offset);
// Sleep for a while
usleep(10);
// Write to SD card
file_write("/vol/storage_sdcard/ramdisk.bin", ramdisk_buf, 0x10, 0x1000, true);
// Increase offset
ramdisk_offset += 0x10 * 0x1000;
}
// Close target device
FSA_RawClose(fsa_raw_handle);
// Free buffer
svcFree(0xCAFF, ramdisk_buf);
}
u16 get_boot1_version()
{
struct
{
u16 version;
u16 nand_block;
u8 empty[8];
u32 checksum;
}
*bootp = (void *)0x05074980;
// Let MCP load and decrypt seeprom boot1 params
load_boot1_params();
// Find the latest valid version installed
u16 version = 0;
for (int i = 0; i < 2; i++) {
if (calc_crc32(&bootp[i], 0xC) != bootp[i].checksum)
continue;
if (bootp[i].version > version)
version = bootp[i].version;
}
return version;
}
void dump_boot1()
{
static const struct
{
u16 version; // Boot1 version
u16 offs_boot_info; // Target boot_info address inside boot1
u16 offs_read_otp; // Boot1 read_otp address
u16 offs_memcpy; // Boot1 memcpy address
u16 offs_return; // Exploit return address
u16 offs_revert0; // Revert runtime changes
u16 offs_revert1;
u16 offs_revert2;
u16 offs_revert3;
u16 offs_revert4;
u16 offs_revert5;
u16 offs_revert6;
u16 offs_revert7;
}
ver_data[] =
{
{8296, 0xA5E5, 0x00FC, 0x959C, 0x0500, 0xD344, 0xD524, 0xD534, 0xD844, 0xD87C, 0xD500, 0xD858, 0xD880},
{8325, 0xA5A5, 0x00FC, 0x9574, 0x0500, 0xD7C4, 0xD9A4, 0xD9B4, 0xDCC4, 0xDCFC, 0xD980, 0xDCD8, 0xDD00},
{8339, 0xA9A5, 0x00DC, 0x995C, 0x04F0, 0xD6E4, 0xD8A4, 0xD8B4, 0xDB3C, 0xDB74, 0xD880, 0xDB50, 0xDB80},
{8342, 0xA9A9, 0x00DC, 0x9960, 0x04F0, 0xD704, 0xD8E4, 0xD8F4, 0xDB7C, 0xDBB4, 0xD8C0, 0xDB90, 0xDBC0},
{8354, 0xA9D5, 0x00DC, 0x998C, 0x04F0, 0xD724, 0xD8E4, 0xD8F4, 0xDB7C, 0xDBB4, 0xD8C0, 0xDB90, 0xDBC0},
{8377, 0xAA6D, 0x00DC, 0x99DC, 0x056A, 0xD884, 0xDA68, 0xDA78, 0xDD00, 0xDD38, 0xDA40, 0xDD14, 0xDD40},
};
u32 ver_count = sizeof(ver_data) / sizeof(*ver_data);
// Get installed boot1 version
u16 boot1_version = get_boot1_version();
// Find correct exploit data for this boot1 version
int ver_idx;
for (ver_idx = 0; ver_idx < ver_count; ver_idx++)
if (ver_data[ver_idx].version == boot1_version)
break;
// Unsupported boot1 version
if (ver_idx == ver_count)
return;
u32 boot1_ancast_magic = *(u32 *)0x1000A000;
// Run boot1hax
if (boot1_ancast_magic != 0xEFA282D9)
{
u32 boot1_addr = 0x0D400200;
// RAM vars
u32 ram_start_addr = 0x10000000;
u32 ram_test_buf_size = 0x400;
// PRSH vars
u32 prsh_hdr_offset = ram_start_addr + ram_test_buf_size + 0x5654;
u32 prsh_hdr_size = 0x1C;
// boot_info vars
u32 boot_info_name_addr = prsh_hdr_offset + prsh_hdr_size;
u32 boot_info_name_size = 0x100;
u32 boot_info_ptr_addr = boot_info_name_addr + boot_info_name_size;
// Calculate PRSH checksum
u32 checksum_old = 0;
u32 word_counter = 0;
while (word_counter < 0x20D)
{
checksum_old ^= *(u32 *)(prsh_hdr_offset + 0x04 + word_counter * 0x04);
word_counter++;
}
// Change boot_info to point inside boot1 memory
*(u32 *)boot_info_ptr_addr = boot1_addr + ver_data[ver_idx].offs_boot_info;
// Re-calculate PRSH checksum
u32 checksum = 0;
word_counter = 0;
while (word_counter < 0x20D)
{
checksum ^= *(u32 *)(prsh_hdr_offset + 0x04 + word_counter * 0x04);
word_counter++;
}
// Update checksum
*(u32 *)prsh_hdr_offset = checksum;
// Copy PRSH IV from IOS-MCP
void* prsh_iv_buf = svcAlloc(0xCAFF, 0x10);
memset(prsh_iv_buf, 0x00, 0x10);
memcpy(prsh_iv_buf, (void *)0x050677C0, 0x10);
// Encrypt PRSH
enc_prsh(0x10000400, 0x7C00, prsh_iv_buf, 0x10);
// Free PRSH IV buffer
svcFree(0xCAFF, prsh_iv_buf);
// Flush cache
flush_dcache(0x10000400, 0x7C00);
// Setup MEM1 payload
kern_write(0x00000000, 0xEA000010); // B sub_00000048
kern_write(0x00000004, 0xDEADC0DE);
kern_write(0x00000008, 0xDEADC0DE);
// Patch PRSH checksum
kern_write(0x00000048, 0xE59F205C); // LDR R2, [PC, #92]
kern_write(0x0000004C, 0xE59F005C); // LDR R0, [PC, #92]
kern_write(0x00000050, 0xE5820000); // STR R0, [R2]
// Patch boot_info_ptr
kern_write(0x00000054, 0xE59F2058); // LDR R2, [PC, #88]
kern_write(0x00000058, 0xE59F0058); // LDR R0, [PC, #88]
kern_write(0x0000005C, 0xE5820000); // STR R0, [R2]
// Dump OTP
kern_write(0x00000060, 0xE59F2054); // LDR R2, =0x0D8001EC
kern_write(0x00000064, 0xE2800B05); // ADD R0, R0, #0x1400
// otp_dump_loop:
kern_write(0x00000068, 0xE2400004); // SUB R0, R0, #4
kern_write(0x0000006C, 0xE1A03220); // MOV R3, R0, LSR #4
kern_write(0x00000070, 0xE2033038); // AND R3, R3, #0x38
kern_write(0x00000074, 0xE1833C80); // ORR R3, R3, R0, LSL #25
kern_write(0x00000078, 0xE1B03DE3); // MOVS R3, R3, ROR #27
kern_write(0x0000007C, 0xE3833102); // ORR R3, R3, #0x80000000
kern_write(0x00000080, 0xE5823000); // STR R3, [R2]
kern_write(0x00000084, 0xE5923004); // LDR R3, [R2, #4]
kern_write(0x00000088, 0xE5803000); // STR R3, [R0]
kern_write(0x0000008C, 0x1AFFFFF5); // BNE otp_dump_loop
// Copy boot1
kern_write(0x00000090, 0xE59F2028); // LDR R2, [PC, #40]
kern_write(0x00000094, 0xE2800CF2); // ADD R0, R0, #0xF200
// boot1_copy_loop:
kern_write(0x00000098, 0xE5323004); // LDR R3, [R2, #-4]!
kern_write(0x0000009C, 0xE5203004); // STR R3, [R0, #-4]!
kern_write(0x000000A0, 0xE1B03802); // MOVS R3, R2, LSL #16
kern_write(0x000000A4, 0x1AFFFFFB); // BNE boot1_copy_loop
// Jump back to boot1
kern_write(0x000000A8, 0xE1A0F001); // MOV PC, R1
// PRSH checksum data
kern_write(0x000000AC, prsh_hdr_offset);
kern_write(0x000000B0, checksum_old);
// boot_info_ptr data
kern_write(0x000000B4, boot_info_ptr_addr);
kern_write(0x000000B8, 0x10008000);
kern_write(0x000000BC, 0x0D8001EC); // HW_OTPCMD
kern_write(0x000000C0, 0x0D40E200); // boot1 end addr
// Reset
svcShutdown(1);
while(1);
}
else // Dump boot1 and OTP from memory
{
u32 boot1_addr = 0x1000A200;
// Fix up corruption from boot1hax
*(u32 *)(0x1000A200 + ver_data[ver_idx].offs_boot_info + 0x8) = 0x0800000D;
// Revert runtime changes for boot1
*(u32 *)(0x1000A200 + ver_data[ver_idx].offs_revert0) = 0xFFFFFFFC;
*(u32 *)(0x1000A200 + ver_data[ver_idx].offs_revert1) = 0xC0000000;
*(u32 *)(0x1000A200 + ver_data[ver_idx].offs_revert2) = 0xC0000000;
*(u32 *)(0x1000A200 + ver_data[ver_idx].offs_revert3) = 0xFFFFFFFF;
*(u32 *)(0x1000A200 + ver_data[ver_idx].offs_revert4) = 0x24100010;
memset((void *)(0x1000A200 + ver_data[ver_idx].offs_revert5), 0x00, 0x28);
memset((void *)(0x1000A200 + ver_data[ver_idx].offs_revert6), 0x00, 0x1C);
memset((void *)(0x1000A200 + ver_data[ver_idx].offs_revert7), 0x00, 0x2C0);
// Dump to SD card
void* otp_buf = svcAlloc(0xCAFF, 0x400);
void* boot1_buf = svcAlloc(0xCAFF, 0xE000);
memset(otp_buf, 0x00, 0x400);
memset(boot1_buf, 0x00, 0xE000);
memcpy(otp_buf, (void *)0x10009000, 0x400);
memcpy(boot1_buf, (void *)0x1000A200, 0xE000);
file_write("/vol/storage_sdcard/otp.bin", otp_buf, 0x01, 0x400, false);
file_write("/vol/storage_sdcard/boot1.bin", boot1_buf, 0x01, 0xE000, false);
svcFree(0xCAFF, otp_buf);
svcFree(0xCAFF, boot1_buf);
// Clear MEM2 region
memset((void *)0x10009000, 0x00, 0x10000);
}
}
void dump(int device)
{
// Clear the screen first
init_screen();
// Print message and dump
if (device == 0)
{
print(10, 10, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Dumping OTP to SD card...");
dump_otp();
}
else if (device == 1)
{
print(10, 10, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Dumping SEEPROM to SD card...");
dump_seeprom();
}
else if (device == 2)
{
print(10, 10, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Dumping SLC to SD card...");
dump_slc();
}
else if (device == 3)
{
print(10, 10, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Dumping SLCCMPT to SD card...");
dump_slccmpt();
}
else if (device == 4)
{
print(10, 10, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Dumping MLC to SD card...");
dump_mlc();
}
else if (device == 5)
{
print(10, 10, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Dumping BOOT1+OTP to SD card...");
dump_boot1();
}
// Clear back the screen
init_screen();
}
void launch_server()
{
int ncl_handle = 0xFFFFFFFF;
int socket_handle = 0xFFFFFFFF;
u16 if_status0 = 0;
u16 if_status1 = 0;
// Clear the screen
init_screen();
print(10, 10, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Initializing /dev/net/ifmgr/ncl...");
// Initialize /dev/net/ifmgr/ncl
while (ncl_handle < 0)
{
ncl_handle = ifmgrnclInit();
usleep(1000);
}
print(10, 20, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Polling interfaces...");
// Keep polling the interfaces until we get a reply
while((if_status0 != 0x01) && (if_status1 != 0x01))
{
IFMGRNCL_GetInterfaceStatus(0, &if_status0);
IFMGRNCL_GetInterfaceStatus(1, &if_status1);
usleep(1000);
}
print(10, 30, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Initializing /dev/socket...");
// Initialize /dev/socket
while (socket_handle < 0)
{
socket_handle = socketInit();
usleep(1000);
}
print(10, 40, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "Launching wupserver...");
// Wait a while
usleep(5 * 1000 * 1000);
// Start listening
server_listen();
}
int get_btn()
{
// Send "SystemEventFlag" (0x41) to SMC (0x50 slave)
u8 reg = 0x41;
i2c_write(0x50, &reg, 0x01);
u8 result = 0xFF;
i2c_read(0x50, &result, 0x01);
if (result == 0x40) // POWER was pressed
return 1;
else if (result == 0x20) // EJECT was pressed
return 2;
else
return 0;
}
u32 read_rtc(u32 offset)
{
// Register device 0x01 (RTC) to EXI0
exi_reg(0x00, 0x01, 0x00);
// Write RTC command
u32 rtc_cmd = offset;
exi_rw(0x00, &rtc_cmd, 0x04, 0x01);
// Wait for the transfer to complete
exi_poll(0x00);
// Read reply from command
u32 reply = 0xFFFFFFFF;
exi_rw(0x00, &reply, 0x04, 0x00);
// Wait for the transfer to complete
exi_poll(0x00);
// Reset EXI0
exi_reset(0x00);
return reply;
}
void write_rtc(u32 offset, u32 data)
{
// Register device 0x01 (RTC) to EXI0
exi_reg(0x00, 0x01, 0x00);
// Write RTC command (ORed with write flag)
u32 rtc_cmd = offset | 0x80000000;
exi_rw(0x00, &rtc_cmd, 0x04, 0x01);
// Wait for the transfer to complete
exi_poll(0x00);
// Write data
u32 rtc_data = data;
exi_rw(0x00, &rtc_data, 0x04, 0x01);
// Wait for the transfer to complete
exi_poll(0x00);
// Reset EXI0
exi_reset(0x00);
}
void test_exi()
{
// Init EXI
exi_init();
// Send command 0x21000400 (RTC_UNK) in read mode
u32 unk_reply = read_rtc(0x21000400);
while (1)
{
// Send command 0x21000C00 (RTC_CONTROL0) in read mode
u32 ctrl0_reply = read_rtc(0x21000C00);
//Send command 0x21000D00 (RTC_CONTROL1) in write mode
u32 ctrl1_reply = read_rtc(0x21000D00);
print(10, 10, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "CMD: 0x%08x Reply: 0x%08x", 0x21000400, unk_reply);
print(10, 20, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "CMD: 0x%08x Reply: 0x%08x", 0x21000C00, ctrl0_reply);
print(10, 30, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "CMD: 0x%08x Reply: 0x%08x", 0x21000D00, ctrl1_reply);
}
}
void test_bsp()
{
void* test_buf = svcAlloc(0xCAFF, 0x100);
memset(test_buf, 0x00, 0x100);
bsp_query("SDIO", 0, "SlotProperties", 0x30, test_buf + 0x00);
bsp_query("SDIO", 1, "SlotProperties", 0x30, test_buf + 0x30);
bsp_query("SDIO", 2, "SlotProperties", 0x30, test_buf + 0x60);
bsp_query("SDIO", 3, "SlotProperties", 0x30, test_buf + 0x90);
bsp_query("SDIO", 4, "SlotProperties", 0x30, test_buf + 0xC0);
file_write("/vol/storage_sdcard/test.bin", test_buf, 0x01, 0x100, false);
print(10, 10, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "DONE");
svcFree(0xCAFF, test_buf);
while (1);
}
void _main()
{
// Clear the screen and set welcome message
init_screen();
// Mount the SD card for storage
mount_storage();
int sel_cnt = 0;
bool do_run = true;
bool do_exec = false;
while (do_run)
{
// Lock PPC
ppc_reset();
// Get button presses
int btn = get_btn();
// Check if the user pressed POWER
if (btn == 1)
do_exec = true;
else if (btn == 2) // Check if the user pressed EJECT
sel_cnt++;
// Check options' list boundaries
// NOTE: Using multiples of 2 compensates
// the button state's transition speed
if ((sel_cnt > 16) && (sel_cnt <= 18))
sel_cnt = 0;
if (sel_cnt <= 0)
print(10, 10, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "- Dump OTP");
else
print(10, 10, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "- Dump OTP");
if ((sel_cnt > 0) && (sel_cnt <= 2))
print(10, 20, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "- Dump SEEPROM");
else
print(10, 20, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "- Dump SEEPROM");
if ((sel_cnt > 2) && (sel_cnt <= 4))
print(10, 30, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "- Dump SLC");
else
print(10, 30, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "- Dump SLC");
if ((sel_cnt > 4) && (sel_cnt <= 6))
print(10, 40, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "- Dump SLCCMPT");
else
print(10, 40, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "- Dump SLCCMPT");
if ((sel_cnt > 6) && (sel_cnt <= 8))
print(10, 50, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "- Dump MLC");
else
print(10, 50, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "- Dump MLC");
if ((sel_cnt > 8) && (sel_cnt <= 10))
print(10, 60, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "- Dump BOOT1+OTP");
else
print(10, 60, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "- Dump BOOT1+OTP");
if ((sel_cnt > 10) && (sel_cnt <= 12))
print(10, 70, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "- Launch wupserver");
else
print(10, 70, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "- Launch wupserver");
if ((sel_cnt > 12) && (sel_cnt <= 14))
print(10, 80, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "- Shutdown");
else
print(10, 80, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "- Shutdown");
if ((sel_cnt > 14) && (sel_cnt <= 16))
print(10, 90, FG_COLOR_REGULAR, BG_COLOR_HIGHLIGHT, "- Credits");
else
print(10, 90, FG_COLOR_REGULAR, BG_COLOR_REGULAR, "- Credits");
// Execute the selected action
if (do_exec)
{
switch (sel_cnt)
{
case 0:
dump(0);
break;
case 1:
case 2:
dump(1);
break;
case 3:
case 4:
dump(2);
break;
case 5:
case 6:
dump(3);
break;
case 7:
case 8:
dump(4);
break;
case 9:
case 10:
dump(5);
break;
case 11:
case 12:
launch_server();
break;
case 13:
case 14:
svcShutdown(0);
break;
case 15:
case 16:
print_credits();
break;
}
do_exec = false;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment