Repository: TheOfficialFloW/enso Branch: master Commit: f012c27cead1 Files: 32 Total size: 116.7 KB Directory structure: gitextract_l0jd6zc5/ ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── fat.tpl ├── first.c ├── first.x ├── gen.py ├── installer/ │ ├── .gitignore │ ├── CMakeLists.txt │ ├── LICENSE │ ├── personalize.sh │ ├── res/ │ │ └── template.xml │ └── src/ │ ├── crc32.c │ ├── debug_screen.c │ ├── debug_screen.h │ ├── debug_screen_font.c │ ├── enso.h │ ├── kernel.c │ ├── kernel2.c │ ├── kernel2.yml │ ├── kernel_exports.yml │ ├── main.c │ ├── sha256.c │ ├── sha256.h │ ├── user.c │ ├── user_exports.yml │ └── version.h.in ├── logo.h ├── nsbl.h ├── second.c └── second.x ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.bin *.o first second ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2017 molecule Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ CC=arm-vita-eabi-gcc CFLAGS=-Os -fno-builtin-printf -fPIC -fno-builtin-memset -Wall -Wextra -Wno-unused-variable -DFW_365 OBJCOPY=arm-vita-eabi-objcopy LDFLAGS=-nodefaultlibs -nostdlib fat.bin: first.bin second.bin ./gen.py fat.tpl first.bin second.bin fat.bin first.bin: first $(OBJCOPY) -O binary $^ $@ second.bin: second $(OBJCOPY) -O binary $^ $@ first: first.o $(CC) -o $@ $^ $(LDFLAGS) -T first.x second: second.o $(CC) -o $@ $^ $(LDFLAGS) -T second.x clean: -rm -f fat.bin second.bin first.bin *.o ================================================ FILE: README.md ================================================ You need [vitasdk](https://vitasdk.org/). 1. `make` the payload 2. Copy `fat.bin` to `installer/res` 3. CMake the installer `mkdir build && cd build && cmake .. && make` Firmware specific offsets are in first.c and nsbl.h. Logo is raw framebuffer data gzipped. If you make this too big (bigger than original logo size), you WILL perma-brick your Vita. The source is for advanced users only. Users should download the [prebuilt package](https://enso.henkaku.xyz/). 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. Again, even if you just change the logo, there's a good chance you will perma-brick your Vita. You have been warned. ================================================ FILE: first.c ================================================ /* first.c -- fixup environment and exec second payload * * Copyright (C) 2017 molecule * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ #include #include "nsbl.h" // ALL OFFSETS ARE SPECIFIC TO 3.60 #define SECOND_PAYLOAD_OFFSET (5) #define SECOND_PAYLOAD_SIZE (0x4000) void go(void) { printf("first\n"); // first payload reinits os0 device and reads second payload from emmc // this is because we only have 0x180 bytes for first payload memset((char*)0x511673A0, 0, 0x600); // clean after us // we need to patch call to read block 1 instead of block 0 as the master block // now that we store a copy of real partition table in block 1 *(uint16_t*)0x510202CE = 0x2101; // movs r1, #1 clean_dcache((void *)0x510202C0, 0x20); flush_icache(); // reinit os0_dev int (*fat_init_dev)() = (void*)0x5101FF21; char *os0_dev = (void*)0x51167784; int ret = fat_init_dev(os0_dev, 0x110000, 0x510010FD, 0x51028010); // os0_dev, flags, read_block, some_storage // TODO: what do these do? but we need them for some reason *(uint32_t*)(os0_dev + 0x2C) = 0; *(uint32_t*)(os0_dev + 0x78) = 0x1A000100; *(uint32_t*)(os0_dev + 0x84) = 0x1A001000; *(uint32_t*)(os0_dev + 0x90) = 0x0001002B; // restore corrupted boot args with our copy memcpy(boot_args, (*sysroot_ctx_ptr)->boot_args, sizeof(*boot_args)); // allocate buffer for code SceKernelAllocMemBlockKernelOpt opt; int blk; void *base; void (*f)(); memset(&opt, 0, sizeof(opt)); opt.size = sizeof(opt); opt.attr = 0xA0400000; blk = sceKernelAllocMemBlock("", 0x1020D006, SECOND_PAYLOAD_SIZE, NULL); f = NULL; if (blk >= 0) { if (sceKernelGetMemBlockBase(blk, &base) >= 0) { // read code buffer if (read_block_os0(0x51028010, SECOND_PAYLOAD_OFFSET, SECOND_PAYLOAD_SIZE/512, base) >= 0) { // TODO: perhaps add some simple integrity check here? if (sceKernelRemapBlock(blk, 0x1020D005) >= 0) { clean_dcache(base, SECOND_PAYLOAD_SIZE); flush_icache(); f = (void*)(base + 1); } } } } // fallback: if for some reason we weren't able to allocate/read the payload, then don't run it if (f != NULL) { f(); } // restore context and resume boot uint32_t *sp = *(uint32_t**)(0x51030100 + 0x220); // sp top for core 0 uint32_t *old_sp = sp - 0x11d; // r0: 0x51167784 os0_dev // r1: 0xfffffffe // r2: sp - 0x110 // r3: 0 __asm__ volatile ( "movw r0, #0x7784\n" "movt r0, #0x5116\n" "movw r1, #0xfffe\n" "movt r1, #0xffff\n" "mov r2, %0\n" "mov r3, #0\n" "mov sp, %1\n" "mov r4, %2\n" "bx r4\n" :: "r" (sp - 0x110), "r" (old_sp), "r" (0x5101F779) : "r0", "r1", "r2", "r3", "r4" ); } __attribute__ ((section (".text.start"), naked)) void start(void) { __asm__ volatile ( "mov r0, #0\n" "movt r0, #0x51f0\n" "mov sp, r0\n" "b go\n" ); } ================================================ FILE: first.x ================================================ OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(start) SECTIONS { . = 0x51167220; .text : { *(.text.start) *(.text .text.* .gnu.linkonce.t.*) *(.sceStub.text.*) } .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .data : { *(.data .data.* .gnu.linkonce.d.*) } .bss : { *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) } } ================================================ FILE: gen.py ================================================ #!/usr/bin/env python2 from sys import argv, exit import struct def p32(x): return struct.pack("= 0x180: print "your first payload is too big!" exit(-1) if len(second_bin) >= 0x2000: print "your second payload is too big!" exit(-1) temp_store = 0x511671A0 pivot = 0x5101504C # e890b672 ldm r0, {r1, r4, r5, r6, r9, sl, ip, sp, pc} pop_pc = 0x5100155F pop_r0_pc = 0x5100E4D1 pop_r1_r2_r4_r6_pc = 0x51024C53 blx_r3_pop_r3_pc = 0x510058AF pop_r3_pc = 0x510058B1 flush_icache = 0x51014691 # ICIALLUIS clean_dcache = 0x510146DD debug_printf = 0x51012D45 pivot_args = [0, 0, 0, 0, 0, 0, 0, temp_store + 0x40, pop_pc] rop = [ pop_r0_pc, temp_store, # r0 pop_r1_r2_r4_r6_pc, 0x800, # r1 0, # r2 0, # r4 0, # r6 pop_r3_pc, clean_dcache, # r3 blx_r3_pop_r3_pc, flush_icache, # r3 blx_r3_pop_r3_pc, 0, # r3 temp_store + 0x80|1, ] BASE = 0x5400 # write pivot_args to temp_store ins(fat_tpl, BASE, pivot_args) # write rop to temp_store + 0x40 ins(fat_tpl, BASE + 0x40, rop) # write payload to temp_store + 0x80 ins(fat_tpl, BASE + 0x80, first_bin) # write second payload starting from block 5 ins(fat_tpl, 5 * 0x200, second_bin) # write func ptr ins(fat_tpl, BASE + 0x638, [pivot]) # write R0 arg to func ptr ins(fat_tpl, BASE + 0x63C, [temp_store]) with open(argv[4], "wb") as fout: fout.write(fat_tpl) if __name__ == "__main__": main() ================================================ FILE: installer/.gitignore ================================================ build ================================================ FILE: installer/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 2.8) if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) if(DEFINED ENV{VITASDK}) set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file") else() message(FATAL_ERROR "Please define VITASDK to point to your SDK path!") endif() endif() set(SHORT_NAME enso_installer) project(${SHORT_NAME}) include("${VITASDK}/share/vita.cmake" REQUIRED) set(VITA_APP_NAME "ensō") set(VITA_TITLEID "MLCL00003") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -fno-builtin-printf") if (DEFINED SAFETY) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror") endif() set(IGNORE_WARNING "${SAFETY}") string(TIMESTAMP BUILD_DATE UTC) set(CID "00000000000000000000000000000000" CACHE STRING "Customized CID") set(PERSONALIZED 0 CACHE BOOL "Personalize build") string(LENGTH ${CID} CID_LEN) if(NOT ${CID_LEN} EQUAL 32) message(FATAL_ERROR "Invalid CID") endif() set(i 0) while(i LESS ${CID_LEN}) string(SUBSTRING ${CID} ${i} 2 ch) if(${i} EQUAL 0) set(BUILD_CID "0x${ch} ^ 0xAA") else() set(BUILD_CID "${BUILD_CID}, 0x${ch} ^ 0xAA") endif() math(EXPR i "${i} + 2") endwhile() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h) include_directories(${PROJECT_BINARY_DIR}) include_directories( src ) link_directories( ${CMAKE_BINARY_DIR}/emmc_helper_stubs ${CMAKE_BINARY_DIR}/emmc_helper_user_stubs ) add_executable(${SHORT_NAME} src/main.c src/debug_screen.c src/debug_screen_font.c src/sha256.c ) add_dependencies(${SHORT_NAME} emmc_helper.skprx) target_link_libraries(${SHORT_NAME} SceDisplay_stub SceCtrl_stub SceShellSvc_stub SceProcessmgr_stub SceVshBridge_stub SceHttp_stub SceNet_stub SceNetCtl_stub SceSysmodule_stub SceSblUpdateMgr_stub taihen_stub emmc_helper_user_stub_weak ) vita_create_self(${SHORT_NAME}.self ${SHORT_NAME} UNSAFE) # emmc_helper: kernel version add_executable(emmc_helper src/kernel.c src/crc32.c ) set_target_properties(emmc_helper PROPERTIES LINK_FLAGS -nostdlib ) target_link_libraries(emmc_helper k gcc SceThreadmgrForDriver_stub SceModulemgrForDriver_stub SceModulemgrForKernel_367_stub SceSblAIMgrForDriver_stub SceIofilemgrForDriver_stub SceSysmemForDriver_stub taihenForKernel_stub ) vita_create_self(emmc_helper.skprx emmc_helper CONFIG ${CMAKE_SOURCE_DIR}/src/kernel_exports.yml UNSAFE ) vita_create_stubs(emmc_helper_stubs emmc_helper ${CMAKE_SOURCE_DIR}/src/kernel_exports.yml KERNEL) # second kernel helper to work around unloading a kernel module with exported funcs add_executable(kernel2 src/kernel2.c ) set_target_properties(kernel2 PROPERTIES LINK_FLAGS -nostdlib ) target_link_libraries(kernel2 gcc taihenForKernel_stub ) vita_create_self(kernel2.skprx kernel2 CONFIG ${CMAKE_SOURCE_DIR}/src/kernel2.yml UNSAFE ) # emmc_helper: user version add_executable(emmc_helper_user src/user.c ) set_target_properties(emmc_helper_user PROPERTIES LINK_FLAGS -nostdlib ) target_link_libraries(emmc_helper_user emmc_helper_stub ) vita_create_self(emmc_helper_user.suprx emmc_helper_user CONFIG ${CMAKE_SOURCE_DIR}/src/user_exports.yml UNSAFE ) vita_create_stubs(emmc_helper_user_stubs emmc_helper_user ${CMAKE_SOURCE_DIR}/src/user_exports.yml) add_dependencies(emmc_helper_user emmc_helper_stubs) add_dependencies(${SHORT_NAME} emmc_helper_user_stubs) add_dependencies(${SHORT_NAME} kernel2.skprx) add_dependencies(${SHORT_NAME} emmc_helper.skprx) add_dependencies(${SHORT_NAME} emmc_helper_user.suprx) vita_create_vpk(${SHORT_NAME}.vpk ${VITA_TITLEID} ${SHORT_NAME}.self VERSION ${VITA_VERSION} NAME ${VITA_APP_NAME} FILE ${CMAKE_SOURCE_DIR}/res/fat.bin fat.bin FILE ${CMAKE_BINARY_DIR}/emmc_helper.skprx emmc_helper.skprx FILE ${CMAKE_BINARY_DIR}/emmc_helper_user.suprx emmc_helper.suprx FILE ${CMAKE_BINARY_DIR}/kernel2.skprx kernel2.skprx FILE ${CMAKE_SOURCE_DIR}/res/icon.png sce_sys/icon0.png FILE ${CMAKE_SOURCE_DIR}/res/template.xml sce_sys/livearea/contents/template.xml FILE ${CMAKE_SOURCE_DIR}/res/bg.png sce_sys/livearea/contents/bg.png FILE ${CMAKE_SOURCE_DIR}/res/startup.png sce_sys/livearea/contents/startup.png ) ================================================ FILE: installer/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2017 molecule Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: installer/personalize.sh ================================================ #!/bin/bash make_flags="-j 4" if (( $# < 2 )); then echo "$0 git_dir [cid1 cid2 ...]" exit 0 else git_dir="$1"; shift src_dir="`pwd`" fi while test $# -gt 0 do cid="`echo $1 | tr '[:upper:]' '[:lower:]'`" echo "Building for ${cid}" mkdir "/tmp/$cid" pushd "/tmp/$cid" cmake -DPERSONALIZED=1 -DCID="${cid}" "${src_dir}" make ${make_flags} popd mv "/tmp/$cid/fat_installer.vpk" "${git_dir}/dl/${cid}.vpk" rm -rf "/tmp/$cid" pushd "${git_dir}" git add "dl/${cid}.vpk" popd list="${list}"$'\n'"${cid}" shift done echo "Committing to git..." pushd "${git_dir}" git commit -m "Added new personalized builds for: ${list}" git push echo "Done." ================================================ FILE: installer/res/template.xml ================================================ bg.png startup.png ================================================ FILE: installer/src/crc32.c ================================================ /*- * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or * code or tables extracted from it, as desired without restriction. * * First, the polynomial itself and its table of feedback terms. The * polynomial is * 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 * * Note that we take it "backwards" and put the highest-order term in * the lowest-order bit. The X^32 term is "implied"; the LSB is the * X^31 term, etc. The X^0 term (usually shown as "+1") results in * the MSB being 1 * * Note that the usual hardware shift register implementation, which * is what we're using (we're merely optimizing it by doing eight-bit * chunks at a time) shifts bits into the lowest-order term. In our * implementation, that means shifting towards the right. Why do we * do it this way? Because the calculated CRC must be transmitted in * order from highest-order term to lowest-order term. UARTs transmit * characters in order from LSB to MSB. By storing the CRC this way * we hand it to the UART in the order low-byte to high-byte; the UART * sends each low-bit to hight-bit; and the result is transmission bit * by bit from highest- to lowest-order term without requiring any bit * shuffling on our part. Reception works similarly * * The feedback terms table consists of 256, 32-bit entries. Notes * * The table can be generated at runtime if desired; code to do so * is shown later. It might not be obvious, but the feedback * terms simply represent the results of eight shift/xor opera * tions for all combinations of data and CRC register values * * The values must be right-shifted by eight bits by the "updcrc * logic; the shift must be unsigned (bring in zeroes). On some * hardware you could probably optimize the shift in assembler by * using byte-swap instructions * polynomial $edb88320 * * * CRC32 code derived from work by Gary S. Brown. */ #include #include static uint32_t crc32_tab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; uint32_t crc32(uint32_t crc, const void *buf, size_t size) { const uint8_t *p; p = buf; crc = crc ^ ~0U; while (size--) crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); return crc ^ ~0U; } ================================================ FILE: installer/src/debug_screen.c ================================================ #include #include #include #include #include #include #include extern unsigned char psvDebugScreenFont[]; #define SCREEN_WIDTH (960) #define SCREEN_HEIGHT (544) #define SCREEN_FB_WIDTH (960) #define SCREEN_FB_SIZE (2 * 1024 * 1024) #define SCREEN_FB_ALIGN (256 * 1024) #define SCREEN_GLYPH_W (8) #define SCREEN_GLYPH_H (8) #define COLOR_BLACK 0xFF000000 #define COLOR_RED 0xFF0000FF #define COLOR_BLUE 0xFF00FF00 #define COLOR_YELLOW 0xFF00FFFF #define COLOR_GREEN 0xFFFF0000 #define COLOR_MAGENTA 0xFFFF00FF #define COLOR_CYAN 0xFFFFFF00 #define COLOR_WHITE 0xFFFFFFFF #define COLOR_GREY 0xFF808080 #define COLOR_DEFAULT_FG COLOR_WHITE #define COLOR_DEFAULT_BG COLOR_BLACK static int psvDebugScreenMutex; /*< avoid race condition when outputing strings */ static uint32_t psvDebugScreenCoordX = 0; static uint32_t psvDebugScreenCoordY = 0; static uint32_t psvDebugScreenColorFg = COLOR_DEFAULT_FG; static uint32_t psvDebugScreenColorBg = COLOR_DEFAULT_BG; static SceDisplayFrameBuf psvDebugScreenFrameBuf = { sizeof(SceDisplayFrameBuf), NULL, SCREEN_WIDTH, 0, SCREEN_WIDTH, SCREEN_HEIGHT}; uint32_t psvDebugScreenSetFgColor(uint32_t color) { uint32_t prev_color = psvDebugScreenColorFg; psvDebugScreenColorFg = color; return prev_color; } uint32_t psvDebugScreenSetBgColor(uint32_t color) { uint32_t prev_color = psvDebugScreenColorBg; psvDebugScreenColorBg = color; return prev_color; } static size_t psvDebugScreenEscape(const char *str){ int i,j, p=0, params[8]={}; for(i=0; i<8 && str[i]!='\0'; i++){ if(str[i] >= '0' && str[i] <= '9'){ params[p]=(params[p]*10) + (str[i] - '0'); }else if(str[i] == ';'){ p++; }else if(str[i] == 'f' || str[i] == 'H'){ psvDebugScreenCoordX = params[0] * SCREEN_GLYPH_W; psvDebugScreenCoordY = params[1] * SCREEN_GLYPH_H; break; }else if (str[i] == 'm'){ for(j=0; j<=p; j++){ switch(params[j]/10){/*bold,dim,underline,blink,invert,hidden => unsupported yet */ #define BIT2BYTE(bit) ( ((!!(bit&4))<<23) | ((!!(bit&2))<<15) | ((!!(bit&1))<<7) ) case 0:psvDebugScreenSetFgColor(COLOR_DEFAULT_FG);psvDebugScreenSetBgColor(COLOR_DEFAULT_BG);break; case 3:psvDebugScreenSetFgColor(BIT2BYTE(params[j]%10));break; case 9:psvDebugScreenSetFgColor(BIT2BYTE(params[j]%10) | 0x7F7F7F7F);break; case 4:psvDebugScreenSetBgColor(BIT2BYTE(params[j]%10));break; case 10:psvDebugScreenSetBgColor(BIT2BYTE(params[j]%10) | 0x7F7F7F7F);break; #undef BIT2BYTE } } break; } } return i; } int psvDebugScreenInit() { psvDebugScreenMutex = sceKernelCreateMutex("log_mutex", 0, 0, NULL); SceUID displayblock = sceKernelAllocMemBlock("display", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, SCREEN_FB_SIZE, NULL); sceKernelGetMemBlockBase(displayblock, (void**)&psvDebugScreenFrameBuf.base); SceDisplayFrameBuf framebuf = { .size = sizeof(framebuf), .base = psvDebugScreenFrameBuf.base, .pitch = SCREEN_WIDTH, .pixelformat = SCE_DISPLAY_PIXELFORMAT_A8B8G8R8, .width = SCREEN_WIDTH, .height = SCREEN_HEIGHT, }; return sceDisplaySetFrameBuf(&framebuf, SCE_DISPLAY_SETBUF_NEXTFRAME); } void psvDebugScreenClear(int bg_color){ psvDebugScreenCoordX = psvDebugScreenCoordY = 0; int i; for(i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; i++) { ((uint32_t*)psvDebugScreenFrameBuf.base)[i] = bg_color; } } void* psvDebugScreenBase(void) { return psvDebugScreenFrameBuf.base; } int psvDebugScreenPuts(const char * text){ int c, i, j, l; uint8_t *font; uint32_t *vram_ptr; uint32_t *vram; sceKernelLockMutex(psvDebugScreenMutex, 1, NULL); for (c = 0; text[c] != '\0' ; c++) { if (psvDebugScreenCoordX + 8 > SCREEN_WIDTH) { psvDebugScreenCoordY += SCREEN_GLYPH_H; psvDebugScreenCoordX = 0; } if (psvDebugScreenCoordY + 8 > SCREEN_HEIGHT) { psvDebugScreenClear(psvDebugScreenColorBg); } if (text[c] == '\n') { psvDebugScreenCoordX = 0; psvDebugScreenCoordY += SCREEN_GLYPH_H; continue; } else if (text[c] == '\r') { psvDebugScreenCoordX = 0; continue; } else if ((text[c] == '\e') && (text[c+1] == '[')) { /* escape code (change color, position ...) */ c+=psvDebugScreenEscape(text+2)+2; continue; } vram = ((uint32_t*)psvDebugScreenFrameBuf.base) + psvDebugScreenCoordX + psvDebugScreenCoordY * SCREEN_FB_WIDTH; font = &psvDebugScreenFont[ (int)text[c] * 8]; for (i = l = 0; i < SCREEN_GLYPH_W; i++, l += SCREEN_GLYPH_W, font++) { vram_ptr = vram; for (j = 0; j < SCREEN_GLYPH_W; j++) { if ((*font & (128 >> j))) *vram_ptr = psvDebugScreenColorFg; else *vram_ptr = psvDebugScreenColorBg; vram_ptr++; } vram += SCREEN_FB_WIDTH; } psvDebugScreenCoordX += SCREEN_GLYPH_W; } sceKernelUnlockMutex(psvDebugScreenMutex, 1); return c; } int psvDebugScreenPrintf(const char *format, ...) { char buf[512]; va_list opt; va_start(opt, format); int ret = vsnprintf(buf, sizeof(buf), format, opt); psvDebugScreenPuts(buf); va_end(opt); return ret; } ================================================ FILE: installer/src/debug_screen.h ================================================ #pragma once int psvDebugScreenPrintf(const char *format, ...); int psvDebugScreenInit(); void* psvDebugScreenBase(void); ================================================ FILE: installer/src/debug_screen_font.c ================================================ /* * PSP Software Development Kit - http://www.pspdev.org * ----------------------------------------------------------------------- * Licensed under the BSD license, see LICENSE in PSPSDK root for details. * * font.c - Debug Font. * * Copyright (c) 2005 Marcus R. Brown * Copyright (c) 2005 James Forshaw * Copyright (c) 2005 John Kelley * * $Id: font.c 540 2005-07-08 19:35:10Z warren $ */ unsigned char psvDebugScreenFont[]= "\x00\x00\x00\x00\x00\x00\x00\x00\x3c\x42\xa5\x81\xa5\x99\x42\x3c" "\x3c\x7e\xdb\xff\xff\xdb\x66\x3c\x6c\xfe\xfe\xfe\x7c\x38\x10\x00" "\x10\x38\x7c\xfe\x7c\x38\x10\x00\x10\x38\x54\xfe\x54\x10\x38\x00" "\x10\x38\x7c\xfe\xfe\x10\x38\x00\x00\x00\x00\x30\x30\x00\x00\x00" "\xff\xff\xff\xe7\xe7\xff\xff\xff\x38\x44\x82\x82\x82\x44\x38\x00" "\xc7\xbb\x7d\x7d\x7d\xbb\xc7\xff\x0f\x03\x05\x79\x88\x88\x88\x70" "\x38\x44\x44\x44\x38\x10\x7c\x10\x30\x28\x24\x24\x28\x20\xe0\xc0" "\x3c\x24\x3c\x24\x24\xe4\xdc\x18\x10\x54\x38\xee\x38\x54\x10\x00" "\x10\x10\x10\x7c\x10\x10\x10\x10\x10\x10\x10\xff\x00\x00\x00\x00" "\x00\x00\x00\xff\x10\x10\x10\x10\x10\x10\x10\xf0\x10\x10\x10\x10" "\x10\x10\x10\x1f\x10\x10\x10\x10\x10\x10\x10\xff\x10\x10\x10\x10" "\x10\x10\x10\x10\x10\x10\x10\x10\x00\x00\x00\xff\x00\x00\x00\x00" "\x00\x00\x00\x1f\x10\x10\x10\x10\x00\x00\x00\xf0\x10\x10\x10\x10" "\x10\x10\x10\x1f\x00\x00\x00\x00\x10\x10\x10\xf0\x00\x00\x00\x00" "\x81\x42\x24\x18\x18\x24\x42\x81\x01\x02\x04\x08\x10\x20\x40\x80" "\x80\x40\x20\x10\x08\x04\x02\x01\x00\x10\x10\xff\x10\x10\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x20\x20\x20\x20\x00\x00\x20\x00" "\x50\x50\x50\x00\x00\x00\x00\x00\x50\x50\xf8\x50\xf8\x50\x50\x00" "\x20\x78\xa0\x70\x28\xf0\x20\x00\xc0\xc8\x10\x20\x40\x98\x18\x00" "\x40\xa0\x40\xa8\x90\x98\x60\x00\x10\x20\x40\x00\x00\x00\x00\x00" "\x10\x20\x40\x40\x40\x20\x10\x00\x40\x20\x10\x10\x10\x20\x40\x00" "\x20\xa8\x70\x20\x70\xa8\x20\x00\x00\x20\x20\xf8\x20\x20\x00\x00" "\x00\x00\x00\x00\x00\x20\x20\x40\x00\x00\x00\x78\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x60\x60\x00\x00\x00\x08\x10\x20\x40\x80\x00" "\x70\x88\x98\xa8\xc8\x88\x70\x00\x20\x60\xa0\x20\x20\x20\xf8\x00" "\x70\x88\x08\x10\x60\x80\xf8\x00\x70\x88\x08\x30\x08\x88\x70\x00" "\x10\x30\x50\x90\xf8\x10\x10\x00\xf8\x80\xe0\x10\x08\x10\xe0\x00" "\x30\x40\x80\xf0\x88\x88\x70\x00\xf8\x88\x10\x20\x20\x20\x20\x00" "\x70\x88\x88\x70\x88\x88\x70\x00\x70\x88\x88\x78\x08\x10\x60\x00" "\x00\x00\x20\x00\x00\x20\x00\x00\x00\x00\x20\x00\x00\x20\x20\x40" "\x18\x30\x60\xc0\x60\x30\x18\x00\x00\x00\xf8\x00\xf8\x00\x00\x00" "\xc0\x60\x30\x18\x30\x60\xc0\x00\x70\x88\x08\x10\x20\x00\x20\x00" "\x70\x88\x08\x68\xa8\xa8\x70\x00\x20\x50\x88\x88\xf8\x88\x88\x00" "\xf0\x48\x48\x70\x48\x48\xf0\x00\x30\x48\x80\x80\x80\x48\x30\x00" "\xe0\x50\x48\x48\x48\x50\xe0\x00\xf8\x80\x80\xf0\x80\x80\xf8\x00" "\xf8\x80\x80\xf0\x80\x80\x80\x00\x70\x88\x80\xb8\x88\x88\x70\x00" "\x88\x88\x88\xf8\x88\x88\x88\x00\x70\x20\x20\x20\x20\x20\x70\x00" "\x38\x10\x10\x10\x90\x90\x60\x00\x88\x90\xa0\xc0\xa0\x90\x88\x00" "\x80\x80\x80\x80\x80\x80\xf8\x00\x88\xd8\xa8\xa8\x88\x88\x88\x00" "\x88\xc8\xc8\xa8\x98\x98\x88\x00\x70\x88\x88\x88\x88\x88\x70\x00" "\xf0\x88\x88\xf0\x80\x80\x80\x00\x70\x88\x88\x88\xa8\x90\x68\x00" "\xf0\x88\x88\xf0\xa0\x90\x88\x00\x70\x88\x80\x70\x08\x88\x70\x00" "\xf8\x20\x20\x20\x20\x20\x20\x00\x88\x88\x88\x88\x88\x88\x70\x00" "\x88\x88\x88\x88\x50\x50\x20\x00\x88\x88\x88\xa8\xa8\xd8\x88\x00" "\x88\x88\x50\x20\x50\x88\x88\x00\x88\x88\x88\x70\x20\x20\x20\x00" "\xf8\x08\x10\x20\x40\x80\xf8\x00\x70\x40\x40\x40\x40\x40\x70\x00" "\x00\x00\x80\x40\x20\x10\x08\x00\x70\x10\x10\x10\x10\x10\x70\x00" "\x20\x50\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\x00" "\x40\x20\x10\x00\x00\x00\x00\x00\x00\x00\x70\x08\x78\x88\x78\x00" "\x80\x80\xb0\xc8\x88\xc8\xb0\x00\x00\x00\x70\x88\x80\x88\x70\x00" "\x08\x08\x68\x98\x88\x98\x68\x00\x00\x00\x70\x88\xf8\x80\x70\x00" "\x10\x28\x20\xf8\x20\x20\x20\x00\x00\x00\x68\x98\x98\x68\x08\x70" "\x80\x80\xf0\x88\x88\x88\x88\x00\x20\x00\x60\x20\x20\x20\x70\x00" "\x10\x00\x30\x10\x10\x10\x90\x60\x40\x40\x48\x50\x60\x50\x48\x00" "\x60\x20\x20\x20\x20\x20\x70\x00\x00\x00\xd0\xa8\xa8\xa8\xa8\x00" "\x00\x00\xb0\xc8\x88\x88\x88\x00\x00\x00\x70\x88\x88\x88\x70\x00" "\x00\x00\xb0\xc8\xc8\xb0\x80\x80\x00\x00\x68\x98\x98\x68\x08\x08" "\x00\x00\xb0\xc8\x80\x80\x80\x00\x00\x00\x78\x80\xf0\x08\xf0\x00" "\x40\x40\xf0\x40\x40\x48\x30\x00\x00\x00\x90\x90\x90\x90\x68\x00" "\x00\x00\x88\x88\x88\x50\x20\x00\x00\x00\x88\xa8\xa8\xa8\x50\x00" "\x00\x00\x88\x50\x20\x50\x88\x00\x00\x00\x88\x88\x98\x68\x08\x70" "\x00\x00\xf8\x10\x20\x40\xf8\x00\x18\x20\x20\x40\x20\x20\x18\x00" "\x20\x20\x20\x00\x20\x20\x20\x00\xc0\x20\x20\x10\x20\x20\xc0\x00" "\x40\xa8\x10\x00\x00\x00\x00\x00\x00\x00\x20\x50\xf8\x00\x00\x00" "\x70\x88\x80\x80\x88\x70\x20\x60\x90\x00\x00\x90\x90\x90\x68\x00" "\x10\x20\x70\x88\xf8\x80\x70\x00\x20\x50\x70\x08\x78\x88\x78\x00" "\x48\x00\x70\x08\x78\x88\x78\x00\x20\x10\x70\x08\x78\x88\x78\x00" "\x20\x00\x70\x08\x78\x88\x78\x00\x00\x70\x80\x80\x80\x70\x10\x60" "\x20\x50\x70\x88\xf8\x80\x70\x00\x50\x00\x70\x88\xf8\x80\x70\x00" "\x20\x10\x70\x88\xf8\x80\x70\x00\x50\x00\x00\x60\x20\x20\x70\x00" "\x20\x50\x00\x60\x20\x20\x70\x00\x40\x20\x00\x60\x20\x20\x70\x00" "\x50\x00\x20\x50\x88\xf8\x88\x00\x20\x00\x20\x50\x88\xf8\x88\x00" "\x10\x20\xf8\x80\xf0\x80\xf8\x00\x00\x00\x6c\x12\x7e\x90\x6e\x00" "\x3e\x50\x90\x9c\xf0\x90\x9e\x00\x60\x90\x00\x60\x90\x90\x60\x00" "\x90\x00\x00\x60\x90\x90\x60\x00\x40\x20\x00\x60\x90\x90\x60\x00" "\x40\xa0\x00\xa0\xa0\xa0\x50\x00\x40\x20\x00\xa0\xa0\xa0\x50\x00" "\x90\x00\x90\x90\xb0\x50\x10\xe0\x50\x00\x70\x88\x88\x88\x70\x00" "\x50\x00\x88\x88\x88\x88\x70\x00\x20\x20\x78\x80\x80\x78\x20\x20" "\x18\x24\x20\xf8\x20\xe2\x5c\x00\x88\x50\x20\xf8\x20\xf8\x20\x00" "\xc0\xa0\xa0\xc8\x9c\x88\x88\x8c\x18\x20\x20\xf8\x20\x20\x20\x40" "\x10\x20\x70\x08\x78\x88\x78\x00\x10\x20\x00\x60\x20\x20\x70\x00" "\x20\x40\x00\x60\x90\x90\x60\x00\x20\x40\x00\x90\x90\x90\x68\x00" "\x50\xa0\x00\xa0\xd0\x90\x90\x00\x28\x50\x00\xc8\xa8\x98\x88\x00" "\x00\x70\x08\x78\x88\x78\x00\xf8\x00\x60\x90\x90\x90\x60\x00\xf0" "\x20\x00\x20\x40\x80\x88\x70\x00\x00\x00\x00\xf8\x80\x80\x00\x00" "\x00\x00\x00\xf8\x08\x08\x00\x00\x84\x88\x90\xa8\x54\x84\x08\x1c" "\x84\x88\x90\xa8\x58\xa8\x3c\x08\x20\x00\x00\x20\x20\x20\x20\x00" "\x00\x00\x24\x48\x90\x48\x24\x00\x00\x00\x90\x48\x24\x48\x90\x00" "\x28\x50\x20\x50\x88\xf8\x88\x00\x28\x50\x70\x08\x78\x88\x78\x00" "\x28\x50\x00\x70\x20\x20\x70\x00\x28\x50\x00\x20\x20\x20\x70\x00" "\x28\x50\x00\x70\x88\x88\x70\x00\x50\xa0\x00\x60\x90\x90\x60\x00" "\x28\x50\x00\x88\x88\x88\x70\x00\x50\xa0\x00\xa0\xa0\xa0\x50\x00" "\xfc\x48\x48\x48\xe8\x08\x50\x20\x00\x50\x00\x50\x50\x50\x10\x20" "\xc0\x44\xc8\x54\xec\x54\x9e\x04\x10\xa8\x40\x00\x00\x00\x00\x00" "\x00\x20\x50\x88\x50\x20\x00\x00\x88\x10\x20\x40\x80\x28\x00\x00" "\x7c\xa8\xa8\x68\x28\x28\x28\x00\x38\x40\x30\x48\x48\x30\x08\x70" "\x00\x00\x00\x00\x00\x00\xff\xff\xf0\xf0\xf0\xf0\x0f\x0f\x0f\x0f" "\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x3c\x3c\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00" "\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x0f\x0f\x0f\x0f\xf0\xf0\xf0\xf0" "\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\x03\x03\x03\x03\x03\x03\x03\x03" "\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x11\x22\x44\x88\x11\x22\x44\x88" "\x88\x44\x22\x11\x88\x44\x22\x11\xfe\x7c\x38\x10\x00\x00\x00\x00" "\x00\x00\x00\x00\x10\x38\x7c\xfe\x80\xc0\xe0\xf0\xe0\xc0\x80\x00" "\x01\x03\x07\x0f\x07\x03\x01\x00\xff\x7e\x3c\x18\x18\x3c\x7e\xff" "\x81\xc3\xe7\xff\xff\xe7\xc3\x81\xf0\xf0\xf0\xf0\x00\x00\x00\x00" "\x00\x00\x00\x00\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x00\x00\x00\x00" "\x00\x00\x00\x00\xf0\xf0\xf0\xf0\x33\x33\xcc\xcc\x33\x33\xcc\xcc" "\x00\x20\x20\x50\x50\x88\xf8\x00\x20\x20\x70\x20\x70\x20\x20\x00" "\x00\x00\x00\x50\x88\xa8\x50\x00\xff\xff\xff\xff\xff\xff\xff\xff" "\x00\x00\x00\x00\xff\xff\xff\xff\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0" "\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\xff\xff\xff\xff\x00\x00\x00\x00" "\x00\x00\x68\x90\x90\x90\x68\x00\x30\x48\x48\x70\x48\x48\x70\xc0" "\xf8\x88\x80\x80\x80\x80\x80\x00\xf8\x50\x50\x50\x50\x50\x98\x00" "\xf8\x88\x40\x20\x40\x88\xf8\x00\x00\x00\x78\x90\x90\x90\x60\x00" "\x00\x50\x50\x50\x50\x68\x80\x80\x00\x50\xa0\x20\x20\x20\x20\x00" "\xf8\x20\x70\xa8\xa8\x70\x20\xf8\x20\x50\x88\xf8\x88\x50\x20\x00" "\x70\x88\x88\x88\x50\x50\xd8\x00\x30\x40\x40\x20\x50\x50\x50\x20" "\x00\x00\x00\x50\xa8\xa8\x50\x00\x08\x70\xa8\xa8\xa8\x70\x80\x00" "\x38\x40\x80\xf8\x80\x40\x38\x00\x70\x88\x88\x88\x88\x88\x88\x00" "\x00\xf8\x00\xf8\x00\xf8\x00\x00\x20\x20\xf8\x20\x20\x00\xf8\x00" "\xc0\x30\x08\x30\xc0\x00\xf8\x00\x18\x60\x80\x60\x18\x00\xf8\x00" "\x10\x28\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\xa0\x40" "\x00\x20\x00\xf8\x00\x20\x00\x00\x00\x50\xa0\x00\x50\xa0\x00\x00" "\x00\x18\x24\x24\x18\x00\x00\x00\x00\x30\x78\x78\x30\x00\x00\x00" "\x00\x00\x00\x00\x30\x00\x00\x00\x3e\x20\x20\x20\xa0\x60\x20\x00" "\xa0\x50\x50\x50\x00\x00\x00\x00\x40\xa0\x20\x40\xe0\x00\x00\x00" "\x00\x38\x38\x38\x38\x38\x38\x00\x00\x00\x00\x00\x00\x00\x00"; ================================================ FILE: installer/src/enso.h ================================================ #pragma once // user prototypes int ensoCheckOs0(void); int ensoCheckMBR(void); int ensoCheckBlocks(void); int ensoWriteConfig(void); int ensoWriteBlocks(void); int ensoWriteMBR(void); int ensoCheckRealMBR(void); int ensoUninstallMBR(void); int ensoCleanUpBlocks(void); // kernel prototypes int k_ensoCheckOs0(void); int k_ensoCheckMBR(void); int k_ensoCheckBlocks(void); int k_ensoWriteConfig(void); int k_ensoWriteBlocks(void); int k_ensoWriteMBR(void); int k_ensoCheckRealMBR(void); int k_ensoUninstallMBR(void); int k_ensoCleanUpBlocks(void); enum { E_PREVIOUS_INSTALL = 1, E_MBR_BUT_UNKNOWN = 2, E_UNKNOWN_DATA = 3, }; #define BLOCKS_OUTPUT "ux0:data/blocks.bin" ================================================ FILE: installer/src/kernel.c ================================================ #include #include #include #include #include #include #include #include #include #include #include "enso.h" #define printf(str, x...) do { printf_file("%s:%d: " str, __PRETTY_FUNCTION__, __LINE__, ## x); } while (0) #define ARRAYSIZE(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) int ksceSblAimgrIsDolce(void); uint32_t crc32(uint32_t crc, const void *buf, size_t size); enum { BLOCK_SIZE = 0x200, OFF_PARTITION_TABLE = 0, OFF_REAL_PARTITION_TABLE = 1 * BLOCK_SIZE, OFF_FAKE_OS0 = 2 * BLOCK_SIZE, FAT_BIN_SIZE = 0x6000, // NOTE: first 0x400 bytes are not written FAT_BIN_USEFUL_SIZE = 0x6000 - 0x400, OS0_SIZE = 0x3820 * BLOCK_SIZE, OS0_CRC32 = 0x69b0c99d, }; typedef struct { uint32_t off; uint32_t sz; uint8_t code; uint8_t type; uint8_t active; uint32_t flags; uint16_t unk; } __attribute__((packed)) partition_t; typedef struct { char magic[0x20]; uint32_t version; uint32_t device_size; char unk1[0x28]; partition_t partitions[0x10]; char unk2[0x5e]; char unk3[0x10 * 4]; uint16_t sig; } __attribute__((packed)) master_block_t; int printf_file(const char *format, ...) { char line[512] = {0}; va_list arg; va_start(arg, format); vsprintf(line, format, arg); va_end(arg); int fd = ksceIoOpen("ux0:data/enso.log", SCE_O_WRONLY | SCE_O_APPEND | SCE_O_CREAT, 0777); if (fd < 0) return 0; ksceIoWrite(fd, line, strlen(line)); ksceIoClose(fd); return 0; } const char *part_code(int code) { static char *codes[] = { "empty", "first_partition", "slb2", "os0", "vs0", "vd0", "tm0", "ur0", "ux0", "gro0", "grw0", "ud0", "sa0", "some_data", "pd0", "invalid" }; return codes[code]; } const char *part_type(int type) { if (type == 6) return "FAT16"; else if (type == 7) return "exFAT"; else if (type == 0xDA) return "raw"; return "unknown"; } const char *device = "sdstor0:int-lp-act-entire"; int run_on_thread(void *func) { int ret = 0; int res = 0; int uid = 0; ret = uid = ksceKernelCreateThread("run_on_thread", func, 64, 0x1000, 0, 0, 0); if (ret < 0) { printf("failed to create a thread: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = ksceKernelStartThread(uid, 0, NULL)) < 0) { printf("failed to start a thread: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = ksceKernelWaitThreadEnd(uid, &res, NULL)) < 0) { printf("failed to wait a thread: 0x%08x\n", ret); ret = -1; goto cleanup; } ret = res; cleanup: if (uid > 0) ksceKernelDeleteThread(uid); return ret; } int find_active_os0(master_block_t *master) { int active_os0 = -1; for (size_t i = 0; i < ARRAYSIZE(master->partitions); ++i) { partition_t *p = &master->partitions[i]; printf("Partition %d, code=%s, type=%s, active=%d, off=0x%08x, sz=0x%08x, flags=0x%08x, unk=0x%08x\n", i, part_code(p->code), part_type(p->type), p->active, p->off, p->sz, p->flags, p->unk); if (p->active == 1 && p->code == 3) active_os0 = i; } return active_os0; } int check_os0(void) { int ret = 0; int fd = 0; printf("checking os0\n"); ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); if (ret < 0) { printf("failed to open the device: 0x%08x\n", ret); ret = -1; goto cleanup; } // read MBR and find active os0 static master_block_t master; if ((ret = ksceIoRead(fd, &master, sizeof(master))) != sizeof(master)) { printf("failed to read master block: 0x%08x\n", ret); ret = -1; goto cleanup; } int active_os0 = find_active_os0(&master); if (active_os0 == -1) { printf("failed to find active os0 partition\n"); ret = -1; goto cleanup; } uint32_t off = master.partitions[active_os0].off * BLOCK_SIZE; if ((ret = ksceIoLseek(fd, off, SCE_SEEK_SET)) != (int)off) { printf("failed to seek to os0: 0x%08x\n", ret); ret = -1; goto cleanup; } uint32_t crc = 0; for (int i = 0; i < OS0_SIZE / BLOCK_SIZE; ++i) { static char buffer[BLOCK_SIZE]; if ((ret = ksceIoRead(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { printf("failed to read a block: 0x%08x\n", ret); ret = -1; goto cleanup; } crc = crc32(crc, buffer, sizeof(buffer)); } printf("got os0 crc32: 0x%08x\n", crc); if (crc != OS0_CRC32) { printf("error: crc does not match!\n"); ret = -1; } else { ret = 0; } cleanup: if (fd > 0) ksceIoClose(fd); return ret; } int k_ensoCheckOs0(void) { int ret = 0; int state = 0; ENTER_SYSCALL(state); ret = run_on_thread(check_os0); EXIT_SYSCALL(state); return ret; } int is_mbr(void *data) { master_block_t *master = data; if (memcmp(master->magic, "Sony Computer Entertainment Inc.", 0x20) != 0) return 0; if (master->sig != 0xAA55) return 0; return 1; } int is_empty(void *data) { uint8_t *buf = data; for (int i = 0; i < BLOCK_SIZE; ++i) if (buf[i] != 0xAA) return 0; return 1; } int check_mbr() { int ret = 0; int fd = 0; printf("check_mbr\n"); static master_block_t master; ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); if (fd < 0) { printf("failed to open the device: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = ksceIoRead(fd, &master, sizeof(master))) != sizeof(master)) { printf("failed to read master block: 0x%08x\n", ret); ret = -1; goto cleanup; } ret = 0; if (!is_mbr(&master)) { printf("error: master block is not MBR\n"); ret = -1; } cleanup: if (fd > 0) ksceIoClose(fd); return ret; } int k_ensoCheckMBR(void) { int ret = 0; int state = 0; ENTER_SYSCALL(state); ret = run_on_thread(check_mbr); EXIT_SYSCALL(state); return ret; } int dump_blocks(void) { int wfd = 0; int fd = 0; int ret = 0; printf("dumping blocks to %s\n", BLOCKS_OUTPUT); ret = wfd = ksceIoOpen(BLOCKS_OUTPUT, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777); if (ret < 0) { printf("failed to open %s for write: 0x%08x\n", BLOCKS_OUTPUT, ret); ret = -1; goto cleanup; } ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); if (ret < 0) { printf("failed to open the device: 0x%08x\n", ret); ret = -1; goto cleanup; } for (int i = 0; i < FAT_BIN_SIZE / BLOCK_SIZE; ++i) { static char buffer[BLOCK_SIZE]; if ((ret = ksceIoRead(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { printf("failed to read block %d: 0x%08x\n", i, ret); ret = -1; goto cleanup; } if ((ret = ksceIoWrite(wfd, buffer, sizeof(buffer))) != sizeof(buffer)) { printf("failed to write block %d: 0x%08x\n", i, ret); ret = -1; goto cleanup; } } ret = 0; printf("copied successfully\n"); cleanup: if (wfd > 0) ksceIoClose(wfd); if (fd > 0) ksceIoClose(fd); return ret; } int check_blocks(void) { int ret = 0; int fd = 0; static master_block_t master; printf("checking blocks\n"); ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); if (ret < 0) { printf("failed to open the device: 0x%08x\n", ret); ret = -1; goto cleanup; } // check that block 1 is MBR if ((ret = ksceIoLseek(fd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { printf("failed to seek the device to real mbr: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = ksceIoRead(fd, &master, sizeof(master))) != sizeof(master)) { printf("failed to read the real mbr block: 0x%08x\n", ret); ret = -1; goto cleanup; } if (is_mbr(&master)) { // if it is, check that the rest of the blocks match a known crc32 value if ((ret = ksceIoLseek(fd, OFF_FAKE_OS0, SCE_SEEK_SET)) != OFF_FAKE_OS0) { printf("failed to seek the device to fake os0: 0x%08x\n", ret); ret = -1; goto cleanup; } uint32_t crc = 0; for (int i = 0; i < FAT_BIN_USEFUL_SIZE / BLOCK_SIZE; ++i) { static char buffer[BLOCK_SIZE]; if ((ret = ksceIoRead(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { printf("failed to read a block: 0x%08x\n", ret); ret = -1; goto cleanup; } crc = crc32(crc, buffer, sizeof(buffer)); } printf("crc32[2; 48] = 0x%08x\n", crc); uint32_t known_crc[] = { 0xa6b37650, 0x723111d1 }; int found = 0; for (size_t i = 0; i < ARRAYSIZE(known_crc); ++i) { if (crc == known_crc[i]) { found = 1; break; } } if (!found) { printf("warning: got unknown checksum\n"); dump_blocks(); ret = E_MBR_BUT_UNKNOWN; } else { ret = E_PREVIOUS_INSTALL; } } else { // otherwise just check that the data's empty, including real mbr if ((ret = ksceIoLseek(fd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { printf("failed to seek the device to real mbr block (2): 0x%08x\n", ret); ret = -1; goto cleanup; } // -1 because block 0 in fat.bin is fake MBR for (int i = 0; i < FAT_BIN_SIZE / 0x200 - 1; ++i) { static char buffer[BLOCK_SIZE]; if ((ret = ksceIoRead(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { printf("failed to read a block (2): 0x%08x\n", ret); ret = -1; goto cleanup; } if (!is_empty(&buffer)) { printf("unknown data was found in block %d\n", i + 1); dump_blocks(); ret = E_UNKNOWN_DATA; goto cleanup; } } // all blocks checked, all good ret = 0; } cleanup: if (fd > 0) ksceIoClose(fd); return ret; } int k_ensoCheckBlocks() { int ret = 0; int state = 0; ENTER_SYSCALL(state); ret = run_on_thread(check_blocks); EXIT_SYSCALL(state); return ret; } int write_config() { int pstv = 0; int uid = 0; int ret = 0; int fd = 0; SceKernelModuleInfo info = {0}; char *pos = NULL; int len = 0; printf("write_config\n"); ksceIoMkdir("ur0:tai", 0777); // make directory if it does not exist pstv = ksceSblAimgrIsDolce(); printf("writing config for %s\n", pstv ? "PSTV" : "PS Vita"); ret = uid = ksceKernelLoadModule(pstv ? "os0:psp2config_dolce.skprx" : "os0:psp2config_vita.skprx", 0, NULL); if (ret < 0) { printf("failed to load psp2config module: 0x%08x\n", ret); ret = -1; goto cleanup; } info.size = sizeof(info); ret = ksceKernelGetModuleInfo(KERNEL_PID, uid, &info); if (ret < 0) { printf("failed to get module info: 0x%08x\n", ret); ret = -1; goto cleanup; } static char config[0x1000]; if (info.segments[0].memsz >= sizeof(config)) { printf("config does not fit, size=0x%08x\n", info.segments[0].memsz); ret = -1; goto cleanup; } memcpy(config, (char*)info.segments[0].vaddr + 0xD4, info.segments[0].memsz - 0xD4); if (memcmp(config, "#\n# PSP2", 8) != 0) { printf("config is corrupt\n"); ret = -1; goto cleanup; } ret = fd = ksceIoOpen("ur0:tai/boot_config.txt", SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777); if (ret < 0) { printf("failed to open ur0:tai/boot_config.txt for write: 0x%08x\n", ret); ret = -1; goto cleanup; } pos = strstr(config, "\n- appspawn vs0:vsh/shell/shell.self"); if (!pos) { printf("failed to patch config: cannot locate appspawn line\n"); ret = -1; goto cleanup; } // write first part: warning message const char *patch1 = "# WARNING: DO NOT EDIT THIS FILE. IF YOU JUST WANT TO RUN A PLUGIN ON BOOT,\n" "# EDIT ux0:tai/config.txt INSTEAD. IF YOU BREAK THIS FILE, YOUR VITA WILL NO\n" "# LONGER BOOT. IF THAT HAPPENS, YOU CAN ENTER SAFE MODE AND RESET ALL SETTINGS\n" "# TO RESET THIS FILE. THIS FILE IS UNIQUE TO EACH VITA MODEL. DO NOT BLINDLY\n" "# USE SOMEONE ELSE'S CONFIG.\n"; len = strlen(patch1); if ((ret = ksceIoWrite(fd, patch1, len)) != len) { printf("failed to write config 1st part: wrote 0x%08x expected 0x%08x\n", ret, len); ret = -1; goto cleanup; } // write second part: everything before appspawn len = pos - config; if ((ret = ksceIoWrite(fd, config, len)) != len) { printf("failed to write config 2nd part: wrote 0x%08x expected 0x%08x\n", ret, len); ret = -1; goto cleanup; } // write 3rd part: patch: load taihen and henkaku const char *patch2 = "\n- load\tur0:tai/taihen.skprx\n- load\tur0:tai/henkaku.skprx\n"; len = strlen(patch2); if ((ret = ksceIoWrite(fd, patch2, len)) != len) { printf("failed to write config 3rd part: wrote 0x%08x expected 0x%08x\n", ret, len); ret = -1; goto cleanup; } // write 4th part: rest of config len = strlen(pos); if ((ret = ksceIoWrite(fd, pos, len)) != len) { printf("failed to write config 4th part: wrote 0x%08x expected 0x%08x\n", ret, len); ret = -1; goto cleanup; } ret = 0; cleanup: if (fd > 0) ksceIoClose(fd); if (uid > 0) ksceKernelUnloadModule(uid, 0, NULL); return ret; } int k_ensoWriteConfig() { int ret = 0; int state = 0; ENTER_SYSCALL(state); ret = run_on_thread(write_config); EXIT_SYSCALL(state); return ret; } int write_blocks(void) { int ret = 0; int fd = 0; int read_fd = 0; int fat_fd = 0; printf("writing blocks 2-..\n"); ret = fat_fd = ksceIoOpen("ux0:app/MLCL00003/fat.bin", SCE_O_RDONLY, 0); if (ret < 0) { printf("failed to open fat.bin for read: 0x%08x\n", ret); ret = -1; goto cleanup; } ret = fd = ksceIoOpen(device, SCE_O_WRONLY, 0777); if (ret < 0) { printf("failed to open device for write: 0x%08x\n", ret); ret = -1; goto cleanup; } ret = read_fd = ksceIoOpen(device, SCE_O_RDONLY, 0); if (ret < 0) { printf("failed to open device for read: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = ksceIoLseek(fd, OFF_FAKE_OS0, SCE_SEEK_SET)) != OFF_FAKE_OS0) { printf("failed to seek the device: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = ksceIoLseek(fat_fd, OFF_FAKE_OS0, SCE_SEEK_SET)) != OFF_FAKE_OS0) { printf("failed to seek fat.bin: 0x%08x\n", ret); ret = -1; goto cleanup; } for (int i = 0; i < FAT_BIN_USEFUL_SIZE / BLOCK_SIZE; ++i) { static char buffer[BLOCK_SIZE]; if ((ret = ksceIoRead(fat_fd, buffer, sizeof(buffer))) != sizeof(buffer)) { printf("failed to read fat.bin at block %d: 0x%08x\n", i + 2, ret); ret = -1; goto cleanup; } if ((ret = ksceIoWrite(fd, buffer, sizeof(buffer))) != sizeof(buffer)) { printf("failed to write fat.bin to device at block %d: 0x%08x\n", i + 2, ret); ret = -1; goto cleanup; } // now read it back and confirm we wrote correctly static char read_buffer[BLOCK_SIZE]; int off = BLOCK_SIZE * (i + 2); if ((ret = ksceIoLseek(read_fd, off, SCE_SEEK_SET)) != off) { printf("failed to seek read_fd: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = ksceIoRead(read_fd, read_buffer, sizeof(read_buffer))) != sizeof(read_buffer)) { printf("failed to read into read_buffer: 0x%08x\n", ret); ret = -1; goto cleanup; } if (memcmp(read_buffer, buffer, BLOCK_SIZE) != 0) { printf("error: write failed\n"); ret = -1; goto cleanup; } } printf("success!\n"); ret = 0; cleanup: if (fat_fd > 0) ksceIoClose(fat_fd); if (read_fd > 0) ksceIoClose(read_fd); if (fd > 0) ksceIoClose(fd); ksceIoSync(device, 0); // sync write return ret; } int k_ensoWriteBlocks(void) { int ret = 0; int state = 0; ENTER_SYSCALL(state); ret = run_on_thread(write_blocks); EXIT_SYSCALL(state); return ret; } int write_mbr(void) { int ret = 0; int fd = 0; int read_fd = 0; ret = read_fd = ksceIoOpen(device, SCE_O_RDONLY, 0); if (ret < 0) { printf("failed to open device for read: 0x%08x\n", ret); ret = -1; goto cleanup; } ret = fd = ksceIoOpen(device, SCE_O_WRONLY, 0777); if (ret < 0) { printf("failed to open device for write: 0x%08x\n", ret); ret = -1; goto cleanup; } static master_block_t master; if ((ret = ksceIoRead(read_fd, &master, sizeof(master))) != sizeof(master)) { printf("failed to read master block: 0x%08x\n", ret); ret = -1; goto cleanup; } // write a copy to block 1 if ((ret = ksceIoLseek(fd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { printf("failed to seek the device: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = ksceIoWrite(fd, &master, sizeof(master))) != sizeof(master)) { printf("failed to write a copy of MBR: 0x%08x\n", ret); ret = -1; goto cleanup; } // check it's actually written by reading back and comparing static uint8_t buffer[BLOCK_SIZE]; if ((ret = ksceIoLseek(read_fd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { printf("failed to seek the device: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = ksceIoRead(read_fd, buffer, sizeof(buffer))) != sizeof(buffer)) { printf("failed to read real mbr: 0x%08x\n", ret); ret = -1; goto cleanup; } if (memcmp(buffer, &master, BLOCK_SIZE) != 0) { printf("error: blocks do not match where they should\n"); ret = -1; goto cleanup; } int active_os0 = find_active_os0(&master); if (active_os0 == -1) { printf("failed to find active os0\n"); ret = -1; goto cleanup; } master.partitions[active_os0].off = 2; if ((ret = ksceIoLseek(fd, OFF_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_PARTITION_TABLE) { printf("failed to seek the device: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = ksceIoWrite(fd, &master, sizeof(master))) != sizeof(master)) { printf("error: failed to write modified MBR\n"); ret = -1; goto cleanup; } ret = 0; printf("success!\n"); cleanup: if (read_fd > 0) ksceIoClose(read_fd); if (fd > 0) ksceIoClose(fd); ksceIoSync(device, 0); // sync write return ret; } int k_ensoWriteMBR(void) { int ret = 0; int state = 0; ENTER_SYSCALL(state); ret = run_on_thread(write_mbr); EXIT_SYSCALL(state); return ret; } int check_real_mbr() { int ret = 0; int fd = 0; printf("check_real_mbr\n"); static master_block_t master; ret = fd = ksceIoOpen(device, SCE_O_RDONLY, 0777); if (fd < 0) { printf("failed to open the device: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = ksceIoRead(fd, &master, sizeof(master))) != sizeof(master)) { printf("failed to read real master block: 0x%08x\n", ret); ret = -1; goto cleanup; } ret = 0; if (!is_mbr(&master)) { printf("error: real master block is not MBR\n"); printf("this really shouldn't happen...\n"); ret = -1; } cleanup: if (fd > 0) ksceIoClose(fd); return ret; } int k_ensoCheckRealMBR(void) { int ret = 0; int state = 0; ENTER_SYSCALL(state); ret = run_on_thread(check_real_mbr); EXIT_SYSCALL(state); return ret; } int uninstall_mbr() { int ret = 0; int rfd = 0; int wfd = 0; printf("uninstall_mbr\n"); ret = rfd = ksceIoOpen(device, SCE_O_RDONLY, 0); if (ret < 0) { printf("failed to open the device for read: 0x%08x\n", ret); ret = -1; goto cleanup; } static master_block_t master; if ((ret = ksceIoRead(rfd, &master, sizeof(master))) != sizeof(master)) { printf("failed to read real master block: 0x%08x\n", ret); ret = -1; goto cleanup; } ksceIoClose(rfd); rfd = 0; if (!is_mbr(&master)) { printf("error: real master block is not MBR\n"); printf("this really shouldn't happen...\n"); ret = -1; goto cleanup; } ret = wfd = ksceIoOpen(device, SCE_O_WRONLY, 0777); if (ret < 0) { printf("failed to open the device for write: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = ksceIoWrite(wfd, &master, sizeof(master))) != sizeof(master)) { printf("failed to write real master block: 0x%08x\n", ret); ret = -1; goto cleanup; } ret = 0; cleanup: if (rfd > 0) ksceIoClose(rfd); if (wfd > 0) ksceIoClose(wfd); ksceIoSync(device, 0); // sync write return ret; } int k_ensoUninstallMBR(void) { int ret = 0; int state = 0; ENTER_SYSCALL(state); ret = run_on_thread(uninstall_mbr); EXIT_SYSCALL(state); return ret; } int clean_up_blocks() { int ret = 0; int wfd = 0; ret = wfd = ksceIoOpen(device, SCE_O_WRONLY, 0777); if (ret < 0) { printf("failed to open the device for write: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = ksceIoLseek(wfd, OFF_REAL_PARTITION_TABLE, SCE_SEEK_SET)) != OFF_REAL_PARTITION_TABLE) { printf("failed to seek the device: 0x%08x\n", ret); ret = -1; goto cleanup; } static uint8_t clean_block[BLOCK_SIZE]; memset(clean_block, 0xAA, sizeof(clean_block)); // wipe it out starting from block 1 for (int i = 1; i < FAT_BIN_SIZE / BLOCK_SIZE; ++i) { if ((ret = ksceIoWrite(wfd, clean_block, sizeof(clean_block))) != sizeof(clean_block)) { printf("failed to clean block %d: 0x%08x\n", i, ret); ret = -1; goto cleanup; } } ret = 0; cleanup: if (wfd > 0) ksceIoClose(wfd); ksceIoSync(device, 0); // sync write return ret; } int k_ensoCleanUpBlocks(void) { int ret = 0; int state = 0; ENTER_SYSCALL(state); ret = run_on_thread(clean_up_blocks); EXIT_SYSCALL(state); return ret; } int module_start(int args, void *argv) { (void)args; (void)argv; printf("enso kernel module started\n"); return SCE_KERNEL_START_SUCCESS; } void _start() __attribute__ ((weak, alias ("module_start"))); int module_stop() { printf("enso kernel module stopped\n"); return SCE_KERNEL_STOP_SUCCESS; } ================================================ FILE: installer/src/kernel2.c ================================================ #include #include static tai_hook_ref_t unload_allowed_hook; static SceUID unload_allowed_uid; int unload_allowed_patched(void) { TAI_CONTINUE(int, unload_allowed_hook); return 1; // always allowed } int module_start(int args, void *argv) { (void)args; (void)argv; unload_allowed_uid = taiHookFunctionImportForKernel(KERNEL_PID, &unload_allowed_hook, // Output a reference "SceKernelModulemgr", // Name of module being hooked 0x11F9B314, // NID specifying SceSblACMgrForKernel 0xBBA13D9C, // Function NID unload_allowed_patched); // Name of the hook function return SCE_KERNEL_START_SUCCESS; } void _start() __attribute__ ((weak, alias ("module_start"))); int module_stop() { taiHookReleaseForKernel(unload_allowed_uid, unload_allowed_hook); return SCE_KERNEL_STOP_SUCCESS; } ================================================ FILE: installer/src/kernel2.yml ================================================ kernel2: attributes: 0 version: major: 1 minor: 1 main: start: module_start stop: module_stop ================================================ FILE: installer/src/kernel_exports.yml ================================================ emmc_helper: attributes: 0 version: major: 1 minor: 1 main: start: module_start stop: module_stop modules: emmc_helper: syscall: true functions: - k_ensoCheckOs0 - k_ensoCheckMBR - k_ensoCheckBlocks - k_ensoWriteConfig - k_ensoWriteBlocks - k_ensoWriteMBR - k_ensoCheckRealMBR - k_ensoUninstallMBR - k_ensoCleanUpBlocks ================================================ FILE: installer/src/main.c ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "debug_screen.h" #include "enso.h" #include "version.h" #include "sha256.h" #define printf psvDebugScreenPrintf #define ARRAYSIZE(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) int _vshSblAimgrGetConsoleId(char cid[32]); int sceSblSsUpdateMgrSetBootMode(int x); int vshPowerRequestColdReset(void); enum { SCREEN_WIDTH = 960, SCREEN_HEIGHT = 544, PROGRESS_BAR_WIDTH = SCREEN_WIDTH, PROGRESS_BAR_HEIGHT = 10, LINE_SIZE = SCREEN_WIDTH, }; static unsigned buttons[] = { SCE_CTRL_SELECT, SCE_CTRL_START, SCE_CTRL_UP, SCE_CTRL_RIGHT, SCE_CTRL_DOWN, SCE_CTRL_LEFT, SCE_CTRL_LTRIGGER, SCE_CTRL_RTRIGGER, SCE_CTRL_TRIANGLE, SCE_CTRL_CIRCLE, SCE_CTRL_CROSS, SCE_CTRL_SQUARE, }; const char check_cid[16] = BUILD_CID; uint32_t get_key(void) { static unsigned prev = 0; SceCtrlData pad; while (1) { memset(&pad, 0, sizeof(pad)); sceCtrlPeekBufferPositive(0, &pad, 1); unsigned new = prev ^ (pad.buttons & prev); prev = pad.buttons; for (size_t i = 0; i < sizeof(buttons)/sizeof(*buttons); ++i) if (new & buttons[i]) return buttons[i]; sceKernelDelayThread(1000); // 1ms } } void press_exit(void) { printf("Press any key to exit this application.\n"); get_key(); sceKernelExitProcess(0); } void press_reboot(void) { printf("Press any key to reboot.\n"); get_key(); vshPowerRequestColdReset(); } int g_kernel_module, g_user_module, g_kernel2_module; #define APP_PATH "ux0:app/MLCL00003/" int load_helper(void) { int ret = 0; tai_module_args_t args = {0}; args.size = sizeof(args); args.args = 0; args.argp = ""; if ((ret = g_kernel2_module = taiLoadStartKernelModuleForUser(APP_PATH "kernel2.skprx", &args)) < 0) { printf("Failed to load kernel workaround: 0x%08x\n", ret); return -1; } if ((ret = g_kernel_module = taiLoadStartKernelModuleForUser(APP_PATH "emmc_helper.skprx", &args)) < 0) { printf("Failed to load kernel module: 0x%08x\n", ret); return -1; } if ((ret = g_user_module = sceKernelLoadStartModule(APP_PATH "emmc_helper.suprx", 0, NULL, 0, NULL, NULL)) < 0) { printf("Failed to load user module: 0x%08x\n", ret); return -1; } return 0; } int stop_helper(void) { tai_module_args_t args = {0}; args.size = sizeof(args); args.args = 0; args.argp = ""; int ret = 0; int res = 0; if (g_user_module > 0) { ret = sceKernelStopUnloadModule(g_user_module, 0, NULL, 0, NULL, NULL); if (ret < 0) { printf("Failed to unload user module: 0x%08x\n", ret); return -1; } } if (g_kernel_module > 0) { ret = taiStopUnloadKernelModuleForUser(g_kernel_module, &args, NULL, &res); if (ret < 0) { printf("Failed to unload kernel module: 0x%08x\n", ret); return -1; } } if (g_kernel2_module > 0) { ret = taiStopUnloadKernelModuleForUser(g_kernel2_module, &args, NULL, &res); if (ret < 0) { printf("Failed to unload kernel workaround module: 0x%08x\n", ret); return -1; } } return ret; } int lock_system(void) { int ret = 0; printf("Locking system...\n"); ret = sceShellUtilInitEvents(0); if (ret < 0) { printf("failed: 0x%08X\n", ret); return -1; } ret = sceShellUtilLock(7); if (ret < 0) { printf("failed: 0x%08X\n", ret); return -1; } ret = sceKernelPowerLock(0); if (ret < 0) { printf("failed: 0x%08X\n", ret); return -1; } return 0; } int unlock_system(void) { sceKernelPowerUnlock(0); sceShellUtilUnlock(7); return 0; } void draw_rect(int x, int y, int width, int height, uint32_t color) { void *base = psvDebugScreenBase(); for (int j = y; j < y + height; ++j) for (int i = x; i < x + width; ++i) ((uint32_t*)base)[j * LINE_SIZE + i] = color; } int g_tpl; int download_file(const char *src, const char *dst, uint8_t *expect_hash) { int ret; int conn = sceHttpCreateConnectionWithURL(g_tpl, src, 0); if (conn < 0) { printf("sceHttpCreateConnectionWithURL: 0x%x\n", conn); return conn; } int req = sceHttpCreateRequestWithURL(conn, 0, src, 0); if (req < 0) { printf("sceHttpCreateRequestWithURL: 0x%x\n", req); sceHttpDeleteConnection(conn); return req; } ret = sceHttpSendRequest(req, NULL, 0); if (ret < 0) { printf("sceHttpSendRequest: 0x%x\n", ret); goto end; } static unsigned char buf[4096]; uint64_t length = 0; ret = sceHttpGetResponseContentLength(req, &length); int fd = sceIoOpen(dst, SCE_O_TRUNC | SCE_O_CREAT | SCE_O_WRONLY, 6); int total_read = 0; if (fd < 0) { printf("sceIoOpen: 0x%x\n", fd); ret = fd; goto end; } SHA256_CTX ctx = {0}; sha256_init(&ctx); // draw progress bar background draw_rect(0, SCREEN_HEIGHT - PROGRESS_BAR_HEIGHT, PROGRESS_BAR_WIDTH, PROGRESS_BAR_HEIGHT, 0xFF666666); while (1) { int read = sceHttpReadData(req, buf, sizeof(buf)); if (read < 0) { printf("sceHttpReadData error! 0x%x\n", read); ret = read; goto end2; } if (read == 0) break; ret = sceIoWrite(fd, buf, read); if (ret < 0 || ret != read) { printf("sceIoWrite error! 0x%x\n", ret); goto end2; } sha256_update(&ctx, buf, read); total_read += read; draw_rect(1, SCREEN_HEIGHT - PROGRESS_BAR_HEIGHT + 1, ((uint64_t)(PROGRESS_BAR_WIDTH - 2)) * total_read / length, PROGRESS_BAR_HEIGHT - 2, 0xFFFFFFFF); } uint8_t hash[32] = {0}; sha256_final(&ctx, hash); if (memcmp(hash, expect_hash, sizeof(hash)) != 0) { printf("the file got corrupted in transit\n"); ret = -1; } else { ret = 0; } end2: sceIoClose(fd); end: sceHttpDeleteRequest(req); sceHttpDeleteConnection(conn); return ret; } int init_net(void) { SceNetInitParam netInitParam; int ret; void *base; ret = sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_NET); if (ret < 0) { printf("SCE_SYSMODULE_PROMOTER_UTIL(SCE_SYSMODULE_NET): %x\n", ret); return -1; } ret = sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_HTTP); if (ret < 0) { printf("SCE_SYSMODULE_PROMOTER_UTIL(SCE_SYSMODULE_HTTP): %x\n", ret); return -1; } ret = sceHttpInit(1*1024*1024); if (ret < 0) { printf("sceHttpInit(): %x\n", ret); return -1; } int block = sceKernelAllocMemBlock("net", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW, 1*1024*1024, NULL); if (block < 0) { printf("failed to allocate net block: 0x%08x\n", block); return -1; } ret = sceKernelGetMemBlockBase(block, &base); netInitParam.memory = base; netInitParam.size = 1*1024*1024; netInitParam.flags = 0; ret = sceNetInit(&netInitParam); if (ret < 0) { printf("sceNetInit(): %x\n", ret); return -1; } ret = sceNetCtlInit(); if (ret < 0) { printf("sceNetCtlInit(): %x\n", ret); return -1; } g_tpl = sceHttpCreateTemplate("enso installer", 2, 1); if (g_tpl < 0) { printf("sceHttpCreateTemplate: 0x%x\n", g_tpl); return -1; } sceHttpSetAutoRedirect(g_tpl, 1); return 0; } int extract(const char *pup, const char *psp2swu) { int inf, outf; if ((inf = sceIoOpen(pup, SCE_O_RDONLY, 0)) < 0) { return -1; } if ((outf = sceIoOpen(psp2swu, SCE_O_CREAT | SCE_O_WRONLY | SCE_O_TRUNC, 6)) < 0) { return -1; } int ret = -1; int count; if (sceIoLseek(inf, 0x18, SCE_SEEK_SET) < 0) { goto end; } if (sceIoRead(inf, &count, 4) < 4) { goto end; } if (sceIoLseek(inf, 0x80, SCE_SEEK_SET) < 0) { goto end; } struct { uint64_t id; uint64_t off; uint64_t len; uint64_t field_18; } __attribute__((packed)) file_entry; for (int i = 0; i < count; i++) { if (sceIoRead(inf, &file_entry, sizeof(file_entry)) != sizeof(file_entry)) { goto end; } if (file_entry.id == 0x200) { break; } } if (file_entry.id == 0x200) { char buffer[1024]; size_t rd; if (sceIoLseek(inf, file_entry.off, SCE_SEEK_SET) < 0) { goto end; } while (file_entry.len && (rd = sceIoRead(inf, buffer, sizeof(buffer))) > 0) { if (rd > file_entry.len) { rd = file_entry.len; } sceIoWrite(outf, buffer, rd); file_entry.len -= rd; } if (file_entry.len == 0) { ret = 0; } } end: sceIoClose(inf); sceIoClose(outf); return ret; } int reinstall_firmware(void) { int ret = 0; stop_helper(); unlock_system(); sceKernelPowerLock(0); // don't want the screen to turn off during download ret = init_net(); if (ret < 0) { printf("failed to init network functions\n"); goto cleanup; } // delete old update files const char *files[] = { "ud0:PSP2UPDATE/PSP2UPDAT.PUP", "ud0:PSP2UPDATE/PSP2UPDAT.PUP_", "ud0:PSP2UPDATE/psp2swu.self", "ud0:PSP2UPDATE/psp2swu.self_" }; for (size_t i = 0; i < ARRAYSIZE(files); ++i) sceIoRemove(files[i]); for (size_t i = 0; i < ARRAYSIZE(files); ++i) { int fd = sceIoOpen(files[i], SCE_O_RDONLY, 0); if (fd != (int)0x80010002) { printf("failed to clean up old files: 0x%08x\n", fd); return -1; } } // make sure directory is present sceIoMkdir("ud0:PSP2UPDATE", 0777); uint8_t psp2updat_hash[] = { 0x8c, 0xc2, 0xe2, 0x66, 0x66, 0x26, 0xc4, 0xff, 0x8f, 0x58, 0x2b, 0xf2, 0x09, 0x47, 0x35, 0x26, 0xe8, 0x25, 0xe2, 0xa5, 0xe3, 0x8e, 0x39, 0xb2, 0x59, 0xa8, 0xa4, 0x6e, 0x25, 0xef, 0x37, 0x1c }; printf("Downloading PSP2UPDAT.PUP...\n"); if (download_file("http://update.henkaku.xyz/update/PSP2UPDAT.FULL.360.PUP", "ud0:PSP2UPDATE/PSP2UPDAT.PUP_", psp2updat_hash) < 0) { printf("Failed to download update file.\n"); ret = -1; goto cleanup; } printf("Extracting updater...\n"); extract("ud0:PSP2UPDATE/PSP2UPDAT.PUP_", "ud0:PSP2UPDATE/psp2swu.self_"); if ((ret = sceIoRename("ud0:PSP2UPDATE/PSP2UPDAT.PUP_", "ud0:PSP2UPDATE/PSP2UPDAT.PUP")) < 0) { printf("failed to rename PSP2UPDAT: 0x%08x\n", ret); ret = -1; goto cleanup; } if ((ret = sceIoRename("ud0:PSP2UPDATE/psp2swu.self_", "ud0:PSP2UPDATE/psp2swu.self")) < 0) { printf("failed to rename psp2swu: 0x%08x\n", ret); ret = -1; goto cleanup; } sceIoSync("ud0:", 0); sceIoSync("ud0:PSP2UPDATE/PSP2UPDAT.PUP", 0); sceIoSync("ud0:PSP2UPDATE/psp2swu.self", 0); printf("Rebooting to update in 5 seconds...\n"); printf("Close this app now if you changed your mind.\n"); sceKernelPowerUnlock(0); sceKernelDelayThread(5 * 1000 * 1000); sceSblSsUpdateMgrSetBootMode(48); vshPowerRequestColdReset(); ret = 0; cleanup: return ret; } int do_install(void) { int ret = 0; if (lock_system() < 0) return -1; printf("Checking MBR... "); ret = ensoCheckMBR(); if (ret < 0) { printf("failed\n"); goto err; } printf("ok!\n"); printf("Checking os0... "); ret = ensoCheckOs0(); if (ret < 0) { printf("failed\n"); printf("\nos0 modifications detected.\nYou should reinstall 3.60 and try again.\n"); printf("Press X to download and install 3.60 PUP, any other key to exit.\n"); if (get_key() == SCE_CTRL_CROSS) { if (reinstall_firmware() < 0) { printf("failed to trigger a reinstall\n"); ret = -1; } } goto err; } printf("ok!\n"); printf("\n"); printf("Checking for previous installation... "); ret = ensoCheckBlocks(); if (ret < 0) { printf("failed\n"); goto err; } printf("ok!\n", ret); if (ret == 0) { // all good, blocks are empty } else if (ret == E_PREVIOUS_INSTALL) { printf("Previous installation was detected and will be overwritten.\nPress X to continue, any other key to exit.\n"); if (get_key() != SCE_CTRL_CROSS) goto err; } else if (ret == E_MBR_BUT_UNKNOWN) { 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); if (get_key() != SCE_CTRL_CROSS) goto err; } else if (ret == E_UNKNOWN_DATA) { printf("Unknown data was detected.\nA dump was created at %s.\nThe installation will be aborted.\n", BLOCKS_OUTPUT); goto err; } else { printf("Unknown error code.\n"); goto err; } printf("Writing config... "); ret = ensoWriteConfig(); if (ret < 0) { printf("failed\n"); goto err; } printf("ok!\n"); printf("Writing blocks... "); ret = ensoWriteBlocks(); if (ret < 0) { printf("failed\n"); goto err; } printf("ok!\n"); printf("Writing MBR... "); ret = ensoWriteMBR(); if (ret < 0) { printf("failed\n"); goto err; } printf("ok!\n"); printf("\nThe installation was completed successfully.\n"); unlock_system(); return 0; err: unlock_system(); return -1; } int do_uninstall(void) { int ret = 0; printf("Checking MBR in block 1... "); ret = ensoCheckRealMBR(); if (ret < 0) { printf("failed\n"); return -1; } printf("ok!\n"); printf("Uninstalling MBR patch... "); ret = ensoUninstallMBR(); if (ret < 0) { printf("failed\n"); return -1; } printf("ok!\n"); printf("Cleaning up payload blocks... "); ret = ensoCleanUpBlocks(); if (ret < 0) { printf("failed\n"); return -1; } printf("ok!\n"); printf("Deleting boot config... "); sceIoRemove("ur0:tai/boot_config.txt"); printf("ok!\n"); return 0; } int do_reinstall_config(void) { int ret = 0; printf("Writing config... "); ret = ensoWriteConfig(); if (ret < 0) { printf("failed\n"); return -1; } printf("ok!\n"); return 0; } int check_build(void) { if (BUILD_PERSONALIZED) { char right_cid[16]; char cur_cid[16]; for (int i = 0; i < 16; i++) { right_cid[i] = check_cid[i] ^ 0xAA; // super leet encryption } _vshSblAimgrGetConsoleId(cur_cid); if (memcmp(cur_cid, right_cid, 16) == 0) { return 1; } else { return 0; } } else { return 1; } } int check_safe_mode(void) { if (sceIoDevctl("ux0:", 0x3001, NULL, 0, NULL, 0) == 0x80010030) { return 1; } else { return 0; } } int check_henkaku(void) { int fd; if ((fd = sceIoOpen("ur0:tai/taihen.skprx", SCE_O_RDONLY, 0)) < 0) { return 0; } sceIoClose(fd); if ((fd = sceIoOpen("ur0:tai/henkaku.skprx", SCE_O_RDONLY, 0)) < 0) { return 0; } sceIoClose(fd); return 1; } int main(int argc, char *argv[]) { (void)argc; (void)argv; int should_reboot = 0; int ret = 0; psvDebugScreenInit(); if (!check_build()) { return 0; } printf("Built On: %s\n\n", BUILD_DATE); if (check_safe_mode()) { printf("Please disable HENkaku Safe Mode from Settings before running this installer.\n\n"); press_exit(); } if (!check_henkaku()) { printf("Your HENkaku version is too old! Please install R10 from https://henkaku.xyz/go/ (not the offline installer!)\n\n"); press_exit(); } #if BUILD_PERSONALIZED printf("Please visit https://enso.henkaku.xyz/beta/ for installation instructions.\n\n"); uint32_t sequence[] = { SCE_CTRL_CROSS, SCE_CTRL_TRIANGLE, SCE_CTRL_SQUARE, SCE_CTRL_CIRCLE }; for (size_t i = 0; i < sizeof(sequence)/sizeof(*sequence); ++i) { if (get_key() != sequence[i]) press_exit(); } #endif printf("This software will make PERMANENT modifications to your Vita. If anything goes wrong, \n" "there is NO RECOVERY (not even with a hardware flasher). The creators provide this \n" "tool \"as is\", without warranty of any kind, express or implied and cannot be held \n" "liable for any damage done.\n\n"); printf("Press CIRCLE to accept these terms or any other key to not accept.\n\n"); if (get_key() != SCE_CTRL_CIRCLE) { press_exit(); } ret = load_helper(); if (ret < 0) goto cleanup; printf("Options:\n\n"); printf(" CROSS Install/reinstall the hack.\n"); printf(" TRIANGLE Uninstall the hack.\n"); printf(" SQUARE Fix boot configuration (choose this if taiHEN isn't loading on boot).\n"); printf(" CIRCLE Exit without doing anything.\n\n"); again: switch (get_key()) { case SCE_CTRL_CROSS: ret = do_install(); should_reboot = 1; break; case SCE_CTRL_TRIANGLE: ret = do_uninstall(); should_reboot = 1; break; case SCE_CTRL_SQUARE: ret = do_reinstall_config(); break; case SCE_CTRL_CIRCLE: break; default: goto again; } if (ret < 0) { printf("\nAn error has occurred.\n"); printf("The log file can be found at ux0:data/enso.log\n\n"); should_reboot = 0; } else { printf("Success.\n\n"); } cleanup: stop_helper(); if (should_reboot) { press_reboot(); } else { press_exit(); } return 0; } ================================================ FILE: installer/src/sha256.c ================================================ /********************************************************************* * Filename: sha256.c * Author: Brad Conte (brad AT bradconte.com) * Copyright: * Disclaimer: This code is presented "as is" without any guarantees. * Details: Implementation of the SHA-256 hashing algorithm. SHA-256 is one of the three algorithms in the SHA2 specification. The others, SHA-384 and SHA-512, are not offered in this implementation. Algorithm specification can be found here: * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf This implementation uses little endian byte order. *********************************************************************/ /*************************** HEADER FILES ***************************/ #include #include #include "sha256.h" /****************************** MACROS ******************************/ #define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) #define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) #define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) #define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) #define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) #define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) #define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) /**************************** VARIABLES *****************************/ static const WORD k[64] = { 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 }; /*********************** FUNCTION DEFINITIONS ***********************/ void sha256_transform(SHA256_CTX *ctx, const BYTE data[]) { WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; for (i = 0, j = 0; i < 16; ++i, j += 4) m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); for ( ; i < 64; ++i) m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; a = ctx->state[0]; b = ctx->state[1]; c = ctx->state[2]; d = ctx->state[3]; e = ctx->state[4]; f = ctx->state[5]; g = ctx->state[6]; h = ctx->state[7]; for (i = 0; i < 64; ++i) { t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; t2 = EP0(a) + MAJ(a,b,c); h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2; } ctx->state[0] += a; ctx->state[1] += b; ctx->state[2] += c; ctx->state[3] += d; ctx->state[4] += e; ctx->state[5] += f; ctx->state[6] += g; ctx->state[7] += h; } void sha256_init(SHA256_CTX *ctx) { ctx->datalen = 0; ctx->bitlen = 0; ctx->state[0] = 0x6a09e667; ctx->state[1] = 0xbb67ae85; ctx->state[2] = 0x3c6ef372; ctx->state[3] = 0xa54ff53a; ctx->state[4] = 0x510e527f; ctx->state[5] = 0x9b05688c; ctx->state[6] = 0x1f83d9ab; ctx->state[7] = 0x5be0cd19; } void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len) { WORD i; for (i = 0; i < len; ++i) { ctx->data[ctx->datalen] = data[i]; ctx->datalen++; if (ctx->datalen == 64) { sha256_transform(ctx, ctx->data); ctx->bitlen += 512; ctx->datalen = 0; } } } void sha256_final(SHA256_CTX *ctx, BYTE hash[]) { WORD i; i = ctx->datalen; // Pad whatever data is left in the buffer. if (ctx->datalen < 56) { ctx->data[i++] = 0x80; while (i < 56) ctx->data[i++] = 0x00; } else { ctx->data[i++] = 0x80; while (i < 64) ctx->data[i++] = 0x00; sha256_transform(ctx, ctx->data); memset(ctx->data, 0, 56); } // Append to the padding the total message's length in bits and transform. ctx->bitlen += ctx->datalen * 8; ctx->data[63] = ctx->bitlen; ctx->data[62] = ctx->bitlen >> 8; ctx->data[61] = ctx->bitlen >> 16; ctx->data[60] = ctx->bitlen >> 24; ctx->data[59] = ctx->bitlen >> 32; ctx->data[58] = ctx->bitlen >> 40; ctx->data[57] = ctx->bitlen >> 48; ctx->data[56] = ctx->bitlen >> 56; sha256_transform(ctx, ctx->data); // Since this implementation uses little endian byte ordering and SHA uses big endian, // reverse all the bytes when copying the final state to the output hash. for (i = 0; i < 4; ++i) { hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; } } ================================================ FILE: installer/src/sha256.h ================================================ /********************************************************************* * Filename: sha256.h * Author: Brad Conte (brad AT bradconte.com) * Copyright: * Disclaimer: This code is presented "as is" without any guarantees. * Details: Defines the API for the corresponding SHA1 implementation. *********************************************************************/ #ifndef SHA256_H #define SHA256_H /*************************** HEADER FILES ***************************/ #include /****************************** MACROS ******************************/ #define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest /**************************** DATA TYPES ****************************/ typedef unsigned char BYTE; // 8-bit byte typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines typedef struct { BYTE data[64]; WORD datalen; unsigned long long bitlen; WORD state[8]; } SHA256_CTX; /*********************** FUNCTION DECLARATIONS **********************/ void sha256_init(SHA256_CTX *ctx); void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len); void sha256_final(SHA256_CTX *ctx, BYTE hash[]); #endif // SHA256_H ================================================ FILE: installer/src/user.c ================================================ #include #include "enso.h" // user library as a workaround to load kernel module at runtime int ensoCheckOs0(void) { return k_ensoCheckOs0(); } int ensoCheckMBR(void) { return k_ensoCheckMBR(); } int ensoCheckBlocks(void) { return k_ensoCheckBlocks(); } int ensoWriteConfig(void) { return k_ensoWriteConfig(); } int ensoWriteBlocks(void) { return k_ensoWriteBlocks(); } int ensoWriteMBR(void) { return k_ensoWriteMBR(); } int ensoCheckRealMBR(void) { return k_ensoCheckRealMBR(); } int ensoUninstallMBR(void) { return k_ensoUninstallMBR(); } int ensoCleanUpBlocks(void) { return k_ensoCleanUpBlocks(); } int module_start(int args, void *argv) { (void)args; (void)argv; return SCE_KERNEL_START_SUCCESS; } void _start() __attribute__ ((weak, alias ("module_start"))); int module_stop() { return SCE_KERNEL_STOP_SUCCESS; } ================================================ FILE: installer/src/user_exports.yml ================================================ emmc_helper_user: attributes: 0 version: major: 1 minor: 1 main: start: module_start stop: module_stop modules: emmc_helper_user: functions: - ensoCheckOs0 - ensoCheckMBR - ensoCheckBlocks - ensoWriteConfig - ensoWriteBlocks - ensoWriteMBR - ensoCheckRealMBR - ensoUninstallMBR - ensoCleanUpBlocks ================================================ FILE: installer/src/version.h.in ================================================ #pragma once #define BUILD_DATE "${BUILD_DATE}" #define BUILD_CID {${BUILD_CID}} #define BUILD_PERSONALIZED (${PERSONALIZED}) ================================================ FILE: logo.h ================================================ static const unsigned char logo_data[] = { 0x1f, 0x8b, 0x08, 0x00, 0x6f, 0xed, 0x0f, 0x59, 0x02, 0x03, 0xed, 0xdc, 0x41, 0x6e, 0x03, 0x21, 0x10, 0x44, 0x51, 0xdf, 0xff, 0xd2, 0xce, 0x09, 0x22, 0xdb, 0x63, 0x18, 0x37, 0x55, 0xef, 0x49, 0xb3, 0x0c, 0xd0, 0xec, 0xbe, 0x48, 0xf2, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x3d, 0x9f, 0xcf, 0x97, 0x1f, 0x00, 0x00, 0x00, 0x24, 0xf6, 0xae, 0x16, 0x06, 0x00, 0x00, 0xa0, 0xb9, 0x7d, 0x75, 0x30, 0x00, 0x00, 0x00, 0x2d, 0xdd, 0xab, 0x81, 0x01, 0x00, 0x00, 0x68, 0x6a, 0x5f, 0x0d, 0x0c, 0x00, 0x00, 0x40, 0x4b, 0xfb, 0x6a, 0x60, 0x00, 0x00, 0x00, 0x5a, 0xda, 0x57, 0x03, 0x03, 0x00, 0x00, 0xd0, 0xd2, 0xbe, 0x1a, 0x18, 0x00, 0x00, 0x00, 0xfd, 0x0b, 0x00, 0x00, 0x00, 0x39, 0xed, 0xab, 0x81, 0x01, 0x00, 0x00, 0x68, 0xea, 0x5f, 0x0d, 0x0c, 0x00, 0x00, 0x40, 0x43, 0xfb, 0xea, 0x5f, 0x00, 0x00, 0x00, 0xf4, 0x2f, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0x38, 0xa5, 0x7d, 0x35, 0x30, 0x00, 0x00, 0x00, 0xfa, 0x17, 0x00, 0x00, 0x00, 0xf4, 0x2f, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0xd0, 0xbf, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0xfd, 0x0b, 0x00, 0x00, 0x80, 0xfe, 0xd5, 0xbf, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0xfd, 0x0b, 0x00, 0x00, 0x80, 0x06, 0xd6, 0xbe, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0xd0, 0xbf, 0x00, 0x00, 0x00, 0x70, 0x76, 0x03, 0x03, 0x00, 0x00, 0x40, 0x7a, 0xff, 0x02, 0x00, 0x00, 0x40, 0x7a, 0x03, 0x03, 0x00, 0x00, 0x80, 0xfe, 0x05, 0x00, 0x00, 0x80, 0xf3, 0x1b, 0x18, 0x00, 0x00, 0x00, 0xd2, 0x1b, 0x18, 0x00, 0x00, 0x00, 0xd2, 0x1b, 0x18, 0x00, 0x00, 0x00, 0xd2, 0x1b, 0x18, 0x00, 0x00, 0x00, 0x92, 0x3b, 0x18, 0x00, 0x00, 0x00, 0x92, 0x3b, 0x18, 0x00, 0x00, 0x00, 0xd2, 0x1b, 0x18, 0x00, 0x00, 0x00, 0xf4, 0x2f, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0xd0, 0xbf, 0x00, 0x00, 0x00, 0xa0, 0x7f, 0x01, 0x00, 0x00, 0x40, 0xff, 0x02, 0x00, 0x00, 0x80, 0xfe, 0x05, 0x00, 0x00, 0x00, 0xfd, 0x0b, 0x00, 0x00, 0x80, 0xfe, 0xd5, 0xbf, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0xd0, 0xbf, 0x00, 0x00, 0x00, 0xa0, 0x7f, 0x01, 0x00, 0x00, 0x40, 0xff, 0x02, 0x00, 0x00, 0x80, 0xfe, 0x05, 0x00, 0x00, 0x00, 0xfd, 0x0b, 0x00, 0x00, 0x00, 0xfa, 0x17, 0x00, 0x00, 0x00, 0xfd, 0xab, 0x7f, 0x01, 0x00, 0x00, 0xd0, 0xbf, 0xfa, 0x17, 0x00, 0x00, 0x00, 0xfd, 0x0b, 0x00, 0x00, 0x00, 0xfa, 0x17, 0x00, 0x00, 0x00, 0xf4, 0x2f, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0xd0, 0xbf, 0x00, 0x00, 0x00, 0xa0, 0x7f, 0x01, 0x00, 0x00, 0x40, 0xff, 0x02, 0x00, 0x00, 0xd0, 0xdd, 0xb8, 0x57, 0x3f, 0x00, 0x00, 0x00, 0x48, 0x6d, 0x5e, 0x3d, 0x0c, 0x00, 0x00, 0x40, 0x6b, 0xf7, 0x6a, 0x60, 0x00, 0x00, 0x00, 0x5a, 0xba, 0x57, 0x07, 0x03, 0x00, 0x00, 0xd0, 0xd4, 0xbd, 0x3a, 0x18, 0x00, 0x00, 0x80, 0xb6, 0xf6, 0xd5, 0xc0, 0x00, 0x00, 0x00, 0xb4, 0xb4, 0xaf, 0x06, 0x06, 0x00, 0x00, 0xa0, 0xa1, 0x7b, 0x75, 0x30, 0x00, 0x00, 0x00, 0x6d, 0xed, 0xab, 0x81, 0x01, 0x00, 0x00, 0x68, 0x69, 0x5f, 0x0d, 0x0c, 0x00, 0x00, 0x40, 0x4b, 0xfb, 0x6a, 0x60, 0x00, 0x00, 0x00, 0xa6, 0xb6, 0xa6, 0x06, 0x06, 0x00, 0x00, 0x60, 0x62, 0xfb, 0x3a, 0x2b, 0x00, 0x00, 0x00, 0xa9, 0xfd, 0xeb, 0xdc, 0x00, 0x00, 0x00, 0x68, 0x5f, 0xe7, 0x07, 0x00, 0x00, 0x40, 0x3b, 0x9a, 0x03, 0x00, 0x00, 0x80, 0xc9, 0xdd, 0xa8, 0xe5, 0x01, 0x00, 0x00, 0xd0, 0xbe, 0x66, 0x02, 0x00, 0x00, 0xe0, 0xec, 0x56, 0xd4, 0xf5, 0x00, 0x00, 0x00, 0x68, 0x5f, 0xf3, 0x01, 0x00, 0x00, 0xa0, 0x0d, 0xcd, 0x09, 0x00, 0x00, 0xc0, 0xe4, 0x2e, 0x34, 0x2b, 0x00, 0x00, 0x00, 0xe9, 0x4d, 0x68, 0x5e, 0x00, 0x00, 0x00, 0xd2, 0x5b, 0xb0, 0xb1, 0x7f, 0x35, 0x30, 0x00, 0x00, 0x40, 0x5f, 0xff, 0x9a, 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x68, 0x6e, 0x00, 0x00, 0x00, 0xce, 0xef, 0x40, 0xb3, 0x03, 0x00, 0x00, 0xa0, 0x01, 0xcd, 0x0e, 0x00, 0x00, 0x80, 0x06, 0x3c, 0x7d, 0x76, 0x0d, 0x0c, 0x00, 0x00, 0xa0, 0xff, 0xcc, 0x0f, 0x00, 0x00, 0x80, 0xfe, 0x33, 0x3f, 0x00, 0x00, 0x00, 0xfa, 0xcf, 0xfc, 0x00, 0x00, 0x00, 0xe8, 0x3f, 0xf3, 0x03, 0x00, 0x00, 0xa0, 0xff, 0xcc, 0x0f, 0x00, 0x00, 0xc0, 0xea, 0xfe, 0x73, 0x07, 0xfa, 0x17, 0x00, 0x00, 0x40, 0xfb, 0xb9, 0x03, 0x00, 0x00, 0x00, 0xb4, 0x9f, 0x3b, 0x00, 0x00, 0x00, 0x40, 0xfb, 0xb9, 0x03, 0x00, 0x00, 0x00, 0xb4, 0x9f, 0x3b, 0x00, 0x00, 0x00, 0x40, 0xfb, 0xb9, 0x03, 0x00, 0x00, 0x00, 0xd6, 0xb6, 0x5f, 0x6a, 0xff, 0xe9, 0x5f, 0x00, 0x00, 0x00, 0xfd, 0xab, 0x7f, 0xf5, 0x2f, 0x00, 0x00, 0x80, 0xfe, 0x35, 0x3f, 0x00, 0x00, 0x00, 0xfa, 0xcf, 0xfc, 0x00, 0x00, 0x00, 0xe8, 0x3f, 0xf3, 0x03, 0x00, 0x00, 0xa0, 0xff, 0xcc, 0x0f, 0x00, 0x00, 0xc0, 0x2f, 0x1b, 0x50, 0xff, 0x02, 0x00, 0x00, 0xa0, 0x7f, 0xcd, 0x0e, 0x00, 0x00, 0x80, 0x06, 0x34, 0x3b, 0x00, 0x00, 0x00, 0xa7, 0x34, 0x60, 0x52, 0x07, 0xfa, 0xdd, 0x67, 0x00, 0x00, 0x00, 0xfd, 0xab, 0x7f, 0xf5, 0x2f, 0x00, 0x00, 0x40, 0x7b, 0xff, 0x26, 0xb4, 0x60, 0xe3, 0xcc, 0x00, 0x00, 0x00, 0x3c, 0xf4, 0xaf, 0xf6, 0x05, 0x00, 0x00, 0xd0, 0xbf, 0x61, 0x4d, 0xe8, 0xed, 0x17, 0x00, 0x00, 0x40, 0xff, 0xa6, 0x77, 0x61, 0xcb, 0x9c, 0x00, 0x00, 0x00, 0xf4, 0xb6, 0xa1, 0xf6, 0x05, 0x00, 0x00, 0x40, 0xff, 0xea, 0x5f, 0x00, 0x00, 0x00, 0x0d, 0x7c, 0x7e, 0x23, 0x6a, 0x5f, 0x00, 0x00, 0x00, 0x56, 0x74, 0xe2, 0xe4, 0x5e, 0x4c, 0x9b, 0x07, 0x00, 0x00, 0x00, 0x0d, 0x9c, 0xde, 0xf2, 0x00, 0x00, 0x00, 0x68, 0x47, 0xed, 0x0b, 0x00, 0x00, 0x40, 0x53, 0x43, 0x6a, 0x5f, 0x00, 0x00, 0x00, 0xee, 0x6e, 0xc9, 0xbb, 0x9a, 0x72, 0xd5, 0x39, 0xf5, 0x2f, 0x00, 0x00, 0x80, 0xfe, 0x9d, 0xd8, 0x96, 0xd3, 0xcf, 0x07, 0x00, 0x00, 0x40, 0x6f, 0x03, 0x4f, 0xfd, 0x00, 0x00, 0x00, 0x40, 0xfb, 0x02, 0x00, 0x00, 0xa0, 0x81, 0xb5, 0x2f, 0x00, 0x00, 0x00, 0x1a, 0x58, 0xfb, 0x02, 0x00, 0x00, 0xa0, 0x83, 0x35, 0x30, 0x00, 0x00, 0x00, 0xfa, 0x57, 0x03, 0x03, 0x00, 0x00, 0xa0, 0x83, 0xf5, 0x2f, 0x00, 0x00, 0x00, 0x3a, 0x58, 0x03, 0x03, 0x00, 0x00, 0xa0, 0x81, 0xf5, 0x2f, 0x00, 0x00, 0x00, 0x19, 0x1d, 0x7c, 0xe5, 0x2c, 0x00, 0x00, 0x00, 0x30, 0xbd, 0x87, 0x57, 0xed, 0x0d, 0x00, 0x00, 0x00, 0x13, 0xba, 0x78, 0xf7, 0x3e, 0x00, 0x00, 0x00, 0xd0, 0xd2, 0xda, 0x00, 0x00, 0x00, 0xd0, 0xd0, 0xbf, 0x1a, 0x18, 0x00, 0x00, 0x80, 0x96, 0x06, 0x06, 0x00, 0x00, 0x00, 0x0d, 0x0c, 0x00, 0x00, 0x00, 0x79, 0xfd, 0xab, 0x8f, 0x01, 0x00, 0x00, 0x48, 0x6f, 0x60, 0xef, 0xc5, 0x00, 0x00, 0x00, 0x68, 0x60, 0x1d, 0x0c, 0x00, 0x00, 0x40, 0x6f, 0xff, 0x6a, 0x60, 0x00, 0x00, 0x00, 0x34, 0x30, 0x00, 0x00, 0x00, 0x64, 0xf5, 0xaf, 0x06, 0x06, 0x00, 0x00, 0xa0, 0xa5, 0x7f, 0x35, 0x30, 0x00, 0x00, 0x00, 0x0d, 0xed, 0xab, 0x81, 0x01, 0x00, 0x00, 0x38, 0xa1, 0x7f, 0xef, 0x5c, 0x0b, 0x00, 0x00, 0x00, 0xee, 0x6e, 0xdf, 0x29, 0xeb, 0x02, 0x00, 0x00, 0xc0, 0xae, 0xfe, 0x9d, 0xb8, 0x36, 0x00, 0x00, 0x00, 0x4c, 0xea, 0x53, 0x0d, 0x0c, 0x00, 0x00, 0xc0, 0xf4, 0xfe, 0x3d, 0x6d, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0xb4, 0x49, 0xf5, 0x2f, 0x00, 0x00, 0x00, 0x0d, 0xfd, 0x7b, 0xfa, 0x7e, 0x00, 0x00, 0x00, 0xa0, 0x7f, 0x01, 0x00, 0x00, 0xd0, 0xbf, 0xfa, 0x17, 0x00, 0x00, 0x80, 0x8e, 0xfe, 0x4d, 0xda, 0x13, 0x00, 0x00, 0x00, 0xfd, 0xab, 0x7f, 0x01, 0x00, 0x00, 0x68, 0xee, 0xdf, 0x5d, 0x3d, 0xaa, 0x7f, 0x01, 0x00, 0x00, 0x48, 0xef, 0x5f, 0x7f, 0xff, 0x0b, 0x00, 0x00, 0x80, 0xfe, 0xd5, 0xbf, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0x48, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0x48, 0x68, 0x60, 0x6f, 0xbf, 0x00, 0x00, 0x00, 0x4c, 0xee, 0xdf, 0x15, 0x6d, 0x7a, 0xc7, 0x1e, 0x00, 0x00, 0x00, 0xf0, 0x4d, 0x97, 0x7e, 0xdb, 0xa7, 0xda, 0x17, 0x00, 0x00, 0x80, 0x53, 0xda, 0xf7, 0x6a, 0xa7, 0xee, 0x6e, 0x6b, 0x00, 0x00, 0x00, 0x58, 0xd9, 0xbd, 0x9f, 0xf6, 0xea, 0x1d, 0xef, 0xca, 0x00, 0x00, 0x00, 0xb0, 0xb3, 0x7d, 0x57, 0x7e, 0x00, 0x00, 0x00, 0x90, 0xde, 0xbe, 0xfa, 0x17, 0x00, 0x00, 0x80, 0x77, 0x3b, 0x56, 0xfb, 0x02, 0x00, 0x00, 0x90, 0xda, 0xbc, 0x9f, 0x36, 0xa5, 0xf6, 0x05, 0x00, 0x00, 0x20, 0xa5, 0x7b, 0x77, 0xb5, 0xa9, 0xee, 0x05, 0x00, 0x00, 0x20, 0xad, 0x7b, 0x77, 0xbf, 0x1f, 0x03, 0x00, 0x00, 0xc0, 0xd4, 0xf6, 0x5d, 0x71, 0x2e, 0x00, 0x00, 0x00, 0x98, 0xd0, 0xbe, 0xab, 0xcf, 0x0a, 0x00, 0x00, 0x00, 0x29, 0xed, 0x0b, 0x00, 0x00, 0x00, 0xa7, 0xf4, 0x2f, 0x00, 0x00, 0x00, 0x4c, 0x6d, 0xdf, 0x15, 0xed, 0x0c, 0x00, 0x00, 0x00, 0x93, 0xfb, 0xf7, 0x8e, 0x35, 0x00, 0x00, 0x00, 0x60, 0x72, 0xfb, 0x6a, 0x60, 0x00, 0x00, 0x00, 0x4e, 0xef, 0xdf, 0x5f, 0xaf, 0x07, 0x00, 0x00, 0x00, 0x13, 0xfb, 0xf7, 0xd5, 0x9a, 0x00, 0x00, 0x00, 0x30, 0xad, 0x7f, 0x27, 0xad, 0x09, 0x00, 0x00, 0x00, 0xfa, 0x17, 0x00, 0x00, 0x00, 0xf4, 0x2f, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0xda, 0xfb, 0xd7, 0xff, 0x7f, 0x06, 0x00, 0x00, 0x40, 0xff, 0xea, 0x5f, 0x00, 0x00, 0x00, 0x3a, 0x1b, 0xf8, 0xd5, 0x3a, 0xfa, 0x17, 0x00, 0x00, 0x80, 0xc9, 0xfd, 0xfb, 0x4e, 0xb7, 0x6a, 0x5f, 0x00, 0x00, 0x00, 0x12, 0xfa, 0xf7, 0xbf, 0x8e, 0xbd, 0xfa, 0x73, 0x00, 0x00, 0x00, 0x70, 0x42, 0x03, 0x7f, 0xd3, 0xcc, 0x00, 0x00, 0x00, 0x90, 0xd8, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x7f, 0x01, 0x00, 0x00, 0xe0, 0xec, 0x0e, 0x06, 0x00, 0x00, 0x80, 0xf4, 0x06, 0x06, 0x00, 0x00, 0x80, 0xf4, 0x06, 0x06, 0x00, 0x00, 0x80, 0xd4, 0x16, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xe7, 0x0f, 0xea, 0x59, 0x23, 0xf7, 0x00, 0xe0, 0x1f, 0x00 }; static const unsigned int logo_len = 2740; ================================================ FILE: nsbl.h ================================================ /* nsbl.h -- imported data from non-secure bootloader * * Copyright (C) 2017 molecule * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ #ifndef NSBL_HEADER #define NSBL_HEADER #include #define NULL ((void *)0) typedef struct SceModuleExports { uint16_t size; // size of this structure; 0x20 for Vita 1.x uint8_t lib_version[2]; // uint16_t attribute; // ? uint16_t num_functions; // number of exported functions uint16_t num_vars; // number of exported variables uint16_t unk; uint32_t num_tls_vars; // number of exported TLS variables? <-- pretty sure wrong // yifanlu uint32_t lib_nid; // NID of this specific export list; one PRX can export several names char *lib_name; // name of the export module uint32_t *nid_table; // array of 32-bit NIDs for the exports, first functions then vars void **entry_table; // array of pointers to exported functions and then variables } __attribute__((packed)) SceModuleExports; #define EI_NIDENT 16 typedef struct Elf32_Ehdr { unsigned char e_ident[EI_NIDENT]; /* ident bytes */ uint16_t e_type; /* file type */ uint16_t e_machine; /* target machine */ uint32_t e_version; /* file version */ uint32_t e_entry; /* start address */ uint32_t e_phoff; /* phdr file offset */ uint32_t e_shoff; /* shdr file offset */ uint32_t e_flags; /* file flags */ uint16_t e_ehsize; /* sizeof ehdr */ uint16_t e_phentsize; /* sizeof phdr */ uint16_t e_phnum; /* number phdrs */ uint16_t e_shentsize; /* sizeof shdr */ uint16_t e_shnum; /* number shdrs */ uint16_t e_shstrndx; /* shdr string index */ } __attribute__((packed)) Elf32_Ehdr; typedef struct { uint32_t p_type; /* entry type */ uint32_t p_offset; /* file offset */ uint32_t p_vaddr; /* virtual address */ uint32_t p_paddr; /* physical address */ uint32_t p_filesz; /* file size */ uint32_t p_memsz; /* memory size */ uint32_t p_flags; /* entry flags */ uint32_t p_align; /* memory/file alignment */ } __attribute__((packed)) Elf32_Phdr; typedef struct SceModuleSelfSectionInfo { uint64_t offset; uint64_t size; uint32_t compressed; // 2=compressed uint32_t unknown1; uint32_t encrypted; // 1=encrypted uint32_t unknown2; } __attribute__((packed)) SceModuleSelfSectionInfo; #ifdef FW_365 // firmware specific internal structures typedef struct SceBootArgs { uint16_t version; uint16_t size; uint32_t fw_version; uint32_t ship_version; uint32_t field_C; uint32_t field_10; uint32_t field_14; uint32_t field_18; uint32_t field_1C; uint32_t field_20; uint32_t field_24; uint32_t field_28; uint8_t debug_flags[8]; uint32_t field_34; uint32_t field_38; uint32_t field_3C; uint32_t field_40; uint32_t field_44; uint32_t field_48; uint32_t aslr_seed; uint32_t field_50; uint32_t field_54; uint32_t field_58; uint32_t field_5C; uint32_t dram_base; uint32_t dram_size; uint32_t field_68; uint32_t boot_type_indicator_1; uint8_t serial[0x10]; uint32_t secure_kernel_enp_addr; uint32_t secure_kernel_enp_size; uint32_t field_88; uint32_t field_8C; uint32_t kprx_auth_sm_self_addr; uint32_t kprx_auth_sm_self_size; uint32_t prog_rvk_srvk_addr; uint32_t prog_rvk_srvk_size; uint16_t model; uint16_t device_type; uint16_t device_config; uint16_t retail_type; uint32_t field_A8; uint32_t field_AC; uint8_t session_id[0x10]; uint32_t field_C0; uint32_t boot_type_indicator_2; uint32_t field_C8; uint32_t field_CC; uint32_t resume_context_addr; uint32_t field_D4; uint32_t field_D8; uint32_t field_DC; uint32_t field_E0; uint32_t field_E4; uint32_t field_E8; uint32_t field_EC; uint32_t field_F0; uint32_t field_F4; uint32_t bootldr_revision; uint32_t magic; uint8_t session_key[0x20]; uint8_t unused[0xE0]; } __attribute__((packed)) SceBootArgs; typedef struct SceSysrootContext { uint32_t reserved[27]; SceBootArgs *boot_args; } __attribute__((packed)) SceSysrootContext; typedef struct SceModuleLoadList { const char *filename; } __attribute__((packed)) SceModuleLoadList; typedef struct SceObject { uint32_t field_0; void *obj_data; char data[]; } __attribute__((packed)) SceObject; typedef struct SceModuleSegment { uint32_t p_filesz; uint32_t p_memsz; uint16_t p_flags; uint16_t p_align_bits; void *buf; int32_t buf_blkid; } __attribute__((packed)) SceModuleSegment; typedef struct SceModuleObject { struct SceModuleObject *next; uint16_t exeflags; uint8_t status; uint8_t field_7; uint32_t min_sysver; int32_t modid; int32_t user_modid; int32_t pid; uint16_t modattribute; uint16_t modversion; uint32_t modid_name; SceModuleExports *ent_top_user; SceModuleExports *ent_end_user; uint32_t stub_start_user; uint32_t stub_end_user; uint32_t module_nid; uint32_t modinfo_field_38; uint32_t modinfo_field_3C; uint32_t modinfo_field_40; uint32_t exidx_start_user; uint32_t exidx_end_user; uint32_t extab_start_user; uint32_t extab_end_user; uint16_t num_export_libs; uint16_t num_import_libs; uint32_t field_54; uint32_t field_58; uint32_t field_5C; uint32_t field_60; void *imports; const char *path; uint32_t total_loadable; struct SceModuleSegment segments[3]; void *type_6FFFFF00_buf; uint32_t type_6FFFFF00_bufsz; void *module_start; void *module_init; void *module_stop; uint32_t field_C0; uint32_t field_C4; uint32_t field_C8; uint32_t field_CC; uint32_t field_D0; struct SceObject *prev_loaded; } __attribute__((packed)) SceModuleObject; typedef struct SceKernelAllocMemBlockKernelOpt { uint32_t size; uint32_t field_4; uint32_t attr; uint32_t field_C; uint32_t paddr; uint32_t alignment; uint32_t field_18; uint32_t field_1C; uint32_t mirror_blkid; int32_t pid; uint32_t field_28; uint32_t field_2C; uint32_t field_30; uint32_t field_34; uint32_t field_38; uint32_t field_3C; uint32_t field_40; uint32_t field_44; uint32_t field_48; uint32_t field_4C; uint32_t field_50; uint32_t field_54; } __attribute__((packed)) SceKernelAllocMemBlockKernelOpt; typedef struct SceModuleDecryptContext { void *header; uint32_t header_len; Elf32_Ehdr *elf_ehdr; Elf32_Phdr *elf_phdr; uint8_t type; uint8_t init_completed; uint8_t field_12; uint8_t field_13; SceModuleSelfSectionInfo *section_info; void *header_buffer; uint32_t sbl_ctx; uint32_t field_20; uint32_t fd; int32_t pid; uint32_t max_size; } __attribute__((packed)) SceModuleDecryptContext; // firmware specific function offsets #ifdef DEBUG static int (*printf)(const char *fmt, ...) = (void*)0x51013919; #else #define printf(...) #endif static void *(*memset)(void *dst, int ch, int sz) = (void*)0x51013C41; static void *(*memcpy)(void *dst, const void *src, int sz) = (void *)0x51013BC1; static void *(*memmove)(void *dst, const void *src, int sz) = (void *)0x5102152D; static void (*clean_dcache)(void *dst, int len) = (void*)0x510146DD; static int (*read_block_os0)() = (void*)0x510010FD; static void (*flush_icache)() = (void*)0x51014691; static int (*strncmp)(const char *s1, const char *s2, int len) = (void *)0x51013CA0; static SceObject *(*get_obj_for_uid)(int uid) = (void *)0x51017785; static int (*module_load)(const SceModuleLoadList *list, int *uids, int count, int) = (void *)0x51001551; static int (*sceKernelAllocMemBlock)(const char *name, int type, int size, SceKernelAllocMemBlockKernelOpt *opt) = (void *)0x51007161; static int (*sceKernelGetMemBlockBase)(int32_t uid, void **basep) = (void *)0x510057E1; static int (*sceKernelRemapBlock)(int32_t uid, int type) = (void *)0x51007171; // firmware specific patch offsets static SceBootArgs *boot_args = (void *)0x51167528; static SceSysrootContext **sysroot_ctx_ptr = (void *)0x51138A3C; static void **module_load_func_ptr = (void *)0x510277A8; // sysstate patches #define SCEDISPLAY_LOGO_OFFSET (0x8990) #define SBLAUTHMGR_OFFSET_PATCH_ARG (168) #define SYSSTATE_IS_MANUFACTURING_MODE_OFFSET (0x1500) #define SYSSTATE_IS_DEV_MODE_OFFSET (0xE28) #define SYSSTATE_RET_CHECK_BUG (0xD92) static const uint8_t sysstate_ret_patch[] = {0x13, 0x22, 0xc8, 0xf2, 0x01, 0x02}; #define SYSSTATE_SD0_STRING (0x2448) static const char ur0_path[] = "ur0:"; #define SYSSTATE_SD0_PSP2CONFIG_STRING (0x2396) static const char ur0_psp2config_path[] = "ur0:tai/boot_config.txt"; #define SYSSTATE_FINAL_CALL (0x130) #define SYSSTATE_FINAL (0x18C9) #else #error "No firmware defined or firmware not supported." #endif #endif ================================================ FILE: second.c ================================================ /* second.c -- bootloader patches * * Copyright (C) 2017 molecule * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ #include #include "nsbl.h" #include "logo.h" #define unlikely(expr) __builtin_expect(!!(expr), 0) #define DACR_OFF(stmt) \ do { \ unsigned prev_dacr; \ __asm__ volatile( \ "mrc p15, 0, %0, c3, c0, 0 \n" \ : "=r" (prev_dacr) \ ); \ __asm__ volatile( \ "mcr p15, 0, %0, c3, c0, 0 \n" \ : : "r" (0xFFFF0000) \ ); \ stmt; \ __asm__ volatile( \ "mcr p15, 0, %0, c3, c0, 0 \n" \ : : "r" (prev_dacr) \ ); \ } while (0) #define INSTALL_HOOK_THUMB(func, addr) \ do { \ unsigned *target; \ target = (unsigned*)(addr); \ *target++ = 0xC004F8DF; /* ldr.w ip, [pc, #4] */ \ *target++ = 0xBF004760; /* bx ip; nop */ \ *target = (unsigned)func; \ } while (0) #define INSTALL_RET_THUMB(addr, ret) \ do { \ unsigned *target; \ target = (unsigned*)(addr); \ *target = 0x47702000 | (ret); /* movs r0, #ret; bx lr */ \ } while (0) // sdstor restore globals static int (*sdstor_read_sector_async)(void* ctx, int sector, char* buffer, int nSectors) = NULL; static int (*sdstor_read_sector)(void* ctx, int sector, char* buffer, int nSectors) = NULL; static void *(*get_sd_context_part_validate_mmc)(int sd_ctx_index) = NULL; // debug globals #ifdef DEBUG static int (*set_crash_flag)(int) = NULL; #endif // sigpatch globals static int g_sigpatch_disabled = 0; static int g_homebrew_decrypt = 0; static int (*sbl_parse_header)(uint32_t ctx, const void *header, int len, void *args) = NULL; static int (*sbl_set_up_buffer)(uint32_t ctx, int segidx) = NULL; static int (*sbl_decrypt)(uint32_t ctx, void *buf, int sz) = NULL; // sysstate final function static void __attribute__((noreturn)) (*sysstate_final)(void) = NULL; // utility functions #if 0 static int hex_dump(const char *addr, unsigned int size) { unsigned int i; for (i = 0; i < (size >> 4); i++) { printf("0x%08X: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", addr, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]); addr += 0x10; } return 0; } #endif static void **get_export_func(SceModuleObject *mod, uint32_t lib_nid, uint32_t func_nid) { for (SceModuleExports *ent = mod->ent_top_user; ent != mod->ent_end_user; ent++) { if (ent->lib_nid == lib_nid) { for (int i = 0; i < ent->num_functions; i++) { if (ent->nid_table[i] == func_nid) { return &ent->entry_table[i]; } } } } return NULL; } static int is_safe_mode(void) { SceBootArgs *boot_args = (*sysroot_ctx_ptr)->boot_args; uint32_t v; if (boot_args->debug_flags[7] != 0xFF) { return 1; } v = boot_args->boot_type_indicator_2 & 0x7F; if (v == 0xB || (v == 4 && boot_args->resume_context_addr)) { v = ~boot_args->field_CC; if (((v >> 8) & 0x54) == 0x54 && (v & 0xC0) == 0) { return 1; } else { return 0; } } else if (v == 4) { return 0; } if (v == 0x1F || (uint32_t)(v - 0x18) <= 1) { return 1; } else { return 0; } } static int is_update_mode(void) { SceBootArgs *boot_args = (*sysroot_ctx_ptr)->boot_args; if (boot_args->debug_flags[4] != 0xFF) { return 1; } else { return 0; } } static inline int skip_patches(void) { return is_safe_mode() || is_update_mode(); } // sdif patches for MBR redirection static int sdstor_read_sector_patched(void* ctx, int sector, char* buffer, int nSectors) { int ret; #ifndef NO_MBR_REDIRECT if (unlikely(sector == 0 && nSectors > 0)) { printf("read sector 0 for %d at context 0x%08X\n", nSectors, ctx); if (get_sd_context_part_validate_mmc(0) == ctx) { printf("patching sector 0 read to sector 1\n"); ret = sdstor_read_sector(ctx, 1, buffer, 1); if (ret >= 0 && nSectors > 1) { ret = sdstor_read_sector(ctx, 1, buffer + 0x200, nSectors-1); } return ret; } } #endif return sdstor_read_sector(ctx, sector, buffer, nSectors); } static int sdstor_read_sector_async_patched(void* ctx, int sector, char* buffer, int nSectors) { int ret; #ifndef NO_MBR_REDIRECT if (unlikely(sector == 0 && nSectors > 0)) { printf("read sector async 0 for %d at context 0x%08X\n", nSectors, ctx); if (get_sd_context_part_validate_mmc(0) == ctx) { printf("patching sector 0 read to sector 1\n"); ret = sdstor_read_sector_async(ctx, 1, buffer, 1); if (ret >= 0 && nSectors > 1) { ret = sdstor_read_sector_async(ctx, 1, buffer + 0x200, nSectors-1); } return ret; } } #endif return sdstor_read_sector_async(ctx, sector, buffer, nSectors); } // sigpatches for bootup static int sbl_parse_header_patched(uint32_t ctx, const void *header, int len, void *args) { int ret = sbl_parse_header(ctx, header, len, args); if (unlikely(!g_sigpatch_disabled)) { DACR_OFF( g_homebrew_decrypt = (ret < 0); ); if (g_homebrew_decrypt) { *(uint32_t *)(args + SBLAUTHMGR_OFFSET_PATCH_ARG) = 0x40; ret = 0; } } return ret; } static int sbl_set_up_buffer_patched(uint32_t ctx, int segidx) { if (unlikely(!g_sigpatch_disabled)) { if (g_homebrew_decrypt) { return 2; // always compressed! } } return sbl_set_up_buffer(ctx, segidx); } static int sbl_decrypt_patched(uint32_t ctx, void *buf, int sz) { if (unlikely(!g_sigpatch_disabled)) { if (g_homebrew_decrypt) { return 0; } } return sbl_decrypt(ctx, buf, sz); } static void __attribute__((noreturn)) sysstate_final_hook(void) { printf("after kernel load! disabling temporary sigpatches\n"); DACR_OFF( g_sigpatch_disabled = 1; ); sysstate_final(); } // main function to hook stuff #define HOOK_EXPORT(name, lib_nid, func_nid) do { \ void **func = get_export_func(mod, lib_nid, func_nid); \ printf(#name ": 0x%08X\n", *func); \ DACR_OFF( \ name = *func; \ *func = name ## _patched; \ ); \ } while (0) #define FIND_EXPORT(name, lib_nid, func_nid) do { \ void **func = get_export_func(mod, lib_nid, func_nid); \ printf(#name ": 0x%08X\n", *func); \ DACR_OFF( \ name = *func; \ ); \ } while (0) static int module_load_patched(const SceModuleLoadList *list, int *uids, int count, int unk) { int ret; SceObject *obj; SceModuleObject *mod; int skip; int sysmem_idx = -1, display_idx = -1, sdif_idx = -1, authmgr_idx = -1, sysstate_idx = -1; skip = skip_patches(); for (int i = 0; i < count; i++) { if (!list[i].filename) { continue; // wtf sony why don't you sanitize input } printf("before start %s\n", list[i].filename); if (!skip && strncmp(list[i].filename, "display.skprx", 13) == 0) { display_idx = i; } else if (strncmp(list[i].filename, "sdif.skprx", 10) == 0) { sdif_idx = i; // never skip MBR redirection patches } else if (!skip && strncmp(list[i].filename, "authmgr.skprx", 13) == 0) { authmgr_idx = i; } else if (!skip && strncmp(list[i].filename, "sysstatemgr.skprx", 17) == 0) { sysstate_idx = i; } #ifdef DEBUG if (strncmp(list[i].filename, "sysmem.skprx", 12) == 0) { sysmem_idx = i; } #endif } ret = module_load(list, uids, count, unk); #ifdef DEBUG // get sysmem functions if (sysmem_idx >= 0) { obj = get_obj_for_uid(uids[sysmem_idx]); if (obj != NULL) { mod = (SceModuleObject *)&obj->data; FIND_EXPORT(set_crash_flag, 0x13D793B7, 0xA465A31A); FIND_EXPORT(printf, 0x88758561, 0x391B74B7); } else { printf("module data invalid for sysmem.skprx!\n"); } } #endif // patch logo if (display_idx >= 0) { obj = get_obj_for_uid(uids[display_idx]); if (obj != NULL) { mod = (SceModuleObject *)&obj->data; printf("logo at offset: %x\n", mod->segments[0].buf + SCEDISPLAY_LOGO_OFFSET); DACR_OFF( memcpy(mod->segments[0].buf + SCEDISPLAY_LOGO_OFFSET, logo_data, logo_len); ); // no cache flush needed because this is just data } else { printf("module data invalid for display.skprx!\n"); } } // patch sdif if (sdif_idx >= 0) { obj = get_obj_for_uid(uids[sdif_idx]); if (obj != NULL) { mod = (SceModuleObject *)&obj->data; HOOK_EXPORT(sdstor_read_sector_async, 0x96D306FA, 0x6F8D529B); HOOK_EXPORT(sdstor_read_sector, 0x96D306FA, 0xB9593652); FIND_EXPORT(get_sd_context_part_validate_mmc, 0x96D306FA, 0x6A71987F); } else { printf("module data invalid for sdif.skprx!\n"); } } // patch authmgr if (authmgr_idx >= 0) { obj = get_obj_for_uid(uids[authmgr_idx]); if (obj != NULL) { mod = (SceModuleObject *)&obj->data; HOOK_EXPORT(sbl_parse_header, 0x7ABF5135, 0xF3411881); HOOK_EXPORT(sbl_set_up_buffer, 0x7ABF5135, 0x89CCDA2C); HOOK_EXPORT(sbl_decrypt, 0x7ABF5135, 0xBC422443); } else { printf("module data invalid for authmgr.skprx!\n"); } } // patch sysstate to load unsigned boot configs if (sysstate_idx >= 0) { obj = get_obj_for_uid(uids[sysstate_idx]); if (obj != NULL) { mod = (SceModuleObject *)&obj->data; DACR_OFF( INSTALL_RET_THUMB(mod->segments[0].buf + SYSSTATE_IS_MANUFACTURING_MODE_OFFSET, 1); *(uint32_t *)(mod->segments[0].buf + SYSSTATE_IS_DEV_MODE_OFFSET) = 0x20012001; memcpy(mod->segments[0].buf + SYSSTATE_RET_CHECK_BUG, sysstate_ret_patch, sizeof(sysstate_ret_patch)); memcpy(mod->segments[0].buf + SYSSTATE_SD0_STRING, ur0_path, sizeof(ur0_path)); memcpy(mod->segments[0].buf + SYSSTATE_SD0_PSP2CONFIG_STRING, ur0_psp2config_path, sizeof(ur0_psp2config_path)); // this patch actually corrupts two words of data, but they are only used in debug printing and seem to be fine INSTALL_HOOK_THUMB(sysstate_final_hook, mod->segments[0].buf + SYSSTATE_FINAL_CALL); sysstate_final = mod->segments[0].buf + SYSSTATE_FINAL; ); } else { printf("module data invalid for sysstatemgr.skprx!\n"); } } return ret; } #undef HOOK_EXPORT #undef FIND_EXPORT void go(void) { printf("second\n"); // patch module_load/module_start *module_load_func_ptr = module_load_patched; printf("module_load_patched: 0x%08X\n", module_load_patched); } __attribute__ ((section (".text.start"))) void start(void) { go(); } ================================================ FILE: second.x ================================================ OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(start) SECTIONS { . = 0x51e00000; .text : { *(.text.start) *(.text .text.* .gnu.linkonce.t.*) *(.sceStub.text.*) } .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .data : { *(.data .data.* .gnu.linkonce.d.*) } .bss : { *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) } }