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