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 <inttypes.h>
#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("<I", x)
def ins(dst, off, src):
if type(src) is list:
out = b""
for x in src:
out += p32(x)
else:
out = src
dst[off:off+len(out)] = out
def main():
# ./gen.py fat.tpl payload.bin fat.out
with open(argv[1], "rb") as fin:
fat_tpl = bytearray(fin.read())
with open(argv[2], "rb") as fin:
first_bin = fin.read()
with open(argv[3], "rb") as fin:
second_bin = fin.read()
if len(first_bin) >= 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
================================================
<?xml version="1.0" encoding="utf-8"?>
<livearea style="a1" format-ver="01.00" content-rev="1">
<livearea-background>
<image>bg.png</image>
</livearea-background>
<gate>
<startup-image>startup.png</startup-image>
</gate>
</livearea>
================================================
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 <stdint.h>
#include <stddef.h>
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 <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <inttypes.h>
#include <psp2/display.h>
#include <psp2/kernel/sysmem.h>
#include <psp2/kernel/threadmgr.h>
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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
* $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 <psp2kern/kernel/modulemgr.h>
#include <psp2kern/io/fcntl.h>
#include <psp2kern/io/stat.h>
#include <psp2kern/kernel/threadmgr.h>
#include <psp2kern/kernel/sysmem.h>
#include <psp2kern/kernel/cpu.h>
#include <taihen.h>
#include <libk/stdarg.h>
#include <libk/string.h>
#include <libk/stdio.h>
#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 <psp2kern/kernel/modulemgr.h>
#include <taihen.h>
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 <psp2/kernel/processmgr.h>
#include <psp2/kernel/modulemgr.h>
#include <psp2/io/fcntl.h>
#include <psp2/io/devctl.h>
#include <psp2/ctrl.h>
#include <psp2/shellutil.h>
#include <psp2/net/http.h>
#include <psp2/net/net.h>
#include <psp2/sysmodule.h>
#include <psp2/kernel/sysmem.h>
#include <psp2/net/netctl.h>
#include <psp2/io/stat.h>
#include <taihen.h>
#include <stdio.h>
#include <string.h>
#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 <stdlib.h>
#include <string.h>
#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 <stddef.h>
/****************************** 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 <psp2/kernel/modulemgr.h>
#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 <inttypes.h>
#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 <inttypes.h>
#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) }
}
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
SYMBOL INDEX (106 symbols across 12 files)
FILE: first.c
function go (line 16) | void go(void) {
function start (line 96) | __attribute__ ((section (".text.start"), naked)) void start(void) {
FILE: gen.py
function p32 (line 6) | def p32(x):
function ins (line 9) | def ins(dst, off, src):
function main (line 18) | def main():
FILE: installer/src/crc32.c
function crc32 (line 92) | uint32_t
FILE: installer/src/debug_screen.c
function psvDebugScreenSetFgColor (line 40) | uint32_t psvDebugScreenSetFgColor(uint32_t color) {
function psvDebugScreenSetBgColor (line 46) | uint32_t psvDebugScreenSetBgColor(uint32_t color) {
function psvDebugScreenEscape (line 52) | static size_t psvDebugScreenEscape(const char *str){
function psvDebugScreenInit (line 81) | int psvDebugScreenInit() {
function psvDebugScreenClear (line 98) | void psvDebugScreenClear(int bg_color){
function psvDebugScreenPuts (line 110) | int psvDebugScreenPuts(const char * text){
function psvDebugScreenPrintf (line 157) | int psvDebugScreenPrintf(const char *format, ...) {
FILE: installer/src/kernel.c
type partition_t (line 34) | typedef struct {
type master_block_t (line 44) | typedef struct {
function printf_file (line 55) | int printf_file(const char *format, ...) {
function run_on_thread (line 106) | int run_on_thread(void *func) {
function find_active_os0 (line 138) | int find_active_os0(master_block_t *master) {
function check_os0 (line 152) | int check_os0(void) {
function k_ensoCheckOs0 (line 213) | int k_ensoCheckOs0(void) {
function is_mbr (line 224) | int is_mbr(void *data) {
function is_empty (line 233) | int is_empty(void *data) {
function check_mbr (line 241) | int check_mbr() {
function k_ensoCheckMBR (line 273) | int k_ensoCheckMBR(void) {
function dump_blocks (line 284) | int dump_blocks(void) {
function check_blocks (line 331) | int check_blocks(void) {
function k_ensoCheckBlocks (line 426) | int k_ensoCheckBlocks() {
function write_config (line 437) | int write_config() {
function k_ensoWriteConfig (line 549) | int k_ensoWriteConfig() {
function write_blocks (line 560) | int write_blocks(void) {
function k_ensoWriteBlocks (line 649) | int k_ensoWriteBlocks(void) {
function write_mbr (line 660) | int write_mbr(void) {
function k_ensoWriteMBR (line 753) | int k_ensoWriteMBR(void) {
function check_real_mbr (line 764) | int check_real_mbr() {
function k_ensoCheckRealMBR (line 798) | int k_ensoCheckRealMBR(void) {
function uninstall_mbr (line 809) | int uninstall_mbr() {
function k_ensoUninstallMBR (line 866) | int k_ensoUninstallMBR(void) {
function clean_up_blocks (line 877) | int clean_up_blocks() {
function k_ensoCleanUpBlocks (line 917) | int k_ensoCleanUpBlocks(void) {
function module_start (line 928) | int module_start(int args, void *argv) {
function module_stop (line 937) | int module_stop() {
FILE: installer/src/kernel2.c
function unload_allowed_patched (line 8) | int unload_allowed_patched(void) {
function module_start (line 13) | int module_start(int args, void *argv) {
function module_stop (line 27) | int module_stop() {
FILE: installer/src/main.c
function get_key (line 55) | uint32_t get_key(void) {
function press_exit (line 71) | void press_exit(void) {
function press_reboot (line 77) | void press_reboot(void) {
function load_helper (line 87) | int load_helper(void) {
function stop_helper (line 113) | int stop_helper(void) {
function lock_system (line 149) | int lock_system(void) {
function unlock_system (line 172) | int unlock_system(void) {
function draw_rect (line 179) | void draw_rect(int x, int y, int width, int height, uint32_t color) {
function download_file (line 189) | int download_file(const char *src, const char *dst, uint8_t *expect_hash) {
function init_net (line 263) | int init_net(void) {
function extract (line 318) | int extract(const char *pup, const char *psp2swu) {
function reinstall_firmware (line 389) | int reinstall_firmware(void) {
function do_install (line 466) | int do_install(void) {
function do_uninstall (line 557) | int do_uninstall(void) {
function do_reinstall_config (line 591) | int do_reinstall_config(void) {
function check_build (line 605) | int check_build(void) {
function check_safe_mode (line 623) | int check_safe_mode(void) {
function check_henkaku (line 631) | int check_henkaku(void) {
function main (line 645) | int main(int argc, char *argv[]) {
FILE: installer/src/sha256.c
function sha256_transform (line 44) | void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
function sha256_init (line 85) | void sha256_init(SHA256_CTX *ctx)
function sha256_update (line 99) | void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
function sha256_final (line 114) | void sha256_final(SHA256_CTX *ctx, BYTE hash[])
FILE: installer/src/sha256.h
type BYTE (line 19) | typedef unsigned char BYTE;
type WORD (line 20) | typedef unsigned int WORD;
type SHA256_CTX (line 22) | typedef struct {
FILE: installer/src/user.c
function ensoCheckOs0 (line 7) | int ensoCheckOs0(void) {
function ensoCheckMBR (line 11) | int ensoCheckMBR(void) {
function ensoCheckBlocks (line 15) | int ensoCheckBlocks(void) {
function ensoWriteConfig (line 19) | int ensoWriteConfig(void) {
function ensoWriteBlocks (line 23) | int ensoWriteBlocks(void) {
function ensoWriteMBR (line 27) | int ensoWriteMBR(void) {
function ensoCheckRealMBR (line 31) | int ensoCheckRealMBR(void) {
function ensoUninstallMBR (line 35) | int ensoUninstallMBR(void) {
function ensoCleanUpBlocks (line 39) | int ensoCleanUpBlocks(void) {
function module_start (line 43) | int module_start(int args, void *argv) {
function module_stop (line 50) | int module_stop() {
FILE: nsbl.h
type SceModuleExports (line 15) | typedef struct SceModuleExports {
type Elf32_Ehdr (line 30) | typedef struct Elf32_Ehdr {
type Elf32_Phdr (line 47) | typedef struct {
type SceModuleSelfSectionInfo (line 58) | typedef struct SceModuleSelfSectionInfo {
type SceBootArgs (line 71) | typedef struct SceBootArgs {
type SceSysrootContext (line 136) | typedef struct SceSysrootContext {
type SceModuleLoadList (line 141) | typedef struct SceModuleLoadList {
type SceObject (line 145) | typedef struct SceObject {
type SceModuleSegment (line 151) | typedef struct SceModuleSegment {
type SceModuleObject (line 160) | typedef struct SceModuleObject {
type SceKernelAllocMemBlockKernelOpt (line 207) | typedef struct SceKernelAllocMemBlockKernelOpt {
type SceModuleDecryptContext (line 232) | typedef struct SceModuleDecryptContext {
FILE: second.c
function hex_dump (line 71) | static int hex_dump(const char *addr, unsigned int size)
function is_safe_mode (line 96) | static int is_safe_mode(void) {
function is_update_mode (line 123) | static int is_update_mode(void) {
function skip_patches (line 133) | static inline int skip_patches(void) {
function sdstor_read_sector_patched (line 139) | static int sdstor_read_sector_patched(void* ctx, int sector, char* buffe...
function sdstor_read_sector_async_patched (line 158) | static int sdstor_read_sector_async_patched(void* ctx, int sector, char*...
function sbl_parse_header_patched (line 179) | static int sbl_parse_header_patched(uint32_t ctx, const void *header, in...
function sbl_set_up_buffer_patched (line 193) | static int sbl_set_up_buffer_patched(uint32_t ctx, int segidx) {
function sbl_decrypt_patched (line 202) | static int sbl_decrypt_patched(uint32_t ctx, void *buf, int sz) {
function sysstate_final_hook (line 211) | static void __attribute__((noreturn)) sysstate_final_hook(void) {
function module_load_patched (line 238) | static int module_load_patched(const SceModuleLoadList *list, int *uids,...
function go (line 342) | void go(void) {
function start (line 350) | __attribute__ ((section (".text.start"))) void start(void) {
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (131K chars).
[
{
"path": ".gitignore",
"chars": 23,
"preview": "*.bin\n*.o\nfirst\nsecond\n"
},
{
"path": "LICENSE",
"chars": 1075,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2017 molecule\n\nPermission is hereby granted, free of charge, to any person obtainin"
},
{
"path": "Makefile",
"chars": 517,
"preview": "CC=arm-vita-eabi-gcc\nCFLAGS=-Os -fno-builtin-printf -fPIC -fno-builtin-memset -Wall -Wextra -Wno-unused-variable -DFW_36"
},
{
"path": "README.md",
"chars": 901,
"preview": "You need [vitasdk](https://vitasdk.org/).\n\n1. `make` the payload\n2. Copy `fat.bin` to `installer/res`\n3. CMake the insta"
},
{
"path": "first.c",
"chars": 3225,
"preview": "/* first.c -- fixup environment and exec second payload\n *\n * Copyright (C) 2017 molecule\n *\n * This software may be mod"
},
{
"path": "first.x",
"chars": 395,
"preview": "OUTPUT_FORMAT(\"elf32-littlearm\", \"elf32-bigarm\", \"elf32-littlearm\")\nOUTPUT_ARCH(arm)\n\nENTRY(start)\n\nSECTIONS\n{\n . = 0x5"
},
{
"path": "gen.py",
"chars": 1974,
"preview": "#!/usr/bin/env python2\n\nfrom sys import argv, exit\nimport struct\n\ndef p32(x):\n\treturn struct.pack(\"<I\", x)\n\ndef ins(dst,"
},
{
"path": "installer/.gitignore",
"chars": 6,
"preview": "build\n"
},
{
"path": "installer/CMakeLists.txt",
"chars": 4219,
"preview": "cmake_minimum_required(VERSION 2.8)\n\nif(NOT DEFINED CMAKE_TOOLCHAIN_FILE)\n if(DEFINED ENV{VITASDK})\n set(CMAKE_TOOLC"
},
{
"path": "installer/LICENSE",
"chars": 1075,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2017 molecule\n\nPermission is hereby granted, free of charge, to any person obtainin"
},
{
"path": "installer/personalize.sh",
"chars": 677,
"preview": "#!/bin/bash\n\nmake_flags=\"-j 4\"\n\nif (( $# < 2 )); then\n echo \"$0 git_dir [cid1 cid2 ...]\"\n exit 0\nelse\n git_dir=\"$1\"; "
},
{
"path": "installer/res/template.xml",
"chars": 244,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<livearea style=\"a1\" format-ver=\"01.00\" content-rev=\"1\">\n\t<livearea-background>\n"
},
{
"path": "installer/src/crc32.c",
"chars": 5388,
"preview": "/*-\n * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or\n * code or tables extracted from it, as desired"
},
{
"path": "installer/src/debug_screen.c",
"chars": 5120,
"preview": "#include <stdio.h>\n#include <string.h>\n#include <stdarg.h>\n#include <inttypes.h>\n\n#include <psp2/display.h>\n#include <ps"
},
{
"path": "installer/src/debug_screen.h",
"chars": 123,
"preview": "#pragma once\n\nint psvDebugScreenPrintf(const char *format, ...);\nint psvDebugScreenInit();\nvoid* psvDebugScreenBase(void"
},
{
"path": "installer/src/debug_screen_font.c",
"chars": 9075,
"preview": "/*\n * PSP Software Development Kit - http://www.pspdev.org\n * ----------------------------------------------------------"
},
{
"path": "installer/src/enso.h",
"chars": 675,
"preview": "#pragma once\n\n// user prototypes\nint ensoCheckOs0(void);\nint ensoCheckMBR(void);\nint ensoCheckBlocks(void);\nint ensoWrit"
},
{
"path": "installer/src/kernel.c",
"chars": 20906,
"preview": "#include <psp2kern/kernel/modulemgr.h>\n#include <psp2kern/io/fcntl.h>\n#include <psp2kern/io/stat.h>\n#include <psp2kern/k"
},
{
"path": "installer/src/kernel2.c",
"chars": 880,
"preview": "#include <psp2kern/kernel/modulemgr.h>\n\n#include <taihen.h>\n\nstatic tai_hook_ref_t unload_allowed_hook;\nstatic SceUID un"
},
{
"path": "installer/src/kernel2.yml",
"chars": 116,
"preview": "kernel2:\n attributes: 0\n version:\n major: 1\n minor: 1\n main:\n start: module_start\n stop: module_stop\n"
},
{
"path": "installer/src/kernel_exports.yml",
"chars": 432,
"preview": "emmc_helper:\n attributes: 0\n version:\n major: 1\n minor: 1\n main:\n start: module_start\n stop: module_stop\n"
},
{
"path": "installer/src/main.c",
"chars": 16292,
"preview": "#include <psp2/kernel/processmgr.h>\n#include <psp2/kernel/modulemgr.h>\n#include <psp2/io/fcntl.h>\n#include <psp2/io/devc"
},
{
"path": "installer/src/sha256.c",
"chars": 5263,
"preview": "/*********************************************************************\n* Filename: sha256.c\n* Author: Brad Conte ("
},
{
"path": "installer/src/sha256.h",
"chars": 1215,
"preview": "/*********************************************************************\n* Filename: sha256.h\n* Author: Brad Conte ("
},
{
"path": "installer/src/user.c",
"chars": 872,
"preview": "#include <psp2/kernel/modulemgr.h>\n\n#include \"enso.h\"\n\n// user library as a workaround to load kernel module at runtime\n"
},
{
"path": "installer/src/user_exports.yml",
"chars": 404,
"preview": "emmc_helper_user:\n attributes: 0\n version:\n major: 1\n minor: 1\n main:\n start: module_start\n stop: module_"
},
{
"path": "installer/src/version.h.in",
"chars": 127,
"preview": "#pragma once\n\n#define BUILD_DATE \"${BUILD_DATE}\"\n#define BUILD_CID {${BUILD_CID}}\n#define BUILD_PERSONALIZED (${PERSONAL"
},
{
"path": "logo.h",
"chars": 16986,
"preview": "static const unsigned char logo_data[] = {\n 0x1f, 0x8b, 0x08, 0x00, 0x6f, 0xed, 0x0f, 0x59, 0x02, 0x03, 0xed, 0xdc,\n 0"
},
{
"path": "nsbl.h",
"chars": 8714,
"preview": "/* nsbl.h -- imported data from non-secure bootloader\n *\n * Copyright (C) 2017 molecule\n *\n * This software may be modif"
},
{
"path": "second.c",
"chars": 12216,
"preview": "/* second.c -- bootloader patches\n *\n * Copyright (C) 2017 molecule\n *\n * This software may be modified and distributed "
},
{
"path": "second.x",
"chars": 395,
"preview": "OUTPUT_FORMAT(\"elf32-littlearm\", \"elf32-bigarm\", \"elf32-littlearm\")\nOUTPUT_ARCH(arm)\n\nENTRY(start)\n\nSECTIONS\n{\n . = 0x5"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the TheOfficialFloW/enso GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (116.7 KB), approximately 50.8k tokens, and a symbol index with 106 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.