From 1d7fb42aa3b366d8143413652e91de5a7868c80a Mon Sep 17 00:00:00 2001 From: koolkdev Date: Mon, 27 Mar 2017 22:59:03 +0300 Subject: [PATCH] Dump OTP and SEEPROM --- ios_fs/Makefile | 1 + ios_fs/link.ld | 3 + ios_fs/source/dumper.c | 52 ++++++++++++++--- ios_fs/source/fs_config.h | 14 +++++ ios_kernel/source/ios_fs_patches.c | 20 ++++++- ios_kernel/source/kernel_patches.c | 6 +- ios_kernel/source/main.c | 94 +++++++++++++++++++++++++++++- src/cfw_config.c | 2 + src/cfw_config.h | 2 + src/menu.c | 8 ++- 10 files changed, 185 insertions(+), 17 deletions(-) create mode 100644 ios_fs/source/fs_config.h diff --git a/ios_fs/Makefile b/ios_fs/Makefile index 211e768..f3c29e6 100644 --- a/ios_fs/Makefile +++ b/ios_fs/Makefile @@ -59,6 +59,7 @@ $(PROJECTNAME)_syms.h: @echo "#define $(PROJECTNAME)_SYMS_H" >> $@ @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep 'g F .text' | grep -v '.hidden' | awk '{print "#define " $$6 " 0x" $$1}' >> $@ @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep -e 'g .text' -e '_bss_' | awk '{print "#define " $$5 " 0x" $$1}' >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep -e 'g O .dumper_config' | awk '{print "#define " $$6 " 0x" $$1}' >> $@ @echo "#endif" >> $@ clean: diff --git a/ios_fs/link.ld b/ios_fs/link.ld index 6028580..ef1bedc 100644 --- a/ios_fs/link.ld +++ b/ios_fs/link.ld @@ -8,6 +8,9 @@ SECTIONS *(.rodata*); } _text_end = .; + .dumper_config : { + *(.dumper_config*); + } .bss (0x10835000 + 0x1406554) : { _bss_start = .; diff --git a/ios_fs/source/dumper.c b/ios_fs/source/dumper.c index 423bab1..40f222c 100644 --- a/ios_fs/source/dumper.c +++ b/ios_fs/source/dumper.c @@ -8,6 +8,9 @@ #include "text.h" #include "hardware_registers.h" #include "svc.h" +#include "fs_config.h" + +fs_config dumper_config __attribute__((section(".dumper_config"))); #define IO_BUFFER_SIZE 0x40000 #define IO_BUFFER_SPARE_SIZE (IO_BUFFER_SIZE+0x2000) @@ -233,15 +236,10 @@ void dump_nand_complete() _printf(20, offset_y, "Init SD card.... Success!"); offset_y += 10; - int * dumpSlc = (int *)(0x107f8200 - 4); - int * dumpSlccmpt = (int *)(0x107f8200 - 8); - int * dumpMlc = (int *)(0x107f8200 - 12); - - //wait_format_confirmation(); u32 mlc_sector_count = 0; - if (*dumpMlc) { + if (dumper_config.dump_mlc) { mlc_init(); FS_SLEEP(1000); @@ -268,17 +266,53 @@ void dump_nand_complete() svcShutdown(SHUTDOWN_TYPE_REBOOT); }*/ - if (*dumpSlc) { + if (dumper_config.dump_otp) { + _printf(20, offset_y, "Writing otp..."); + FL_FILE *file = fl_fopen("/otp.bin", "w"); + if (!file) { + _printf(20, offset_y+10, "Failed to open /otp.bin for writing!"); + goto error; + } + // It doesn't work if we try write directly this buffer, does it try to access too much? + memcpy(io_buffer, dumper_config.otp_buffer, sizeof(dumper_config.otp_buffer)); + if (fl_fwrite(io_buffer, 1, sizeof(dumper_config.otp_buffer), file) != sizeof(dumper_config.otp_buffer)) { + fl_fclose(file); + _printf(20, offset_y+10, "Failed to write otp to file!"); + goto error; + } + fl_fclose(file); + _printf(20, offset_y, "Writing otp... Success!"); + offset_y += 10; + } + if (dumper_config.dump_seeprom) { + _printf(20, offset_y, "Writing seeprom..."); + FL_FILE *file = fl_fopen("/seeprom.bin", "w"); + if (!file) { + _printf(20, offset_y+10, "Failed to open /seeprom.bin for writing!"); + goto error; + } + // It doesn't work if we try write directly this buffer, does it try to access too much? + memcpy(io_buffer, dumper_config.seeprom_buffer, sizeof(dumper_config.seeprom_buffer)); + if (fl_fwrite(io_buffer, 1, sizeof(dumper_config.seeprom_buffer), file) != sizeof(dumper_config.seeprom_buffer)) { + fl_fclose(file); + _printf(20, offset_y+10, "Failed to write seeprom to file!"); + goto error; + } + fl_fclose(file); + _printf(20, offset_y, "Writing seeprom... Success!"); + offset_y += 10; + } + if (dumper_config.dump_slc) { if (slc_dump(FS_SLC_PHYS_DEV_STRUCT, "slc ", "/slc.bin", offset_y)) goto error; offset_y += 10; } - if (*dumpSlccmpt) { + if (dumper_config.dump_slccmpt) { if (slc_dump(FS_SLCCMPT_PHYS_DEV_STRUCT, "slccmpt", "/slccmpt.bin", offset_y)) goto error; offset_y += 10; } - if (*dumpMlc) { + if (dumper_config.dump_mlc) { if (mlc_dump(mlc_sector_count, offset_y)) goto error; offset_y += 10; diff --git a/ios_fs/source/fs_config.h b/ios_fs/source/fs_config.h new file mode 100644 index 0000000..cabbe8c --- /dev/null +++ b/ios_fs/source/fs_config.h @@ -0,0 +1,14 @@ +#ifndef _FS_CONFIG_H +#define _FS_CONFIG_H + +typedef struct { + int dump_slc; + int dump_slccmpt; + int dump_mlc; + int dump_otp; + int dump_seeprom; + char otp_buffer[0x400]; + char seeprom_buffer[0x200]; +} fs_config; + +#endif \ No newline at end of file diff --git a/ios_kernel/source/ios_fs_patches.c b/ios_kernel/source/ios_fs_patches.c index b0d86af..aee0ffd 100644 --- a/ios_kernel/source/ios_fs_patches.c +++ b/ios_kernel/source/ios_fs_patches.c @@ -25,7 +25,9 @@ #include "elf_patcher.h" #include "ios_fs_patches.h" #include "config.h" +#include "utils.h" #include "../../ios_fs/ios_fs_syms.h" +#include "../../ios_fs/source/fs_config.h" #define FS_PHYS_DIFF 0 @@ -51,6 +53,9 @@ extern const patch_table_t fs_patches_table[]; extern const patch_table_t fs_patches_table_end[]; +extern unsigned char otp_buffer[0x400]; +extern unsigned char seeprom_buffer[0x400]; + u32 fs_get_phys_code_base(void) { return _text_start + FS_PHYS_DIFF; @@ -58,6 +63,8 @@ u32 fs_get_phys_code_base(void) void fs_run_patches(u32 ios_elf_start) { + fs_config config; + // write wupserver code and bss section_write(ios_elf_start, _text_start, (void*)fs_get_phys_code_base(), _text_end - _text_start); section_write_bss(ios_elf_start, _bss_start, _bss_end - _bss_start); @@ -78,9 +85,16 @@ void fs_run_patches(u32 ios_elf_start) section_write_word(ios_elf_start, FS_SLC_ECC_CHECK, ARM_B(FS_SLC_ECC_CHECK, eccCheck_patch)); - section_write_word(ios_elf_start, (_text_start - 4), cfw_config.dumpSlc); - section_write_word(ios_elf_start, (_text_start - 8), cfw_config.dumpSlccmpt); - section_write_word(ios_elf_start, (_text_start - 12), cfw_config.dumpMlc); + config.dump_slc = cfw_config.dumpSlc; + config.dump_slccmpt = cfw_config.dumpSlccmpt; + config.dump_mlc = cfw_config.dumpMlc; + config.dump_otp = cfw_config.dumpOtp; + config.dump_seeprom = cfw_config.dumpSeeprom; + if (cfw_config.dumpOtp) + kernel_memcpy(config.otp_buffer, otp_buffer, sizeof(config.otp_buffer)); + if (cfw_config.dumpSeeprom) + kernel_memcpy(config.seeprom_buffer, seeprom_buffer, sizeof(config.seeprom_buffer)); + section_write(ios_elf_start, dumper_config, &config, sizeof(config)); //section_write_word(ios_elf_start, FS_USB_READ, ARM_B(FS_USB_READ, usbRead_patch)); //section_write_word(ios_elf_start, FS_USB_WRITE, ARM_B(FS_USB_WRITE, usbWrite_patch)); diff --git a/ios_kernel/source/kernel_patches.c b/ios_kernel/source/kernel_patches.c index dc3cf43..ab5aa4a 100644 --- a/ios_kernel/source/kernel_patches.c +++ b/ios_kernel/source/kernel_patches.c @@ -38,7 +38,7 @@ extern void __KERNEL_CODE_END(void); extern const patch_table_t kernel_patches_table[]; extern const patch_table_t kernel_patches_table_end[]; -static u8 otp_buffer[0x400]; +//static u8 otp_buffer[0x400]; static const u32 mcpIoMappings_patch[] = { @@ -60,7 +60,7 @@ static u32 kernel_syscall_0x81(u32 address) return *(volatile u32*)address; } -static int kernel_read_otp_internal(int index, void* out_buf, u32 size) +/*static int kernel_read_otp_internal(int index, void* out_buf, u32 size) { kernel_memcpy(out_buf, otp_buffer + (index << 2), size); return 0; @@ -85,7 +85,7 @@ int kernel_init_otp_buffer(u32 sd_sector, int dumpFound) FSA_SDWriteRawSectors(otp_buffer, sd_sector, 2); } return res; -} +}*/ void kernel_launch_ios(u32 launch_address, u32 L, u32 C, u32 H) { diff --git a/ios_kernel/source/main.c b/ios_kernel/source/main.c index 442190d..c74a72a 100644 --- a/ios_kernel/source/main.c +++ b/ios_kernel/source/main.c @@ -34,6 +34,9 @@ cfw_config_t cfw_config; +unsigned char otp_buffer[0x400]; +unsigned char seeprom_buffer[0x400]; + typedef struct { u32 size; @@ -64,16 +67,105 @@ static const char repairData_usb_root_thread[] = { 0xE5,0x9F,0x0E,0x68,0xEB,0x00,0xB3,0x20, }; +// based on mini implementation by sven peter +#define LT_TIMER 0x0d800010 +#define LT_GPIO_OUT 0x0d8000e0 +#define LT_GPIO_IN 0x0d8000e8 + +#define EEPROM_SPI_CS 0x400 +#define EEPROM_SPI_SCK 0x800 +#define EEPROM_SPI_MOSI 0x1000 +#define EEPROM_SPI_MISO 0x2000 + +#define HW_REG(reg) (*(volatile unsigned int*)(reg)) + +static inline void _delay(u32 ticks) +{ + u32 now = HW_REG(LT_TIMER); + while((HW_REG(LT_TIMER) - now) < ticks); +} + +static u32 spi_read(int bit_count) +{ + u32 word = 0; + while(bit_count--) + { + word <<= 1; + + HW_REG(LT_GPIO_OUT) |= EEPROM_SPI_SCK; + _delay(9); + + HW_REG(LT_GPIO_OUT) &= ~EEPROM_SPI_SCK; + _delay(9); + + word |= ((HW_REG(LT_GPIO_IN) & EEPROM_SPI_MISO) != 0); + } + return word; +} + +static void spi_write(u32 word, int bit_count) +{ + while(bit_count--) + { + if(word & (1 << bit_count)) + { + HW_REG(LT_GPIO_OUT) |= EEPROM_SPI_MOSI; + } + else + { + HW_REG(LT_GPIO_OUT) &= ~EEPROM_SPI_MOSI; + } + _delay(9); + + HW_REG(LT_GPIO_OUT) |= EEPROM_SPI_SCK; + _delay(9); + + HW_REG(LT_GPIO_OUT) &= ~EEPROM_SPI_SCK; + _delay(9); + } +} + +static int seeprom_read(u16 *dst, int offset, int size) +{ + int i; + offset >>= 1; + size >>= 1; + + HW_REG(LT_GPIO_OUT) &= ~EEPROM_SPI_SCK; + HW_REG(LT_GPIO_OUT) &= ~EEPROM_SPI_CS; + _delay(9); + + for(i = 0; i < size; ++i, ++offset) + { + HW_REG(LT_GPIO_OUT) |= EEPROM_SPI_CS; + spi_write((0x600 | offset), 11); + + dst[i] = spi_read(16); + + HW_REG(LT_GPIO_OUT) &= ~EEPROM_SPI_CS; + _delay(9); + } + + return size; +} + int _main() { void(*invalidate_icache)() = (void(*)())0x0812DCF0; void(*invalidate_dcache)(unsigned int, unsigned int) = (void(*)())0x08120164; void(*flush_dcache)(unsigned int, unsigned int) = (void(*)())0x08120160; + int (*orig_kernel_read_otp_internal)(int index, void* out_buf, u32 size) = (void*)0x08120248; - flush_dcache(0x081200F0, 0x4001); // giving a size >= 0x4000 flushes all cache + // We don't have the config yet, so read it anyway + orig_kernel_read_otp_internal(0, otp_buffer, 0x400); + + flush_dcache(0x081200F0, 0x4001); // giving a size >= 0x4000 flushes all cache int level = disable_interrupts(); + // We don't have the config yet, so read it anyway + seeprom_read(seeprom_buffer, 0, 0x200); + unsigned int control_register = disable_mmu(); /* Save the request handle so we can reply later */ diff --git a/src/cfw_config.c b/src/cfw_config.c index 041c77b..9135fc5 100644 --- a/src/cfw_config.c +++ b/src/cfw_config.c @@ -88,6 +88,8 @@ void default_config(cfw_config_t * config) config->dumpSlc = 1; config->dumpSlccmpt = 1; config->dumpMlc = 0; + config->dumpOtp = 1; + config->dumpSeeprom = 1; } /*int read_config(cfw_config_t * config) diff --git a/src/cfw_config.h b/src/cfw_config.h index 9c1e29c..4e67665 100644 --- a/src/cfw_config.h +++ b/src/cfw_config.h @@ -42,6 +42,8 @@ typedef struct int dumpSlc; int dumpSlccmpt; int dumpMlc; + int dumpOtp; + int dumpSeeprom; } cfw_config_t; void default_config(cfw_config_t * config); diff --git a/src/menu.c b/src/menu.c index 34f532b..c4e06df 100644 --- a/src/menu.c +++ b/src/menu.c @@ -36,7 +36,7 @@ #include "dynamic_libs/socket_functions.h" #include "cfw_config.h" -#define MAX_CONFIG_SETTINGS 3 +#define MAX_CONFIG_SETTINGS 5 //#define MAX_CONFIG_SETTINGS_EXPERT 9 //#define MAX_CONFIG_SETTINGS_DEFAULT (MAX_CONFIG_SETTINGS_EXPERT - 3) @@ -163,6 +163,12 @@ int ShowMenu(cfw_config_t * currentConfig) case 2: config.dumpMlc = !config.dumpMlc; break; + case 3: + config.dumpOtp = !config.dumpOtp; + break; + case 4: + config.dumpSeeprom = !config.dumpSeeprom; + break; /*case 0: config.viewMode = !config.viewMode; max_config_item = config.viewMode ? MAX_CONFIG_SETTINGS_EXPERT : MAX_CONFIG_SETTINGS_DEFAULT;