├── .clang-format ├── .editorconfig ├── .github └── workflows │ └── build.yml ├── .gitignore ├── Makefile ├── README.md ├── include └── main.h └── src └── main.c /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: false 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 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | 2 | name: CI 3 | 4 | on: 5 | push: 6 | pull_request: 7 | repository_dispatch: 8 | types: [run_build] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | container: ps2dev/ps2dev:latest 14 | steps: 15 | 16 | - name: Install dependencies 17 | run: | 18 | apk add build-base git zip 19 | 20 | - uses: actions/checkout@v2 21 | - run: | 22 | git config --global --add safe.directory "$GITHUB_WORKSPACE" 23 | git fetch --prune --unshallow 24 | 25 | 26 | - name: Compile 27 | run: | 28 | make --trace 29 | 30 | - name: Get short SHA 31 | id: slug 32 | run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" 33 | 34 | - name: Upload artifacts 35 | if: ${{ success() }} 36 | uses: actions/upload-artifact@v2 37 | with: 38 | name: OPL-PATINFO-${{ steps.slug.outputs.sha8 }} 39 | path: OPL-Launcher.elf 40 | 41 | - name: Create release 42 | if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' 43 | uses: marvinpinto/action-automatic-releases@latest 44 | with: 45 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 46 | automatic_release_tag: "latest" 47 | title: "Latest development build" 48 | files: OPL-Launcher.elf 49 | -------------------------------------------------------------------------------- /.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 | *.s 21 | *.zip 22 | *.ZIP 23 | *.a 24 | obj/ 25 | asm/ 26 | 27 | # 28 | # files that we don't want to ignore 29 | # 30 | !.gitignore 31 | !.gitattributes 32 | !.github 33 | !.editorconfig 34 | !.clang-format 35 | !modules/debug/*.irx 36 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .SILENT: 2 | 3 | FRONTEND_OBJS = obj/main.o 4 | 5 | EECORE_OBJS = obj/ps2dev9.o obj/ps2atad.o obj/ps2fs.o obj/ps2hdd.o \ 6 | obj/iomanx.o obj/filexio.o 7 | 8 | EE_BIN = OPL-Launcher.elf 9 | EE_SRC_DIR = src/ 10 | EE_OBJS_DIR = obj/ 11 | EE_ASM_DIR = asm/ 12 | EE_OBJS = $(FRONTEND_OBJS) $(EECORE_OBJS) 13 | 14 | EE_LIBS = -lfileXio -lpatches -lelf-loader-nocolour 15 | EE_LIB_DIRS += -L$(PS2SDK)/ee/lib 16 | EE_INCS += -I$(PS2SDK)/ports/include 17 | EE_CFLAGS := -O2 -G8192 -mgpopt -Wno-stringop-truncation 18 | 19 | all: 20 | @mkdir -p $(EE_OBJS_DIR) 21 | @mkdir -p $(EE_ASM_DIR) 22 | 23 | echo "Building OPL Launcher..." 24 | $(MAKE) $(EE_BIN) 25 | 26 | clean: 27 | rm -f -r $(EE_OBJS_DIR) $(EE_ASM_DIR) $(EE_BIN) 28 | 29 | rebuild: clean all 30 | 31 | ps2dev9.s: 32 | bin2s $(PS2SDK)/iop/irx/ps2dev9.irx asm/ps2dev9.s ps2dev9_irx 33 | 34 | ps2atad.s: 35 | bin2s $(PS2SDK)/iop/irx/ps2atad.irx asm/ps2atad.s ps2atad_irx 36 | 37 | ps2fs.s: 38 | bin2s $(PS2SDK)/iop/irx/ps2fs.irx asm/ps2fs.s ps2fs_irx 39 | 40 | ps2hdd.s: 41 | bin2s $(PS2SDK)/iop/irx/ps2hdd-osd.irx asm/ps2hdd.s ps2hdd_irx 42 | 43 | iomanx.s: 44 | bin2s $(PS2SDK)/iop/irx/iomanX.irx asm/iomanx.s iomanx_irx 45 | 46 | filexio.s: 47 | bin2s $(PS2SDK)/iop/irx/fileXio.irx asm/filexio.s filexio_irx 48 | 49 | $(EE_OBJS_DIR)%.o : $(EE_SRC_DIR)%.c 50 | $(EE_CC) $(EE_CFLAGS) $(EE_INCS) -c $< -o $@ 51 | 52 | $(EE_OBJS_DIR)%.o : %.s 53 | $(EE_AS) $(EE_ASFLAGS) $(EE_ASM_DIR)$< -o $@ 54 | 55 | include $(PS2SDK)/samples/Makefile.pref 56 | include $(PS2SDK)/samples/Makefile.eeglobal 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OPL-Launcher 2 | 3 | [![CI](https://github.com/ps2homebrew/OPL-Launcher/workflows/CI/badge.svg)](https://github.com/ps2homebrew/OPL-Launcher/actions?query=workflow%3ACI) 4 | 5 | OPL-Launcher reads `hdd0:/__common/OPL/conf_hdd.cfg` to launch `$OPL/OPNPS2LD.ELF`. 6 | 7 | You can inject OPL-Launcher into APA using, i.e. [HDL Dump](https://github.com/ps2homebrew/hdl-dump): 8 | 9 | ```cmd 10 | hdl_dump.exe modify_header hdd: 11 | ``` 12 | 13 | To do so, You must also prepare few files for the injection process: 14 | 15 | 1. Signed executable which You can make by [this application](https://www.psx-place.com/resources/kelftool-fmcb-compatible-fork.1104/) 16 | 17 | ```cmd 18 | kelftool encrypt mbr OPL-Launcher.elf boot.kelf 19 | ``` 20 | 21 | 2. `system.cnf` file that contains: 22 | 23 | ```ini 24 | BOOT2 = PATINFO 25 | VER = 1.00 26 | VMODE = NTSC 27 | HDDUNITPOWER = NICHDD 28 | ``` 29 | 30 | 3. Standard PS2 game icon. Just take one from game save and rename it to `list.ico`. 31 | 32 | 4. `icon.sys` file, which is not binary like in Memory Card case but fully text one. Example file, `title0` replaced by game name, `title1` replaced by Game ID and region (information from ): 33 | 34 | ```ini 35 | PS2X 36 | title0=ICO 37 | title1=SCUS-97113 (NTSC-U) 38 | bgcola=0 39 | bgcol0=0,0,0 40 | bgcol1=0,0,0 41 | bgcol2=0,0,0 42 | bgcol3=0,0,0 43 | lightdir0=1.0,-1.0,1.0 44 | lightdir1=-1.0,1.0,-1.0 45 | lightdir2=0.0,0.0,0.0 46 | lightcolamb=64,64,64 47 | lightcol0=64,64,64 48 | lightcol1=16,16,16 49 | lightcol2=0,0,0 50 | uninstallmes0= 51 | uninstallmes1= 52 | uninstallmes2= 53 | ``` 54 | 55 | 5. You can use a combination of 2 partitions: `` and `<__. Partition with PS2 game>`. Partition names should only differ in the first two characters. 56 | This will add compatibility with BB Navigator / PSX DESR XMB users. `` will contain game resources, `<__. Partition with PS2 game>` is the game in HDL format. 57 | 58 |
59 | Detailed guide for installing on PSX DESR / BB Navigator 60 |

