2012-11-01 15:19:01 +00:00
|
|
|
// Copyright (C) 2012 PPSSPP Project
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
2012-11-04 22:01:49 +00:00
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official git repository and contact information can be found at
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
2014-04-20 15:00:05 +00:00
|
|
|
#ifdef __SYMBIAN32__
|
2014-04-20 15:04:59 +00:00
|
|
|
#include <sys/cdefs.h>
|
2014-04-20 15:00:05 +00:00
|
|
|
#include <sys/syslimits.h>
|
|
|
|
#endif
|
|
|
|
|
2013-12-29 22:28:31 +00:00
|
|
|
#include "file/file_util.h"
|
|
|
|
|
|
|
|
#include "Common/StringUtils.h"
|
|
|
|
|
|
|
|
#include "Core/ELF/ElfReader.h"
|
|
|
|
#include "Core/ELF/ParamSFO.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-03-30 14:44:10 +00:00
|
|
|
#include "FileSystems/BlockDevices.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
#include "FileSystems/DirectoryFileSystem.h"
|
|
|
|
#include "FileSystems/ISOFileSystem.h"
|
2013-12-29 22:28:31 +00:00
|
|
|
#include "FileSystems/MetaFileSystem.h"
|
2013-07-28 06:46:26 +00:00
|
|
|
#include "FileSystems/VirtualDiscFileSystem.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-12-29 22:28:31 +00:00
|
|
|
#include "Core/MemMap.h"
|
2014-03-15 17:38:46 +00:00
|
|
|
#include "Core/HDRemaster.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-12-29 22:28:31 +00:00
|
|
|
#include "Core/MIPS/MIPS.h"
|
|
|
|
#include "Core/MIPS/MIPSAnalyst.h"
|
|
|
|
#include "Core/MIPS/MIPSCodeUtils.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
#include "Host.h"
|
|
|
|
|
2013-11-28 19:37:10 +00:00
|
|
|
#include "Core/Config.h"
|
2013-12-29 22:28:31 +00:00
|
|
|
#include "Core/System.h"
|
|
|
|
#include "Core/PSPLoaders.h"
|
|
|
|
#include "Core/HLE/HLE.h"
|
|
|
|
#include "Core/HLE/sceKernel.h"
|
|
|
|
#include "Core/HLE/sceKernelThread.h"
|
|
|
|
#include "Core/HLE/sceKernelModule.h"
|
|
|
|
#include "Core/HLE/sceKernelMemory.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-06-22 08:05:28 +00:00
|
|
|
// We gather the game info before actually loading/booting the ISO
|
|
|
|
// to determine if the emulator should enable extra memory and
|
|
|
|
// double-sized texture coordinates.
|
2013-06-22 09:14:01 +00:00
|
|
|
void InitMemoryForGameISO(std::string fileToStart) {
|
2013-07-23 15:24:33 +00:00
|
|
|
IFileSystem* umd2;
|
|
|
|
|
|
|
|
// check if it's a disc directory
|
|
|
|
FileInfo info;
|
|
|
|
if (!getFileInfo(fileToStart.c_str(), &info)) return;
|
|
|
|
|
|
|
|
if (info.isDirectory)
|
|
|
|
{
|
2013-07-24 20:49:45 +00:00
|
|
|
umd2 = new VirtualDiscFileSystem(&pspFileSystem, fileToStart);
|
2013-07-23 15:24:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto bd = constructBlockDevice(fileToStart.c_str());
|
|
|
|
// Can't init anything without a block device...
|
|
|
|
if (!bd)
|
|
|
|
return;
|
|
|
|
umd2 = new ISOFileSystem(&pspFileSystem, bd);
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2012-11-30 20:49:59 +00:00
|
|
|
// Parse PARAM.SFO
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
//pspFileSystem.Mount("host0:",umd2);
|
|
|
|
pspFileSystem.Mount("umd0:", umd2);
|
|
|
|
pspFileSystem.Mount("umd1:", umd2);
|
2013-01-09 08:46:47 +00:00
|
|
|
pspFileSystem.Mount("disc0:", umd2);
|
2012-11-30 16:47:04 +00:00
|
|
|
pspFileSystem.Mount("umd:", umd2);
|
2013-11-24 03:02:36 +00:00
|
|
|
|
2013-06-22 08:05:28 +00:00
|
|
|
std::string gameID;
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2012-11-30 20:49:59 +00:00
|
|
|
std::string sfoPath("disc0:/PSP_GAME/PARAM.SFO");
|
|
|
|
PSPFileInfo fileInfo = pspFileSystem.GetFileInfo(sfoPath.c_str());
|
2013-06-22 08:05:28 +00:00
|
|
|
|
2012-11-30 20:49:59 +00:00
|
|
|
if (fileInfo.exists)
|
|
|
|
{
|
2013-12-08 20:02:37 +00:00
|
|
|
std::vector<u8> paramsfo;
|
|
|
|
pspFileSystem.ReadEntireFile(sfoPath, paramsfo);
|
|
|
|
if (g_paramSFO.ReadSFO(paramsfo))
|
2012-11-30 20:49:59 +00:00
|
|
|
{
|
2013-06-22 08:05:28 +00:00
|
|
|
gameID = g_paramSFO.GetValueString("DISC_ID");
|
|
|
|
|
2013-07-08 01:24:53 +00:00
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(g_HDRemasters); i++) {
|
2013-06-21 17:34:57 +00:00
|
|
|
if(g_HDRemasters[i].gameID == gameID) {
|
2013-06-21 05:19:47 +00:00
|
|
|
g_RemasterMode = true;
|
2013-06-21 17:34:57 +00:00
|
|
|
Memory::g_MemorySize = g_HDRemasters[i].MemorySize;
|
2013-06-22 08:05:28 +00:00
|
|
|
if(g_HDRemasters[i].DoubleTextureCoordinates)
|
|
|
|
g_DoubleTextureCoordinates = true;
|
2013-06-21 05:19:47 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 05:33:42 +00:00
|
|
|
DEBUG_LOG(LOADER, "HDRemaster mode is %s", g_RemasterMode? "true": "false");
|
2013-06-22 08:05:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-15 13:30:40 +00:00
|
|
|
|
|
|
|
// Chinese translators like to rename EBOOT.BIN and replace it with some kind of stub
|
|
|
|
// that probably loads a plugin and then launches the actual game. These stubs don't work in PPSSPP.
|
|
|
|
// No idea why they are doing this, but it works to just bypass it. They could stop
|
|
|
|
// inventing new filenames though...
|
|
|
|
static const char *altBootNames[] = {
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/EBOOT.OLD",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/EBOOT.DAT",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/EBOOT.BI",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/EBOOT.LLD",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/OLD_EBOOT.BIN",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/EBOOT.123",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/EBOOT_LRC_CH.BIN",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/BOOT0.OLD",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/BOOT1.OLD",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/BINOT.BIN",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/EBOOT.FRY",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/EBOOT.Z.Y",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/EBOOT.LEI",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/EBOOT.DNR",
|
|
|
|
"disc0:/PSP_GAME/SYSDIR/DBZ2.BIN",
|
2014-02-15 15:52:08 +00:00
|
|
|
"disc0:/PSP_GAME/SYSDIR/ss.RAW",
|
2014-02-15 13:30:40 +00:00
|
|
|
};
|
|
|
|
|
2013-06-22 08:05:28 +00:00
|
|
|
bool Load_PSP_ISO(const char *filename, std::string *error_string)
|
|
|
|
{
|
2013-06-23 05:37:24 +00:00
|
|
|
// Mounting stuff relocated to InitMemoryForGameISO due to HD Remaster restructuring of code.
|
2013-06-22 08:05:28 +00:00
|
|
|
|
|
|
|
std::string sfoPath("disc0:/PSP_GAME/PARAM.SFO");
|
|
|
|
PSPFileInfo fileInfo = pspFileSystem.GetFileInfo(sfoPath.c_str());
|
|
|
|
if (fileInfo.exists)
|
|
|
|
{
|
2013-12-08 20:02:37 +00:00
|
|
|
std::vector<u8> paramsfo;
|
|
|
|
pspFileSystem.ReadEntireFile(sfoPath, paramsfo);
|
|
|
|
if (g_paramSFO.ReadSFO(paramsfo))
|
2013-06-22 08:05:28 +00:00
|
|
|
{
|
|
|
|
char title[1024];
|
|
|
|
sprintf(title, "%s : %s", g_paramSFO.GetValueString("DISC_ID").c_str(), g_paramSFO.GetValueString("TITLE").c_str());
|
|
|
|
INFO_LOG(LOADER, "%s", title);
|
|
|
|
host->SetWindowTitle(title);
|
2012-11-30 20:49:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-05 13:54:28 +00:00
|
|
|
std::string bootpath("disc0:/PSP_GAME/SYSDIR/EBOOT.BIN");
|
2014-02-15 13:30:40 +00:00
|
|
|
|
|
|
|
// Bypass Chinese translation patches, see comment above.
|
2014-03-03 08:08:32 +00:00
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(altBootNames); i++) {
|
2014-02-15 13:30:40 +00:00
|
|
|
if (pspFileSystem.GetFileInfo(altBootNames[i]).exists) {
|
2014-02-16 02:51:45 +00:00
|
|
|
bootpath = altBootNames[i];
|
2014-02-15 13:30:40 +00:00
|
|
|
}
|
2014-02-14 12:39:08 +00:00
|
|
|
}
|
2013-03-01 16:48:20 +00:00
|
|
|
|
2014-02-15 14:40:39 +00:00
|
|
|
// Bypass another more dangerous one where the file is in USRDIR - this could collide with files in some game.
|
2014-02-15 14:44:32 +00:00
|
|
|
std::string id = g_paramSFO.GetValueString("DISC_ID");
|
|
|
|
if (id == "NPJH50624" && pspFileSystem.GetFileInfo("disc0:/PSP_GAME/USRDIR/PAKFILE2.BIN").exists) {
|
2014-02-16 02:51:45 +00:00
|
|
|
bootpath = "disc0:/PSP_GAME/USRDIR/PAKFILE2.BIN";
|
2014-02-15 14:40:39 +00:00
|
|
|
}
|
2014-05-30 04:28:27 +00:00
|
|
|
if (id == "NPJH00100" && pspFileSystem.GetFileInfo("disc0:/PSP_GAME/USRDIR/DATA/GIM/GBL").exists) {
|
|
|
|
bootpath = "disc0:/PSP_GAME/USRDIR/DATA/GIM/GBL";
|
|
|
|
}
|
2014-02-15 14:40:39 +00:00
|
|
|
|
2012-11-05 13:54:28 +00:00
|
|
|
bool hasEncrypted = false;
|
|
|
|
u32 fd;
|
|
|
|
if ((fd = pspFileSystem.OpenFile(bootpath, FILEACCESS_READ)) != 0)
|
|
|
|
{
|
|
|
|
u8 head[4];
|
|
|
|
pspFileSystem.ReadFile(fd, head, 4);
|
2012-11-06 15:20:13 +00:00
|
|
|
if (memcmp(head, "~PSP", 4) == 0 || memcmp(head, "\x7F""ELF", 4) == 0) {
|
2012-11-05 13:54:28 +00:00
|
|
|
hasEncrypted = true;
|
|
|
|
}
|
2012-11-30 20:49:59 +00:00
|
|
|
pspFileSystem.CloseFile(fd);
|
2012-11-05 13:54:28 +00:00
|
|
|
}
|
|
|
|
if (!hasEncrypted)
|
|
|
|
{
|
|
|
|
// try unencrypted BOOT.BIN
|
|
|
|
bootpath = "disc0:/PSP_GAME/SYSDIR/BOOT.BIN";
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
INFO_LOG(LOADER,"Loading %s...", bootpath.c_str());
|
|
|
|
return __KernelLoadExec(bootpath.c_str(), 0, error_string);
|
|
|
|
}
|
|
|
|
|
2014-04-19 19:52:43 +00:00
|
|
|
static std::string NormalizePath(const std::string &path)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
char buf[512] = {0};
|
|
|
|
if (GetFullPathNameA(path.c_str(), sizeof(buf) - 1, buf, NULL) == 0)
|
|
|
|
return "";
|
|
|
|
#else
|
|
|
|
char buf[PATH_MAX + 1];
|
|
|
|
if (realpath(path.c_str(), buf) == NULL)
|
|
|
|
return "";
|
|
|
|
#endif
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
bool Load_PSP_ELF_PBP(const char *filename, std::string *error_string)
|
|
|
|
{
|
2013-05-08 15:36:57 +00:00
|
|
|
// This is really just for headless, might need tweaking later.
|
|
|
|
if (!PSP_CoreParameter().mountIso.empty())
|
|
|
|
{
|
2013-07-01 07:33:19 +00:00
|
|
|
auto bd = constructBlockDevice(PSP_CoreParameter().mountIso.c_str());
|
|
|
|
if (bd != NULL) {
|
|
|
|
ISOFileSystem *umd2 = new ISOFileSystem(&pspFileSystem, bd);
|
2013-01-09 08:46:47 +00:00
|
|
|
|
2013-07-01 07:33:19 +00:00
|
|
|
pspFileSystem.Mount("umd1:", umd2);
|
|
|
|
pspFileSystem.Mount("disc0:", umd2);
|
|
|
|
pspFileSystem.Mount("umd:", umd2);
|
|
|
|
}
|
2013-05-08 15:36:57 +00:00
|
|
|
}
|
2013-01-09 08:46:47 +00:00
|
|
|
|
2013-05-08 15:36:57 +00:00
|
|
|
std::string full_path = filename;
|
|
|
|
std::string path, file, extension;
|
|
|
|
SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
|
2012-11-01 15:19:01 +00:00
|
|
|
#ifdef _WIN32
|
2013-05-08 15:36:57 +00:00
|
|
|
path = ReplaceAll(path, "/", "\\");
|
2012-11-01 15:19:01 +00:00
|
|
|
#endif
|
|
|
|
|
2014-04-19 19:52:43 +00:00
|
|
|
if (!PSP_CoreParameter().mountRoot.empty())
|
|
|
|
{
|
|
|
|
// We don't want to worry about .. and cwd and such.
|
|
|
|
const std::string rootNorm = NormalizePath(PSP_CoreParameter().mountRoot + "/");
|
|
|
|
const std::string pathNorm = NormalizePath(path + "/");
|
|
|
|
|
|
|
|
// If root is not a subpath of path, we can't boot the game.
|
|
|
|
if (!startsWith(pathNorm, rootNorm))
|
|
|
|
{
|
|
|
|
*error_string = "Cannot boot ELF located outside mountRoot.";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::string filepath = ReplaceAll(pathNorm.substr(rootNorm.size()), "\\", "/");
|
|
|
|
file = filepath + "/" + file;
|
|
|
|
path = rootNorm;
|
|
|
|
pspFileSystem.SetStartingDirectory(filepath);
|
|
|
|
}
|
|
|
|
|
2013-05-08 15:36:57 +00:00
|
|
|
DirectoryFileSystem *fs = new DirectoryFileSystem(&pspFileSystem, path);
|
|
|
|
pspFileSystem.Mount("umd0:", fs);
|
2013-04-27 21:16:51 +00:00
|
|
|
|
2013-05-08 15:36:57 +00:00
|
|
|
std::string finalName = "umd0:/" + file + extension;
|
|
|
|
return __KernelLoadExec(finalName.c_str(), 0, error_string);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|