├── 360 ├── fat.tpl ├── gen.py ├── first.c └── nsbl.h ├── 365 ├── fat.tpl ├── gen.py ├── first.c └── nsbl.h ├── installer ├── .gitignore ├── res │ ├── bg.png │ ├── icon.png │ ├── startup.png │ └── template.xml ├── 365_stubs │ └── libSceModulemgrForKernel_367_stub.a ├── src │ ├── debug_screen.h │ ├── kernel2.yml │ ├── version.h.in │ ├── user_exports.yml │ ├── kernel_exports.yml │ ├── enso.h │ ├── user.c │ ├── sha256.h │ ├── kernel2.c │ ├── crc32.c │ ├── debug_screen.c │ ├── sha256.c │ ├── debug_screen_font.c │ ├── main.c │ ├── kernel_360.c │ └── kernel_365.c ├── personalize.sh ├── LICENSE └── CMakeLists.txt ├── .gitignore ├── create_vpk.sh ├── first.x ├── second.x ├── README.md ├── Makefile ├── LICENSE └── second.c /installer/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | *.o 3 | first 4 | second 5 | -------------------------------------------------------------------------------- /360/fat.tpl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKGleba/enso/HEAD/360/fat.tpl -------------------------------------------------------------------------------- /365/fat.tpl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKGleba/enso/HEAD/365/fat.tpl -------------------------------------------------------------------------------- /installer/res/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKGleba/enso/HEAD/installer/res/bg.png -------------------------------------------------------------------------------- /installer/res/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKGleba/enso/HEAD/installer/res/icon.png -------------------------------------------------------------------------------- /installer/res/startup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKGleba/enso/HEAD/installer/res/startup.png -------------------------------------------------------------------------------- /installer/365_stubs/libSceModulemgrForKernel_367_stub.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SKGleba/enso/HEAD/installer/365_stubs/libSceModulemgrForKernel_367_stub.a -------------------------------------------------------------------------------- /installer/src/debug_screen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | int psvDebugScreenPrintf(const char *format, ...); 4 | int psvDebugScreenInit(); 5 | void* psvDebugScreenBase(void); 6 | -------------------------------------------------------------------------------- /installer/src/kernel2.yml: -------------------------------------------------------------------------------- 1 | kernel2: 2 | attributes: 0 3 | version: 4 | major: 1 5 | minor: 1 6 | main: 7 | start: module_start 8 | stop: module_stop 9 | -------------------------------------------------------------------------------- /installer/src/version.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define BUILD_DATE "${BUILD_DATE}" 4 | #define BUILD_CID {${BUILD_CID}} 5 | #define BUILD_PERSONALIZED (${PERSONALIZED}) 6 | -------------------------------------------------------------------------------- /installer/res/template.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bg.png 6 | 7 | 8 | 9 | startup.png 10 | 11 | 12 | -------------------------------------------------------------------------------- /create_vpk.sh: -------------------------------------------------------------------------------- 1 | ( 2 | make FW=360; 3 | make FW=365; 4 | mv fat_360.bin installer/res/fat_360.bin; 5 | mv fat_365.bin installer/res/fat_365.bin; 6 | cd installer/; 7 | cmake ./ && make; 8 | mv enso_installer.vpk ../enso.vpk; 9 | rm -rf CMakeFiles && rm cmake_install.cmake && rm CMakeCache.txt && rm Makefile; 10 | rm -rf emmc_* && rm enso_* && rm kernel2* && rm version.h; 11 | echo ""; 12 | echo "DONE! [ enso.vpk ]"; 13 | echo ""; 14 | ) -------------------------------------------------------------------------------- /first.x: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | 4 | ENTRY(start) 5 | 6 | SECTIONS 7 | { 8 | . = 0x51167220; 9 | .text : { *(.text.start) *(.text .text.* .gnu.linkonce.t.*) *(.sceStub.text.*) } 10 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } 11 | .data : { *(.data .data.* .gnu.linkonce.d.*) } 12 | .bss : { *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) } 13 | } 14 | -------------------------------------------------------------------------------- /second.x: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | 4 | ENTRY(start) 5 | 6 | SECTIONS 7 | { 8 | . = 0x51e00000; 9 | .text : { *(.text.start) *(.text .text.* .gnu.linkonce.t.*) *(.sceStub.text.*) } 10 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } 11 | .data : { *(.data .data.* .gnu.linkonce.d.*) } 12 | .bss : { *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) } 13 | } 14 | -------------------------------------------------------------------------------- /installer/src/user_exports.yml: -------------------------------------------------------------------------------- 1 | emmc_helper_user: 2 | attributes: 0 3 | version: 4 | major: 1 5 | minor: 1 6 | main: 7 | start: module_start 8 | stop: module_stop 9 | modules: 10 | emmc_helper_user: 11 | functions: 12 | - ensoCheckOs0 13 | - ensoCheckMBR 14 | - ensoCheckBlocks 15 | - ensoWriteConfig 16 | - ensoWriteBlocks 17 | - ensoWriteMBR 18 | - ensoCheckRealMBR 19 | - ensoUninstallMBR 20 | - ensoCleanUpBlocks 21 | -------------------------------------------------------------------------------- /installer/src/kernel_exports.yml: -------------------------------------------------------------------------------- 1 | emmc_helper: 2 | attributes: 0 3 | version: 4 | major: 1 5 | minor: 1 6 | main: 7 | start: module_start 8 | stop: module_stop 9 | modules: 10 | emmc_helper: 11 | syscall: true 12 | functions: 13 | - k_ensoCheckOs0 14 | - k_ensoCheckMBR 15 | - k_ensoCheckBlocks 16 | - k_ensoWriteConfig 17 | - k_ensoWriteBlocks 18 | - k_ensoWriteMBR 19 | - k_ensoCheckRealMBR 20 | - k_ensoUninstallMBR 21 | - k_ensoCleanUpBlocks 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | You need [vitasdk](https://vitasdk.org/). 2 | 3 | Run "create_vpk.sh" to build a package. 4 | 5 | Firmware specific offsets are in first.c and nsbl.h. 6 | 7 | The source is for advanced users only. Users should download the [prebuilt package](https://github.com/SKGleba/enso/releases/latest). If something goes wrong, you WILL perma-brick your Vita. There is no recovery, even if you have a hardware mod. The only possible recovery is if you have a hardware mod and you dump the eMMC _before_ getting bricked, then you can restore the dump. Dumps are device-specific and encrypted with a device-specific key. 8 | 9 | Again, even if you just add a custom boot logo, there's a good chance you will perma-brick your Vita. You have been warned. 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=arm-vita-eabi-gcc 2 | FW=365 3 | CFLAGS=-Os -fno-builtin-printf -fPIC -fno-builtin-memset -Wall -Wextra -Wno-unused-variable -DFW_$(FW) 4 | OBJCOPY=arm-vita-eabi-objcopy 5 | LDFLAGS=-nodefaultlibs -nostdlib 6 | 7 | all: fat_$(FW).bin 8 | rm first_* && rm second_* && rm second.o && rm $(FW)/first.o 9 | 10 | fat_$(FW).bin: first_$(FW).bin second_$(FW).bin 11 | ./$(FW)/gen.py $(FW)/fat.tpl first_$(FW).bin second_$(FW).bin fat_$(FW).bin 12 | 13 | first_$(FW).bin: first_$(FW) 14 | $(OBJCOPY) -O binary $^ $@ 15 | 16 | second_$(FW).bin: second_$(FW) 17 | $(OBJCOPY) -O binary $^ $@ 18 | 19 | first_$(FW): $(FW)/first.o 20 | $(CC) -o $@ $^ $(LDFLAGS) -T first.x 21 | 22 | second_$(FW): second.o 23 | $(CC) -o $@ $^ $(LDFLAGS) -T second.x 24 | -------------------------------------------------------------------------------- /installer/src/enso.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // user prototypes 4 | int ensoCheckOs0(void); 5 | int ensoCheckMBR(void); 6 | int ensoCheckBlocks(void); 7 | int ensoWriteConfig(void); 8 | int ensoWriteBlocks(void); 9 | int ensoWriteMBR(void); 10 | int ensoCheckRealMBR(void); 11 | int ensoUninstallMBR(void); 12 | int ensoCleanUpBlocks(void); 13 | 14 | // kernel prototypes 15 | int k_ensoCheckOs0(void); 16 | int k_ensoCheckMBR(void); 17 | int k_ensoCheckBlocks(void); 18 | int k_ensoWriteConfig(void); 19 | int k_ensoWriteBlocks(void); 20 | int k_ensoWriteMBR(void); 21 | int k_ensoCheckRealMBR(void); 22 | int k_ensoUninstallMBR(void); 23 | int k_ensoCleanUpBlocks(void); 24 | 25 | enum { 26 | E_PREVIOUS_INSTALL = 1, 27 | E_MBR_BUT_UNKNOWN = 2, 28 | E_UNKNOWN_DATA = 3, 29 | }; 30 | 31 | #define BLOCKS_OUTPUT "ux0:data/blocks.bin" 32 | -------------------------------------------------------------------------------- /installer/personalize.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make_flags="-j 4" 4 | 5 | if (( $# < 2 )); then 6 | echo "$0 git_dir [cid1 cid2 ...]" 7 | exit 0 8 | else 9 | git_dir="$1"; shift 10 | src_dir="`pwd`" 11 | fi 12 | 13 | while test $# -gt 0 14 | do 15 | cid="`echo $1 | tr '[:upper:]' '[:lower:]'`" 16 | echo "Building for ${cid}" 17 | mkdir "/tmp/$cid" 18 | pushd "/tmp/$cid" 19 | cmake -DPERSONALIZED=1 -DCID="${cid}" "${src_dir}" 20 | make ${make_flags} 21 | popd 22 | mv "/tmp/$cid/fat_installer.vpk" "${git_dir}/dl/${cid}.vpk" 23 | rm -rf "/tmp/$cid" 24 | pushd "${git_dir}" 25 | git add "dl/${cid}.vpk" 26 | popd 27 | list="${list}"$'\n'"${cid}" 28 | shift 29 | done 30 | 31 | echo "Committing to git..." 32 | pushd "${git_dir}" 33 | git commit -m "Added new personalized builds for: ${list}" 34 | git push 35 | echo "Done." 36 | -------------------------------------------------------------------------------- /installer/src/user.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "enso.h" 4 | 5 | // user library as a workaround to load kernel module at runtime 6 | 7 | int ensoCheckOs0(void) { 8 | return k_ensoCheckOs0(); 9 | } 10 | 11 | int ensoCheckMBR(void) { 12 | return k_ensoCheckMBR(); 13 | } 14 | 15 | int ensoCheckBlocks(void) { 16 | return k_ensoCheckBlocks(); 17 | } 18 | 19 | int ensoWriteConfig(void) { 20 | return k_ensoWriteConfig(); 21 | } 22 | 23 | int ensoWriteBlocks(void) { 24 | return k_ensoWriteBlocks(); 25 | } 26 | 27 | int ensoWriteMBR(void) { 28 | return k_ensoWriteMBR(); 29 | } 30 | 31 | int ensoCheckRealMBR(void) { 32 | return k_ensoCheckRealMBR(); 33 | } 34 | 35 | int ensoUninstallMBR(void) { 36 | return k_ensoUninstallMBR(); 37 | } 38 | 39 | int ensoCleanUpBlocks(void) { 40 | return k_ensoCleanUpBlocks(); 41 | } 42 | 43 | int module_start(int args, void *argv) { 44 | (void)args; 45 | (void)argv; 46 | return SCE_KERNEL_START_SUCCESS; 47 | } 48 | void _start() __attribute__ ((weak, alias ("module_start"))); 49 | 50 | int module_stop() { 51 | return SCE_KERNEL_STOP_SUCCESS; 52 | } 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 molecule 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /installer/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 molecule 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /installer/src/sha256.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: sha256.h 3 | * Author: Brad Conte (brad AT bradconte.com) 4 | * Copyright: 5 | * Disclaimer: This code is presented "as is" without any guarantees. 6 | * Details: Defines the API for the corresponding SHA1 implementation. 7 | *********************************************************************/ 8 | 9 | #ifndef SHA256_H 10 | #define SHA256_H 11 | 12 | /*************************** HEADER FILES ***************************/ 13 | #include 14 | 15 | /****************************** MACROS ******************************/ 16 | #define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest 17 | 18 | /**************************** DATA TYPES ****************************/ 19 | typedef unsigned char BYTE; // 8-bit byte 20 | typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines 21 | 22 | typedef struct { 23 | BYTE data[64]; 24 | WORD datalen; 25 | unsigned long long bitlen; 26 | WORD state[8]; 27 | } SHA256_CTX; 28 | 29 | /*********************** FUNCTION DECLARATIONS **********************/ 30 | void sha256_init(SHA256_CTX *ctx); 31 | void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len); 32 | void sha256_final(SHA256_CTX *ctx, BYTE hash[]); 33 | 34 | #endif // SHA256_H 35 | -------------------------------------------------------------------------------- /365/gen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | from sys import argv, exit 4 | import struct 5 | 6 | def p32(x): 7 | return struct.pack("= 0x180: 29 | print "your first payload is too big!" 30 | exit(-1) 31 | if len(second_bin) >= 0x2000: 32 | print "your second payload is too big!" 33 | exit(-1) 34 | 35 | temp_store = 0x511671A0 36 | pivot = 0x5101504C # e890b672 ldm r0, {r1, r4, r5, r6, r9, sl, ip, sp, pc} 37 | pop_pc = 0x5100155F 38 | pop_r0_pc = 0x5100E4D1 39 | pop_r1_r2_r4_r6_pc = 0x51024C53 40 | blx_r3_pop_r3_pc = 0x510058AF 41 | pop_r3_pc = 0x510058B1 42 | flush_icache = 0x51014691 # ICIALLUIS 43 | clean_dcache = 0x510146DD 44 | debug_printf = 0x51012D45 45 | 46 | pivot_args = [0, 0, 0, 0, 0, 0, 0, temp_store + 0x40, pop_pc] 47 | rop = [ 48 | pop_r0_pc, 49 | temp_store, # r0 50 | 51 | pop_r1_r2_r4_r6_pc, 52 | 0x800, # r1 53 | 0, # r2 54 | 0, # r4 55 | 0, # r6 56 | 57 | pop_r3_pc, 58 | clean_dcache, # r3 59 | 60 | blx_r3_pop_r3_pc, 61 | flush_icache, # r3 62 | 63 | blx_r3_pop_r3_pc, 64 | 0, # r3 65 | temp_store + 0x80|1, 66 | ] 67 | 68 | BASE = 0x5400 69 | 70 | # write pivot_args to temp_store 71 | ins(fat_tpl, BASE, pivot_args) 72 | # write rop to temp_store + 0x40 73 | ins(fat_tpl, BASE + 0x40, rop) 74 | # write payload to temp_store + 0x80 75 | ins(fat_tpl, BASE + 0x80, first_bin) 76 | # write second payload starting from block 5 77 | ins(fat_tpl, 5 * 0x200, second_bin) 78 | # write func ptr 79 | ins(fat_tpl, BASE + 0x638, [pivot]) 80 | # write R0 arg to func ptr 81 | ins(fat_tpl, BASE + 0x63C, [temp_store]) 82 | 83 | with open(argv[4], "wb") as fout: 84 | fout.write(fat_tpl) 85 | 86 | 87 | if __name__ == "__main__": 88 | main() 89 | -------------------------------------------------------------------------------- /360/gen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | from sys import argv, exit 4 | import struct 5 | 6 | def p32(x): 7 | return struct.pack("= 0x180: 29 | print "your first payload is too big!" 30 | exit(-1) 31 | if len(second_bin) >= 0x2000: 32 | print "your second payload is too big!" 33 | exit(-1) 34 | 35 | temp_store = 0x511671A0 36 | 37 | pivot = 0x51014f10 # e890b672 ldm r0, {r1, r4, r5, r6, r9, sl, ip, sp, pc} 38 | pop_pc = 0x5100155f 39 | pop_r0_pc = 0x5100fa31 40 | pop_r1_r2_r4_r6_pc = 0x51024b87 41 | blx_r3_pop_r3_pc = 0x51010033 42 | pop_r3_pc = 0x51010035 43 | flush_icache = 0x51014521 # ICIALLUIS 44 | clean_dcache = 0x5101456D 45 | debug_printf = 0x51012BD5 46 | 47 | pivot_args = [0, 0, 0, 0, 0, 0, 0, temp_store + 0x40, pop_pc] 48 | rop = [ 49 | pop_r0_pc, 50 | temp_store, # r0 51 | 52 | pop_r1_r2_r4_r6_pc, 53 | 0x800, # r1 54 | 0, # r2 55 | 0, # r4 56 | 0, # r6 57 | 58 | pop_r3_pc, 59 | clean_dcache, # r3 60 | 61 | blx_r3_pop_r3_pc, 62 | flush_icache, # r3 63 | 64 | blx_r3_pop_r3_pc, 65 | 0, # r3 66 | temp_store + 0x80|1, 67 | ] 68 | 69 | BASE = 0x5400 70 | 71 | # write pivot_args to temp_store 72 | ins(fat_tpl, BASE, pivot_args) 73 | # write rop to temp_store + 0x40 74 | ins(fat_tpl, BASE + 0x40, rop) 75 | # write payload to temp_store + 0x80 76 | ins(fat_tpl, BASE + 0x80, first_bin) 77 | # write second payload starting from block 5 78 | ins(fat_tpl, 5 * 0x200, second_bin) 79 | # write func ptr 80 | ins(fat_tpl, BASE + 0x638, [pivot]) 81 | # write R0 arg to func ptr 82 | ins(fat_tpl, BASE + 0x63C, [temp_store]) 83 | 84 | with open(argv[4], "wb") as fout: 85 | fout.write(fat_tpl) 86 | 87 | 88 | if __name__ == "__main__": 89 | main() 90 | -------------------------------------------------------------------------------- /installer/src/kernel2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | int siofix(void *func) { 11 | int ret = 0; 12 | int res = 0; 13 | int uid = 0; 14 | ret = uid = ksceKernelCreateThread("siofix", func, 64, 0x10000, 0, 0, 0); 15 | if (ret < 0){ret = -1; goto cleanup;} 16 | if ((ret = ksceKernelStartThread(uid, 0, NULL)) < 0) {ret = -1; goto cleanup;} 17 | if ((ret = ksceKernelWaitThreadEnd(uid, &res, NULL)) < 0) {ret = -1; goto cleanup;} 18 | ret = res; 19 | cleanup: 20 | if (uid > 0) ksceKernelDeleteThread(uid); 21 | return ret;} 22 | 23 | static void *pa2va(unsigned int pa) { 24 | unsigned int va = 0; 25 | unsigned int vaddr; 26 | unsigned int paddr; 27 | unsigned int i; 28 | 29 | for (i = 0; i < 0x100000; i++) { 30 | vaddr = i << 12; 31 | __asm__("mcr p15,0,%1,c7,c8,0\n\t" 32 | "mrc p15,0,%0,c7,c4,0\n\t" : "=r" (paddr) : "r" (vaddr)); 33 | if ((pa & 0xFFFFF000) == (paddr & 0xFFFFF000)) { 34 | va = vaddr + (pa & 0xFFF); 35 | break; 36 | } 37 | } 38 | return (void *)va; 39 | } 40 | 41 | static tai_hook_ref_t unload_allowed_hook; 42 | static SceUID unload_allowed_uid; 43 | 44 | int unload_allowed_patched(void) { 45 | TAI_CONTINUE(int, unload_allowed_hook); 46 | return 1; // always allowed 47 | } 48 | 49 | int checkfw(void) { 50 | int fd; 51 | unsigned int *tbl = NULL; 52 | void *vaddr; 53 | unsigned int paddr; 54 | unsigned int i; 55 | int write; 56 | unsigned int btw; 57 | unsigned int ttbr0; 58 | __asm__ volatile ("mrc p15, 0, %0, c2, c0, 0" : "=r" (ttbr0)); 59 | tbl = (unsigned int *) pa2va(ttbr0 & ~0xFF); 60 | fd = ksceIoOpen("ur0:temp/temp.t", SCE_O_WRONLY | SCE_O_TRUNC | SCE_O_CREAT, 6); 61 | if (fd < 0) 62 | return 0; 63 | i = 0x1F8; 64 | tbl[0x3E0] = (i << 20) | 0x10592; 65 | vaddr = &tbl[0x3E0]; 66 | __asm__ volatile ("dmb sy"); 67 | __asm__ volatile ("mcr p15,0,%0,c7,c14,1" :: "r" (vaddr) : "memory"); 68 | __asm__ volatile ("dsb sy\n\t" 69 | "mcr p15,0,r0,c8,c7,0\n\t" 70 | "dsb sy\n\t" 71 | "isb sy" ::: "memory"); 72 | vaddr = (void *) 0x3E000000; 73 | __asm__ volatile ("mcr p15,0,%1,c7,c8,0\n\t" 74 | "mrc p15,0,%0,c7,c4,0\n\t" : "=r" (paddr) : "r" (vaddr)); 75 | ksceIoWrite(fd, (void *)vaddr + 0x50044, 3); 76 | ksceIoClose(fd); 77 | fd = ksceIoOpen("ur0:temp/temp.t", SCE_O_RDONLY, 0777); 78 | static char ubuf[3]; 79 | ksceIoRead(fd, ubuf, 3); 80 | static char fwchkloc[14]; 81 | sprintf(fwchkloc, "ur0:temp/%s.t", ubuf); 82 | ksceIoClose(fd); 83 | ksceIoRename("ur0:temp/temp.t", fwchkloc); 84 | return 1; 85 | } 86 | 87 | int module_start(int args, void *argv) { 88 | (void)args; 89 | (void)argv; 90 | unload_allowed_uid = taiHookFunctionImportForKernel(KERNEL_PID, 91 | &unload_allowed_hook, // Output a reference 92 | "SceKernelModulemgr", // Name of module being hooked 93 | 0x11F9B314, // NID specifying SceSblACMgrForKernel 94 | 0xBBA13D9C, // Function NID 95 | unload_allowed_patched); // Name of the hook function 96 | 97 | int ret = 0, state = 0; 98 | ENTER_SYSCALL(state); 99 | siofix(checkfw); 100 | EXIT_SYSCALL(state); 101 | 102 | return SCE_KERNEL_START_SUCCESS; 103 | } 104 | void _start() __attribute__ ((weak, alias ("module_start"))); 105 | 106 | int module_stop() { 107 | taiHookReleaseForKernel(unload_allowed_uid, unload_allowed_hook); 108 | 109 | return SCE_KERNEL_STOP_SUCCESS; 110 | } 111 | -------------------------------------------------------------------------------- /360/first.c: -------------------------------------------------------------------------------- 1 | /* first.c -- fixup environment and exec second payload 2 | * 3 | * Copyright (C) 2017 molecule 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #include 9 | #include "nsbl.h" 10 | 11 | // ALL OFFSETS ARE SPECIFIC TO 3.60 12 | 13 | #define SECOND_PAYLOAD_OFFSET (5) 14 | #define SECOND_PAYLOAD_SIZE (0x4000) 15 | 16 | void go(void) { 17 | // first payload reinits os0 device and reads second payload from emmc 18 | // this is because we only have 0x180 bytes for first payload 19 | 20 | memset((char*)0x511673A0, 0, 0x600); // clean after us 21 | 22 | // we need to patch call to read block 1 instead of block 0 as the master block 23 | // now that we store a copy of real partition table in block 1 24 | *(uint16_t*)0x510200C6 = 0x2101; // movs r1, #1 25 | 26 | clean_dcache((void *)0x510200C0, 0x20); 27 | flush_icache(); 28 | 29 | // reinit os0_dev 30 | int (*fat_init_dev)() = (void*)0x5101FD19; 31 | char *os0_dev = (void*)0x51167784; 32 | int ret = fat_init_dev(os0_dev, 0x110000, 0x510010FD, 0x51028010); // os0_dev, flags, read_block, some_storage 33 | 34 | // TODO: what do these do? but we need them for some reason 35 | *(uint32_t*)(os0_dev + 0x2C) = 0; 36 | *(uint32_t*)(os0_dev + 0x78) = 0x1A000100; 37 | *(uint32_t*)(os0_dev + 0x84) = 0x1A001000; 38 | *(uint32_t*)(os0_dev + 0x90) = 0x0001002B; 39 | 40 | // restore corrupted boot args with our copy 41 | memcpy(boot_args, (*sysroot_ctx_ptr)->boot_args, sizeof(*boot_args)); 42 | 43 | // allocate buffer for code 44 | SceKernelAllocMemBlockKernelOpt opt; 45 | int blk; 46 | void *base; 47 | void (*f)(); 48 | memset(&opt, 0, sizeof(opt)); 49 | opt.size = sizeof(opt); 50 | opt.attr = 0xA0400000; 51 | blk = sceKernelAllocMemBlock("", 0x1020D006, SECOND_PAYLOAD_SIZE, NULL); 52 | f = NULL; 53 | if (blk >= 0) { 54 | if (sceKernelGetMemBlockBase(blk, &base) >= 0) { 55 | // read code buffer 56 | if (read_block_os0(0x51028010, SECOND_PAYLOAD_OFFSET, SECOND_PAYLOAD_SIZE/512, base) >= 0) { 57 | // TODO: perhaps add some simple integrity check here? 58 | if (sceKernelRemapBlock(blk, 0x1020D005) >= 0) { 59 | clean_dcache(base, SECOND_PAYLOAD_SIZE); 60 | flush_icache(); 61 | f = (void*)(base + 1); 62 | } 63 | } 64 | } 65 | } 66 | 67 | // fallback: if for some reason we weren't able to allocate/read the payload, then don't run it 68 | if (f != NULL) { 69 | f(); 70 | } 71 | 72 | // restore context and resume boot 73 | 74 | uint32_t *sp = *(uint32_t**)(0x51030100 + 0x220); // sp top for core 0 75 | uint32_t *old_sp = sp - 0x11d; 76 | 77 | // r0: 0x51167784 os0_dev 78 | // r1: 0xfffffffe 79 | // r2: sp - 0x110 80 | // r3: 0 81 | 82 | __asm__ volatile ( 83 | "movw r0, #0x7784\n" 84 | "movt r0, #0x5116\n" 85 | "movw r1, #0xfffe\n" 86 | "movt r1, #0xffff\n" 87 | "mov r2, %0\n" 88 | "mov r3, #0\n" 89 | "mov sp, %1\n" 90 | "mov r4, %2\n" 91 | "bx r4\n" :: "r" (sp - 0x110), "r" (old_sp), "r" (0x5101F571) : "r0", "r1", "r2", "r3", "r4" 92 | ); 93 | } 94 | 95 | __attribute__ ((section (".text.start"), naked)) void start(void) { 96 | __asm__ volatile ( 97 | "mov r0, #0\n" 98 | "movt r0, #0x51f0\n" 99 | "mov sp, r0\n" 100 | "b go\n" 101 | ); 102 | } 103 | -------------------------------------------------------------------------------- /365/first.c: -------------------------------------------------------------------------------- 1 | /* first.c -- fixup environment and exec second payload 2 | * 3 | * Copyright (C) 2017 molecule 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #include 9 | #include "nsbl.h" 10 | 11 | // ALL OFFSETS ARE SPECIFIC TO 3.60 12 | 13 | #define SECOND_PAYLOAD_OFFSET (5) 14 | #define SECOND_PAYLOAD_SIZE (0x4000) 15 | 16 | void go(void) { 17 | // first payload reinits os0 device and reads second payload from emmc 18 | // this is because we only have 0x180 bytes for first payload 19 | 20 | memset((char*)0x511673A0, 0, 0x600); // clean after us 21 | 22 | // we need to patch call to read block 1 instead of block 0 as the master block 23 | // now that we store a copy of real partition table in block 1 24 | *(uint16_t*)0x510202CE = 0x2101; // movs r1, #1 25 | 26 | clean_dcache((void *)0x510202C0, 0x20); 27 | flush_icache(); 28 | 29 | // reinit os0_dev 30 | int (*fat_init_dev)() = (void*)0x5101FF21; 31 | char *os0_dev = (void*)0x51167784; 32 | int ret = fat_init_dev(os0_dev, 0x110000, 0x510010FD, 0x51028010); // os0_dev, flags, read_block, some_storage 33 | 34 | // TODO: what do these do? but we need them for some reason 35 | *(uint32_t*)(os0_dev + 0x2C) = 0; 36 | *(uint32_t*)(os0_dev + 0x78) = 0x1A000100; 37 | *(uint32_t*)(os0_dev + 0x84) = 0x1A001000; 38 | *(uint32_t*)(os0_dev + 0x90) = 0x0001002B; 39 | 40 | // restore corrupted boot args with our copy 41 | memcpy(boot_args, (*sysroot_ctx_ptr)->boot_args, sizeof(*boot_args)); 42 | 43 | // allocate buffer for code 44 | SceKernelAllocMemBlockKernelOpt opt; 45 | int blk; 46 | void *base; 47 | void (*f)(); 48 | memset(&opt, 0, sizeof(opt)); 49 | opt.size = sizeof(opt); 50 | opt.attr = 0xA0400000; 51 | blk = sceKernelAllocMemBlock("", 0x1020D006, SECOND_PAYLOAD_SIZE, NULL); 52 | f = NULL; 53 | if (blk >= 0) { 54 | if (sceKernelGetMemBlockBase(blk, &base) >= 0) { 55 | // read code buffer 56 | if (read_block_os0(0x51028010, SECOND_PAYLOAD_OFFSET, SECOND_PAYLOAD_SIZE/512, base) >= 0) { 57 | // TODO: perhaps add some simple integrity check here? 58 | if (sceKernelRemapBlock(blk, 0x1020D005) >= 0) { 59 | clean_dcache(base, SECOND_PAYLOAD_SIZE); 60 | flush_icache(); 61 | f = (void*)(base + 1); 62 | } 63 | } 64 | } 65 | } 66 | 67 | // fallback: if for some reason we weren't able to allocate/read the payload, then don't run it 68 | if (f != NULL) { 69 | f(); 70 | } 71 | 72 | // restore context and resume boot 73 | 74 | uint32_t *sp = *(uint32_t**)(0x51030100 + 0x220); // sp top for core 0 75 | uint32_t *old_sp = sp - 0x11d; 76 | 77 | // r0: 0x51167784 os0_dev 78 | // r1: 0xfffffffe 79 | // r2: sp - 0x110 80 | // r3: 0 81 | 82 | __asm__ volatile ( 83 | "movw r0, #0x7784\n" 84 | "movt r0, #0x5116\n" 85 | "movw r1, #0xfffe\n" 86 | "movt r1, #0xffff\n" 87 | "mov r2, %0\n" 88 | "mov r3, #0\n" 89 | "mov sp, %1\n" 90 | "mov r4, %2\n" 91 | "bx r4\n" :: "r" (sp - 0x110), "r" (old_sp), "r" (0x5101F779) : "r0", "r1", "r2", "r3", "r4" 92 | ); 93 | } 94 | 95 | __attribute__ ((section (".text.start"), naked)) void start(void) { 96 | __asm__ volatile ( 97 | "mov r0, #0\n" 98 | "movt r0, #0x51f0\n" 99 | "mov sp, r0\n" 100 | "b go\n" 101 | ); 102 | } 103 | -------------------------------------------------------------------------------- /installer/src/crc32.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or 3 | * code or tables extracted from it, as desired without restriction. 4 | * 5 | * First, the polynomial itself and its table of feedback terms. The 6 | * polynomial is 7 | * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 8 | * 9 | * Note that we take it "backwards" and put the highest-order term in 10 | * the lowest-order bit. The X^32 term is "implied"; the LSB is the 11 | * X^31 term, etc. The X^0 term (usually shown as "+1") results in 12 | * the MSB being 1 13 | * 14 | * Note that the usual hardware shift register implementation, which 15 | * is what we're using (we're merely optimizing it by doing eight-bit 16 | * chunks at a time) shifts bits into the lowest-order term. In our 17 | * implementation, that means shifting towards the right. Why do we 18 | * do it this way? Because the calculated CRC must be transmitted in 19 | * order from highest-order term to lowest-order term. UARTs transmit 20 | * characters in order from LSB to MSB. By storing the CRC this way 21 | * we hand it to the UART in the order low-byte to high-byte; the UART 22 | * sends each low-bit to hight-bit; and the result is transmission bit 23 | * by bit from highest- to lowest-order term without requiring any bit 24 | * shuffling on our part. Reception works similarly 25 | * 26 | * The feedback terms table consists of 256, 32-bit entries. Notes 27 | * 28 | * The table can be generated at runtime if desired; code to do so 29 | * is shown later. It might not be obvious, but the feedback 30 | * terms simply represent the results of eight shift/xor opera 31 | * tions for all combinations of data and CRC register values 32 | * 33 | * The values must be right-shifted by eight bits by the "updcrc 34 | * logic; the shift must be unsigned (bring in zeroes). On some 35 | * hardware you could probably optimize the shift in assembler by 36 | * using byte-swap instructions 37 | * polynomial $edb88320 38 | * 39 | * 40 | * CRC32 code derived from work by Gary S. Brown. 41 | */ 42 | 43 | #include 44 | #include 45 | 46 | static uint32_t crc32_tab[] = { 47 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 48 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 49 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 50 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 51 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 52 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 53 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 54 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 55 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 56 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 57 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 58 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 59 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 60 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 61 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 62 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 63 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 64 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 65 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 66 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 67 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 68 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 69 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 70 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 71 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 72 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 73 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 74 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 75 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 76 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 77 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 78 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 79 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 80 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 81 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 82 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 83 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 84 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 85 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 86 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 87 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 88 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 89 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 90 | }; 91 | 92 | uint32_t 93 | crc32(uint32_t crc, const void *buf, size_t size) 94 | { 95 | const uint8_t *p; 96 | 97 | p = buf; 98 | crc = crc ^ ~0U; 99 | 100 | while (size--) 101 | crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); 102 | 103 | return crc ^ ~0U; 104 | } 105 | -------------------------------------------------------------------------------- /installer/src/debug_screen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | extern unsigned char psvDebugScreenFont[]; 11 | 12 | #define SCREEN_WIDTH (960) 13 | #define SCREEN_HEIGHT (544) 14 | #define SCREEN_FB_WIDTH (960) 15 | #define SCREEN_FB_SIZE (2 * 1024 * 1024) 16 | #define SCREEN_FB_ALIGN (256 * 1024) 17 | #define SCREEN_GLYPH_W (8) 18 | #define SCREEN_GLYPH_H (8) 19 | 20 | #define COLOR_BLACK 0xFF000000 21 | #define COLOR_RED 0xFF0000FF 22 | #define COLOR_BLUE 0xFF00FF00 23 | #define COLOR_YELLOW 0xFF00FFFF 24 | #define COLOR_GREEN 0xFFFF0000 25 | #define COLOR_MAGENTA 0xFFFF00FF 26 | #define COLOR_CYAN 0xFFFFFF00 27 | #define COLOR_WHITE 0xFFFFFFFF 28 | #define COLOR_GREY 0xFF808080 29 | #define COLOR_DEFAULT_FG COLOR_WHITE 30 | #define COLOR_DEFAULT_BG COLOR_BLACK 31 | 32 | static int psvDebugScreenMutex; /*< avoid race condition when outputing strings */ 33 | static uint32_t psvDebugScreenCoordX = 0; 34 | static uint32_t psvDebugScreenCoordY = 0; 35 | static uint32_t psvDebugScreenColorFg = COLOR_DEFAULT_FG; 36 | static uint32_t psvDebugScreenColorBg = COLOR_DEFAULT_BG; 37 | static SceDisplayFrameBuf psvDebugScreenFrameBuf = { 38 | sizeof(SceDisplayFrameBuf), NULL, SCREEN_WIDTH, 0, SCREEN_WIDTH, SCREEN_HEIGHT}; 39 | 40 | uint32_t psvDebugScreenSetFgColor(uint32_t color) { 41 | uint32_t prev_color = psvDebugScreenColorFg; 42 | psvDebugScreenColorFg = color; 43 | return prev_color; 44 | } 45 | 46 | uint32_t psvDebugScreenSetBgColor(uint32_t color) { 47 | uint32_t prev_color = psvDebugScreenColorBg; 48 | psvDebugScreenColorBg = color; 49 | return prev_color; 50 | } 51 | 52 | static size_t psvDebugScreenEscape(const char *str){ 53 | int i,j, p=0, params[8]={}; 54 | for(i=0; i<8 && str[i]!='\0'; i++){ 55 | if(str[i] >= '0' && str[i] <= '9'){ 56 | params[p]=(params[p]*10) + (str[i] - '0'); 57 | }else if(str[i] == ';'){ 58 | p++; 59 | }else if(str[i] == 'f' || str[i] == 'H'){ 60 | psvDebugScreenCoordX = params[0] * SCREEN_GLYPH_W; 61 | psvDebugScreenCoordY = params[1] * SCREEN_GLYPH_H; 62 | break; 63 | }else if (str[i] == 'm'){ 64 | for(j=0; j<=p; j++){ 65 | switch(params[j]/10){/*bold,dim,underline,blink,invert,hidden => unsupported yet */ 66 | #define BIT2BYTE(bit) ( ((!!(bit&4))<<23) | ((!!(bit&2))<<15) | ((!!(bit&1))<<7) ) 67 | case 0:psvDebugScreenSetFgColor(COLOR_DEFAULT_FG);psvDebugScreenSetBgColor(COLOR_DEFAULT_BG);break; 68 | case 3:psvDebugScreenSetFgColor(BIT2BYTE(params[j]%10));break; 69 | case 9:psvDebugScreenSetFgColor(BIT2BYTE(params[j]%10) | 0x7F7F7F7F);break; 70 | case 4:psvDebugScreenSetBgColor(BIT2BYTE(params[j]%10));break; 71 | case 10:psvDebugScreenSetBgColor(BIT2BYTE(params[j]%10) | 0x7F7F7F7F);break; 72 | #undef BIT2BYTE 73 | } 74 | } 75 | break; 76 | } 77 | } 78 | return i; 79 | } 80 | 81 | int psvDebugScreenInit() { 82 | psvDebugScreenMutex = sceKernelCreateMutex("log_mutex", 0, 0, NULL); 83 | SceUID displayblock = sceKernelAllocMemBlock("display", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, SCREEN_FB_SIZE, NULL); 84 | sceKernelGetMemBlockBase(displayblock, (void**)&psvDebugScreenFrameBuf.base); 85 | 86 | SceDisplayFrameBuf framebuf = { 87 | .size = sizeof(framebuf), 88 | .base = psvDebugScreenFrameBuf.base, 89 | .pitch = SCREEN_WIDTH, 90 | .pixelformat = SCE_DISPLAY_PIXELFORMAT_A8B8G8R8, 91 | .width = SCREEN_WIDTH, 92 | .height = SCREEN_HEIGHT, 93 | }; 94 | 95 | return sceDisplaySetFrameBuf(&framebuf, SCE_DISPLAY_SETBUF_NEXTFRAME); 96 | } 97 | 98 | void psvDebugScreenClear(int bg_color){ 99 | psvDebugScreenCoordX = psvDebugScreenCoordY = 0; 100 | int i; 101 | for(i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; i++) { 102 | ((uint32_t*)psvDebugScreenFrameBuf.base)[i] = bg_color; 103 | } 104 | } 105 | 106 | void* psvDebugScreenBase(void) { 107 | return psvDebugScreenFrameBuf.base; 108 | } 109 | 110 | int psvDebugScreenPuts(const char * text){ 111 | int c, i, j, l; 112 | uint8_t *font; 113 | uint32_t *vram_ptr; 114 | uint32_t *vram; 115 | 116 | sceKernelLockMutex(psvDebugScreenMutex, 1, NULL); 117 | 118 | for (c = 0; text[c] != '\0' ; c++) { 119 | if (psvDebugScreenCoordX + 8 > SCREEN_WIDTH) { 120 | psvDebugScreenCoordY += SCREEN_GLYPH_H; 121 | psvDebugScreenCoordX = 0; 122 | } 123 | if (psvDebugScreenCoordY + 8 > SCREEN_HEIGHT) { 124 | psvDebugScreenClear(psvDebugScreenColorBg); 125 | } 126 | if (text[c] == '\n') { 127 | psvDebugScreenCoordX = 0; 128 | psvDebugScreenCoordY += SCREEN_GLYPH_H; 129 | continue; 130 | } else if (text[c] == '\r') { 131 | psvDebugScreenCoordX = 0; 132 | continue; 133 | } else if ((text[c] == '\e') && (text[c+1] == '[')) { /* escape code (change color, position ...) */ 134 | c+=psvDebugScreenEscape(text+2)+2; 135 | continue; 136 | } 137 | 138 | vram = ((uint32_t*)psvDebugScreenFrameBuf.base) + psvDebugScreenCoordX + psvDebugScreenCoordY * SCREEN_FB_WIDTH; 139 | 140 | font = &psvDebugScreenFont[ (int)text[c] * 8]; 141 | for (i = l = 0; i < SCREEN_GLYPH_W; i++, l += SCREEN_GLYPH_W, font++) { 142 | vram_ptr = vram; 143 | for (j = 0; j < SCREEN_GLYPH_W; j++) { 144 | if ((*font & (128 >> j))) *vram_ptr = psvDebugScreenColorFg; 145 | else *vram_ptr = psvDebugScreenColorBg; 146 | vram_ptr++; 147 | } 148 | vram += SCREEN_FB_WIDTH; 149 | } 150 | psvDebugScreenCoordX += SCREEN_GLYPH_W; 151 | } 152 | 153 | sceKernelUnlockMutex(psvDebugScreenMutex, 1); 154 | return c; 155 | } 156 | 157 | int psvDebugScreenPrintf(const char *format, ...) { 158 | char buf[512]; 159 | 160 | va_list opt; 161 | va_start(opt, format); 162 | int ret = vsnprintf(buf, sizeof(buf), format, opt); 163 | psvDebugScreenPuts(buf); 164 | va_end(opt); 165 | 166 | return ret; 167 | } 168 | -------------------------------------------------------------------------------- /installer/src/sha256.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: sha256.c 3 | * Author: Brad Conte (brad AT bradconte.com) 4 | * Copyright: 5 | * Disclaimer: This code is presented "as is" without any guarantees. 6 | * Details: Implementation of the SHA-256 hashing algorithm. 7 | SHA-256 is one of the three algorithms in the SHA2 8 | specification. The others, SHA-384 and SHA-512, are not 9 | offered in this implementation. 10 | Algorithm specification can be found here: 11 | * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf 12 | This implementation uses little endian byte order. 13 | *********************************************************************/ 14 | 15 | /*************************** HEADER FILES ***************************/ 16 | #include 17 | #include 18 | #include "sha256.h" 19 | 20 | /****************************** MACROS ******************************/ 21 | #define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) 22 | #define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) 23 | 24 | #define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) 25 | #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) 26 | #define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) 27 | #define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) 28 | #define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) 29 | #define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) 30 | 31 | /**************************** VARIABLES *****************************/ 32 | static const WORD k[64] = { 33 | 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 34 | 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 35 | 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, 36 | 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, 37 | 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, 38 | 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, 39 | 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, 40 | 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 41 | }; 42 | 43 | /*********************** FUNCTION DEFINITIONS ***********************/ 44 | void sha256_transform(SHA256_CTX *ctx, const BYTE data[]) 45 | { 46 | WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; 47 | 48 | for (i = 0, j = 0; i < 16; ++i, j += 4) 49 | m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); 50 | for ( ; i < 64; ++i) 51 | m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; 52 | 53 | a = ctx->state[0]; 54 | b = ctx->state[1]; 55 | c = ctx->state[2]; 56 | d = ctx->state[3]; 57 | e = ctx->state[4]; 58 | f = ctx->state[5]; 59 | g = ctx->state[6]; 60 | h = ctx->state[7]; 61 | 62 | for (i = 0; i < 64; ++i) { 63 | t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; 64 | t2 = EP0(a) + MAJ(a,b,c); 65 | h = g; 66 | g = f; 67 | f = e; 68 | e = d + t1; 69 | d = c; 70 | c = b; 71 | b = a; 72 | a = t1 + t2; 73 | } 74 | 75 | ctx->state[0] += a; 76 | ctx->state[1] += b; 77 | ctx->state[2] += c; 78 | ctx->state[3] += d; 79 | ctx->state[4] += e; 80 | ctx->state[5] += f; 81 | ctx->state[6] += g; 82 | ctx->state[7] += h; 83 | } 84 | 85 | void sha256_init(SHA256_CTX *ctx) 86 | { 87 | ctx->datalen = 0; 88 | ctx->bitlen = 0; 89 | ctx->state[0] = 0x6a09e667; 90 | ctx->state[1] = 0xbb67ae85; 91 | ctx->state[2] = 0x3c6ef372; 92 | ctx->state[3] = 0xa54ff53a; 93 | ctx->state[4] = 0x510e527f; 94 | ctx->state[5] = 0x9b05688c; 95 | ctx->state[6] = 0x1f83d9ab; 96 | ctx->state[7] = 0x5be0cd19; 97 | } 98 | 99 | void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len) 100 | { 101 | WORD i; 102 | 103 | for (i = 0; i < len; ++i) { 104 | ctx->data[ctx->datalen] = data[i]; 105 | ctx->datalen++; 106 | if (ctx->datalen == 64) { 107 | sha256_transform(ctx, ctx->data); 108 | ctx->bitlen += 512; 109 | ctx->datalen = 0; 110 | } 111 | } 112 | } 113 | 114 | void sha256_final(SHA256_CTX *ctx, BYTE hash[]) 115 | { 116 | WORD i; 117 | 118 | i = ctx->datalen; 119 | 120 | // Pad whatever data is left in the buffer. 121 | if (ctx->datalen < 56) { 122 | ctx->data[i++] = 0x80; 123 | while (i < 56) 124 | ctx->data[i++] = 0x00; 125 | } 126 | else { 127 | ctx->data[i++] = 0x80; 128 | while (i < 64) 129 | ctx->data[i++] = 0x00; 130 | sha256_transform(ctx, ctx->data); 131 | memset(ctx->data, 0, 56); 132 | } 133 | 134 | // Append to the padding the total message's length in bits and transform. 135 | ctx->bitlen += ctx->datalen * 8; 136 | ctx->data[63] = ctx->bitlen; 137 | ctx->data[62] = ctx->bitlen >> 8; 138 | ctx->data[61] = ctx->bitlen >> 16; 139 | ctx->data[60] = ctx->bitlen >> 24; 140 | ctx->data[59] = ctx->bitlen >> 32; 141 | ctx->data[58] = ctx->bitlen >> 40; 142 | ctx->data[57] = ctx->bitlen >> 48; 143 | ctx->data[56] = ctx->bitlen >> 56; 144 | sha256_transform(ctx, ctx->data); 145 | 146 | // Since this implementation uses little endian byte ordering and SHA uses big endian, 147 | // reverse all the bytes when copying the final state to the output hash. 148 | for (i = 0; i < 4; ++i) { 149 | hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; 150 | hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; 151 | hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; 152 | hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; 153 | hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; 154 | hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; 155 | hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; 156 | hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /installer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) 4 | if(DEFINED ENV{VITASDK}) 5 | set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file") 6 | else() 7 | message(FATAL_ERROR "Please define VITASDK to point to your SDK path!") 8 | endif() 9 | endif() 10 | 11 | set(SHORT_NAME enso_installer) 12 | project(${SHORT_NAME}) 13 | include("${VITASDK}/share/vita.cmake" REQUIRED) 14 | 15 | set(VITA_APP_NAME "ensō") 16 | set(VITA_TITLEID "MLCL00003") 17 | 18 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -fno-builtin-printf") 19 | if (DEFINED SAFETY) 20 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror") 21 | endif() 22 | set(IGNORE_WARNING "${SAFETY}") 23 | 24 | string(TIMESTAMP BUILD_DATE UTC) 25 | 26 | set(CID "00000000000000000000000000000000" CACHE STRING "Customized CID") 27 | set(PERSONALIZED 0 CACHE BOOL "Personalize build") 28 | 29 | string(LENGTH ${CID} CID_LEN) 30 | 31 | if(NOT ${CID_LEN} EQUAL 32) 32 | message(FATAL_ERROR "Invalid CID") 33 | endif() 34 | 35 | set(i 0) 36 | while(i LESS ${CID_LEN}) 37 | string(SUBSTRING ${CID} ${i} 2 ch) 38 | if(${i} EQUAL 0) 39 | set(BUILD_CID "0x${ch} ^ 0xAA") 40 | else() 41 | set(BUILD_CID "${BUILD_CID}, 0x${ch} ^ 0xAA") 42 | endif() 43 | math(EXPR i "${i} + 2") 44 | endwhile() 45 | 46 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h) 47 | include_directories(${PROJECT_BINARY_DIR}) 48 | 49 | include_directories( 50 | src 51 | ) 52 | 53 | link_directories( 54 | ${CMAKE_BINARY_DIR}/emmc_helper_stubs 55 | ${CMAKE_BINARY_DIR}/emmc_helper_user_stubs 56 | ${CMAKE_BINARY_DIR}/365_stubs 57 | ) 58 | 59 | add_executable(${SHORT_NAME} 60 | src/main.c 61 | src/debug_screen.c 62 | src/debug_screen_font.c 63 | src/sha256.c 64 | ) 65 | 66 | add_dependencies(${SHORT_NAME} emmc_helper_365.skprx) 67 | add_dependencies(${SHORT_NAME} emmc_helper_360.skprx) 68 | 69 | target_link_libraries(${SHORT_NAME} 70 | SceDisplay_stub 71 | SceCtrl_stub 72 | SceShellSvc_stub 73 | SceProcessmgr_stub 74 | SceVshBridge_stub 75 | SceHttp_stub 76 | SceNet_stub 77 | SceNetCtl_stub 78 | SceSysmodule_stub 79 | SceSblUpdateMgr_stub 80 | taihen_stub 81 | emmc_helper_user_stub_weak 82 | ) 83 | 84 | vita_create_self(${SHORT_NAME}.self ${SHORT_NAME} UNSAFE) 85 | 86 | # emmc_helper: kernel version 360 87 | add_executable(emmc_helper_360 88 | src/kernel_360.c 89 | src/crc32.c 90 | ) 91 | set_target_properties(emmc_helper_360 92 | PROPERTIES LINK_FLAGS 93 | -nostdlib 94 | ) 95 | target_link_libraries(emmc_helper_360 96 | k 97 | gcc 98 | SceThreadmgrForDriver_stub 99 | SceModulemgrForDriver_stub 100 | SceModulemgrForKernel_stub 101 | SceSblAIMgrForDriver_stub 102 | SceIofilemgrForDriver_stub 103 | SceSysmemForKernel_stub 104 | SceSysmemForDriver_stub 105 | taihenForKernel_stub 106 | ) 107 | vita_create_self(emmc_helper_360.skprx emmc_helper_360 108 | CONFIG ${CMAKE_SOURCE_DIR}/src/kernel_exports.yml 109 | UNSAFE 110 | ) 111 | vita_create_stubs(emmc_helper_stubs emmc_helper_360 ${CMAKE_SOURCE_DIR}/src/kernel_exports.yml KERNEL) 112 | 113 | # emmc_helper: kernel version 365 114 | add_executable(emmc_helper_365 115 | src/kernel_365.c 116 | src/crc32.c 117 | ) 118 | set_target_properties(emmc_helper_365 119 | PROPERTIES LINK_FLAGS 120 | -nostdlib 121 | ) 122 | target_link_libraries(emmc_helper_365 123 | k 124 | gcc 125 | SceThreadmgrForDriver_stub 126 | SceModulemgrForDriver_stub 127 | SceModulemgrForKernel_367_stub 128 | SceSblAIMgrForDriver_stub 129 | SceIofilemgrForDriver_stub 130 | SceSysmemForKernel_stub 131 | SceSysmemForDriver_stub 132 | taihenForKernel_stub 133 | ) 134 | vita_create_self(emmc_helper_365.skprx emmc_helper_365 135 | CONFIG ${CMAKE_SOURCE_DIR}/src/kernel_exports.yml 136 | UNSAFE 137 | ) 138 | 139 | # second kernel helper to work around unloading a kernel module with exported funcs 140 | add_executable(kernel2 141 | src/kernel2.c 142 | ) 143 | set_target_properties(kernel2 144 | PROPERTIES LINK_FLAGS 145 | -nostdlib 146 | ) 147 | target_link_libraries(kernel2 148 | k 149 | gcc 150 | SceIofilemgrForDriver_stub 151 | SceSysmemForDriver_stub 152 | taihenForKernel_stub 153 | SceThreadmgrForDriver_stub 154 | ) 155 | vita_create_self(kernel2.skprx kernel2 156 | CONFIG ${CMAKE_SOURCE_DIR}/src/kernel2.yml 157 | UNSAFE 158 | ) 159 | 160 | # emmc_helper: user version 161 | add_executable(emmc_helper_user 162 | src/user.c 163 | ) 164 | set_target_properties(emmc_helper_user 165 | PROPERTIES LINK_FLAGS 166 | -nostdlib 167 | ) 168 | target_link_libraries(emmc_helper_user 169 | emmc_helper_stub 170 | ) 171 | vita_create_self(emmc_helper_user.suprx emmc_helper_user 172 | CONFIG ${CMAKE_SOURCE_DIR}/src/user_exports.yml 173 | UNSAFE 174 | ) 175 | vita_create_stubs(emmc_helper_user_stubs emmc_helper_user ${CMAKE_SOURCE_DIR}/src/user_exports.yml) 176 | 177 | 178 | add_dependencies(emmc_helper_user emmc_helper_stubs) 179 | add_dependencies(${SHORT_NAME} emmc_helper_user_stubs) 180 | add_dependencies(${SHORT_NAME} kernel2.skprx) 181 | add_dependencies(${SHORT_NAME} emmc_helper_360.skprx) 182 | add_dependencies(${SHORT_NAME} emmc_helper_365.skprx) 183 | add_dependencies(${SHORT_NAME} emmc_helper_user.suprx) 184 | 185 | vita_create_vpk(${SHORT_NAME}.vpk ${VITA_TITLEID} ${SHORT_NAME}.self 186 | VERSION ${VITA_VERSION} 187 | NAME ${VITA_APP_NAME} 188 | FILE ${CMAKE_SOURCE_DIR}/res/fat_360.bin oldfw/fat.bin 189 | FILE ${CMAKE_SOURCE_DIR}/res/fat_365.bin gudfw/fat.bin 190 | FILE ${CMAKE_BINARY_DIR}/emmc_helper_360.skprx oldfw/emmc_helper.skprx 191 | FILE ${CMAKE_BINARY_DIR}/emmc_helper_365.skprx gudfw/emmc_helper.skprx 192 | FILE ${CMAKE_BINARY_DIR}/emmc_helper_user.suprx emmc_helper.suprx 193 | FILE ${CMAKE_BINARY_DIR}/kernel2.skprx kernel2.skprx 194 | FILE ${CMAKE_SOURCE_DIR}/res/icon.png sce_sys/icon0.png 195 | FILE ${CMAKE_SOURCE_DIR}/res/template.xml sce_sys/livearea/contents/template.xml 196 | FILE ${CMAKE_SOURCE_DIR}/res/bg.png sce_sys/livearea/contents/bg.png 197 | FILE ${CMAKE_SOURCE_DIR}/res/startup.png sce_sys/livearea/contents/startup.png 198 | ) 199 | -------------------------------------------------------------------------------- /installer/src/debug_screen_font.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PSP Software Development Kit - http://www.pspdev.org 3 | * ----------------------------------------------------------------------- 4 | * Licensed under the BSD license, see LICENSE in PSPSDK root for details. 5 | * 6 | * font.c - Debug Font. 7 | * 8 | * Copyright (c) 2005 Marcus R. Brown 9 | * Copyright (c) 2005 James Forshaw 10 | * Copyright (c) 2005 John Kelley 11 | * 12 | * $Id: font.c 540 2005-07-08 19:35:10Z warren $ 13 | */ 14 | 15 | unsigned char psvDebugScreenFont[]= 16 | "\x00\x00\x00\x00\x00\x00\x00\x00\x3c\x42\xa5\x81\xa5\x99\x42\x3c" 17 | "\x3c\x7e\xdb\xff\xff\xdb\x66\x3c\x6c\xfe\xfe\xfe\x7c\x38\x10\x00" 18 | "\x10\x38\x7c\xfe\x7c\x38\x10\x00\x10\x38\x54\xfe\x54\x10\x38\x00" 19 | "\x10\x38\x7c\xfe\xfe\x10\x38\x00\x00\x00\x00\x30\x30\x00\x00\x00" 20 | "\xff\xff\xff\xe7\xe7\xff\xff\xff\x38\x44\x82\x82\x82\x44\x38\x00" 21 | "\xc7\xbb\x7d\x7d\x7d\xbb\xc7\xff\x0f\x03\x05\x79\x88\x88\x88\x70" 22 | "\x38\x44\x44\x44\x38\x10\x7c\x10\x30\x28\x24\x24\x28\x20\xe0\xc0" 23 | "\x3c\x24\x3c\x24\x24\xe4\xdc\x18\x10\x54\x38\xee\x38\x54\x10\x00" 24 | "\x10\x10\x10\x7c\x10\x10\x10\x10\x10\x10\x10\xff\x00\x00\x00\x00" 25 | "\x00\x00\x00\xff\x10\x10\x10\x10\x10\x10\x10\xf0\x10\x10\x10\x10" 26 | "\x10\x10\x10\x1f\x10\x10\x10\x10\x10\x10\x10\xff\x10\x10\x10\x10" 27 | "\x10\x10\x10\x10\x10\x10\x10\x10\x00\x00\x00\xff\x00\x00\x00\x00" 28 | "\x00\x00\x00\x1f\x10\x10\x10\x10\x00\x00\x00\xf0\x10\x10\x10\x10" 29 | "\x10\x10\x10\x1f\x00\x00\x00\x00\x10\x10\x10\xf0\x00\x00\x00\x00" 30 | "\x81\x42\x24\x18\x18\x24\x42\x81\x01\x02\x04\x08\x10\x20\x40\x80" 31 | "\x80\x40\x20\x10\x08\x04\x02\x01\x00\x10\x10\xff\x10\x10\x00\x00" 32 | "\x00\x00\x00\x00\x00\x00\x00\x00\x20\x20\x20\x20\x00\x00\x20\x00" 33 | "\x50\x50\x50\x00\x00\x00\x00\x00\x50\x50\xf8\x50\xf8\x50\x50\x00" 34 | "\x20\x78\xa0\x70\x28\xf0\x20\x00\xc0\xc8\x10\x20\x40\x98\x18\x00" 35 | "\x40\xa0\x40\xa8\x90\x98\x60\x00\x10\x20\x40\x00\x00\x00\x00\x00" 36 | "\x10\x20\x40\x40\x40\x20\x10\x00\x40\x20\x10\x10\x10\x20\x40\x00" 37 | "\x20\xa8\x70\x20\x70\xa8\x20\x00\x00\x20\x20\xf8\x20\x20\x00\x00" 38 | "\x00\x00\x00\x00\x00\x20\x20\x40\x00\x00\x00\x78\x00\x00\x00\x00" 39 | "\x00\x00\x00\x00\x00\x60\x60\x00\x00\x00\x08\x10\x20\x40\x80\x00" 40 | "\x70\x88\x98\xa8\xc8\x88\x70\x00\x20\x60\xa0\x20\x20\x20\xf8\x00" 41 | "\x70\x88\x08\x10\x60\x80\xf8\x00\x70\x88\x08\x30\x08\x88\x70\x00" 42 | "\x10\x30\x50\x90\xf8\x10\x10\x00\xf8\x80\xe0\x10\x08\x10\xe0\x00" 43 | "\x30\x40\x80\xf0\x88\x88\x70\x00\xf8\x88\x10\x20\x20\x20\x20\x00" 44 | "\x70\x88\x88\x70\x88\x88\x70\x00\x70\x88\x88\x78\x08\x10\x60\x00" 45 | "\x00\x00\x20\x00\x00\x20\x00\x00\x00\x00\x20\x00\x00\x20\x20\x40" 46 | "\x18\x30\x60\xc0\x60\x30\x18\x00\x00\x00\xf8\x00\xf8\x00\x00\x00" 47 | "\xc0\x60\x30\x18\x30\x60\xc0\x00\x70\x88\x08\x10\x20\x00\x20\x00" 48 | "\x70\x88\x08\x68\xa8\xa8\x70\x00\x20\x50\x88\x88\xf8\x88\x88\x00" 49 | "\xf0\x48\x48\x70\x48\x48\xf0\x00\x30\x48\x80\x80\x80\x48\x30\x00" 50 | "\xe0\x50\x48\x48\x48\x50\xe0\x00\xf8\x80\x80\xf0\x80\x80\xf8\x00" 51 | "\xf8\x80\x80\xf0\x80\x80\x80\x00\x70\x88\x80\xb8\x88\x88\x70\x00" 52 | "\x88\x88\x88\xf8\x88\x88\x88\x00\x70\x20\x20\x20\x20\x20\x70\x00" 53 | "\x38\x10\x10\x10\x90\x90\x60\x00\x88\x90\xa0\xc0\xa0\x90\x88\x00" 54 | "\x80\x80\x80\x80\x80\x80\xf8\x00\x88\xd8\xa8\xa8\x88\x88\x88\x00" 55 | "\x88\xc8\xc8\xa8\x98\x98\x88\x00\x70\x88\x88\x88\x88\x88\x70\x00" 56 | "\xf0\x88\x88\xf0\x80\x80\x80\x00\x70\x88\x88\x88\xa8\x90\x68\x00" 57 | "\xf0\x88\x88\xf0\xa0\x90\x88\x00\x70\x88\x80\x70\x08\x88\x70\x00" 58 | "\xf8\x20\x20\x20\x20\x20\x20\x00\x88\x88\x88\x88\x88\x88\x70\x00" 59 | "\x88\x88\x88\x88\x50\x50\x20\x00\x88\x88\x88\xa8\xa8\xd8\x88\x00" 60 | "\x88\x88\x50\x20\x50\x88\x88\x00\x88\x88\x88\x70\x20\x20\x20\x00" 61 | "\xf8\x08\x10\x20\x40\x80\xf8\x00\x70\x40\x40\x40\x40\x40\x70\x00" 62 | "\x00\x00\x80\x40\x20\x10\x08\x00\x70\x10\x10\x10\x10\x10\x70\x00" 63 | "\x20\x50\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\x00" 64 | "\x40\x20\x10\x00\x00\x00\x00\x00\x00\x00\x70\x08\x78\x88\x78\x00" 65 | "\x80\x80\xb0\xc8\x88\xc8\xb0\x00\x00\x00\x70\x88\x80\x88\x70\x00" 66 | "\x08\x08\x68\x98\x88\x98\x68\x00\x00\x00\x70\x88\xf8\x80\x70\x00" 67 | "\x10\x28\x20\xf8\x20\x20\x20\x00\x00\x00\x68\x98\x98\x68\x08\x70" 68 | "\x80\x80\xf0\x88\x88\x88\x88\x00\x20\x00\x60\x20\x20\x20\x70\x00" 69 | "\x10\x00\x30\x10\x10\x10\x90\x60\x40\x40\x48\x50\x60\x50\x48\x00" 70 | "\x60\x20\x20\x20\x20\x20\x70\x00\x00\x00\xd0\xa8\xa8\xa8\xa8\x00" 71 | "\x00\x00\xb0\xc8\x88\x88\x88\x00\x00\x00\x70\x88\x88\x88\x70\x00" 72 | "\x00\x00\xb0\xc8\xc8\xb0\x80\x80\x00\x00\x68\x98\x98\x68\x08\x08" 73 | "\x00\x00\xb0\xc8\x80\x80\x80\x00\x00\x00\x78\x80\xf0\x08\xf0\x00" 74 | "\x40\x40\xf0\x40\x40\x48\x30\x00\x00\x00\x90\x90\x90\x90\x68\x00" 75 | "\x00\x00\x88\x88\x88\x50\x20\x00\x00\x00\x88\xa8\xa8\xa8\x50\x00" 76 | "\x00\x00\x88\x50\x20\x50\x88\x00\x00\x00\x88\x88\x98\x68\x08\x70" 77 | "\x00\x00\xf8\x10\x20\x40\xf8\x00\x18\x20\x20\x40\x20\x20\x18\x00" 78 | "\x20\x20\x20\x00\x20\x20\x20\x00\xc0\x20\x20\x10\x20\x20\xc0\x00" 79 | "\x40\xa8\x10\x00\x00\x00\x00\x00\x00\x00\x20\x50\xf8\x00\x00\x00" 80 | "\x70\x88\x80\x80\x88\x70\x20\x60\x90\x00\x00\x90\x90\x90\x68\x00" 81 | "\x10\x20\x70\x88\xf8\x80\x70\x00\x20\x50\x70\x08\x78\x88\x78\x00" 82 | "\x48\x00\x70\x08\x78\x88\x78\x00\x20\x10\x70\x08\x78\x88\x78\x00" 83 | "\x20\x00\x70\x08\x78\x88\x78\x00\x00\x70\x80\x80\x80\x70\x10\x60" 84 | "\x20\x50\x70\x88\xf8\x80\x70\x00\x50\x00\x70\x88\xf8\x80\x70\x00" 85 | "\x20\x10\x70\x88\xf8\x80\x70\x00\x50\x00\x00\x60\x20\x20\x70\x00" 86 | "\x20\x50\x00\x60\x20\x20\x70\x00\x40\x20\x00\x60\x20\x20\x70\x00" 87 | "\x50\x00\x20\x50\x88\xf8\x88\x00\x20\x00\x20\x50\x88\xf8\x88\x00" 88 | "\x10\x20\xf8\x80\xf0\x80\xf8\x00\x00\x00\x6c\x12\x7e\x90\x6e\x00" 89 | "\x3e\x50\x90\x9c\xf0\x90\x9e\x00\x60\x90\x00\x60\x90\x90\x60\x00" 90 | "\x90\x00\x00\x60\x90\x90\x60\x00\x40\x20\x00\x60\x90\x90\x60\x00" 91 | "\x40\xa0\x00\xa0\xa0\xa0\x50\x00\x40\x20\x00\xa0\xa0\xa0\x50\x00" 92 | "\x90\x00\x90\x90\xb0\x50\x10\xe0\x50\x00\x70\x88\x88\x88\x70\x00" 93 | "\x50\x00\x88\x88\x88\x88\x70\x00\x20\x20\x78\x80\x80\x78\x20\x20" 94 | "\x18\x24\x20\xf8\x20\xe2\x5c\x00\x88\x50\x20\xf8\x20\xf8\x20\x00" 95 | "\xc0\xa0\xa0\xc8\x9c\x88\x88\x8c\x18\x20\x20\xf8\x20\x20\x20\x40" 96 | "\x10\x20\x70\x08\x78\x88\x78\x00\x10\x20\x00\x60\x20\x20\x70\x00" 97 | "\x20\x40\x00\x60\x90\x90\x60\x00\x20\x40\x00\x90\x90\x90\x68\x00" 98 | "\x50\xa0\x00\xa0\xd0\x90\x90\x00\x28\x50\x00\xc8\xa8\x98\x88\x00" 99 | "\x00\x70\x08\x78\x88\x78\x00\xf8\x00\x60\x90\x90\x90\x60\x00\xf0" 100 | "\x20\x00\x20\x40\x80\x88\x70\x00\x00\x00\x00\xf8\x80\x80\x00\x00" 101 | "\x00\x00\x00\xf8\x08\x08\x00\x00\x84\x88\x90\xa8\x54\x84\x08\x1c" 102 | "\x84\x88\x90\xa8\x58\xa8\x3c\x08\x20\x00\x00\x20\x20\x20\x20\x00" 103 | "\x00\x00\x24\x48\x90\x48\x24\x00\x00\x00\x90\x48\x24\x48\x90\x00" 104 | "\x28\x50\x20\x50\x88\xf8\x88\x00\x28\x50\x70\x08\x78\x88\x78\x00" 105 | "\x28\x50\x00\x70\x20\x20\x70\x00\x28\x50\x00\x20\x20\x20\x70\x00" 106 | "\x28\x50\x00\x70\x88\x88\x70\x00\x50\xa0\x00\x60\x90\x90\x60\x00" 107 | "\x28\x50\x00\x88\x88\x88\x70\x00\x50\xa0\x00\xa0\xa0\xa0\x50\x00" 108 | "\xfc\x48\x48\x48\xe8\x08\x50\x20\x00\x50\x00\x50\x50\x50\x10\x20" 109 | "\xc0\x44\xc8\x54\xec\x54\x9e\x04\x10\xa8\x40\x00\x00\x00\x00\x00" 110 | "\x00\x20\x50\x88\x50\x20\x00\x00\x88\x10\x20\x40\x80\x28\x00\x00" 111 | "\x7c\xa8\xa8\x68\x28\x28\x28\x00\x38\x40\x30\x48\x48\x30\x08\x70" 112 | "\x00\x00\x00\x00\x00\x00\xff\xff\xf0\xf0\xf0\xf0\x0f\x0f\x0f\x0f" 113 | "\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00" 114 | "\x00\x00\x00\x3c\x3c\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00" 115 | "\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x0f\x0f\x0f\x0f\xf0\xf0\xf0\xf0" 116 | "\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\x03\x03\x03\x03\x03\x03\x03\x03" 117 | "\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x11\x22\x44\x88\x11\x22\x44\x88" 118 | "\x88\x44\x22\x11\x88\x44\x22\x11\xfe\x7c\x38\x10\x00\x00\x00\x00" 119 | "\x00\x00\x00\x00\x10\x38\x7c\xfe\x80\xc0\xe0\xf0\xe0\xc0\x80\x00" 120 | "\x01\x03\x07\x0f\x07\x03\x01\x00\xff\x7e\x3c\x18\x18\x3c\x7e\xff" 121 | "\x81\xc3\xe7\xff\xff\xe7\xc3\x81\xf0\xf0\xf0\xf0\x00\x00\x00\x00" 122 | "\x00\x00\x00\x00\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x00\x00\x00\x00" 123 | "\x00\x00\x00\x00\xf0\xf0\xf0\xf0\x33\x33\xcc\xcc\x33\x33\xcc\xcc" 124 | "\x00\x20\x20\x50\x50\x88\xf8\x00\x20\x20\x70\x20\x70\x20\x20\x00" 125 | "\x00\x00\x00\x50\x88\xa8\x50\x00\xff\xff\xff\xff\xff\xff\xff\xff" 126 | "\x00\x00\x00\x00\xff\xff\xff\xff\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0" 127 | "\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\xff\xff\xff\xff\x00\x00\x00\x00" 128 | "\x00\x00\x68\x90\x90\x90\x68\x00\x30\x48\x48\x70\x48\x48\x70\xc0" 129 | "\xf8\x88\x80\x80\x80\x80\x80\x00\xf8\x50\x50\x50\x50\x50\x98\x00" 130 | "\xf8\x88\x40\x20\x40\x88\xf8\x00\x00\x00\x78\x90\x90\x90\x60\x00" 131 | "\x00\x50\x50\x50\x50\x68\x80\x80\x00\x50\xa0\x20\x20\x20\x20\x00" 132 | "\xf8\x20\x70\xa8\xa8\x70\x20\xf8\x20\x50\x88\xf8\x88\x50\x20\x00" 133 | "\x70\x88\x88\x88\x50\x50\xd8\x00\x30\x40\x40\x20\x50\x50\x50\x20" 134 | "\x00\x00\x00\x50\xa8\xa8\x50\x00\x08\x70\xa8\xa8\xa8\x70\x80\x00" 135 | "\x38\x40\x80\xf8\x80\x40\x38\x00\x70\x88\x88\x88\x88\x88\x88\x00" 136 | "\x00\xf8\x00\xf8\x00\xf8\x00\x00\x20\x20\xf8\x20\x20\x00\xf8\x00" 137 | "\xc0\x30\x08\x30\xc0\x00\xf8\x00\x18\x60\x80\x60\x18\x00\xf8\x00" 138 | "\x10\x28\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\xa0\x40" 139 | "\x00\x20\x00\xf8\x00\x20\x00\x00\x00\x50\xa0\x00\x50\xa0\x00\x00" 140 | "\x00\x18\x24\x24\x18\x00\x00\x00\x00\x30\x78\x78\x30\x00\x00\x00" 141 | "\x00\x00\x00\x00\x30\x00\x00\x00\x3e\x20\x20\x20\xa0\x60\x20\x00" 142 | "\xa0\x50\x50\x50\x00\x00\x00\x00\x40\xa0\x20\x40\xe0\x00\x00\x00" 143 | "\x00\x38\x38\x38\x38\x38\x38\x00\x00\x00\x00\x00\x00\x00\x00"; 144 | 145 | 146 | -------------------------------------------------------------------------------- /360/nsbl.h: -------------------------------------------------------------------------------- 1 | /* nsbl.h -- imported data from non-secure bootloader 2 | * 3 | * Copyright (C) 2017 molecule 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #ifndef NSBL_HEADER 9 | #define NSBL_HEADER 10 | 11 | #include 12 | 13 | #define NULL ((void *)0) 14 | 15 | typedef struct SceModuleExports { 16 | uint16_t size; // size of this structure; 0x20 for Vita 1.x 17 | uint8_t lib_version[2]; // 18 | uint16_t attribute; // ? 19 | uint16_t num_functions; // number of exported functions 20 | uint16_t num_vars; // number of exported variables 21 | uint16_t unk; 22 | uint32_t num_tls_vars; // number of exported TLS variables? <-- pretty sure wrong // yifanlu 23 | uint32_t lib_nid; // NID of this specific export list; one PRX can export several names 24 | char *lib_name; // name of the export module 25 | uint32_t *nid_table; // array of 32-bit NIDs for the exports, first functions then vars 26 | void **entry_table; // array of pointers to exported functions and then variables 27 | } __attribute__((packed)) SceModuleExports; 28 | 29 | #define EI_NIDENT 16 30 | typedef struct Elf32_Ehdr { 31 | unsigned char e_ident[EI_NIDENT]; /* ident bytes */ 32 | uint16_t e_type; /* file type */ 33 | uint16_t e_machine; /* target machine */ 34 | uint32_t e_version; /* file version */ 35 | uint32_t e_entry; /* start address */ 36 | uint32_t e_phoff; /* phdr file offset */ 37 | uint32_t e_shoff; /* shdr file offset */ 38 | uint32_t e_flags; /* file flags */ 39 | uint16_t e_ehsize; /* sizeof ehdr */ 40 | uint16_t e_phentsize; /* sizeof phdr */ 41 | uint16_t e_phnum; /* number phdrs */ 42 | uint16_t e_shentsize; /* sizeof shdr */ 43 | uint16_t e_shnum; /* number shdrs */ 44 | uint16_t e_shstrndx; /* shdr string index */ 45 | } __attribute__((packed)) Elf32_Ehdr; 46 | 47 | typedef struct { 48 | uint32_t p_type; /* entry type */ 49 | uint32_t p_offset; /* file offset */ 50 | uint32_t p_vaddr; /* virtual address */ 51 | uint32_t p_paddr; /* physical address */ 52 | uint32_t p_filesz; /* file size */ 53 | uint32_t p_memsz; /* memory size */ 54 | uint32_t p_flags; /* entry flags */ 55 | uint32_t p_align; /* memory/file alignment */ 56 | } __attribute__((packed)) Elf32_Phdr; 57 | 58 | typedef struct SceModuleSelfSectionInfo { 59 | uint64_t offset; 60 | uint64_t size; 61 | uint32_t compressed; // 2=compressed 62 | uint32_t unknown1; 63 | uint32_t encrypted; // 1=encrypted 64 | uint32_t unknown2; 65 | } __attribute__((packed)) SceModuleSelfSectionInfo; 66 | 67 | #ifdef FW_360 68 | 69 | // firmware specific internal structures 70 | 71 | typedef struct SceBootArgs { 72 | uint16_t version; 73 | uint16_t size; 74 | uint32_t fw_version; 75 | uint32_t ship_version; 76 | uint32_t field_C; 77 | uint32_t field_10; 78 | uint32_t field_14; 79 | uint32_t field_18; 80 | uint32_t field_1C; 81 | uint32_t field_20; 82 | uint32_t field_24; 83 | uint32_t field_28; 84 | uint8_t debug_flags[8]; 85 | uint32_t field_34; 86 | uint32_t field_38; 87 | uint32_t field_3C; 88 | uint32_t field_40; 89 | uint32_t field_44; 90 | uint32_t field_48; 91 | uint32_t aslr_seed; 92 | uint32_t field_50; 93 | uint32_t field_54; 94 | uint32_t field_58; 95 | uint32_t field_5C; 96 | uint32_t dram_base; 97 | uint32_t dram_size; 98 | uint32_t field_68; 99 | uint32_t boot_type_indicator_1; 100 | uint8_t serial[0x10]; 101 | uint32_t secure_kernel_enp_addr; 102 | uint32_t secure_kernel_enp_size; 103 | uint32_t field_88; 104 | uint32_t field_8C; 105 | uint32_t kprx_auth_sm_self_addr; 106 | uint32_t kprx_auth_sm_self_size; 107 | uint32_t prog_rvk_srvk_addr; 108 | uint32_t prog_rvk_srvk_size; 109 | uint16_t model; 110 | uint16_t device_type; 111 | uint16_t device_config; 112 | uint16_t retail_type; 113 | uint32_t field_A8; 114 | uint32_t field_AC; 115 | uint8_t session_id[0x10]; 116 | uint32_t field_C0; 117 | uint32_t boot_type_indicator_2; 118 | uint32_t field_C8; 119 | uint32_t field_CC; 120 | uint32_t resume_context_addr; 121 | uint32_t field_D4; 122 | uint32_t field_D8; 123 | uint32_t field_DC; 124 | uint32_t field_E0; 125 | uint32_t field_E4; 126 | uint32_t field_E8; 127 | uint32_t field_EC; 128 | uint32_t field_F0; 129 | uint32_t field_F4; 130 | uint32_t bootldr_revision; 131 | uint32_t magic; 132 | uint8_t session_key[0x20]; 133 | uint8_t unused[0xE0]; 134 | } __attribute__((packed)) SceBootArgs; 135 | 136 | typedef struct SceSysrootContext { 137 | uint32_t reserved[27]; 138 | SceBootArgs *boot_args; 139 | } __attribute__((packed)) SceSysrootContext; 140 | 141 | typedef struct SceModuleLoadList { 142 | const char *filename; 143 | } __attribute__((packed)) SceModuleLoadList; 144 | 145 | typedef struct SceObject { 146 | uint32_t field_0; 147 | void *obj_data; 148 | char data[]; 149 | } __attribute__((packed)) SceObject; 150 | 151 | typedef struct SceModuleSegment { 152 | uint32_t p_filesz; 153 | uint32_t p_memsz; 154 | uint16_t p_flags; 155 | uint16_t p_align_bits; 156 | void *buf; 157 | int32_t buf_blkid; 158 | } __attribute__((packed)) SceModuleSegment; 159 | 160 | typedef struct SceModuleObject { 161 | struct SceModuleObject *next; 162 | uint16_t exeflags; 163 | uint8_t status; 164 | uint8_t field_7; 165 | uint32_t min_sysver; 166 | int32_t modid; 167 | int32_t user_modid; 168 | int32_t pid; 169 | uint16_t modattribute; 170 | uint16_t modversion; 171 | uint32_t modid_name; 172 | SceModuleExports *ent_top_user; 173 | SceModuleExports *ent_end_user; 174 | uint32_t stub_start_user; 175 | uint32_t stub_end_user; 176 | uint32_t module_nid; 177 | uint32_t modinfo_field_38; 178 | uint32_t modinfo_field_3C; 179 | uint32_t modinfo_field_40; 180 | uint32_t exidx_start_user; 181 | uint32_t exidx_end_user; 182 | uint32_t extab_start_user; 183 | uint32_t extab_end_user; 184 | uint16_t num_export_libs; 185 | uint16_t num_import_libs; 186 | uint32_t field_54; 187 | uint32_t field_58; 188 | uint32_t field_5C; 189 | uint32_t field_60; 190 | void *imports; 191 | const char *path; 192 | uint32_t total_loadable; 193 | struct SceModuleSegment segments[3]; 194 | void *type_6FFFFF00_buf; 195 | uint32_t type_6FFFFF00_bufsz; 196 | void *module_start; 197 | void *module_init; 198 | void *module_stop; 199 | uint32_t field_C0; 200 | uint32_t field_C4; 201 | uint32_t field_C8; 202 | uint32_t field_CC; 203 | uint32_t field_D0; 204 | struct SceObject *prev_loaded; 205 | } __attribute__((packed)) SceModuleObject; 206 | 207 | typedef struct SceKernelAllocMemBlockKernelOpt { 208 | uint32_t size; 209 | uint32_t field_4; 210 | uint32_t attr; 211 | uint32_t field_C; 212 | uint32_t paddr; 213 | uint32_t alignment; 214 | uint32_t field_18; 215 | uint32_t field_1C; 216 | uint32_t mirror_blkid; 217 | int32_t pid; 218 | uint32_t field_28; 219 | uint32_t field_2C; 220 | uint32_t field_30; 221 | uint32_t field_34; 222 | uint32_t field_38; 223 | uint32_t field_3C; 224 | uint32_t field_40; 225 | uint32_t field_44; 226 | uint32_t field_48; 227 | uint32_t field_4C; 228 | uint32_t field_50; 229 | uint32_t field_54; 230 | } __attribute__((packed)) SceKernelAllocMemBlockKernelOpt; 231 | 232 | typedef struct SceModuleDecryptContext { 233 | void *header; 234 | uint32_t header_len; 235 | Elf32_Ehdr *elf_ehdr; 236 | Elf32_Phdr *elf_phdr; 237 | uint8_t type; 238 | uint8_t init_completed; 239 | uint8_t field_12; 240 | uint8_t field_13; 241 | SceModuleSelfSectionInfo *section_info; 242 | void *header_buffer; 243 | uint32_t sbl_ctx; 244 | uint32_t field_20; 245 | uint32_t fd; 246 | int32_t pid; 247 | uint32_t max_size; 248 | } __attribute__((packed)) SceModuleDecryptContext; 249 | 250 | // firmware specific function offsets 251 | static void *(*memset)(void *dst, int ch, int sz) = (void*)0x51013AD1; 252 | static void *(*memcpy)(void *dst, const void *src, int sz) = (void *)0x51013A51; 253 | static void *(*memmove)(void *dst, const void *src, int sz) = (void *)0x51021325; 254 | static void (*clean_dcache)(void *dst, int len) = (void*)0x5101456D; 255 | static int (*read_block_os0)() = (void*)0x510010FD; 256 | static void (*flush_icache)() = (void*)0x51014521; 257 | static int (*strncmp)(const char *s1, const char *s2, int len) = (void *)0x51013B30; 258 | static SceObject *(*get_obj_for_uid)(int uid) = (void *)0x51017649; 259 | static int (*module_load)(const SceModuleLoadList *list, int *uids, int count, int) = (void *)0x51001551; 260 | static int (*sceKernelAllocMemBlock)(const char *name, int type, int size, SceKernelAllocMemBlockKernelOpt *opt) = (void *)0x510086C1; 261 | static int (*sceKernelGetMemBlockBase)(int32_t uid, void **basep) = (void *)0x510040E5; 262 | static int (*sceKernelRemapBlock)(int32_t uid, int type) = (void *)0x510086D1; 263 | 264 | // firmware specific patch offsets 265 | 266 | static SceBootArgs *boot_args = (void *)0x51167528; 267 | static SceSysrootContext **sysroot_ctx_ptr = (void *)0x51138A3C; 268 | static void **module_load_func_ptr = (void *)0x51027630; 269 | 270 | // sysstate patches 271 | #define SBLAUTHMGR_OFFSET_PATCH_ARG (168) 272 | #define SYSSTATE_IS_MANUFACTURING_MODE_OFFSET (0x1500) 273 | #define SYSSTATE_IS_DEV_MODE_OFFSET (0xE28) 274 | #define SYSSTATE_RET_CHECK_BUG (0xD92) 275 | static const uint8_t sysstate_ret_patch[] = {0x13, 0x22, 0xc8, 0xf2, 0x01, 0x02}; 276 | #define SYSSTATE_SD0_STRING (0x2460) 277 | static const char ur0_path[] = "ur0:"; 278 | #define SYSSTATE_SD0_PSP2CONFIG_STRING (0x23AE) 279 | static const char ur0_psp2config_path[] = "ur0:tai/boot_config.txt"; 280 | #define SYSSTATE_FINAL_CALL (0x130) 281 | #define SYSSTATE_FINAL (0x18C9) 282 | 283 | #else 284 | #error "No firmware defined or firmware not supported." 285 | #endif 286 | 287 | #endif 288 | -------------------------------------------------------------------------------- /365/nsbl.h: -------------------------------------------------------------------------------- 1 | /* nsbl.h -- imported data from non-secure bootloader 2 | * 3 | * Copyright (C) 2017 molecule 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #ifndef NSBL_HEADER 9 | #define NSBL_HEADER 10 | 11 | #include 12 | 13 | #define NULL ((void *)0) 14 | 15 | typedef struct SceModuleExports { 16 | uint16_t size; // size of this structure; 0x20 for Vita 1.x 17 | uint8_t lib_version[2]; // 18 | uint16_t attribute; // ? 19 | uint16_t num_functions; // number of exported functions 20 | uint16_t num_vars; // number of exported variables 21 | uint16_t unk; 22 | uint32_t num_tls_vars; // number of exported TLS variables? <-- pretty sure wrong // yifanlu 23 | uint32_t lib_nid; // NID of this specific export list; one PRX can export several names 24 | char *lib_name; // name of the export module 25 | uint32_t *nid_table; // array of 32-bit NIDs for the exports, first functions then vars 26 | void **entry_table; // array of pointers to exported functions and then variables 27 | } __attribute__((packed)) SceModuleExports; 28 | 29 | #define EI_NIDENT 16 30 | typedef struct Elf32_Ehdr { 31 | unsigned char e_ident[EI_NIDENT]; /* ident bytes */ 32 | uint16_t e_type; /* file type */ 33 | uint16_t e_machine; /* target machine */ 34 | uint32_t e_version; /* file version */ 35 | uint32_t e_entry; /* start address */ 36 | uint32_t e_phoff; /* phdr file offset */ 37 | uint32_t e_shoff; /* shdr file offset */ 38 | uint32_t e_flags; /* file flags */ 39 | uint16_t e_ehsize; /* sizeof ehdr */ 40 | uint16_t e_phentsize; /* sizeof phdr */ 41 | uint16_t e_phnum; /* number phdrs */ 42 | uint16_t e_shentsize; /* sizeof shdr */ 43 | uint16_t e_shnum; /* number shdrs */ 44 | uint16_t e_shstrndx; /* shdr string index */ 45 | } __attribute__((packed)) Elf32_Ehdr; 46 | 47 | typedef struct { 48 | uint32_t p_type; /* entry type */ 49 | uint32_t p_offset; /* file offset */ 50 | uint32_t p_vaddr; /* virtual address */ 51 | uint32_t p_paddr; /* physical address */ 52 | uint32_t p_filesz; /* file size */ 53 | uint32_t p_memsz; /* memory size */ 54 | uint32_t p_flags; /* entry flags */ 55 | uint32_t p_align; /* memory/file alignment */ 56 | } __attribute__((packed)) Elf32_Phdr; 57 | 58 | typedef struct SceModuleSelfSectionInfo { 59 | uint64_t offset; 60 | uint64_t size; 61 | uint32_t compressed; // 2=compressed 62 | uint32_t unknown1; 63 | uint32_t encrypted; // 1=encrypted 64 | uint32_t unknown2; 65 | } __attribute__((packed)) SceModuleSelfSectionInfo; 66 | 67 | #ifdef FW_365 68 | 69 | // firmware specific internal structures 70 | 71 | typedef struct SceBootArgs { 72 | uint16_t version; 73 | uint16_t size; 74 | uint32_t fw_version; 75 | uint32_t ship_version; 76 | uint32_t field_C; 77 | uint32_t field_10; 78 | uint32_t field_14; 79 | uint32_t field_18; 80 | uint32_t field_1C; 81 | uint32_t field_20; 82 | uint32_t field_24; 83 | uint32_t field_28; 84 | uint8_t debug_flags[8]; 85 | uint32_t field_34; 86 | uint32_t field_38; 87 | uint32_t field_3C; 88 | uint32_t field_40; 89 | uint32_t field_44; 90 | uint32_t field_48; 91 | uint32_t aslr_seed; 92 | uint32_t field_50; 93 | uint32_t field_54; 94 | uint32_t field_58; 95 | uint32_t field_5C; 96 | uint32_t dram_base; 97 | uint32_t dram_size; 98 | uint32_t field_68; 99 | uint32_t boot_type_indicator_1; 100 | uint8_t serial[0x10]; 101 | uint32_t secure_kernel_enp_addr; 102 | uint32_t secure_kernel_enp_size; 103 | uint32_t field_88; 104 | uint32_t field_8C; 105 | uint32_t kprx_auth_sm_self_addr; 106 | uint32_t kprx_auth_sm_self_size; 107 | uint32_t prog_rvk_srvk_addr; 108 | uint32_t prog_rvk_srvk_size; 109 | uint16_t model; 110 | uint16_t device_type; 111 | uint16_t device_config; 112 | uint16_t retail_type; 113 | uint32_t field_A8; 114 | uint32_t field_AC; 115 | uint8_t session_id[0x10]; 116 | uint32_t field_C0; 117 | uint32_t boot_type_indicator_2; 118 | uint32_t field_C8; 119 | uint32_t field_CC; 120 | uint32_t resume_context_addr; 121 | uint32_t field_D4; 122 | uint32_t field_D8; 123 | uint32_t field_DC; 124 | uint32_t field_E0; 125 | uint32_t field_E4; 126 | uint32_t field_E8; 127 | uint32_t field_EC; 128 | uint32_t field_F0; 129 | uint32_t field_F4; 130 | uint32_t bootldr_revision; 131 | uint32_t magic; 132 | uint8_t session_key[0x20]; 133 | uint8_t unused[0xE0]; 134 | } __attribute__((packed)) SceBootArgs; 135 | 136 | typedef struct SceSysrootContext { 137 | uint32_t reserved[27]; 138 | SceBootArgs *boot_args; 139 | } __attribute__((packed)) SceSysrootContext; 140 | 141 | typedef struct SceModuleLoadList { 142 | const char *filename; 143 | } __attribute__((packed)) SceModuleLoadList; 144 | 145 | typedef struct SceObject { 146 | uint32_t field_0; 147 | void *obj_data; 148 | char data[]; 149 | } __attribute__((packed)) SceObject; 150 | 151 | typedef struct SceModuleSegment { 152 | uint32_t p_filesz; 153 | uint32_t p_memsz; 154 | uint16_t p_flags; 155 | uint16_t p_align_bits; 156 | void *buf; 157 | int32_t buf_blkid; 158 | } __attribute__((packed)) SceModuleSegment; 159 | 160 | typedef struct SceModuleObject { 161 | struct SceModuleObject *next; 162 | uint16_t exeflags; 163 | uint8_t status; 164 | uint8_t field_7; 165 | uint32_t min_sysver; 166 | int32_t modid; 167 | int32_t user_modid; 168 | int32_t pid; 169 | uint16_t modattribute; 170 | uint16_t modversion; 171 | uint32_t modid_name; 172 | SceModuleExports *ent_top_user; 173 | SceModuleExports *ent_end_user; 174 | uint32_t stub_start_user; 175 | uint32_t stub_end_user; 176 | uint32_t module_nid; 177 | uint32_t modinfo_field_38; 178 | uint32_t modinfo_field_3C; 179 | uint32_t modinfo_field_40; 180 | uint32_t exidx_start_user; 181 | uint32_t exidx_end_user; 182 | uint32_t extab_start_user; 183 | uint32_t extab_end_user; 184 | uint16_t num_export_libs; 185 | uint16_t num_import_libs; 186 | uint32_t field_54; 187 | uint32_t field_58; 188 | uint32_t field_5C; 189 | uint32_t field_60; 190 | void *imports; 191 | const char *path; 192 | uint32_t total_loadable; 193 | struct SceModuleSegment segments[3]; 194 | void *type_6FFFFF00_buf; 195 | uint32_t type_6FFFFF00_bufsz; 196 | void *module_start; 197 | void *module_init; 198 | void *module_stop; 199 | uint32_t field_C0; 200 | uint32_t field_C4; 201 | uint32_t field_C8; 202 | uint32_t field_CC; 203 | uint32_t field_D0; 204 | struct SceObject *prev_loaded; 205 | } __attribute__((packed)) SceModuleObject; 206 | 207 | typedef struct SceKernelAllocMemBlockKernelOpt { 208 | uint32_t size; 209 | uint32_t field_4; 210 | uint32_t attr; 211 | uint32_t field_C; 212 | uint32_t paddr; 213 | uint32_t alignment; 214 | uint32_t field_18; 215 | uint32_t field_1C; 216 | uint32_t mirror_blkid; 217 | int32_t pid; 218 | uint32_t field_28; 219 | uint32_t field_2C; 220 | uint32_t field_30; 221 | uint32_t field_34; 222 | uint32_t field_38; 223 | uint32_t field_3C; 224 | uint32_t field_40; 225 | uint32_t field_44; 226 | uint32_t field_48; 227 | uint32_t field_4C; 228 | uint32_t field_50; 229 | uint32_t field_54; 230 | } __attribute__((packed)) SceKernelAllocMemBlockKernelOpt; 231 | 232 | typedef struct SceModuleDecryptContext { 233 | void *header; 234 | uint32_t header_len; 235 | Elf32_Ehdr *elf_ehdr; 236 | Elf32_Phdr *elf_phdr; 237 | uint8_t type; 238 | uint8_t init_completed; 239 | uint8_t field_12; 240 | uint8_t field_13; 241 | SceModuleSelfSectionInfo *section_info; 242 | void *header_buffer; 243 | uint32_t sbl_ctx; 244 | uint32_t field_20; 245 | uint32_t fd; 246 | int32_t pid; 247 | uint32_t max_size; 248 | } __attribute__((packed)) SceModuleDecryptContext; 249 | 250 | // firmware specific function offsets 251 | static void *(*memset)(void *dst, int ch, int sz) = (void*)0x51013C41; 252 | static void *(*memcpy)(void *dst, const void *src, int sz) = (void *)0x51013BC1; 253 | static void *(*memmove)(void *dst, const void *src, int sz) = (void *)0x5102152D; 254 | static void (*clean_dcache)(void *dst, int len) = (void*)0x510146DD; 255 | static int (*read_block_os0)() = (void*)0x510010FD; 256 | static void (*flush_icache)() = (void*)0x51014691; 257 | static int (*strncmp)(const char *s1, const char *s2, int len) = (void *)0x51013CA0; 258 | static SceObject *(*get_obj_for_uid)(int uid) = (void *)0x51017785; 259 | static int (*module_load)(const SceModuleLoadList *list, int *uids, int count, int) = (void *)0x51001551; 260 | static int (*sceKernelAllocMemBlock)(const char *name, int type, int size, SceKernelAllocMemBlockKernelOpt *opt) = (void *)0x51007161; 261 | static int (*sceKernelGetMemBlockBase)(int32_t uid, void **basep) = (void *)0x510057E1; 262 | static int (*sceKernelRemapBlock)(int32_t uid, int type) = (void *)0x51007171; 263 | 264 | // firmware specific patch offsets 265 | 266 | static SceBootArgs *boot_args = (void *)0x51167528; 267 | static SceSysrootContext **sysroot_ctx_ptr = (void *)0x51138A3C; 268 | static void **module_load_func_ptr = (void *)0x510277A8; 269 | 270 | // sysstate patches 271 | #define SBLAUTHMGR_OFFSET_PATCH_ARG (168) 272 | #define SYSSTATE_IS_MANUFACTURING_MODE_OFFSET (0x1500) 273 | #define SYSSTATE_IS_DEV_MODE_OFFSET (0xE28) 274 | #define SYSSTATE_RET_CHECK_BUG (0xD92) 275 | static const uint8_t sysstate_ret_patch[] = {0x13, 0x22, 0xc8, 0xf2, 0x01, 0x02}; 276 | #define SYSSTATE_SD0_STRING (0x2448) 277 | static const char ur0_path[] = "ur0:"; 278 | #define SYSSTATE_SD0_PSP2CONFIG_STRING (0x2396) 279 | static const char ur0_psp2config_path[] = "ur0:tai/boot_config.txt"; 280 | #define SYSSTATE_FINAL_CALL (0x130) 281 | #define SYSSTATE_FINAL (0x18C9) 282 | 283 | #else 284 | #error "No firmware defined or firmware not supported." 285 | #endif 286 | 287 | #endif 288 | -------------------------------------------------------------------------------- /second.c: -------------------------------------------------------------------------------- 1 | /* second.c -- bootloader patches 2 | * 3 | * Copyright (C) 2017 molecule 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | #include 9 | #ifdef FW_360 10 | #include "360/nsbl.h" 11 | #else 12 | #include "365/nsbl.h" 13 | #endif 14 | 15 | #define unlikely(expr) __builtin_expect(!!(expr), 0) 16 | 17 | #define DACR_OFF(stmt) \ 18 | do { \ 19 | unsigned prev_dacr; \ 20 | __asm__ volatile( \ 21 | "mrc p15, 0, %0, c3, c0, 0 \n" \ 22 | : "=r" (prev_dacr) \ 23 | ); \ 24 | __asm__ volatile( \ 25 | "mcr p15, 0, %0, c3, c0, 0 \n" \ 26 | : : "r" (0xFFFF0000) \ 27 | ); \ 28 | stmt; \ 29 | __asm__ volatile( \ 30 | "mcr p15, 0, %0, c3, c0, 0 \n" \ 31 | : : "r" (prev_dacr) \ 32 | ); \ 33 | } while (0) 34 | 35 | #define INSTALL_HOOK_THUMB(func, addr) \ 36 | do { \ 37 | unsigned *target; \ 38 | target = (unsigned*)(addr); \ 39 | *target++ = 0xC004F8DF; /* ldr.w ip, [pc, #4] */ \ 40 | *target++ = 0xBF004760; /* bx ip; nop */ \ 41 | *target = (unsigned)func; \ 42 | } while (0) 43 | 44 | #define INSTALL_RET_THUMB(addr, ret) \ 45 | do { \ 46 | unsigned *target; \ 47 | target = (unsigned*)(addr); \ 48 | *target = 0x47702000 | (ret); /* movs r0, #ret; bx lr */ \ 49 | } while (0) 50 | 51 | // sdstor restore globals 52 | static int (*sdif_read_sector_mmc)(void* ctx, int sector, char* buffer, int nSectors) = NULL; 53 | static int (*sdif_read_sector_sd)(void* ctx, int sector, char* buffer, int nSectors) = NULL; 54 | static void *(*get_sd_context_part_validate_mmc)(int sd_ctx_index) = NULL; 55 | 56 | // sigpatch globals 57 | static int g_sigpatch_disabled = 0; 58 | static int g_homebrew_decrypt = 0; 59 | static int (*sbl_parse_header)(uint32_t ctx, const void *header, int len, void *args) = NULL; 60 | static int (*sbl_set_up_buffer)(uint32_t ctx, int segidx) = NULL; 61 | static int (*sbl_decrypt)(uint32_t ctx, void *buf, int sz) = NULL; 62 | 63 | // sysstate final function 64 | static void __attribute__((noreturn)) (*sysstate_final)(void) = NULL; 65 | 66 | // utility functions 67 | static void **get_export_func(SceModuleObject *mod, uint32_t lib_nid, uint32_t func_nid) { 68 | for (SceModuleExports *ent = mod->ent_top_user; ent != mod->ent_end_user; ent++) { 69 | if (ent->lib_nid == lib_nid) { 70 | for (int i = 0; i < ent->num_functions; i++) { 71 | if (ent->nid_table[i] == func_nid) { 72 | return &ent->entry_table[i]; 73 | } 74 | } 75 | } 76 | } 77 | return NULL; 78 | } 79 | 80 | static int is_safe_mode(void) { 81 | SceBootArgs *boot_args = (*sysroot_ctx_ptr)->boot_args; 82 | uint32_t v; 83 | 84 | if (boot_args->debug_flags[7] != 0xFF) { 85 | return 1; 86 | } 87 | 88 | v = boot_args->boot_type_indicator_2 & 0x7F; 89 | if (v == 0xB || (v == 4 && boot_args->resume_context_addr)) { 90 | v = ~boot_args->field_CC; 91 | if (((v >> 8) & 0x54) == 0x54 && (v & 0xC0) == 0) { 92 | return 1; 93 | } else { 94 | return 0; 95 | } 96 | } else if (v == 4) { 97 | return 0; 98 | } 99 | 100 | if (v == 0x1F || (uint32_t)(v - 0x18) <= 1) { 101 | return 1; 102 | } else { 103 | return 0; 104 | } 105 | } 106 | 107 | static int is_update_mode(void) { 108 | SceBootArgs *boot_args = (*sysroot_ctx_ptr)->boot_args; 109 | 110 | if (boot_args->debug_flags[4] != 0xFF) { 111 | return 1; 112 | } else { 113 | return 0; 114 | } 115 | } 116 | 117 | static inline int skip_patches(void) { 118 | return is_safe_mode() || is_update_mode(); 119 | } 120 | 121 | // sdif patches for MBR redirection 122 | 123 | static int sdif_read_sector_sd_patched(void* ctx, int sector, char* buffer, int nSectors) { 124 | int ret; 125 | #ifndef NO_MBR_REDIRECT 126 | if (unlikely(sector == 0 && nSectors > 0)) { 127 | if (get_sd_context_part_validate_mmc(0) == ctx) { // check if SD == MMC; no questions 128 | ret = sdif_read_sector_sd(ctx, 1, buffer, 1); 129 | if (ret >= 0 && nSectors > 1) { 130 | ret = sdif_read_sector_sd(ctx, 1, buffer + 0x200, nSectors-1); 131 | } 132 | return ret; 133 | } 134 | } 135 | #endif 136 | 137 | return sdif_read_sector_sd(ctx, sector, buffer, nSectors); 138 | } 139 | 140 | static int sdif_read_sector_mmc_patched(void* ctx, int sector, char* buffer, int nSectors) { 141 | int ret; 142 | #ifndef NO_MBR_REDIRECT 143 | if (unlikely(sector == 0 && nSectors > 0)) { 144 | if (get_sd_context_part_validate_mmc(0) == ctx) { 145 | ret = sdif_read_sector_mmc(ctx, 1, buffer, 1); 146 | if (ret >= 0 && nSectors > 1) { 147 | ret = sdif_read_sector_mmc(ctx, 1, buffer + 0x200, nSectors-1); 148 | } 149 | return ret; 150 | } 151 | } 152 | #endif 153 | 154 | return sdif_read_sector_mmc(ctx, sector, buffer, nSectors); 155 | } 156 | 157 | // sigpatches for bootup 158 | 159 | static int sbl_parse_header_patched(uint32_t ctx, const void *header, int len, void *args) { 160 | int ret = sbl_parse_header(ctx, header, len, args); 161 | if (unlikely(!g_sigpatch_disabled)) { 162 | DACR_OFF( 163 | g_homebrew_decrypt = (ret < 0); 164 | ); 165 | if (g_homebrew_decrypt) { 166 | *(uint32_t *)(args + SBLAUTHMGR_OFFSET_PATCH_ARG) = 0x40; 167 | ret = 0; 168 | } 169 | } 170 | return ret; 171 | } 172 | 173 | static int sbl_set_up_buffer_patched(uint32_t ctx, int segidx) { 174 | if (unlikely(!g_sigpatch_disabled)) { 175 | if (g_homebrew_decrypt) { 176 | return 2; // always compressed! 177 | } 178 | } 179 | return sbl_set_up_buffer(ctx, segidx); 180 | } 181 | 182 | static int sbl_decrypt_patched(uint32_t ctx, void *buf, int sz) { 183 | if (unlikely(!g_sigpatch_disabled)) { 184 | if (g_homebrew_decrypt) { 185 | return 0; 186 | } 187 | } 188 | return sbl_decrypt(ctx, buf, sz); 189 | } 190 | 191 | static void __attribute__((noreturn)) sysstate_final_hook(void) { 192 | DACR_OFF( 193 | g_sigpatch_disabled = 1; 194 | ); 195 | sysstate_final(); 196 | } 197 | 198 | // main function to hook stuff 199 | 200 | #define HOOK_EXPORT(name, lib_nid, func_nid) do { \ 201 | void **func = get_export_func(mod, lib_nid, func_nid); \ 202 | DACR_OFF( \ 203 | name = *func; \ 204 | *func = name ## _patched; \ 205 | ); \ 206 | } while (0) 207 | #define FIND_EXPORT(name, lib_nid, func_nid) do { \ 208 | void **func = get_export_func(mod, lib_nid, func_nid); \ 209 | DACR_OFF( \ 210 | name = *func; \ 211 | ); \ 212 | } while (0) 213 | static int module_load_patched(const SceModuleLoadList *list, int *uids, int count, int unk) { 214 | int ret; 215 | SceObject *obj; 216 | SceModuleObject *mod; 217 | int skip; 218 | int sysmem_idx = -1, sdif_idx = -1, authmgr_idx = -1, sysstate_idx = -1; 219 | 220 | skip = skip_patches(); 221 | for (int i = 0; i < count; i++) { 222 | if (!list[i].filename) { 223 | continue; // wtf sony why don't you sanitize input 224 | } 225 | if (strncmp(list[i].filename, "sdif.skprx", 10) == 0) { 226 | sdif_idx = i; // never skip MBR redirection patches 227 | } else if (!skip && strncmp(list[i].filename, "authmgr.skprx", 13) == 0) { 228 | authmgr_idx = i; 229 | } else if (!skip && strncmp(list[i].filename, "sysstatemgr.skprx", 17) == 0) { 230 | sysstate_idx = i; 231 | } 232 | } 233 | 234 | ret = module_load(list, uids, count, unk); 235 | 236 | // patch sdif 237 | if (sdif_idx >= 0) { 238 | obj = get_obj_for_uid(uids[sdif_idx]); 239 | if (obj != NULL) { 240 | mod = (SceModuleObject *)&obj->data; 241 | HOOK_EXPORT(sdif_read_sector_mmc, 0x96D306FA, 0x6F8D529B); 242 | HOOK_EXPORT(sdif_read_sector_sd, 0x96D306FA, 0xB9593652); 243 | FIND_EXPORT(get_sd_context_part_validate_mmc, 0x96D306FA, 0x6A71987F); 244 | } 245 | } 246 | // patch authmgr 247 | if (authmgr_idx >= 0) { 248 | obj = get_obj_for_uid(uids[authmgr_idx]); 249 | if (obj != NULL) { 250 | mod = (SceModuleObject *)&obj->data; 251 | HOOK_EXPORT(sbl_parse_header, 0x7ABF5135, 0xF3411881); 252 | HOOK_EXPORT(sbl_set_up_buffer, 0x7ABF5135, 0x89CCDA2C); 253 | HOOK_EXPORT(sbl_decrypt, 0x7ABF5135, 0xBC422443); 254 | } 255 | } 256 | // patch sysstate to load unsigned boot configs 257 | if (sysstate_idx >= 0) { 258 | obj = get_obj_for_uid(uids[sysstate_idx]); 259 | if (obj != NULL) { 260 | mod = (SceModuleObject *)&obj->data; 261 | DACR_OFF( 262 | INSTALL_RET_THUMB(mod->segments[0].buf + SYSSTATE_IS_MANUFACTURING_MODE_OFFSET, 1); 263 | *(uint32_t *)(mod->segments[0].buf + SYSSTATE_IS_DEV_MODE_OFFSET) = 0x20012001; 264 | memcpy(mod->segments[0].buf + SYSSTATE_RET_CHECK_BUG, sysstate_ret_patch, sizeof(sysstate_ret_patch)); 265 | memcpy(mod->segments[0].buf + SYSSTATE_SD0_STRING, ur0_path, sizeof(ur0_path)); 266 | memcpy(mod->segments[0].buf + SYSSTATE_SD0_PSP2CONFIG_STRING, ur0_psp2config_path, sizeof(ur0_psp2config_path)); 267 | // this patch actually corrupts two words of data, but they are only used in debug printing and seem to be fine 268 | INSTALL_HOOK_THUMB(sysstate_final_hook, mod->segments[0].buf + SYSSTATE_FINAL_CALL); 269 | sysstate_final = mod->segments[0].buf + SYSSTATE_FINAL; 270 | ); 271 | } 272 | } 273 | return ret; 274 | } 275 | #undef HOOK_EXPORT 276 | #undef FIND_EXPORT 277 | 278 | void go(void) { 279 | // patch module_load/module_start 280 | *module_load_func_ptr = module_load_patched; 281 | } 282 | 283 | __attribute__ ((section (".text.start"))) void start(void) { 284 | go(); 285 | } 286 | -------------------------------------------------------------------------------- /installer/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include "debug_screen.h" 19 | #include "enso.h" 20 | #include "version.h" 21 | #include "sha256.h" 22 | 23 | #define printf psvDebugScreenPrintf 24 | #define ARRAYSIZE(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) 25 | 26 | int _vshSblAimgrGetConsoleId(char cid[32]); 27 | int sceSblSsUpdateMgrSetBootMode(int x); 28 | int vshPowerRequestColdReset(void); 29 | int curfw = 69; 30 | 31 | enum { 32 | SCREEN_WIDTH = 960, 33 | SCREEN_HEIGHT = 544, 34 | PROGRESS_BAR_WIDTH = SCREEN_WIDTH, 35 | PROGRESS_BAR_HEIGHT = 10, 36 | LINE_SIZE = SCREEN_WIDTH, 37 | }; 38 | 39 | static unsigned buttons[] = { 40 | SCE_CTRL_SELECT, 41 | SCE_CTRL_START, 42 | SCE_CTRL_UP, 43 | SCE_CTRL_RIGHT, 44 | SCE_CTRL_DOWN, 45 | SCE_CTRL_LEFT, 46 | SCE_CTRL_LTRIGGER, 47 | SCE_CTRL_RTRIGGER, 48 | SCE_CTRL_TRIANGLE, 49 | SCE_CTRL_CIRCLE, 50 | SCE_CTRL_CROSS, 51 | SCE_CTRL_SQUARE, 52 | }; 53 | 54 | const char check_cid[16] = BUILD_CID; 55 | 56 | int ex(const char *fname) { 57 | FILE *file; 58 | if ((file = fopen(fname, "r"))) 59 | { 60 | fclose(file); 61 | return 1; 62 | } 63 | return 0; 64 | } 65 | 66 | uint32_t get_key(void) { 67 | static unsigned prev = 0; 68 | SceCtrlData pad; 69 | while (1) { 70 | memset(&pad, 0, sizeof(pad)); 71 | sceCtrlPeekBufferPositive(0, &pad, 1); 72 | unsigned new = prev ^ (pad.buttons & prev); 73 | prev = pad.buttons; 74 | for (size_t i = 0; i < sizeof(buttons)/sizeof(*buttons); ++i) 75 | if (new & buttons[i]) 76 | return buttons[i]; 77 | 78 | sceKernelDelayThread(1000); // 1ms 79 | } 80 | } 81 | 82 | void press_exit(void) { 83 | printf("Press any key to exit this application.\n"); 84 | get_key(); 85 | sceKernelExitProcess(0); 86 | } 87 | 88 | void press_reboot(void) { 89 | printf("Press any key to reboot.\n"); 90 | get_key(); 91 | vshPowerRequestColdReset(); 92 | } 93 | 94 | int g_kernel_module, g_user_module, g_kernel2_module; 95 | 96 | #define APP_PATH "ux0:app/MLCL00003/" 97 | 98 | int load_helper(void) { 99 | int ret = 0; 100 | 101 | tai_module_args_t args = {0}; 102 | args.size = sizeof(args); 103 | args.args = 0; 104 | args.argp = ""; 105 | 106 | if ((ret = g_kernel2_module = taiLoadStartKernelModuleForUser(APP_PATH "kernel2.skprx", &args)) < 0) { 107 | printf("Failed to load kernel workaround: 0x%08x\n", ret); 108 | return -1; 109 | } 110 | 111 | if (ex("ur0:temp/365.t") == 1) { 112 | sceIoRemove("ur0:temp/365.t"); 113 | if ((ret = g_kernel_module = taiLoadStartKernelModuleForUser(APP_PATH "gudfw/emmc_helper.skprx", &args)) < 0) { 114 | printf("Failed to load kernel module: 0x%08x\n", ret); 115 | return -1; 116 | } 117 | } else if (ex("ur0:temp/360.t") == 1) { 118 | curfw = 34; 119 | sceIoRemove("ur0:temp/360.t"); 120 | if ((ret = g_kernel_module = taiLoadStartKernelModuleForUser(APP_PATH "oldfw/emmc_helper.skprx", &args)) < 0) { 121 | printf("Failed to load kernel module: 0x%08x\n", ret); 122 | return -1; 123 | } 124 | } else { 125 | printf("Failed to get fw version, please disable all the plugins and try again\n", ret); 126 | return -1; 127 | } 128 | 129 | if ((ret = g_user_module = sceKernelLoadStartModule(APP_PATH "emmc_helper.suprx", 0, NULL, 0, NULL, NULL)) < 0) { 130 | printf("Failed to load user module: 0x%08x\n", ret); 131 | return -1; 132 | } 133 | 134 | return 0; 135 | } 136 | 137 | int stop_helper(void) { 138 | tai_module_args_t args = {0}; 139 | args.size = sizeof(args); 140 | args.args = 0; 141 | args.argp = ""; 142 | 143 | int ret = 0; 144 | int res = 0; 145 | 146 | if (g_user_module > 0) { 147 | ret = sceKernelStopUnloadModule(g_user_module, 0, NULL, 0, NULL, NULL); 148 | if (ret < 0) { 149 | printf("Failed to unload user module: 0x%08x\n", ret); 150 | return -1; 151 | } 152 | } 153 | 154 | if (g_kernel_module > 0) { 155 | ret = taiStopUnloadKernelModuleForUser(g_kernel_module, &args, NULL, &res); 156 | if (ret < 0) { 157 | printf("Failed to unload kernel module: 0x%08x\n", ret); 158 | return -1; 159 | } 160 | } 161 | 162 | if (g_kernel2_module > 0) { 163 | ret = taiStopUnloadKernelModuleForUser(g_kernel2_module, &args, NULL, &res); 164 | if (ret < 0) { 165 | printf("Failed to unload kernel workaround module: 0x%08x\n", ret); 166 | return -1; 167 | } 168 | } 169 | 170 | return ret; 171 | } 172 | 173 | int lock_system(void) { 174 | int ret = 0; 175 | 176 | printf("Locking system...\n"); 177 | ret = sceShellUtilInitEvents(0); 178 | if (ret < 0) { 179 | printf("failed: 0x%08X\n", ret); 180 | return -1; 181 | } 182 | ret = sceShellUtilLock(7); 183 | if (ret < 0) { 184 | printf("failed: 0x%08X\n", ret); 185 | return -1; 186 | } 187 | ret = sceKernelPowerLock(0); 188 | if (ret < 0) { 189 | printf("failed: 0x%08X\n", ret); 190 | return -1; 191 | } 192 | 193 | return 0; 194 | } 195 | 196 | int unlock_system(void) { 197 | sceKernelPowerUnlock(0); 198 | sceShellUtilUnlock(7); 199 | 200 | return 0; 201 | } 202 | 203 | void draw_rect(int x, int y, int width, int height, uint32_t color) { 204 | void *base = psvDebugScreenBase(); 205 | 206 | for (int j = y; j < y + height; ++j) 207 | for (int i = x; i < x + width; ++i) 208 | ((uint32_t*)base)[j * LINE_SIZE + i] = color; 209 | } 210 | 211 | int do_install(void) { 212 | int ret = 0; 213 | 214 | if (lock_system() < 0) 215 | return -1; 216 | 217 | printf("Checking MBR... "); 218 | ret = ensoCheckMBR(); 219 | if (ret < 0) { 220 | printf("failed\n"); 221 | goto err; 222 | } 223 | printf("ok!\n"); 224 | 225 | printf("Checking os0... "); 226 | ret = ensoCheckOs0(); 227 | if (ret < 0) { 228 | printf("failed\n"); 229 | printf("\nos0 modifications detected.\nYou should reinstall the firmware and try again.\n"); 230 | goto err; 231 | } 232 | printf("ok!\n"); 233 | printf("\n"); 234 | 235 | printf("Checking for previous installation... "); 236 | ret = ensoCheckBlocks(); 237 | if (ret < 0) { 238 | printf("failed\n"); 239 | goto err; 240 | } 241 | printf("ok!\n", ret); 242 | if (ret == 0) { 243 | // all good, blocks are empty 244 | } else if (ret == E_PREVIOUS_INSTALL) { 245 | printf("Previous installation was detected and will be overwritten.\nPress X to continue, any other key to exit.\n"); 246 | if (get_key() != SCE_CTRL_CROSS) 247 | goto err; 248 | } else if (ret == E_MBR_BUT_UNKNOWN) { 249 | printf("MBR was detected but installation checksum does not match.\nA dump was created at %s.\nPress X to continue, any other key to exit.\n", BLOCKS_OUTPUT); 250 | if (get_key() != SCE_CTRL_CROSS) 251 | goto err; 252 | } else if (ret == E_UNKNOWN_DATA) { 253 | printf("Unknown data was detected.\nA dump was created at %s.\nThe installation will be aborted.\n", BLOCKS_OUTPUT); 254 | goto err; 255 | } else { 256 | printf("Unknown error code.\n"); 257 | goto err; 258 | } 259 | 260 | printf("Writing config... "); 261 | ret = ensoWriteConfig(); 262 | if (ret < 0) { 263 | printf("failed\n"); 264 | goto err; 265 | } 266 | printf("ok!\n"); 267 | 268 | printf("Writing blocks... "); 269 | ret = ensoWriteBlocks(); 270 | if (ret < 0) { 271 | printf("failed\n"); 272 | goto err; 273 | } 274 | printf("ok!\n"); 275 | 276 | printf("Writing MBR... "); 277 | ret = ensoWriteMBR(); 278 | if (ret < 0) { 279 | printf("failed\n"); 280 | goto err; 281 | } 282 | printf("ok!\n"); 283 | 284 | printf("\nThe installation was completed successfully.\n"); 285 | 286 | unlock_system(); 287 | return 0; 288 | err: 289 | unlock_system(); 290 | return -1; 291 | } 292 | 293 | int do_uninstall(void) { 294 | int ret = 0; 295 | 296 | printf("Checking MBR in block 1... "); 297 | ret = ensoCheckRealMBR(); 298 | if (ret < 0) { 299 | printf("failed\n"); 300 | return -1; 301 | } 302 | printf("ok!\n"); 303 | 304 | printf("Uninstalling MBR patch... "); 305 | ret = ensoUninstallMBR(); 306 | if (ret < 0) { 307 | printf("failed\n"); 308 | return -1; 309 | } 310 | printf("ok!\n"); 311 | 312 | printf("Cleaning up payload blocks... "); 313 | ret = ensoCleanUpBlocks(); 314 | if (ret < 0) { 315 | printf("failed\n"); 316 | return -1; 317 | } 318 | printf("ok!\n"); 319 | 320 | printf("Deleting boot config... "); 321 | sceIoRemove("ur0:tai/boot_config.txt"); 322 | printf("ok!\n"); 323 | 324 | return 0; 325 | } 326 | 327 | int do_reinstall_config(void) { 328 | int ret = 0; 329 | 330 | printf("Writing config... "); 331 | ret = ensoWriteConfig(); 332 | if (ret < 0) { 333 | printf("failed\n"); 334 | return -1; 335 | } 336 | printf("ok!\n"); 337 | 338 | return 0; 339 | } 340 | 341 | int check_build(void) { 342 | if (BUILD_PERSONALIZED) { 343 | char right_cid[16]; 344 | char cur_cid[16]; 345 | for (int i = 0; i < 16; i++) { 346 | right_cid[i] = check_cid[i] ^ 0xAA; // super leet encryption 347 | } 348 | _vshSblAimgrGetConsoleId(cur_cid); 349 | if (memcmp(cur_cid, right_cid, 16) == 0) { 350 | return 1; 351 | } else { 352 | return 0; 353 | } 354 | } else { 355 | return 1; 356 | } 357 | } 358 | 359 | int check_safe_mode(void) { 360 | if (sceIoDevctl("ux0:", 0x3001, NULL, 0, NULL, 0) == 0x80010030) { 361 | return 1; 362 | } else { 363 | return 0; 364 | } 365 | } 366 | 367 | int check_henkaku(void) { 368 | int fd; 369 | 370 | if ((fd = sceIoOpen("ur0:tai/taihen.skprx", SCE_O_RDONLY, 0)) < 0) { 371 | return 0; 372 | } 373 | sceIoClose(fd); 374 | if ((fd = sceIoOpen("ur0:tai/henkaku.skprx", SCE_O_RDONLY, 0)) < 0) { 375 | return 0; 376 | } 377 | sceIoClose(fd); 378 | return 1; 379 | } 380 | 381 | int main(int argc, char *argv[]) { 382 | (void)argc; 383 | (void)argv; 384 | 385 | int should_reboot = 0; 386 | int ret = 0; 387 | 388 | psvDebugScreenInit(); 389 | 390 | if (!check_build()) { 391 | return 0; 392 | } 393 | 394 | printf("Built On: %s by SKGleba\n\n", BUILD_DATE); 395 | 396 | if (check_safe_mode()) { 397 | printf("Please disable HENkaku Safe Mode from Settings before running this installer.\n\n"); 398 | press_exit(); 399 | } 400 | 401 | if (!check_henkaku()) { 402 | printf("Your HENkaku version is too old! Please install R10 from https://henkaku.xyz/go/ (not the offline installer!)\n\n"); 403 | press_exit(); 404 | } 405 | 406 | #if BUILD_PERSONALIZED 407 | printf("Please visit https://enso.henkaku.xyz/beta/ for installation instructions.\n\n"); 408 | 409 | uint32_t sequence[] = { SCE_CTRL_CROSS, SCE_CTRL_TRIANGLE, SCE_CTRL_SQUARE, SCE_CTRL_CIRCLE }; 410 | for (size_t i = 0; i < sizeof(sequence)/sizeof(*sequence); ++i) { 411 | if (get_key() != sequence[i]) 412 | press_exit(); 413 | } 414 | #endif 415 | 416 | printf("This software will make PERMANENT modifications to your Vita. If anything goes wrong, \n" 417 | "there is NO RECOVERY (not even with a hardware flasher). The creators provide this \n" 418 | "tool \"as is\", without warranty of any kind, express or implied and cannot be held \n" 419 | "liable for any damage done.\n\n"); 420 | printf("Press CIRCLE to accept these terms or any other key to not accept.\n\n"); 421 | 422 | if (get_key() != SCE_CTRL_CIRCLE) { 423 | press_exit(); 424 | } 425 | 426 | ret = load_helper(); 427 | if (ret < 0) 428 | goto cleanup; 429 | 430 | printf("Options:\n\n"); 431 | printf(" CROSS Install/reinstall the hack.\n"); 432 | printf(" TRIANGLE Uninstall the hack.\n"); 433 | printf(" SQUARE Fix boot configuration (choose this if taiHEN isn't loading on boot).\n"); 434 | printf(" CIRCLE Exit without doing anything.\n\n"); 435 | 436 | again: 437 | switch (get_key()) { 438 | case SCE_CTRL_CROSS: 439 | ret = do_install(); 440 | should_reboot = 1; 441 | break; 442 | case SCE_CTRL_TRIANGLE: 443 | ret = do_uninstall(); 444 | should_reboot = 1; 445 | break; 446 | case SCE_CTRL_SQUARE: 447 | ret = do_reinstall_config(); 448 | break; 449 | case SCE_CTRL_CIRCLE: 450 | break; 451 | default: 452 | goto again; 453 | } 454 | 455 | if (ret < 0) { 456 | printf("\nAn error has occurred.\n"); 457 | printf("The log file can be found at ux0:data/enso.log\n\n"); 458 | should_reboot = 0; 459 | } else { 460 | printf("Success.\n\n"); 461 | } 462 | 463 | cleanup: 464 | stop_helper(); 465 | 466 | if (should_reboot) { 467 | press_reboot(); 468 | } else { 469 | press_exit(); 470 | } 471 | 472 | return 0; 473 | } 474 | -------------------------------------------------------------------------------- /installer/src/kernel_360.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "enso.h" 15 | 16 | #define printf(str, x...) do { printf_file("%s:%d: " str, __PRETTY_FUNCTION__, __LINE__, ## x); } while (0) 17 | #define ARRAYSIZE(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) 18 | 19 | int ksceSblAimgrIsDolce(void); 20 | uint32_t crc32(uint32_t crc, const void *buf, size_t size); 21 | 22 | enum { 23 | BLOCK_SIZE = 0x200, 24 | OFF_PARTITION_TABLE = 0, 25 | OFF_REAL_PARTITION_TABLE = 1 * BLOCK_SIZE, 26 | OFF_FAKE_OS0 = 2 * BLOCK_SIZE, 27 | FAT_BIN_SIZE = 0x6000, // NOTE: first 0x400 bytes are not written 28 | FAT_BIN_USEFUL_SIZE = 0x6000 - 0x400, 29 | 30 | OS0_SIZE = 0x3820 * BLOCK_SIZE, 31 | OS0_CRC32 = 0xb776951d, 32 | }; 33 | 34 | typedef struct { 35 | uint32_t off; 36 | uint32_t sz; 37 | uint8_t code; 38 | uint8_t type; 39 | uint8_t active; 40 | uint32_t flags; 41 | uint16_t unk; 42 | } __attribute__((packed)) partition_t; 43 | 44 | typedef struct { 45 | char magic[0x20]; 46 | uint32_t version; 47 | uint32_t device_size; 48 | char unk1[0x28]; 49 | partition_t partitions[0x10]; 50 | char unk2[0x5e]; 51 | char unk3[0x10 * 4]; 52 | uint16_t sig; 53 | } __attribute__((packed)) master_block_t; 54 | 55 | int printf_file(const char *format, ...) { 56 | char line[512] = {0}; 57 | va_list arg; 58 | 59 | va_start(arg, format); 60 | vsprintf(line, format, arg); 61 | va_end(arg); 62 | 63 | int fd = ksceIoOpen("ux0:data/enso.log", SCE_O_WRONLY | SCE_O_APPEND | SCE_O_CREAT, 0777); 64 | if (fd < 0) 65 | return 0; 66 | ksceIoWrite(fd, line, strlen(line)); 67 | ksceIoClose(fd); 68 | 69 | return 0; 70 | } 71 | 72 | const char *part_code(int code) { 73 | static char *codes[] = { 74 | "empty", 75 | "first_partition", 76 | "slb2", 77 | "os0", 78 | "vs0", 79 | "vd0", 80 | "tm0", 81 | "ur0", 82 | "ux0", 83 | "gro0", 84 | "grw0", 85 | "ud0", 86 | "sa0", 87 | "some_data", 88 | "pd0", 89 | "invalid" 90 | }; 91 | return codes[code]; 92 | } 93 | 94 | const char *part_type(int type) { 95 | if (type == 6) 96 | return "FAT16"; 97 | else if (type == 7) 98 | return "exFAT"; 99 | else if (type == 0xDA) 100 | return "raw"; 101 | return "unknown"; 102 | } 103 | 104 | const char *device = "sdstor0:int-lp-act-entire"; 105 | 106 | int run_on_thread(void *func) { 107 | int ret = 0; 108 | int res = 0; 109 | int uid = 0; 110 | 111 | ret = uid = ksceKernelCreateThread("run_on_thread", func, 64, 0x1000, 0, 0, 0); 112 | 113 | if (ret < 0) { 114 | printf("failed to create a thread: 0x%08x\n", ret); 115 | ret = -1; 116 | goto cleanup; 117 | } 118 | if ((ret = ksceKernelStartThread(uid, 0, NULL)) < 0) { 119 | printf("failed to start a thread: 0x%08x\n", ret); 120 | ret = -1; 121 | goto cleanup; 122 | } 123 | if ((ret = ksceKernelWaitThreadEnd(uid, &res, NULL)) < 0) { 124 | printf("failed to wait a thread: 0x%08x\n", ret); 125 | ret = -1; 126 | goto cleanup; 127 | } 128 | 129 | ret = res; 130 | 131 | cleanup: 132 | if (uid > 0) 133 | ksceKernelDeleteThread(uid); 134 | 135 | return ret; 136 | } 137 | 138 | int find_active_os0(master_block_t *master) { 139 | int active_os0 = -1; 140 | 141 | for (size_t i = 0; i < ARRAYSIZE(master->partitions); ++i) { 142 | partition_t *p = &master->partitions[i]; 143 | printf("Partition %d, code=%s, type=%s, active=%d, off=0x%08x, sz=0x%08x, flags=0x%08x, unk=0x%08x\n", 144 | i, part_code(p->code), part_type(p->type), p->active, p->off, p->sz, p->flags, p->unk); 145 | if (p->active == 1 && p->code == 3) 146 | active_os0 = i; 147 | } 148 | 149 | return active_os0; 150 | } 151 | 152 | int check_os0(void) { 153 | int ret = 0; 154 | int fd = 0; 155 | 156 | printf("checking os0\n"); 157 | 158 | ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); 159 | if (ret < 0) { 160 | printf("failed to open the device: 0x%08x\n", ret); 161 | ret = -1; 162 | goto cleanup; 163 | } 164 | 165 | // read MBR and find active os0 166 | static master_block_t master; 167 | if ((ret = ksceIoRead(fd, &master, sizeof(master))) != sizeof(master)) { 168 | printf("failed to read master block: 0x%08x\n", ret); 169 | ret = -1; 170 | goto cleanup; 171 | } 172 | 173 | int active_os0 = find_active_os0(&master); 174 | if (active_os0 == -1) { 175 | printf("failed to find active os0 partition\n"); 176 | ret = -1; 177 | goto cleanup; 178 | } 179 | 180 | uint32_t off = master.partitions[active_os0].off * BLOCK_SIZE; 181 | if ((ret = ksceIoLseek(fd, off, SCE_SEEK_SET)) != (int)off) { 182 | printf("failed to seek to os0: 0x%08x\n", ret); 183 | ret = -1; 184 | goto cleanup; 185 | } 186 | 187 | uint32_t crc = 0; 188 | for (int i = 0; i < OS0_SIZE / BLOCK_SIZE; ++i) { 189 | static char buffer[BLOCK_SIZE]; 190 | if ((ret = ksceIoRead(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 191 | printf("failed to read a block: 0x%08x\n", ret); 192 | ret = -1; 193 | goto cleanup; 194 | } 195 | crc = crc32(crc, buffer, sizeof(buffer)); 196 | } 197 | 198 | printf("got os0 crc32: 0x%08x\n", crc); 199 | if (crc != OS0_CRC32) { 200 | printf("error: crc does not match!\n"); 201 | ret = -1; 202 | } else { 203 | ret = 0; 204 | } 205 | 206 | cleanup: 207 | if (fd > 0) 208 | ksceIoClose(fd); 209 | 210 | return ret; 211 | } 212 | 213 | int k_ensoCheckOs0(void) { 214 | int ret = 0; 215 | int state = 0; 216 | 217 | ENTER_SYSCALL(state); 218 | ret = run_on_thread(check_os0); 219 | EXIT_SYSCALL(state); 220 | 221 | return ret; 222 | } 223 | 224 | int is_mbr(void *data) { 225 | master_block_t *master = data; 226 | if (memcmp(master->magic, "Sony Computer Entertainment Inc.", 0x20) != 0) 227 | return 0; 228 | if (master->sig != 0xAA55) 229 | return 0; 230 | return 1; 231 | } 232 | 233 | int is_empty(void *data) { 234 | uint8_t *buf = data; 235 | for (int i = 0; i < BLOCK_SIZE; ++i) 236 | if (buf[i] != 0xAA) 237 | return 0; 238 | return 1; 239 | } 240 | 241 | int check_mbr() { 242 | int ret = 0; 243 | int fd = 0; 244 | 245 | printf("check_mbr\n"); 246 | 247 | static master_block_t master; 248 | ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); 249 | if (fd < 0) { 250 | printf("failed to open the device: 0x%08x\n", ret); 251 | ret = -1; 252 | goto cleanup; 253 | } 254 | if ((ret = ksceIoRead(fd, &master, sizeof(master))) != sizeof(master)) { 255 | printf("failed to read master block: 0x%08x\n", ret); 256 | ret = -1; 257 | goto cleanup; 258 | } 259 | 260 | ret = 0; 261 | if (!is_mbr(&master)) { 262 | printf("error: master block is not MBR\n"); 263 | ret = -1; 264 | } 265 | 266 | cleanup: 267 | if (fd > 0) 268 | ksceIoClose(fd); 269 | 270 | return ret; 271 | } 272 | 273 | int k_ensoCheckMBR(void) { 274 | int ret = 0; 275 | int state = 0; 276 | 277 | ENTER_SYSCALL(state); 278 | ret = run_on_thread(check_mbr); 279 | EXIT_SYSCALL(state); 280 | 281 | return ret; 282 | } 283 | 284 | int dump_blocks(void) { 285 | int wfd = 0; 286 | int fd = 0; 287 | int ret = 0; 288 | 289 | printf("dumping blocks to %s\n", BLOCKS_OUTPUT); 290 | 291 | ret = wfd = ksceIoOpen(BLOCKS_OUTPUT, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777); 292 | if (ret < 0) { 293 | printf("failed to open %s for write: 0x%08x\n", BLOCKS_OUTPUT, ret); 294 | ret = -1; 295 | goto cleanup; 296 | } 297 | 298 | ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); 299 | if (ret < 0) { 300 | printf("failed to open the device: 0x%08x\n", ret); 301 | ret = -1; 302 | goto cleanup; 303 | } 304 | 305 | for (int i = 0; i < FAT_BIN_SIZE / BLOCK_SIZE; ++i) { 306 | static char buffer[BLOCK_SIZE]; 307 | if ((ret = ksceIoRead(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 308 | printf("failed to read block %d: 0x%08x\n", i, ret); 309 | ret = -1; 310 | goto cleanup; 311 | } 312 | if ((ret = ksceIoWrite(wfd, buffer, sizeof(buffer))) != sizeof(buffer)) { 313 | printf("failed to write block %d: 0x%08x\n", i, ret); 314 | ret = -1; 315 | goto cleanup; 316 | } 317 | } 318 | 319 | ret = 0; 320 | printf("copied successfully\n"); 321 | 322 | cleanup: 323 | if (wfd > 0) 324 | ksceIoClose(wfd); 325 | if (fd > 0) 326 | ksceIoClose(fd); 327 | 328 | return ret; 329 | } 330 | 331 | int check_blocks(void) { 332 | int ret = 0; 333 | int fd = 0; 334 | 335 | static master_block_t master; 336 | 337 | printf("checking blocks\n"); 338 | 339 | ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); 340 | if (ret < 0) { 341 | printf("failed to open the device: 0x%08x\n", ret); 342 | ret = -1; 343 | goto cleanup; 344 | } 345 | 346 | // check that block 1 is MBR 347 | if ((ret = ksceIoLseek(fd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { 348 | printf("failed to seek the device to real mbr: 0x%08x\n", ret); 349 | ret = -1; 350 | goto cleanup; 351 | } 352 | if ((ret = ksceIoRead(fd, &master, sizeof(master))) != sizeof(master)) { 353 | printf("failed to read the real mbr block: 0x%08x\n", ret); 354 | ret = -1; 355 | goto cleanup; 356 | } 357 | if (is_mbr(&master)) { 358 | // if it is, check that the rest of the blocks match a known crc32 value 359 | if ((ret = ksceIoLseek(fd, OFF_FAKE_OS0, SCE_SEEK_SET)) != OFF_FAKE_OS0) { 360 | printf("failed to seek the device to fake os0: 0x%08x\n", ret); 361 | ret = -1; 362 | goto cleanup; 363 | } 364 | 365 | uint32_t crc = 0; 366 | for (int i = 0; i < FAT_BIN_USEFUL_SIZE / BLOCK_SIZE; ++i) { 367 | static char buffer[BLOCK_SIZE]; 368 | if ((ret = ksceIoRead(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 369 | printf("failed to read a block: 0x%08x\n", ret); 370 | ret = -1; 371 | goto cleanup; 372 | } 373 | crc = crc32(crc, buffer, sizeof(buffer)); 374 | } 375 | printf("crc32[2; 48] = 0x%08x\n", crc); 376 | uint32_t known_crc[] = { 0xd40a32e8, 0x8cd78813 }; 377 | int found = 0; 378 | for (size_t i = 0; i < ARRAYSIZE(known_crc); ++i) { 379 | if (crc == known_crc[i]) { 380 | found = 1; 381 | break; 382 | } 383 | } 384 | if (!found) { 385 | printf("warning: got unknown checksum\n"); 386 | dump_blocks(); 387 | ret = E_MBR_BUT_UNKNOWN; 388 | } else { 389 | ret = E_PREVIOUS_INSTALL; 390 | } 391 | } else { 392 | // otherwise just check that the data's empty, including real mbr 393 | if ((ret = ksceIoLseek(fd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { 394 | printf("failed to seek the device to real mbr block (2): 0x%08x\n", ret); 395 | ret = -1; 396 | goto cleanup; 397 | } 398 | 399 | // -1 because block 0 in fat.bin is fake MBR 400 | for (int i = 0; i < FAT_BIN_SIZE / 0x200 - 1; ++i) { 401 | static char buffer[BLOCK_SIZE]; 402 | if ((ret = ksceIoRead(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 403 | printf("failed to read a block (2): 0x%08x\n", ret); 404 | ret = -1; 405 | goto cleanup; 406 | } 407 | if (!is_empty(&buffer)) { 408 | printf("unknown data was found in block %d\n", i + 1); 409 | dump_blocks(); 410 | ret = E_UNKNOWN_DATA; 411 | goto cleanup; 412 | } 413 | } 414 | 415 | // all blocks checked, all good 416 | ret = 0; 417 | } 418 | 419 | cleanup: 420 | if (fd > 0) 421 | ksceIoClose(fd); 422 | 423 | return ret; 424 | } 425 | 426 | int k_ensoCheckBlocks() { 427 | int ret = 0; 428 | int state = 0; 429 | 430 | ENTER_SYSCALL(state); 431 | ret = run_on_thread(check_blocks); 432 | EXIT_SYSCALL(state); 433 | 434 | return ret; 435 | } 436 | 437 | int write_config() { 438 | int pstv = 0; 439 | int uid = 0; 440 | int ret = 0; 441 | int fd = 0; 442 | SceKernelModuleInfo info = {0}; 443 | char *pos = NULL; 444 | int len = 0; 445 | 446 | printf("write_config\n"); 447 | 448 | ksceIoMkdir("ur0:tai", 0777); // make directory if it does not exist 449 | 450 | pstv = ksceSblAimgrIsDolce(); 451 | printf("writing config for %s\n", pstv ? "PSTV" : "PS Vita"); 452 | 453 | ret = uid = ksceKernelLoadModule(pstv ? "os0:psp2config_dolce.skprx" : "os0:psp2config_vita.skprx", 0, NULL); 454 | if (ret < 0) { 455 | printf("failed to load psp2config module: 0x%08x\n", ret); 456 | ret = -1; 457 | goto cleanup; 458 | } 459 | 460 | info.size = sizeof(info); 461 | ret = ksceKernelGetModuleInfo(KERNEL_PID, uid, &info); 462 | if (ret < 0) { 463 | printf("failed to get module info: 0x%08x\n", ret); 464 | ret = -1; 465 | goto cleanup; 466 | } 467 | 468 | static char config[0x1000]; 469 | 470 | if (info.segments[0].memsz >= sizeof(config)) { 471 | printf("config does not fit, size=0x%08x\n", info.segments[0].memsz); 472 | ret = -1; 473 | goto cleanup; 474 | } 475 | 476 | memcpy(config, (char*)info.segments[0].vaddr + 0xD4, info.segments[0].memsz - 0xD4); 477 | 478 | if (memcmp(config, "#\n# PSP2", 8) != 0) { 479 | printf("config is corrupt\n"); 480 | ret = -1; 481 | goto cleanup; 482 | } 483 | 484 | ret = fd = ksceIoOpen("ur0:tai/boot_config.txt", SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777); 485 | if (ret < 0) { 486 | printf("failed to open ur0:tai/boot_config.txt for write: 0x%08x\n", ret); 487 | ret = -1; 488 | goto cleanup; 489 | } 490 | 491 | pos = strstr(config, "\n- appspawn vs0:vsh/shell/shell.self"); 492 | if (!pos) { 493 | printf("failed to patch config: cannot locate appspawn line\n"); 494 | ret = -1; 495 | goto cleanup; 496 | } 497 | 498 | // write first part: warning message 499 | const char *patch1 = 500 | "# WARNING: DO NOT EDIT THIS FILE. IF YOU JUST WANT TO RUN A PLUGIN ON BOOT,\n" 501 | "# EDIT ux0:tai/config.txt INSTEAD. IF YOU BREAK THIS FILE, YOUR VITA WILL NO\n" 502 | "# LONGER BOOT. IF THAT HAPPENS, YOU CAN ENTER SAFE MODE AND RESET ALL SETTINGS\n" 503 | "# TO RESET THIS FILE. THIS FILE IS UNIQUE TO EACH VITA MODEL. DO NOT BLINDLY\n" 504 | "# USE SOMEONE ELSE'S CONFIG.\n"; 505 | len = strlen(patch1); 506 | if ((ret = ksceIoWrite(fd, patch1, len)) != len) { 507 | printf("failed to write config 1st part: wrote 0x%08x expected 0x%08x\n", ret, len); 508 | ret = -1; 509 | goto cleanup; 510 | } 511 | 512 | // write second part: everything before appspawn 513 | len = pos - config; 514 | if ((ret = ksceIoWrite(fd, config, len)) != len) { 515 | printf("failed to write config 2nd part: wrote 0x%08x expected 0x%08x\n", ret, len); 516 | ret = -1; 517 | goto cleanup; 518 | } 519 | 520 | // write 3rd part: patch: load taihen and henkaku 521 | const char *patch2 = "\n- load\tur0:tai/taihen.skprx\n- load\tur0:tai/henkaku.skprx\n"; 522 | len = strlen(patch2); 523 | if ((ret = ksceIoWrite(fd, patch2, len)) != len) { 524 | printf("failed to write config 3rd part: wrote 0x%08x expected 0x%08x\n", ret, len); 525 | ret = -1; 526 | goto cleanup; 527 | } 528 | 529 | // write 4th part: rest of config 530 | len = strlen(pos); 531 | if ((ret = ksceIoWrite(fd, pos, len)) != len) { 532 | printf("failed to write config 4th part: wrote 0x%08x expected 0x%08x\n", ret, len); 533 | ret = -1; 534 | goto cleanup; 535 | } 536 | 537 | ret = 0; 538 | 539 | cleanup: 540 | if (fd > 0) 541 | ksceIoClose(fd); 542 | 543 | if (uid > 0) 544 | ksceKernelUnloadModule(uid, 0, NULL); 545 | 546 | return ret; 547 | } 548 | 549 | int k_ensoWriteConfig() { 550 | int ret = 0; 551 | int state = 0; 552 | 553 | ENTER_SYSCALL(state); 554 | ret = run_on_thread(write_config); 555 | EXIT_SYSCALL(state); 556 | 557 | return ret; 558 | } 559 | 560 | int write_blocks(void) { 561 | int ret = 0; 562 | int fd = 0; 563 | int read_fd = 0; 564 | int fat_fd = 0; 565 | 566 | printf("writing blocks 2-..\n"); 567 | 568 | ret = fat_fd = ksceIoOpen("ux0:app/MLCL00003/oldfw/fat.bin", SCE_O_RDONLY, 0); 569 | if (ret < 0) { 570 | printf("failed to open fat.bin for read: 0x%08x\n", ret); 571 | ret = -1; 572 | goto cleanup; 573 | } 574 | 575 | ret = fd = ksceIoOpen(device, SCE_O_WRONLY, 0777); 576 | if (ret < 0) { 577 | printf("failed to open device for write: 0x%08x\n", ret); 578 | ret = -1; 579 | goto cleanup; 580 | } 581 | 582 | ret = read_fd = ksceIoOpen(device, SCE_O_RDONLY, 0); 583 | if (ret < 0) { 584 | printf("failed to open device for read: 0x%08x\n", ret); 585 | ret = -1; 586 | goto cleanup; 587 | } 588 | 589 | if ((ret = ksceIoLseek(fd, OFF_FAKE_OS0, SCE_SEEK_SET)) != OFF_FAKE_OS0) { 590 | printf("failed to seek the device: 0x%08x\n", ret); 591 | ret = -1; 592 | goto cleanup; 593 | } 594 | 595 | if ((ret = ksceIoLseek(fat_fd, OFF_FAKE_OS0, SCE_SEEK_SET)) != OFF_FAKE_OS0) { 596 | printf("failed to seek fat.bin: 0x%08x\n", ret); 597 | ret = -1; 598 | goto cleanup; 599 | } 600 | 601 | for (int i = 0; i < FAT_BIN_USEFUL_SIZE / BLOCK_SIZE; ++i) { 602 | static char buffer[BLOCK_SIZE]; 603 | if ((ret = ksceIoRead(fat_fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 604 | printf("failed to read fat.bin at block %d: 0x%08x\n", i + 2, ret); 605 | ret = -1; 606 | goto cleanup; 607 | } 608 | if ((ret = ksceIoWrite(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 609 | printf("failed to write fat.bin to device at block %d: 0x%08x\n", i + 2, ret); 610 | ret = -1; 611 | goto cleanup; 612 | } 613 | // now read it back and confirm we wrote correctly 614 | static char read_buffer[BLOCK_SIZE]; 615 | int off = BLOCK_SIZE * (i + 2); 616 | if ((ret = ksceIoLseek(read_fd, off, SCE_SEEK_SET)) != off) { 617 | printf("failed to seek read_fd: 0x%08x\n", ret); 618 | ret = -1; 619 | goto cleanup; 620 | } 621 | if ((ret = ksceIoRead(read_fd, read_buffer, sizeof(read_buffer))) != sizeof(read_buffer)) { 622 | printf("failed to read into read_buffer: 0x%08x\n", ret); 623 | ret = -1; 624 | goto cleanup; 625 | } 626 | if (memcmp(read_buffer, buffer, BLOCK_SIZE) != 0) { 627 | printf("error: write failed\n"); 628 | ret = -1; 629 | goto cleanup; 630 | } 631 | } 632 | 633 | printf("success!\n"); 634 | ret = 0; 635 | 636 | cleanup: 637 | if (fat_fd > 0) 638 | ksceIoClose(fat_fd); 639 | if (read_fd > 0) 640 | ksceIoClose(read_fd); 641 | if (fd > 0) 642 | ksceIoClose(fd); 643 | 644 | ksceIoSync(device, 0); // sync write 645 | 646 | return ret; 647 | } 648 | 649 | int k_ensoWriteBlocks(void) { 650 | int ret = 0; 651 | int state = 0; 652 | 653 | ENTER_SYSCALL(state); 654 | ret = run_on_thread(write_blocks); 655 | EXIT_SYSCALL(state); 656 | 657 | return ret; 658 | } 659 | 660 | int write_mbr(void) { 661 | int ret = 0; 662 | int fd = 0; 663 | int read_fd = 0; 664 | 665 | ret = read_fd = ksceIoOpen(device, SCE_O_RDONLY, 0); 666 | if (ret < 0) { 667 | printf("failed to open device for read: 0x%08x\n", ret); 668 | ret = -1; 669 | goto cleanup; 670 | } 671 | 672 | ret = fd = ksceIoOpen(device, SCE_O_WRONLY, 0777); 673 | if (ret < 0) { 674 | printf("failed to open device for write: 0x%08x\n", ret); 675 | ret = -1; 676 | goto cleanup; 677 | } 678 | 679 | static master_block_t master; 680 | if ((ret = ksceIoRead(read_fd, &master, sizeof(master))) != sizeof(master)) { 681 | printf("failed to read master block: 0x%08x\n", ret); 682 | ret = -1; 683 | goto cleanup; 684 | } 685 | 686 | // write a copy to block 1 687 | if ((ret = ksceIoLseek(fd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { 688 | printf("failed to seek the device: 0x%08x\n", ret); 689 | ret = -1; 690 | goto cleanup; 691 | } 692 | 693 | if ((ret = ksceIoWrite(fd, &master, sizeof(master))) != sizeof(master)) { 694 | printf("failed to write a copy of MBR: 0x%08x\n", ret); 695 | ret = -1; 696 | goto cleanup; 697 | } 698 | 699 | // check it's actually written by reading back and comparing 700 | static uint8_t buffer[BLOCK_SIZE]; 701 | if ((ret = ksceIoLseek(read_fd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { 702 | printf("failed to seek the device: 0x%08x\n", ret); 703 | ret = -1; 704 | goto cleanup; 705 | } 706 | 707 | if ((ret = ksceIoRead(read_fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 708 | printf("failed to read real mbr: 0x%08x\n", ret); 709 | ret = -1; 710 | goto cleanup; 711 | } 712 | 713 | if (memcmp(buffer, &master, BLOCK_SIZE) != 0) { 714 | printf("error: blocks do not match where they should\n"); 715 | ret = -1; 716 | goto cleanup; 717 | } 718 | 719 | int active_os0 = find_active_os0(&master); 720 | if (active_os0 == -1) { 721 | printf("failed to find active os0\n"); 722 | ret = -1; 723 | goto cleanup; 724 | } 725 | master.partitions[active_os0].off = 2; 726 | 727 | if ((ret = ksceIoLseek(fd, OFF_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_PARTITION_TABLE) { 728 | printf("failed to seek the device: 0x%08x\n", ret); 729 | ret = -1; 730 | goto cleanup; 731 | } 732 | 733 | if ((ret = ksceIoWrite(fd, &master, sizeof(master))) != sizeof(master)) { 734 | printf("error: failed to write modified MBR\n"); 735 | ret = -1; 736 | goto cleanup; 737 | } 738 | 739 | ret = 0; 740 | printf("success!\n"); 741 | 742 | cleanup: 743 | if (read_fd > 0) 744 | ksceIoClose(read_fd); 745 | if (fd > 0) 746 | ksceIoClose(fd); 747 | 748 | ksceIoSync(device, 0); // sync write 749 | 750 | return ret; 751 | } 752 | 753 | int k_ensoWriteMBR(void) { 754 | int ret = 0; 755 | int state = 0; 756 | 757 | ENTER_SYSCALL(state); 758 | ret = run_on_thread(write_mbr); 759 | EXIT_SYSCALL(state); 760 | 761 | return ret; 762 | } 763 | 764 | int check_real_mbr() { 765 | int ret = 0; 766 | int fd = 0; 767 | 768 | printf("check_real_mbr\n"); 769 | 770 | static master_block_t master; 771 | ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); 772 | if (fd < 0) { 773 | printf("failed to open the device: 0x%08x\n", ret); 774 | ret = -1; 775 | goto cleanup; 776 | } 777 | 778 | if ((ret = ksceIoRead(fd, &master, sizeof(master))) != sizeof(master)) { 779 | printf("failed to read real master block: 0x%08x\n", ret); 780 | ret = -1; 781 | goto cleanup; 782 | } 783 | 784 | ret = 0; 785 | if (!is_mbr(&master)) { 786 | printf("error: real master block is not MBR\n"); 787 | printf("this really shouldn't happen...\n"); 788 | ret = -1; 789 | } 790 | 791 | cleanup: 792 | if (fd > 0) 793 | ksceIoClose(fd); 794 | 795 | return ret; 796 | } 797 | 798 | int k_ensoCheckRealMBR(void) { 799 | int ret = 0; 800 | int state = 0; 801 | 802 | ENTER_SYSCALL(state); 803 | ret = run_on_thread(check_real_mbr); 804 | EXIT_SYSCALL(state); 805 | 806 | return ret; 807 | } 808 | 809 | int uninstall_mbr() { 810 | int ret = 0; 811 | int rfd = 0; 812 | int wfd = 0; 813 | 814 | printf("uninstall_mbr\n"); 815 | 816 | ret = rfd = ksceIoOpen(device, SCE_O_RDONLY, 0); 817 | if (ret < 0) { 818 | printf("failed to open the device for read: 0x%08x\n", ret); 819 | ret = -1; 820 | goto cleanup; 821 | } 822 | 823 | static master_block_t master; 824 | if ((ret = ksceIoRead(rfd, &master, sizeof(master))) != sizeof(master)) { 825 | printf("failed to read real master block: 0x%08x\n", ret); 826 | ret = -1; 827 | goto cleanup; 828 | } 829 | 830 | ksceIoClose(rfd); 831 | rfd = 0; 832 | 833 | if (!is_mbr(&master)) { 834 | printf("error: real master block is not MBR\n"); 835 | printf("this really shouldn't happen...\n"); 836 | ret = -1; 837 | goto cleanup; 838 | } 839 | 840 | ret = wfd = ksceIoOpen(device, SCE_O_WRONLY, 0777); 841 | if (ret < 0) { 842 | printf("failed to open the device for write: 0x%08x\n", ret); 843 | ret = -1; 844 | goto cleanup; 845 | } 846 | 847 | if ((ret = ksceIoWrite(wfd, &master, sizeof(master))) != sizeof(master)) { 848 | printf("failed to write real master block: 0x%08x\n", ret); 849 | ret = -1; 850 | goto cleanup; 851 | } 852 | 853 | ret = 0; 854 | 855 | cleanup: 856 | if (rfd > 0) 857 | ksceIoClose(rfd); 858 | if (wfd > 0) 859 | ksceIoClose(wfd); 860 | 861 | ksceIoSync(device, 0); // sync write 862 | 863 | return ret; 864 | } 865 | 866 | int k_ensoUninstallMBR(void) { 867 | int ret = 0; 868 | int state = 0; 869 | 870 | ENTER_SYSCALL(state); 871 | ret = run_on_thread(uninstall_mbr); 872 | EXIT_SYSCALL(state); 873 | 874 | return ret; 875 | } 876 | 877 | int clean_up_blocks() { 878 | int ret = 0; 879 | int wfd = 0; 880 | 881 | ret = wfd = ksceIoOpen(device, SCE_O_WRONLY, 0777); 882 | if (ret < 0) { 883 | printf("failed to open the device for write: 0x%08x\n", ret); 884 | ret = -1; 885 | goto cleanup; 886 | } 887 | 888 | if ((ret = ksceIoLseek(wfd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { 889 | printf("failed to seek the device: 0x%08x\n", ret); 890 | ret = -1; 891 | goto cleanup; 892 | } 893 | 894 | static uint8_t clean_block[BLOCK_SIZE]; 895 | memset(clean_block, 0xAA, sizeof(clean_block)); 896 | 897 | // wipe it out starting from block 1 898 | for (int i = 1; i < FAT_BIN_SIZE / BLOCK_SIZE; ++i) { 899 | if ((ret = ksceIoWrite(wfd, clean_block, sizeof(clean_block))) != sizeof(clean_block)) { 900 | printf("failed to clean block %d: 0x%08x\n", i, ret); 901 | ret = -1; 902 | goto cleanup; 903 | } 904 | } 905 | 906 | ret = 0; 907 | 908 | cleanup: 909 | if (wfd > 0) 910 | ksceIoClose(wfd); 911 | 912 | ksceIoSync(device, 0); // sync write 913 | 914 | return ret; 915 | } 916 | 917 | int k_ensoCleanUpBlocks(void) { 918 | int ret = 0; 919 | int state = 0; 920 | 921 | ENTER_SYSCALL(state); 922 | ret = run_on_thread(clean_up_blocks); 923 | EXIT_SYSCALL(state); 924 | 925 | return ret; 926 | } 927 | 928 | int module_start(int args, void *argv) { 929 | (void)args; 930 | (void)argv; 931 | printf("enso kernel module started\n"); 932 | 933 | return SCE_KERNEL_START_SUCCESS; 934 | } 935 | void _start() __attribute__ ((weak, alias ("module_start"))); 936 | 937 | int module_stop() { 938 | printf("enso kernel module stopped\n"); 939 | 940 | return SCE_KERNEL_STOP_SUCCESS; 941 | } 942 | -------------------------------------------------------------------------------- /installer/src/kernel_365.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "enso.h" 15 | 16 | #define printf(str, x...) do { printf_file("%s:%d: " str, __PRETTY_FUNCTION__, __LINE__, ## x); } while (0) 17 | #define ARRAYSIZE(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) 18 | 19 | int ksceSblAimgrIsDolce(void); 20 | uint32_t crc32(uint32_t crc, const void *buf, size_t size); 21 | 22 | enum { 23 | BLOCK_SIZE = 0x200, 24 | OFF_PARTITION_TABLE = 0, 25 | OFF_REAL_PARTITION_TABLE = 1 * BLOCK_SIZE, 26 | OFF_FAKE_OS0 = 2 * BLOCK_SIZE, 27 | FAT_BIN_SIZE = 0x6000, // NOTE: first 0x400 bytes are not written 28 | FAT_BIN_USEFUL_SIZE = 0x6000 - 0x400, 29 | 30 | OS0_SIZE = 0x3820 * BLOCK_SIZE, 31 | OS0_CRC32 = 0x69b0c99d, 32 | }; 33 | 34 | typedef struct { 35 | uint32_t off; 36 | uint32_t sz; 37 | uint8_t code; 38 | uint8_t type; 39 | uint8_t active; 40 | uint32_t flags; 41 | uint16_t unk; 42 | } __attribute__((packed)) partition_t; 43 | 44 | typedef struct { 45 | char magic[0x20]; 46 | uint32_t version; 47 | uint32_t device_size; 48 | char unk1[0x28]; 49 | partition_t partitions[0x10]; 50 | char unk2[0x5e]; 51 | char unk3[0x10 * 4]; 52 | uint16_t sig; 53 | } __attribute__((packed)) master_block_t; 54 | 55 | int printf_file(const char *format, ...) { 56 | char line[512] = {0}; 57 | va_list arg; 58 | 59 | va_start(arg, format); 60 | vsprintf(line, format, arg); 61 | va_end(arg); 62 | 63 | int fd = ksceIoOpen("ux0:data/enso.log", SCE_O_WRONLY | SCE_O_APPEND | SCE_O_CREAT, 0777); 64 | if (fd < 0) 65 | return 0; 66 | ksceIoWrite(fd, line, strlen(line)); 67 | ksceIoClose(fd); 68 | 69 | return 0; 70 | } 71 | 72 | const char *part_code(int code) { 73 | static char *codes[] = { 74 | "empty", 75 | "first_partition", 76 | "slb2", 77 | "os0", 78 | "vs0", 79 | "vd0", 80 | "tm0", 81 | "ur0", 82 | "ux0", 83 | "gro0", 84 | "grw0", 85 | "ud0", 86 | "sa0", 87 | "some_data", 88 | "pd0", 89 | "invalid" 90 | }; 91 | return codes[code]; 92 | } 93 | 94 | const char *part_type(int type) { 95 | if (type == 6) 96 | return "FAT16"; 97 | else if (type == 7) 98 | return "exFAT"; 99 | else if (type == 0xDA) 100 | return "raw"; 101 | return "unknown"; 102 | } 103 | 104 | const char *device = "sdstor0:int-lp-act-entire"; 105 | 106 | int run_on_thread(void *func) { 107 | int ret = 0; 108 | int res = 0; 109 | int uid = 0; 110 | 111 | ret = uid = ksceKernelCreateThread("run_on_thread", func, 64, 0x1000, 0, 0, 0); 112 | 113 | if (ret < 0) { 114 | printf("failed to create a thread: 0x%08x\n", ret); 115 | ret = -1; 116 | goto cleanup; 117 | } 118 | if ((ret = ksceKernelStartThread(uid, 0, NULL)) < 0) { 119 | printf("failed to start a thread: 0x%08x\n", ret); 120 | ret = -1; 121 | goto cleanup; 122 | } 123 | if ((ret = ksceKernelWaitThreadEnd(uid, &res, NULL)) < 0) { 124 | printf("failed to wait a thread: 0x%08x\n", ret); 125 | ret = -1; 126 | goto cleanup; 127 | } 128 | 129 | ret = res; 130 | 131 | cleanup: 132 | if (uid > 0) 133 | ksceKernelDeleteThread(uid); 134 | 135 | return ret; 136 | } 137 | 138 | int find_active_os0(master_block_t *master) { 139 | int active_os0 = -1; 140 | 141 | for (size_t i = 0; i < ARRAYSIZE(master->partitions); ++i) { 142 | partition_t *p = &master->partitions[i]; 143 | printf("Partition %d, code=%s, type=%s, active=%d, off=0x%08x, sz=0x%08x, flags=0x%08x, unk=0x%08x\n", 144 | i, part_code(p->code), part_type(p->type), p->active, p->off, p->sz, p->flags, p->unk); 145 | if (p->active == 1 && p->code == 3) 146 | active_os0 = i; 147 | } 148 | 149 | return active_os0; 150 | } 151 | 152 | int check_os0(void) { 153 | int ret = 0; 154 | int fd = 0; 155 | 156 | printf("checking os0\n"); 157 | 158 | ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); 159 | if (ret < 0) { 160 | printf("failed to open the device: 0x%08x\n", ret); 161 | ret = -1; 162 | goto cleanup; 163 | } 164 | 165 | // read MBR and find active os0 166 | static master_block_t master; 167 | if ((ret = ksceIoRead(fd, &master, sizeof(master))) != sizeof(master)) { 168 | printf("failed to read master block: 0x%08x\n", ret); 169 | ret = -1; 170 | goto cleanup; 171 | } 172 | 173 | int active_os0 = find_active_os0(&master); 174 | if (active_os0 == -1) { 175 | printf("failed to find active os0 partition\n"); 176 | ret = -1; 177 | goto cleanup; 178 | } 179 | 180 | uint32_t off = master.partitions[active_os0].off * BLOCK_SIZE; 181 | if ((ret = ksceIoLseek(fd, off, SCE_SEEK_SET)) != (int)off) { 182 | printf("failed to seek to os0: 0x%08x\n", ret); 183 | ret = -1; 184 | goto cleanup; 185 | } 186 | 187 | uint32_t crc = 0; 188 | for (int i = 0; i < OS0_SIZE / BLOCK_SIZE; ++i) { 189 | static char buffer[BLOCK_SIZE]; 190 | if ((ret = ksceIoRead(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 191 | printf("failed to read a block: 0x%08x\n", ret); 192 | ret = -1; 193 | goto cleanup; 194 | } 195 | crc = crc32(crc, buffer, sizeof(buffer)); 196 | } 197 | 198 | printf("got os0 crc32: 0x%08x\n", crc); 199 | if (crc != OS0_CRC32) { 200 | printf("error: crc does not match!\n"); 201 | ret = -1; 202 | } else { 203 | ret = 0; 204 | } 205 | 206 | cleanup: 207 | if (fd > 0) 208 | ksceIoClose(fd); 209 | 210 | return ret; 211 | } 212 | 213 | int k_ensoCheckOs0(void) { 214 | int ret = 0; 215 | int state = 0; 216 | 217 | ENTER_SYSCALL(state); 218 | ret = run_on_thread(check_os0); 219 | EXIT_SYSCALL(state); 220 | 221 | return ret; 222 | } 223 | 224 | int is_mbr(void *data) { 225 | master_block_t *master = data; 226 | if (memcmp(master->magic, "Sony Computer Entertainment Inc.", 0x20) != 0) 227 | return 0; 228 | if (master->sig != 0xAA55) 229 | return 0; 230 | return 1; 231 | } 232 | 233 | int is_empty(void *data) { 234 | uint8_t *buf = data; 235 | for (int i = 0; i < BLOCK_SIZE; ++i) 236 | if (buf[i] != 0xAA) 237 | return 0; 238 | return 1; 239 | } 240 | 241 | int check_mbr() { 242 | int ret = 0; 243 | int fd = 0; 244 | 245 | printf("check_mbr\n"); 246 | 247 | static master_block_t master; 248 | ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); 249 | if (fd < 0) { 250 | printf("failed to open the device: 0x%08x\n", ret); 251 | ret = -1; 252 | goto cleanup; 253 | } 254 | if ((ret = ksceIoRead(fd, &master, sizeof(master))) != sizeof(master)) { 255 | printf("failed to read master block: 0x%08x\n", ret); 256 | ret = -1; 257 | goto cleanup; 258 | } 259 | 260 | ret = 0; 261 | if (!is_mbr(&master)) { 262 | printf("error: master block is not MBR\n"); 263 | ret = -1; 264 | } 265 | 266 | cleanup: 267 | if (fd > 0) 268 | ksceIoClose(fd); 269 | 270 | return ret; 271 | } 272 | 273 | int k_ensoCheckMBR(void) { 274 | int ret = 0; 275 | int state = 0; 276 | 277 | ENTER_SYSCALL(state); 278 | ret = run_on_thread(check_mbr); 279 | EXIT_SYSCALL(state); 280 | 281 | return ret; 282 | } 283 | 284 | int dump_blocks(void) { 285 | int wfd = 0; 286 | int fd = 0; 287 | int ret = 0; 288 | 289 | printf("dumping blocks to %s\n", BLOCKS_OUTPUT); 290 | 291 | ret = wfd = ksceIoOpen(BLOCKS_OUTPUT, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777); 292 | if (ret < 0) { 293 | printf("failed to open %s for write: 0x%08x\n", BLOCKS_OUTPUT, ret); 294 | ret = -1; 295 | goto cleanup; 296 | } 297 | 298 | ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); 299 | if (ret < 0) { 300 | printf("failed to open the device: 0x%08x\n", ret); 301 | ret = -1; 302 | goto cleanup; 303 | } 304 | 305 | for (int i = 0; i < FAT_BIN_SIZE / BLOCK_SIZE; ++i) { 306 | static char buffer[BLOCK_SIZE]; 307 | if ((ret = ksceIoRead(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 308 | printf("failed to read block %d: 0x%08x\n", i, ret); 309 | ret = -1; 310 | goto cleanup; 311 | } 312 | if ((ret = ksceIoWrite(wfd, buffer, sizeof(buffer))) != sizeof(buffer)) { 313 | printf("failed to write block %d: 0x%08x\n", i, ret); 314 | ret = -1; 315 | goto cleanup; 316 | } 317 | } 318 | 319 | ret = 0; 320 | printf("copied successfully\n"); 321 | 322 | cleanup: 323 | if (wfd > 0) 324 | ksceIoClose(wfd); 325 | if (fd > 0) 326 | ksceIoClose(fd); 327 | 328 | return ret; 329 | } 330 | 331 | int check_blocks(void) { 332 | int ret = 0; 333 | int fd = 0; 334 | 335 | static master_block_t master; 336 | 337 | printf("checking blocks\n"); 338 | 339 | ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); 340 | if (ret < 0) { 341 | printf("failed to open the device: 0x%08x\n", ret); 342 | ret = -1; 343 | goto cleanup; 344 | } 345 | 346 | // check that block 1 is MBR 347 | if ((ret = ksceIoLseek(fd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { 348 | printf("failed to seek the device to real mbr: 0x%08x\n", ret); 349 | ret = -1; 350 | goto cleanup; 351 | } 352 | if ((ret = ksceIoRead(fd, &master, sizeof(master))) != sizeof(master)) { 353 | printf("failed to read the real mbr block: 0x%08x\n", ret); 354 | ret = -1; 355 | goto cleanup; 356 | } 357 | if (is_mbr(&master)) { 358 | // if it is, check that the rest of the blocks match a known crc32 value 359 | if ((ret = ksceIoLseek(fd, OFF_FAKE_OS0, SCE_SEEK_SET)) != OFF_FAKE_OS0) { 360 | printf("failed to seek the device to fake os0: 0x%08x\n", ret); 361 | ret = -1; 362 | goto cleanup; 363 | } 364 | 365 | uint32_t crc = 0; 366 | for (int i = 0; i < FAT_BIN_USEFUL_SIZE / BLOCK_SIZE; ++i) { 367 | static char buffer[BLOCK_SIZE]; 368 | if ((ret = ksceIoRead(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 369 | printf("failed to read a block: 0x%08x\n", ret); 370 | ret = -1; 371 | goto cleanup; 372 | } 373 | crc = crc32(crc, buffer, sizeof(buffer)); 374 | } 375 | printf("crc32[2; 48] = 0x%08x\n", crc); 376 | uint32_t known_crc[] = { 0xa6b37650, 0x723111d1 }; 377 | int found = 0; 378 | for (size_t i = 0; i < ARRAYSIZE(known_crc); ++i) { 379 | if (crc == known_crc[i]) { 380 | found = 1; 381 | break; 382 | } 383 | } 384 | if (!found) { 385 | printf("warning: got unknown checksum\n"); 386 | dump_blocks(); 387 | ret = E_MBR_BUT_UNKNOWN; 388 | } else { 389 | ret = E_PREVIOUS_INSTALL; 390 | } 391 | } else { 392 | // otherwise just check that the data's empty, including real mbr 393 | if ((ret = ksceIoLseek(fd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { 394 | printf("failed to seek the device to real mbr block (2): 0x%08x\n", ret); 395 | ret = -1; 396 | goto cleanup; 397 | } 398 | 399 | // -1 because block 0 in fat.bin is fake MBR 400 | for (int i = 0; i < FAT_BIN_SIZE / 0x200 - 1; ++i) { 401 | static char buffer[BLOCK_SIZE]; 402 | if ((ret = ksceIoRead(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 403 | printf("failed to read a block (2): 0x%08x\n", ret); 404 | ret = -1; 405 | goto cleanup; 406 | } 407 | if (!is_empty(&buffer)) { 408 | printf("unknown data was found in block %d\n", i + 1); 409 | dump_blocks(); 410 | ret = E_UNKNOWN_DATA; 411 | goto cleanup; 412 | } 413 | } 414 | 415 | // all blocks checked, all good 416 | ret = 0; 417 | } 418 | 419 | cleanup: 420 | if (fd > 0) 421 | ksceIoClose(fd); 422 | 423 | return ret; 424 | } 425 | 426 | int k_ensoCheckBlocks() { 427 | int ret = 0; 428 | int state = 0; 429 | 430 | ENTER_SYSCALL(state); 431 | ret = run_on_thread(check_blocks); 432 | EXIT_SYSCALL(state); 433 | 434 | return ret; 435 | } 436 | 437 | int write_config() { 438 | int pstv = 0; 439 | int uid = 0; 440 | int ret = 0; 441 | int fd = 0; 442 | SceKernelModuleInfo info = {0}; 443 | char *pos = NULL; 444 | int len = 0; 445 | 446 | printf("write_config\n"); 447 | 448 | ksceIoMkdir("ur0:tai", 0777); // make directory if it does not exist 449 | 450 | pstv = ksceSblAimgrIsDolce(); 451 | printf("writing config for %s\n", pstv ? "PSTV" : "PS Vita"); 452 | 453 | ret = uid = ksceKernelLoadModule(pstv ? "os0:psp2config_dolce.skprx" : "os0:psp2config_vita.skprx", 0, NULL); 454 | if (ret < 0) { 455 | printf("failed to load psp2config module: 0x%08x\n", ret); 456 | ret = -1; 457 | goto cleanup; 458 | } 459 | 460 | info.size = sizeof(info); 461 | ret = ksceKernelGetModuleInfo(KERNEL_PID, uid, &info); 462 | if (ret < 0) { 463 | printf("failed to get module info: 0x%08x\n", ret); 464 | ret = -1; 465 | goto cleanup; 466 | } 467 | 468 | static char config[0x1000]; 469 | 470 | if (info.segments[0].memsz >= sizeof(config)) { 471 | printf("config does not fit, size=0x%08x\n", info.segments[0].memsz); 472 | ret = -1; 473 | goto cleanup; 474 | } 475 | 476 | memcpy(config, (char*)info.segments[0].vaddr + 0xD4, info.segments[0].memsz - 0xD4); 477 | 478 | if (memcmp(config, "#\n# PSP2", 8) != 0) { 479 | printf("config is corrupt\n"); 480 | ret = -1; 481 | goto cleanup; 482 | } 483 | 484 | ret = fd = ksceIoOpen("ur0:tai/boot_config.txt", SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777); 485 | if (ret < 0) { 486 | printf("failed to open ur0:tai/boot_config.txt for write: 0x%08x\n", ret); 487 | ret = -1; 488 | goto cleanup; 489 | } 490 | 491 | pos = strstr(config, "\n- appspawn vs0:vsh/shell/shell.self"); 492 | if (!pos) { 493 | printf("failed to patch config: cannot locate appspawn line\n"); 494 | ret = -1; 495 | goto cleanup; 496 | } 497 | 498 | // write first part: warning message 499 | const char *patch1 = 500 | "# WARNING: DO NOT EDIT THIS FILE. IF YOU JUST WANT TO RUN A PLUGIN ON BOOT,\n" 501 | "# EDIT ux0:tai/config.txt INSTEAD. IF YOU BREAK THIS FILE, YOUR VITA WILL NO\n" 502 | "# LONGER BOOT. IF THAT HAPPENS, YOU CAN ENTER SAFE MODE AND RESET ALL SETTINGS\n" 503 | "# TO RESET THIS FILE. THIS FILE IS UNIQUE TO EACH VITA MODEL. DO NOT BLINDLY\n" 504 | "# USE SOMEONE ELSE'S CONFIG.\n"; 505 | len = strlen(patch1); 506 | if ((ret = ksceIoWrite(fd, patch1, len)) != len) { 507 | printf("failed to write config 1st part: wrote 0x%08x expected 0x%08x\n", ret, len); 508 | ret = -1; 509 | goto cleanup; 510 | } 511 | 512 | // write second part: everything before appspawn 513 | len = pos - config; 514 | if ((ret = ksceIoWrite(fd, config, len)) != len) { 515 | printf("failed to write config 2nd part: wrote 0x%08x expected 0x%08x\n", ret, len); 516 | ret = -1; 517 | goto cleanup; 518 | } 519 | 520 | // write 3rd part: patch: load taihen and henkaku 521 | const char *patch2 = "\n- load\tur0:tai/taihen.skprx\n- load\tur0:tai/henkaku.skprx\n"; 522 | len = strlen(patch2); 523 | if ((ret = ksceIoWrite(fd, patch2, len)) != len) { 524 | printf("failed to write config 3rd part: wrote 0x%08x expected 0x%08x\n", ret, len); 525 | ret = -1; 526 | goto cleanup; 527 | } 528 | 529 | // write 4th part: rest of config 530 | len = strlen(pos); 531 | if ((ret = ksceIoWrite(fd, pos, len)) != len) { 532 | printf("failed to write config 4th part: wrote 0x%08x expected 0x%08x\n", ret, len); 533 | ret = -1; 534 | goto cleanup; 535 | } 536 | 537 | ret = 0; 538 | 539 | cleanup: 540 | if (fd > 0) 541 | ksceIoClose(fd); 542 | 543 | if (uid > 0) 544 | ksceKernelUnloadModule(uid, 0, NULL); 545 | 546 | return ret; 547 | } 548 | 549 | int k_ensoWriteConfig() { 550 | int ret = 0; 551 | int state = 0; 552 | 553 | ENTER_SYSCALL(state); 554 | ret = run_on_thread(write_config); 555 | EXIT_SYSCALL(state); 556 | 557 | return ret; 558 | } 559 | 560 | int write_blocks(void) { 561 | int ret = 0; 562 | int fd = 0; 563 | int read_fd = 0; 564 | int fat_fd = 0; 565 | 566 | printf("writing blocks 2-..\n"); 567 | 568 | ret = fat_fd = ksceIoOpen("ux0:app/MLCL00003/gudfw/fat.bin", SCE_O_RDONLY, 0); 569 | if (ret < 0) { 570 | printf("failed to open fat.bin for read: 0x%08x\n", ret); 571 | ret = -1; 572 | goto cleanup; 573 | } 574 | 575 | ret = fd = ksceIoOpen(device, SCE_O_WRONLY, 0777); 576 | if (ret < 0) { 577 | printf("failed to open device for write: 0x%08x\n", ret); 578 | ret = -1; 579 | goto cleanup; 580 | } 581 | 582 | ret = read_fd = ksceIoOpen(device, SCE_O_RDONLY, 0); 583 | if (ret < 0) { 584 | printf("failed to open device for read: 0x%08x\n", ret); 585 | ret = -1; 586 | goto cleanup; 587 | } 588 | 589 | if ((ret = ksceIoLseek(fd, OFF_FAKE_OS0, SCE_SEEK_SET)) != OFF_FAKE_OS0) { 590 | printf("failed to seek the device: 0x%08x\n", ret); 591 | ret = -1; 592 | goto cleanup; 593 | } 594 | 595 | if ((ret = ksceIoLseek(fat_fd, OFF_FAKE_OS0, SCE_SEEK_SET)) != OFF_FAKE_OS0) { 596 | printf("failed to seek fat.bin: 0x%08x\n", ret); 597 | ret = -1; 598 | goto cleanup; 599 | } 600 | 601 | for (int i = 0; i < FAT_BIN_USEFUL_SIZE / BLOCK_SIZE; ++i) { 602 | static char buffer[BLOCK_SIZE]; 603 | if ((ret = ksceIoRead(fat_fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 604 | printf("failed to read fat.bin at block %d: 0x%08x\n", i + 2, ret); 605 | ret = -1; 606 | goto cleanup; 607 | } 608 | if ((ret = ksceIoWrite(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 609 | printf("failed to write fat.bin to device at block %d: 0x%08x\n", i + 2, ret); 610 | ret = -1; 611 | goto cleanup; 612 | } 613 | // now read it back and confirm we wrote correctly 614 | static char read_buffer[BLOCK_SIZE]; 615 | int off = BLOCK_SIZE * (i + 2); 616 | if ((ret = ksceIoLseek(read_fd, off, SCE_SEEK_SET)) != off) { 617 | printf("failed to seek read_fd: 0x%08x\n", ret); 618 | ret = -1; 619 | goto cleanup; 620 | } 621 | if ((ret = ksceIoRead(read_fd, read_buffer, sizeof(read_buffer))) != sizeof(read_buffer)) { 622 | printf("failed to read into read_buffer: 0x%08x\n", ret); 623 | ret = -1; 624 | goto cleanup; 625 | } 626 | if (memcmp(read_buffer, buffer, BLOCK_SIZE) != 0) { 627 | printf("error: write failed\n"); 628 | ret = -1; 629 | goto cleanup; 630 | } 631 | } 632 | 633 | printf("success!\n"); 634 | ret = 0; 635 | 636 | cleanup: 637 | if (fat_fd > 0) 638 | ksceIoClose(fat_fd); 639 | if (read_fd > 0) 640 | ksceIoClose(read_fd); 641 | if (fd > 0) 642 | ksceIoClose(fd); 643 | 644 | ksceIoSync(device, 0); // sync write 645 | 646 | return ret; 647 | } 648 | 649 | int k_ensoWriteBlocks(void) { 650 | int ret = 0; 651 | int state = 0; 652 | 653 | ENTER_SYSCALL(state); 654 | ret = run_on_thread(write_blocks); 655 | EXIT_SYSCALL(state); 656 | 657 | return ret; 658 | } 659 | 660 | int write_mbr(void) { 661 | int ret = 0; 662 | int fd = 0; 663 | int read_fd = 0; 664 | 665 | ret = read_fd = ksceIoOpen(device, SCE_O_RDONLY, 0); 666 | if (ret < 0) { 667 | printf("failed to open device for read: 0x%08x\n", ret); 668 | ret = -1; 669 | goto cleanup; 670 | } 671 | 672 | ret = fd = ksceIoOpen(device, SCE_O_WRONLY, 0777); 673 | if (ret < 0) { 674 | printf("failed to open device for write: 0x%08x\n", ret); 675 | ret = -1; 676 | goto cleanup; 677 | } 678 | 679 | static master_block_t master; 680 | if ((ret = ksceIoRead(read_fd, &master, sizeof(master))) != sizeof(master)) { 681 | printf("failed to read master block: 0x%08x\n", ret); 682 | ret = -1; 683 | goto cleanup; 684 | } 685 | 686 | // write a copy to block 1 687 | if ((ret = ksceIoLseek(fd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { 688 | printf("failed to seek the device: 0x%08x\n", ret); 689 | ret = -1; 690 | goto cleanup; 691 | } 692 | 693 | if ((ret = ksceIoWrite(fd, &master, sizeof(master))) != sizeof(master)) { 694 | printf("failed to write a copy of MBR: 0x%08x\n", ret); 695 | ret = -1; 696 | goto cleanup; 697 | } 698 | 699 | // check it's actually written by reading back and comparing 700 | static uint8_t buffer[BLOCK_SIZE]; 701 | if ((ret = ksceIoLseek(read_fd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { 702 | printf("failed to seek the device: 0x%08x\n", ret); 703 | ret = -1; 704 | goto cleanup; 705 | } 706 | 707 | if ((ret = ksceIoRead(read_fd, buffer, sizeof(buffer))) != sizeof(buffer)) { 708 | printf("failed to read real mbr: 0x%08x\n", ret); 709 | ret = -1; 710 | goto cleanup; 711 | } 712 | 713 | if (memcmp(buffer, &master, BLOCK_SIZE) != 0) { 714 | printf("error: blocks do not match where they should\n"); 715 | ret = -1; 716 | goto cleanup; 717 | } 718 | 719 | int active_os0 = find_active_os0(&master); 720 | if (active_os0 == -1) { 721 | printf("failed to find active os0\n"); 722 | ret = -1; 723 | goto cleanup; 724 | } 725 | master.partitions[active_os0].off = 2; 726 | 727 | if ((ret = ksceIoLseek(fd, OFF_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_PARTITION_TABLE) { 728 | printf("failed to seek the device: 0x%08x\n", ret); 729 | ret = -1; 730 | goto cleanup; 731 | } 732 | 733 | if ((ret = ksceIoWrite(fd, &master, sizeof(master))) != sizeof(master)) { 734 | printf("error: failed to write modified MBR\n"); 735 | ret = -1; 736 | goto cleanup; 737 | } 738 | 739 | ret = 0; 740 | printf("success!\n"); 741 | 742 | cleanup: 743 | if (read_fd > 0) 744 | ksceIoClose(read_fd); 745 | if (fd > 0) 746 | ksceIoClose(fd); 747 | 748 | ksceIoSync(device, 0); // sync write 749 | 750 | return ret; 751 | } 752 | 753 | int k_ensoWriteMBR(void) { 754 | int ret = 0; 755 | int state = 0; 756 | 757 | ENTER_SYSCALL(state); 758 | ret = run_on_thread(write_mbr); 759 | EXIT_SYSCALL(state); 760 | 761 | return ret; 762 | } 763 | 764 | int check_real_mbr() { 765 | int ret = 0; 766 | int fd = 0; 767 | 768 | printf("check_real_mbr\n"); 769 | 770 | static master_block_t master; 771 | ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); 772 | if (fd < 0) { 773 | printf("failed to open the device: 0x%08x\n", ret); 774 | ret = -1; 775 | goto cleanup; 776 | } 777 | 778 | if ((ret = ksceIoRead(fd, &master, sizeof(master))) != sizeof(master)) { 779 | printf("failed to read real master block: 0x%08x\n", ret); 780 | ret = -1; 781 | goto cleanup; 782 | } 783 | 784 | ret = 0; 785 | if (!is_mbr(&master)) { 786 | printf("error: real master block is not MBR\n"); 787 | printf("this really shouldn't happen...\n"); 788 | ret = -1; 789 | } 790 | 791 | cleanup: 792 | if (fd > 0) 793 | ksceIoClose(fd); 794 | 795 | return ret; 796 | } 797 | 798 | int k_ensoCheckRealMBR(void) { 799 | int ret = 0; 800 | int state = 0; 801 | 802 | ENTER_SYSCALL(state); 803 | ret = run_on_thread(check_real_mbr); 804 | EXIT_SYSCALL(state); 805 | 806 | return ret; 807 | } 808 | 809 | int uninstall_mbr() { 810 | int ret = 0; 811 | int rfd = 0; 812 | int wfd = 0; 813 | 814 | printf("uninstall_mbr\n"); 815 | 816 | ret = rfd = ksceIoOpen(device, SCE_O_RDONLY, 0); 817 | if (ret < 0) { 818 | printf("failed to open the device for read: 0x%08x\n", ret); 819 | ret = -1; 820 | goto cleanup; 821 | } 822 | 823 | static master_block_t master; 824 | if ((ret = ksceIoRead(rfd, &master, sizeof(master))) != sizeof(master)) { 825 | printf("failed to read real master block: 0x%08x\n", ret); 826 | ret = -1; 827 | goto cleanup; 828 | } 829 | 830 | ksceIoClose(rfd); 831 | rfd = 0; 832 | 833 | if (!is_mbr(&master)) { 834 | printf("error: real master block is not MBR\n"); 835 | printf("this really shouldn't happen...\n"); 836 | ret = -1; 837 | goto cleanup; 838 | } 839 | 840 | ret = wfd = ksceIoOpen(device, SCE_O_WRONLY, 0777); 841 | if (ret < 0) { 842 | printf("failed to open the device for write: 0x%08x\n", ret); 843 | ret = -1; 844 | goto cleanup; 845 | } 846 | 847 | if ((ret = ksceIoWrite(wfd, &master, sizeof(master))) != sizeof(master)) { 848 | printf("failed to write real master block: 0x%08x\n", ret); 849 | ret = -1; 850 | goto cleanup; 851 | } 852 | 853 | ret = 0; 854 | 855 | cleanup: 856 | if (rfd > 0) 857 | ksceIoClose(rfd); 858 | if (wfd > 0) 859 | ksceIoClose(wfd); 860 | 861 | ksceIoSync(device, 0); // sync write 862 | 863 | return ret; 864 | } 865 | 866 | int k_ensoUninstallMBR(void) { 867 | int ret = 0; 868 | int state = 0; 869 | 870 | ENTER_SYSCALL(state); 871 | ret = run_on_thread(uninstall_mbr); 872 | EXIT_SYSCALL(state); 873 | 874 | return ret; 875 | } 876 | 877 | int clean_up_blocks() { 878 | int ret = 0; 879 | int wfd = 0; 880 | 881 | ret = wfd = ksceIoOpen(device, SCE_O_WRONLY, 0777); 882 | if (ret < 0) { 883 | printf("failed to open the device for write: 0x%08x\n", ret); 884 | ret = -1; 885 | goto cleanup; 886 | } 887 | 888 | if ((ret = ksceIoLseek(wfd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { 889 | printf("failed to seek the device: 0x%08x\n", ret); 890 | ret = -1; 891 | goto cleanup; 892 | } 893 | 894 | static uint8_t clean_block[BLOCK_SIZE]; 895 | memset(clean_block, 0xAA, sizeof(clean_block)); 896 | 897 | // wipe it out starting from block 1 898 | for (int i = 1; i < FAT_BIN_SIZE / BLOCK_SIZE; ++i) { 899 | if ((ret = ksceIoWrite(wfd, clean_block, sizeof(clean_block))) != sizeof(clean_block)) { 900 | printf("failed to clean block %d: 0x%08x\n", i, ret); 901 | ret = -1; 902 | goto cleanup; 903 | } 904 | } 905 | 906 | ret = 0; 907 | 908 | cleanup: 909 | if (wfd > 0) 910 | ksceIoClose(wfd); 911 | 912 | ksceIoSync(device, 0); // sync write 913 | 914 | return ret; 915 | } 916 | 917 | int k_ensoCleanUpBlocks(void) { 918 | int ret = 0; 919 | int state = 0; 920 | 921 | ENTER_SYSCALL(state); 922 | ret = run_on_thread(clean_up_blocks); 923 | EXIT_SYSCALL(state); 924 | 925 | return ret; 926 | } 927 | 928 | int module_start(int args, void *argv) { 929 | (void)args; 930 | (void)argv; 931 | printf("enso kernel module started\n"); 932 | 933 | return SCE_KERNEL_START_SUCCESS; 934 | } 935 | void _start() __attribute__ ((weak, alias ("module_start"))); 936 | 937 | int module_stop() { 938 | printf("enso kernel module stopped\n"); 939 | 940 | return SCE_KERNEL_STOP_SUCCESS; 941 | } 942 | --------------------------------------------------------------------------------