61 | 62 | 1. Install the game with [HDL Dump](https://github.com/ps2homebrew/hdl-dump) by using the switch `-hide`. If you already installed the game without that switch, rename the partition and change the first three characters to `__.`. 63 | 64 | 2. Create PFS partition ``. The name should match the installed game name in the previous step, except that the first three characters should be `PP.`. 65 | 66 | 3. Prepare signed executable (for example, by [this app](https://www.psx-place.com/resources/kelftool-fmcb-compatible-fork.1104/)) 67 | 68 | ```cmd 69 | kelftool encrypt mbr OPL-Launcher.elf boot.kelf 70 | ``` 71 | 72 | 4. Put signed executable into partition from step 2. For example, you can place it in `/EXECUTE.KELF` 73 | 74 | 5. Create text file `system.cnf`, BOOT2 should be the same path as in step 4, only replace `` with `pfs:`: 75 | 76 | ```ini 77 | BOOT2 = pfs:/EXECUTE.KELF 78 | VER = 1.00 79 | VMODE = NTSC 80 | HDDUNITPOWER = NICHDD 81 | ``` 82 | 83 | 6. `list.ico` and `icon.sys` are the same as in the first part of this Readme. These files are not used in BB Navigator / PSX DESR XMB, but you can keep them if you plan to use HDD OSD. 84 | 85 | 7. You can now inject all files into PP. with that command: 86 | 87 | ```cmd 88 | hdl_dump.exe modify_header hdd: 89 | ``` 90 | 91 | 8. Create folder `res` in ``. This folder will contain all resources. 92 | 93 | 9. Create inside `res` folder text file `info.sys`. Example file, `title` replaced by game name, `title_id` replaced by Game ID and region (information from ) 94 | 95 | ```ini 96 | title = ICO 97 | title_id = SCUS-97113 (NTSC-U) 98 | title_sub_id = 0 99 | release_date = 100 | developer_id = 101 | publisher_id = 102 | note = 103 | content_web = 104 | image_topviewflag = 0 105 | image_type = 0 106 | image_count = 1 107 | image_viewsec = 600 108 | copyright_viewflag = 0 109 | copyright_imgcount = 0 110 | genre = 111 | parental_lock = 1 112 | effective_date = 0 113 | expire_date = 0 114 | area = J 115 | violence_flag = 0 116 | content_type = 255 117 | content_subtype = 0 118 | ``` 119 | 120 | 10. Place `jkt_001.png` and `jkt_002.png` in `res` folder. These two pictures will be used as mini-thumbnails for the game. It can be the same picture as used in OPL art. `jkt_001.png` used in BB Navigator, `jkt_002.png` used in PSX XMB. 121 | 122 |

123 |
124 | 125 | ## Credits 126 | 127 | Modified from miniOPL/diskload, credit to [sp193](https://github.com/sp193) & [l_oliveira](https://github.com/7l-oliveira) 128 | -------------------------------------------------------------------------------- /include/main.h: -------------------------------------------------------------------------------- 1 | #ifndef __MAIN_H 2 | #define __MAIN_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define NEWLIB_PORT_AWARE 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #ifdef __EESIO_DEBUG 25 | #include 26 | #define DPRINTF(args...) sio_printf(args) 27 | #define DINIT() sio_init(38400, 0, 0, 0, 0) 28 | #define LOG(args...) sio_printf(args) 29 | #else 30 | #define LOG(args...) 31 | #define DPRINTF(args...) 32 | #define DINIT() 33 | #endif 34 | 35 | #define PS2PART_IDMAX 32 36 | #define HDL_GAME_NAME_MAX 64 37 | #define HDL_GAME_DATA_OFFSET 0x100000 /* Sector 0x800 in the user data area. */ 38 | 39 | typedef struct 40 | { 41 | char partition_name[PS2PART_IDMAX + 1]; 42 | char name[HDL_GAME_NAME_MAX + 1]; 43 | char startup[8 + 1 + 3 + 1]; 44 | u8 hdl_compat_flags; 45 | u8 ops2l_compat_flags; 46 | u8 dma_type; 47 | u8 dma_mode; 48 | u32 layer_break; 49 | int disctype; 50 | u32 start_sector; 51 | u32 total_size_in_kb; 52 | } hdl_game_info_t; 53 | 54 | typedef struct // size = 1024 55 | { 56 | u32 magic; // HDL uses 0xdeadfeed magic here 57 | u16 reserved; 58 | u16 version; 59 | char gamename[160]; 60 | u8 hdl_compat_flags; 61 | u8 ops2l_compat_flags; 62 | u8 dma_type; 63 | u8 dma_mode; 64 | char startup[60]; 65 | u32 layer1_start; 66 | u32 discType; 67 | int num_partitions; 68 | struct 69 | { 70 | u32 part_offset; // in MB 71 | u32 data_start; // in sectors 72 | u32 part_size; // in KB 73 | } part_specs[65]; 74 | } hdl_apa_header; 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include "include/main.h" 2 | 3 | extern unsigned char ps2dev9_irx[]; 4 | extern unsigned int size_ps2dev9_irx; 5 | 6 | extern unsigned char ps2atad_irx[]; 7 | extern unsigned int size_ps2atad_irx; 8 | 9 | extern unsigned char ps2hdd_irx[]; 10 | extern unsigned int size_ps2hdd_irx; 11 | 12 | extern unsigned char iomanx_irx[]; 13 | extern unsigned int size_iomanx_irx; 14 | 15 | extern unsigned char filexio_irx[]; 16 | extern unsigned int size_filexio_irx; 17 | 18 | extern unsigned char ps2fs_irx[]; 19 | extern unsigned int size_ps2fs_irx; 20 | 21 | static int hddGetHDLGameInfo(const char *partition, hdl_game_info_t *ginfo) 22 | { 23 | u32 size; 24 | int fd, ret; 25 | iox_stat_t PartStat; 26 | char *PathToPart; 27 | 28 | PathToPart = malloc(strlen(partition) + 6); 29 | sprintf(PathToPart, "hdd0:%s", partition); 30 | 31 | if ((fd = open(PathToPart, O_RDONLY, 0666)) >= 0) { 32 | static char buf[1024] ALIGNED(64); 33 | lseek(fd, HDL_GAME_DATA_OFFSET, SEEK_SET); 34 | ret = read(fd, buf, 1024); 35 | close(fd); 36 | 37 | if (ret == 1024) { 38 | fileXioGetStat(PathToPart, &PartStat); 39 | 40 | // determine if partition is of HDL type 41 | if (PartStat.mode == 0x1337) { 42 | hdl_apa_header *hdl_header = (hdl_apa_header *)buf; 43 | 44 | // calculate total size 45 | size = PartStat.size; 46 | 47 | strncpy(ginfo->partition_name, partition, sizeof(ginfo->partition_name) - 1); 48 | ginfo->partition_name[sizeof(ginfo->partition_name) - 1] = '\0'; 49 | strncpy(ginfo->name, hdl_header->gamename, sizeof(ginfo->name) - 1); 50 | ginfo->name[sizeof(ginfo->name) - 1] = '\0'; 51 | strncpy(ginfo->startup, hdl_header->startup, sizeof(ginfo->startup) - 1); 52 | ginfo->startup[sizeof(ginfo->startup) - 1] = '\0'; 53 | ginfo->hdl_compat_flags = hdl_header->hdl_compat_flags; 54 | ginfo->ops2l_compat_flags = hdl_header->ops2l_compat_flags; 55 | ginfo->dma_type = hdl_header->dma_type; 56 | ginfo->dma_mode = hdl_header->dma_mode; 57 | ginfo->layer_break = hdl_header->layer1_start; 58 | ginfo->disctype = hdl_header->discType; 59 | ginfo->start_sector = PartStat.private_5 + (HDL_GAME_DATA_OFFSET + 4096) / 512; /* Note: The APA specification states that there is a 4KB area used for storing the partition's information, before the extended attribute area. */ 60 | ginfo->total_size_in_kb = size / 2; 61 | } else 62 | ret = -1; 63 | } else 64 | ret = -1; 65 | } else 66 | ret = fd; 67 | 68 | free(PathToPart); 69 | 70 | return ret; 71 | } 72 | 73 | static inline const char *GetMountParams(const char *command, char *BlockDevice) 74 | { 75 | const char *MountPath; 76 | 77 | if ((MountPath = strchr(&command[5], ':')) != NULL) { 78 | int BlockDeviceNameLen = (unsigned int)MountPath - (unsigned int)command; 79 | strncpy(BlockDevice, command, BlockDeviceNameLen); 80 | BlockDevice[BlockDeviceNameLen] = '\0'; 81 | 82 | MountPath++; // This is the location of the mount path; 83 | } 84 | 85 | return MountPath; 86 | } 87 | 88 | static inline void BootError(void) 89 | { 90 | SifExitRpc(); 91 | 92 | char *args[2]; 93 | args[0] = "BootError"; 94 | args[1] = NULL; 95 | ExecOSD(1, args); 96 | } 97 | 98 | int main(int argc, char *argv[]) 99 | { 100 | char PartitionName[33], BlockDevice[38]; 101 | int result, is_Game = 0; 102 | hdl_game_info_t GameInfo; 103 | char name[128]; 104 | char oplPartition[256]; 105 | char oplFilePath[256]; 106 | char *prefix = "pfs0:"; 107 | 108 | SifInitRpc(0); 109 | 110 | /* Do as many things as possible while the IOP slowly resets itself. */ 111 | if (argc > 1) { 112 | /* Argument 1 will contain the name of the partition containing the game. */ 113 | /* Unfortunately, it'll mean that some homebrew loader was most likely used to launch this program... and it might already have IOMANX loaded. That thing can't register devices that are added via IOMAN after it gets loaded. */ 114 | /* Reset the IOP to clear out all these stupid homebrew modules... */ 115 | while (!SifIopReset(NULL, 0)) {}; 116 | 117 | if (strlen(argv[1]) <= 32) { 118 | strncpy(PartitionName, argv[1], sizeof(PartitionName) - 1); 119 | PartitionName[sizeof(PartitionName) - 1] = '\0'; 120 | result = 0; 121 | } else 122 | result = -1; 123 | 124 | while (!SifIopSync()) {}; 125 | 126 | SifInitRpc(0); 127 | 128 | if (result < 0) 129 | BootError(); 130 | } else { 131 | if (GetMountParams(argv[0], BlockDevice) != NULL) { 132 | strncpy(PartitionName, &BlockDevice[5], sizeof(PartitionName) - 1); 133 | PartitionName[sizeof(PartitionName) - 1] = '\0'; 134 | } else 135 | BootError(); 136 | } 137 | 138 | SifInitIopHeap(); 139 | SifLoadFileInit(); 140 | 141 | sbv_patch_enable_lmb(); 142 | 143 | SifExecModuleBuffer(ps2dev9_irx, size_ps2dev9_irx, 0, NULL, NULL); 144 | 145 | SifExecModuleBuffer(iomanx_irx, size_iomanx_irx, 0, NULL, NULL); 146 | SifExecModuleBuffer(filexio_irx, size_filexio_irx, 0, NULL, NULL); 147 | 148 | fileXioInit(); 149 | 150 | SifExecModuleBuffer(ps2atad_irx, size_ps2atad_irx, 0, NULL, NULL); 151 | SifExecModuleBuffer(ps2hdd_irx, size_ps2hdd_irx, 0, NULL, NULL); 152 | SifExecModuleBuffer(ps2fs_irx, size_ps2fs_irx, 0, NULL, NULL); 153 | 154 | SifLoadFileExit(); 155 | SifExitIopHeap(); 156 | 157 | fileXioUmount("pfs0:"); 158 | 159 | DPRINTF("Retrieving game information...\n"); 160 | 161 | result = hddGetHDLGameInfo(PartitionName, &GameInfo); 162 | if (result < 0) { 163 | // some users use PP. for storing game icons and settings 164 | // for example BB.Navigator users and PSX DESR 1st gen (which just doesnt support PATINFO) 165 | // they store game inside hidden partition: __. 166 | PartitionName[0] = '_'; 167 | PartitionName[1] = '_'; 168 | result = hddGetHDLGameInfo(PartitionName, &GameInfo); 169 | if (result >= 0) 170 | is_Game = 1; 171 | } else 172 | is_Game = 1; 173 | 174 | result = fileXioMount("pfs0:", "hdd0:__common", FIO_MT_RDWR); 175 | if (result == 0) { 176 | FILE *fd = fopen("pfs0:OPL/conf_hdd.cfg", "rb"); 177 | if (fd != NULL) { 178 | char line[128]; 179 | if (fgets(line, 128, fd) != NULL) { 180 | char *val; 181 | if ((val = strchr(line, '=')) != NULL) 182 | val++; 183 | 184 | sprintf(name, val); 185 | // OPL adds windows CR+LF (0x0D 0x0A) .. remove that shiz from the string.. second check is 'just in case' 186 | if ((val = strchr(name, '\r')) != NULL) 187 | *val = '\0'; 188 | 189 | if ((val = strchr(name, '\n')) != NULL) 190 | *val = '\0'; 191 | } else 192 | sprintf(name, "+OPL"); 193 | 194 | fclose(fd); 195 | 196 | } else 197 | sprintf(name, "+OPL"); 198 | 199 | fileXioUmount("pfs0:"); 200 | } else 201 | sprintf(name, "+OPL"); 202 | 203 | snprintf(oplPartition, sizeof(oplPartition), "hdd0:%s", name); 204 | 205 | if (oplPartition[5] != '+') 206 | prefix = "pfs0:OPL/"; 207 | 208 | sprintf(oplFilePath, "%sOPNPS2LD.ELF", prefix); 209 | 210 | result = fileXioMount("pfs0:", oplPartition, FIO_MT_RDWR); 211 | if (result == 0) { 212 | if (is_Game) { 213 | 214 | char *boot_argv[4]; 215 | char start[128]; 216 | 217 | boot_argv[0] = GameInfo.startup; 218 | sprintf(start, "%u", GameInfo.start_sector); 219 | boot_argv[1] = start; 220 | boot_argv[2] = name; 221 | boot_argv[3] = "mini"; 222 | 223 | LoadELFFromFile(oplFilePath, 4, boot_argv); // args will be shifted +1 and oplFilePath will be the new argv0 224 | } else 225 | // if both partition candidates PP. and __. doesnt have HDL game type try to boot opl with no arguments 226 | LoadELFFromFile(oplFilePath, 0, NULL); 227 | } 228 | 229 | DPRINTF("Error loading game: %s, code: %d\n", PartitionName, result); 230 | 231 | BootError(); 232 | 233 | return 0; 234 | } 235 | --------------------------------------------------------------------------------