mirror of
https://github.com/spicyjpeg/573in1.git
synced 2025-03-01 07:20:42 +01:00
Fix crashes, add custom shell detection, update schemas
This commit is contained in:
parent
f4a8d16b20
commit
11d07e1e51
@ -6,13 +6,13 @@
|
|||||||
|
|
||||||
"App": {
|
"App": {
|
||||||
"ideInitWorker": {
|
"ideInitWorker": {
|
||||||
"init": "Initializing IDE devices...\nDo not turn off the 573 or unplug drives."
|
"init": "Initializing IDE devices...\nDo not turn off the 573 or unplug drives.",
|
||||||
|
"autoboot": "Searching for boot executables...\nDo not turn off the 573 or unplug drives."
|
||||||
},
|
},
|
||||||
"fileInitWorker": {
|
"fileInitWorker": {
|
||||||
"unmount": "Unmounting all mounted filesystems...\nDo not turn off the 573 or unplug drives.",
|
"unmount": "Unmounting all mounted filesystems...\nDo not turn off the 573 or unplug drives.",
|
||||||
"mount": "Detecting and mounting filesystems...\nDo not turn off the 573 or unplug drives.",
|
"mount": "Detecting and mounting filesystems...\nDo not turn off the 573 or unplug drives.",
|
||||||
"loadResources": "Loading resource pack...\nDo not turn off the 573 or unplug drives.",
|
"loadResources": "Loading resource pack...\nDo not turn off the 573 or unplug drives."
|
||||||
"autoboot": "Searching for boot executables...\nDo not turn off the 573 or unplug drives."
|
|
||||||
},
|
},
|
||||||
"cartDetectWorker": {
|
"cartDetectWorker": {
|
||||||
"readDigitalIO": "Retrieving digital I/O board ID...",
|
"readDigitalIO": "Retrieving digital I/O board ID...",
|
||||||
@ -59,7 +59,8 @@
|
|||||||
"init": "Validating executable file...\nDo not turn off the 573 or unplug drives.",
|
"init": "Validating executable file...\nDo not turn off the 573 or unplug drives.",
|
||||||
"load": "Loading executable file...\nDo not turn off the 573 or unplug drives.",
|
"load": "Loading executable file...\nDo not turn off the 573 or unplug drives.",
|
||||||
"fileError": "The selected file could not be accessed or is not a valid System 573 executable. Make sure the file has been copied properly.\n\nFile: %s",
|
"fileError": "The selected file could not be accessed or is not a valid System 573 executable. Make sure the file has been copied properly.\n\nFile: %s",
|
||||||
"addressError": "The selected file cannot be loaded as it overlaps the memory region reserved for use by the executable launcher.\n\nFile:\t\t%s\nRegion:\t%08X-%08X\nStack top:\t%08X"
|
"addressError": "The selected file cannot be loaded as it overlaps the memory region reserved for use by the executable launcher.\n\nFile:\t\t%s\nRegion:\t%08X-%08X\nStack top:\t%08X",
|
||||||
|
"fragmentError": "The selected file cannot be loaded as it is fragmented across too many non-contiguous areas on the filesystem. Try defragging or reformatting the drive.\n\nFile:\t\t\t%s\nTotal fragments:\t%d\nOverflow:\t\t%d"
|
||||||
},
|
},
|
||||||
"flashHeaderWriteWorker": {
|
"flashHeaderWriteWorker": {
|
||||||
"erase": "Erasing existing header...\nDo not turn off the 573.",
|
"erase": "Erasing existing header...\nDo not turn off the 573.",
|
||||||
@ -583,11 +584,12 @@
|
|||||||
"kernelInfo": {
|
"kernelInfo": {
|
||||||
"sony": " Kernel type:\tSony PlayStation kernel\n Kernel version:\t%s\n Kernel date:\t%04X-%02X-%02X\n",
|
"sony": " Kernel type:\tSony PlayStation kernel\n Kernel version:\t%s\n Kernel date:\t%04X-%02X-%02X\n",
|
||||||
"openbios": " Kernel type:\tOpenBIOS\n Kernel build ID:\n %s\n",
|
"openbios": " Kernel type:\tOpenBIOS\n Kernel build ID:\n %s\n",
|
||||||
"unknown": " Kernel type:\tUnknown\n"
|
"unknown": " Kernel type:\tunknown\n"
|
||||||
},
|
},
|
||||||
"shellInfo": {
|
"shellInfo": {
|
||||||
"konami": " Shell type:\t\t%s\n Boot file name:\t%s\n",
|
"konami": " Shell type:\t\t%s\n Boot file name:\t%s\n",
|
||||||
"unknown": " Shell type:\t\tUnknown\n"
|
"custom": " Shell type:\t\tcustom executable\n Shell name:\n %s\n",
|
||||||
|
"unknown": " Shell type:\t\tunknown\n"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rtc": {
|
"rtc": {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"title": "Security cartridge description",
|
"title": "Security cartridge description",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|
||||||
"required": [ "pcb", "dataFormat" ],
|
"required": [ "pcb", "dataKey", "dataFormat" ],
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
|
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -27,6 +27,14 @@
|
|||||||
"PWB0000088954"
|
"PWB0000088954"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"dataKey": {
|
||||||
|
"title": "Data key",
|
||||||
|
"description": "The 8-byte key this cartridge's EEPROM is normally locked with. Must be specified as 8 hexadecimal values separated by dashes.",
|
||||||
|
"type": "string",
|
||||||
|
|
||||||
|
"pattern": "^([0-9a-f]{2}-){7}[0-9a-f]{2}$",
|
||||||
|
"default": "00-00-00-00-00-00-00-00"
|
||||||
|
},
|
||||||
"dataFormat": {
|
"dataFormat": {
|
||||||
"title": "Data format type",
|
"title": "Data format type",
|
||||||
"description": "Format of the data stored in the cartridge's EEPROM. The 'simple' format is just the region string, the 'basic' format includes some additional information and the 'extended' format is the full 16-byte game header plus any IDs.",
|
"description": "Format of the data stored in the cartridge's EEPROM. The 'simple' format is just the region string, the 'basic' format includes some additional information and the 'extended' format is the full 16-byte game header plus any IDs.",
|
||||||
|
@ -86,12 +86,17 @@
|
|||||||
"maximum": 2004,
|
"maximum": 2004,
|
||||||
"default": 2000
|
"default": 2000
|
||||||
},
|
},
|
||||||
"identifier": {
|
"identifiers": {
|
||||||
|
"title": "MAME game identifier list",
|
||||||
|
"description": "The names used by MAME to identify this game, one for each region/version listed in the regions field. Omit if the game is not currently emulated by MAME.",
|
||||||
|
"type": "array",
|
||||||
|
|
||||||
|
"items": {
|
||||||
"title": "MAME game identifier",
|
"title": "MAME game identifier",
|
||||||
"description": "The name used by MAME to identify this game. Omit if the game is not currently emulated by MAME.",
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|
||||||
"pattern": "^[0-9a-z_]*$"
|
"pattern": "^[0-9a-z_]*$"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"ioBoard": {
|
"ioBoard": {
|
||||||
|
@ -69,8 +69,10 @@ int main(int argc, const char **argv) {
|
|||||||
loader.addArgument(_lengthArg);
|
loader.addArgument(_lengthArg);
|
||||||
|
|
||||||
#ifdef ENABLE_ARGV
|
#ifdef ENABLE_ARGV
|
||||||
for (; argc > 0; argc--)
|
for (; argc > 0; argc--) {
|
||||||
loader.addArgument(*(argv++));
|
if (!loader.copyArgument(*(argv++)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
io::clearWatchdog();
|
io::clearWatchdog();
|
||||||
|
@ -88,7 +88,7 @@ bool ExecutableLauncherArgs::parseArgument(const char *arg) {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case "device"_h:
|
case "device"_h:
|
||||||
device = int(strtol(&arg[6], nullptr, 0));
|
device = int(strtol(&arg[7], nullptr, 0));
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case "frag"_h:
|
case "frag"_h:
|
||||||
|
@ -202,7 +202,8 @@ bool VFSProvider::mount(const char *prefix, Provider *provider, bool force) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
freeMP->prefix = hash;
|
freeMP->prefix = hash;
|
||||||
freeMP->pathOffset = __builtin_strlen(prefix);
|
freeMP->pathOffset =
|
||||||
|
(__builtin_strchr(prefix, VFS_PREFIX_SEPARATOR) - prefix) + 1;
|
||||||
freeMP->provider = provider;
|
freeMP->provider = provider;
|
||||||
|
|
||||||
LOG_FS("mapped %s", prefix);
|
LOG_FS("mapped %s", prefix);
|
||||||
|
@ -232,8 +232,10 @@ bool Device::_writeDMA(const void *data, size_t length) const {
|
|||||||
|
|
||||||
static constexpr int _COMMAND_TIMEOUT = 30000000;
|
static constexpr int _COMMAND_TIMEOUT = 30000000;
|
||||||
static constexpr int _DRQ_TIMEOUT = 30000000;
|
static constexpr int _DRQ_TIMEOUT = 30000000;
|
||||||
static constexpr int _DETECT_TIMEOUT = 500000;
|
static constexpr int _DETECT_TIMEOUT = 2500000;
|
||||||
static constexpr int _SRST_DELAY = 5000;
|
|
||||||
|
static constexpr int _SRST_SET_DELAY = 5000;
|
||||||
|
static constexpr int _SRST_CLEAR_DELAY = 50000;
|
||||||
|
|
||||||
// Note that ATA drives will always assert DRDY when ready, but ATAPI drives
|
// Note that ATA drives will always assert DRDY when ready, but ATAPI drives
|
||||||
// will not. This is an intentional feature meant to prevent ATA-only drivers
|
// will not. This is an intentional feature meant to prevent ATA-only drivers
|
||||||
@ -309,8 +311,10 @@ void Device::_handleError(void) {
|
|||||||
|
|
||||||
// Issuing a device reset command to an ATAPI drive would result in the
|
// Issuing a device reset command to an ATAPI drive would result in the
|
||||||
// error's sense data being lost.
|
// error's sense data being lost.
|
||||||
if (!(flags & DEVICE_ATAPI))
|
#if 0
|
||||||
|
if (flags & DEVICE_ATAPI)
|
||||||
_write(CS0_COMMAND, ATA_DEVICE_RESET);
|
_write(CS0_COMMAND, ATA_DEVICE_RESET);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::_handleTimeout(void) {
|
void Device::_handleTimeout(void) {
|
||||||
@ -323,15 +327,16 @@ void Device::_handleTimeout(void) {
|
|||||||
lastErrorReg, lastCountReg
|
lastErrorReg, lastCountReg
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (flags & DEVICE_ATAPI)
|
||||||
_write(CS0_COMMAND, ATA_DEVICE_RESET);
|
_write(CS0_COMMAND, ATA_DEVICE_RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceError Device::_resetDrive(void) {
|
DeviceError Device::_resetDrive(void) {
|
||||||
// Issue a software reset, which affects both devices on the bus.
|
// Issue a software reset, which affects both devices on the bus.
|
||||||
_write(CS1_DEVICE_CTRL, CS1_DEVICE_CTRL_IEN | CS1_DEVICE_CTRL_SRST);
|
_write(CS1_DEVICE_CTRL, CS1_DEVICE_CTRL_IEN | CS1_DEVICE_CTRL_SRST);
|
||||||
delayMicroseconds(_SRST_DELAY);
|
delayMicroseconds(_SRST_SET_DELAY);
|
||||||
_write(CS1_DEVICE_CTRL, CS1_DEVICE_CTRL_IEN);
|
_write(CS1_DEVICE_CTRL, CS1_DEVICE_CTRL_IEN);
|
||||||
delayMicroseconds(_SRST_DELAY);
|
delayMicroseconds(_SRST_CLEAR_DELAY);
|
||||||
|
|
||||||
_select(0);
|
_select(0);
|
||||||
|
|
||||||
@ -344,6 +349,7 @@ DeviceError Device::_resetDrive(void) {
|
|||||||
io::clearWatchdog();
|
io::clearWatchdog();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
// Issue dummy writes to the sector count register and attempt to read back
|
// Issue dummy writes to the sector count register and attempt to read back
|
||||||
// the written value. This should not fail even if the drive is busy.
|
// the written value. This should not fail even if the drive is busy.
|
||||||
uint8_t pattern = 0x55;
|
uint8_t pattern = 0x55;
|
||||||
@ -366,6 +372,9 @@ DeviceError Device::_resetDrive(void) {
|
|||||||
|
|
||||||
LOG_IDE("drive %d not responding", getDriveIndex());
|
LOG_IDE("drive %d not responding", getDriveIndex());
|
||||||
return NO_DRIVE;
|
return NO_DRIVE;
|
||||||
|
#else
|
||||||
|
return NO_ERROR;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ATA-specific function */
|
/* ATA-specific function */
|
||||||
|
@ -62,37 +62,37 @@ enum CS0CountFlag : uint8_t {
|
|||||||
/* ATA command definitions */
|
/* ATA command definitions */
|
||||||
|
|
||||||
enum ATACommand : uint8_t {
|
enum ATACommand : uint8_t {
|
||||||
ATA_NOP = 0x00,
|
ATA_NOP = 0x00, // ATAPI
|
||||||
ATA_DEVICE_RESET = 0x08,
|
ATA_DEVICE_RESET = 0x08, // ATAPI
|
||||||
ATA_READ_SECTORS = 0x20,
|
ATA_READ_SECTORS = 0x20, // ATA
|
||||||
ATA_READ_SECTORS_EXT = 0x24,
|
ATA_READ_SECTORS_EXT = 0x24, // ATA
|
||||||
ATA_READ_DMA_EXT = 0x25,
|
ATA_READ_DMA_EXT = 0x25, // ATA
|
||||||
ATA_READ_DMA_QUEUED_EXT = 0x26,
|
ATA_READ_DMA_QUEUED_EXT = 0x26, // ATA
|
||||||
ATA_WRITE_SECTORS = 0x30,
|
ATA_WRITE_SECTORS = 0x30, // ATA
|
||||||
ATA_WRITE_SECTORS_EXT = 0x34,
|
ATA_WRITE_SECTORS_EXT = 0x34, // ATA
|
||||||
ATA_WRITE_DMA_EXT = 0x35,
|
ATA_WRITE_DMA_EXT = 0x35, // ATA
|
||||||
ATA_WRITE_DMA_QUEUED_EXT = 0x36,
|
ATA_WRITE_DMA_QUEUED_EXT = 0x36, // ATA
|
||||||
ATA_SEEK = 0x70,
|
ATA_SEEK = 0x70, // ATA
|
||||||
ATA_EXECUTE_DIAGNOSTIC = 0x90,
|
ATA_EXECUTE_DIAGNOSTIC = 0x90, // ATA/ATAPI
|
||||||
ATA_PACKET = 0xa0,
|
ATA_PACKET = 0xa0, // ATAPI
|
||||||
ATA_IDENTIFY_PACKET = 0xa1,
|
ATA_IDENTIFY_PACKET = 0xa1, // ATAPI
|
||||||
ATA_SERVICE = 0xa2,
|
ATA_SERVICE = 0xa2, // ATA/ATAPI
|
||||||
ATA_DEVICE_CONFIG = 0xb1,
|
ATA_DEVICE_CONFIG = 0xb1, // ATA
|
||||||
ATA_ERASE_SECTORS = 0xc0,
|
ATA_ERASE_SECTORS = 0xc0, // ATA
|
||||||
ATA_READ_DMA_QUEUED = 0xc7,
|
ATA_READ_DMA_QUEUED = 0xc7, // ATA
|
||||||
ATA_READ_DMA = 0xc8,
|
ATA_READ_DMA = 0xc8, // ATA
|
||||||
ATA_WRITE_DMA = 0xca,
|
ATA_WRITE_DMA = 0xca, // ATA
|
||||||
ATA_WRITE_DMA_QUEUED = 0xcc,
|
ATA_WRITE_DMA_QUEUED = 0xcc, // ATA
|
||||||
ATA_STANDBY_IMMEDIATE = 0xe0,
|
ATA_STANDBY_IMMEDIATE = 0xe0, // ATA/ATAPI
|
||||||
ATA_IDLE_IMMEDIATE = 0xe1,
|
ATA_IDLE_IMMEDIATE = 0xe1, // ATA/ATAPI
|
||||||
ATA_STANDBY = 0xe2,
|
ATA_STANDBY = 0xe2, // ATA
|
||||||
ATA_IDLE = 0xe3,
|
ATA_IDLE = 0xe3, // ATA
|
||||||
ATA_CHECK_POWER_MODE = 0xe5,
|
ATA_CHECK_POWER_MODE = 0xe5, // ATA/ATAPI
|
||||||
ATA_SLEEP = 0xe6,
|
ATA_SLEEP = 0xe6, // ATA/ATAPI
|
||||||
ATA_FLUSH_CACHE = 0xe7,
|
ATA_FLUSH_CACHE = 0xe7, // ATA
|
||||||
ATA_FLUSH_CACHE_EXT = 0xea,
|
ATA_FLUSH_CACHE_EXT = 0xea, // ATA
|
||||||
ATA_IDENTIFY = 0xec,
|
ATA_IDENTIFY = 0xec, // ATA
|
||||||
ATA_SET_FEATURES = 0xef
|
ATA_SET_FEATURES = 0xef // ATA/ATAPI
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ATAFeature : uint8_t {
|
enum ATAFeature : uint8_t {
|
||||||
|
@ -301,22 +301,28 @@ const FlashRegion pcmcia[2]{
|
|||||||
|
|
||||||
/* BIOS ROM headers */
|
/* BIOS ROM headers */
|
||||||
|
|
||||||
static const ShellInfo _SHELL_VERSIONS[]{
|
static const ShellInfo _KONAMI_SHELLS[]{
|
||||||
{
|
{
|
||||||
.name = "700A01",
|
.name = "700A01",
|
||||||
.bootFileName = reinterpret_cast<const char *>(DEV2_BASE | 0x40890),
|
.bootFileName = reinterpret_cast<const char *>(DEV2_BASE | 0x40890),
|
||||||
.headerPtr = reinterpret_cast<const uint8_t *>(DEV2_BASE | 0x40000),
|
.headerHash = 0x9c615f57,
|
||||||
.headerHash = 0x9c615f57
|
.header = reinterpret_cast<const util::ExecutableHeader *>(
|
||||||
|
DEV2_BASE | 0x40000
|
||||||
|
)
|
||||||
}, {
|
}, {
|
||||||
.name = "700A01 (Gachagachamp)",
|
.name = "700A01 (Gachagachamp)",
|
||||||
.bootFileName = reinterpret_cast<const char *>(DEV2_BASE | 0x40890),
|
.bootFileName = reinterpret_cast<const char *>(DEV2_BASE | 0x40890),
|
||||||
.headerPtr = reinterpret_cast<const uint8_t *>(DEV2_BASE | 0x40000),
|
.headerHash = 0x7e31a844,
|
||||||
.headerHash = 0x7e31a844
|
.header = reinterpret_cast<const util::ExecutableHeader *>(
|
||||||
|
DEV2_BASE | 0x40000
|
||||||
|
)
|
||||||
}, {
|
}, {
|
||||||
.name = "700B01",
|
.name = "700B01",
|
||||||
.bootFileName = reinterpret_cast<const char *>(DEV2_BASE | 0x61334),
|
.bootFileName = reinterpret_cast<const char *>(DEV2_BASE | 0x61334),
|
||||||
.headerPtr = reinterpret_cast<const uint8_t *>(DEV2_BASE | 0x28000),
|
.headerHash = 0xb257d3b5,
|
||||||
.headerHash = 0xb257d3b5
|
.header = reinterpret_cast<const util::ExecutableHeader *>(
|
||||||
|
DEV2_BASE | 0x28000
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -331,16 +337,43 @@ bool OpenBIOSHeader::validateMagic(void) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ShellInfo::validateHash(void) const {
|
bool ShellInfo::validateHash(void) const {
|
||||||
return (util::hash(headerPtr, sizeof(util::ExecutableHeader)) == headerHash);
|
return (util::hash(
|
||||||
|
reinterpret_cast<const uint8_t *>(header), sizeof(util::ExecutableHeader)
|
||||||
|
) == headerHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ShellInfo *getShellInfo(void) {
|
bool getShellInfo(ShellInfo &output) {
|
||||||
for (auto &shell : _SHELL_VERSIONS) {
|
for (auto &shell : _KONAMI_SHELLS) {
|
||||||
if (shell.validateHash())
|
if (!shell.validateHash())
|
||||||
return &shell;
|
continue;
|
||||||
|
|
||||||
|
__builtin_memcpy(&output, &shell, sizeof(ShellInfo));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
// If no official shell was found, fall back to searching the entire ROM for
|
||||||
|
// a valid PS1 executable. Note that the executable has to be 32-byte
|
||||||
|
// aligned for this to work.
|
||||||
|
// TODO: use a binary search instead of a linear one
|
||||||
|
for (uintptr_t ptr = DEV2_BASE; ptr < (DEV2_BASE + 0x80000); ptr += 32) {
|
||||||
|
auto header = reinterpret_cast<const util::ExecutableHeader *>(ptr);
|
||||||
|
|
||||||
|
if (!header->validateMagic())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
output.name = header->getRegionString();
|
||||||
|
output.bootFileName = nullptr;
|
||||||
|
#if 0
|
||||||
|
output.headerHash = util::hash(
|
||||||
|
reinterpret_cast<const uint8_t *>(header),
|
||||||
|
sizeof(util::ExecutableHeader)
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
output.header = header;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ extern const FlashRegion flash, pcmcia[2];
|
|||||||
|
|
||||||
/* BIOS ROM headers */
|
/* BIOS ROM headers */
|
||||||
|
|
||||||
struct SonyKernelHeader {
|
class SonyKernelHeader {
|
||||||
public:
|
public:
|
||||||
uint8_t day, month;
|
uint8_t day, month;
|
||||||
uint16_t year;
|
uint16_t year;
|
||||||
@ -90,7 +90,7 @@ public:
|
|||||||
bool validateMagic(void) const;
|
bool validateMagic(void) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OpenBIOSHeader {
|
class OpenBIOSHeader {
|
||||||
public:
|
public:
|
||||||
uint8_t magic[8];
|
uint8_t magic[8];
|
||||||
uint32_t idNameLength, idDescLength, idType;
|
uint32_t idNameLength, idDescLength, idType;
|
||||||
@ -103,12 +103,13 @@ public:
|
|||||||
bool validateMagic(void) const;
|
bool validateMagic(void) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ShellInfo {
|
class ShellInfo {
|
||||||
public:
|
public:
|
||||||
const char *name, *bootFileName;
|
const char *name, *bootFileName;
|
||||||
const uint8_t *headerPtr;
|
|
||||||
util::Hash headerHash;
|
util::Hash headerHash;
|
||||||
|
|
||||||
|
const util::ExecutableHeader *header;
|
||||||
|
|
||||||
bool validateHash(void) const;
|
bool validateHash(void) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -117,6 +118,6 @@ static const auto &sonyKernelHeader =
|
|||||||
static const auto &openBIOSHeader =
|
static const auto &openBIOSHeader =
|
||||||
*reinterpret_cast<const OpenBIOSHeader *>(DEV2_BASE | 0x78);
|
*reinterpret_cast<const OpenBIOSHeader *>(DEV2_BASE | 0x78);
|
||||||
|
|
||||||
const ShellInfo *getShellInfo(void);
|
bool getShellInfo(ShellInfo &output);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -599,7 +599,20 @@ size_t encodeBase41(char *output, const uint8_t *input, size_t length) {
|
|||||||
/* PS1 executable loader */
|
/* PS1 executable loader */
|
||||||
|
|
||||||
bool ExecutableHeader::validateMagic(void) const {
|
bool ExecutableHeader::validateMagic(void) const {
|
||||||
return (hash(magic, sizeof(magic)) == "PS-X EXE"_h);
|
#if 0
|
||||||
|
return (
|
||||||
|
hash(magic, sizeof(magic)) ==
|
||||||
|
hash("PS-X EXE\0\0\0\0\0\0\0\0", sizeof(magic), 0)
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
return true
|
||||||
|
&& (magic[0] == 0x582d5350)
|
||||||
|
&& (magic[1] == 0x45584520)
|
||||||
|
&& !magic[2]
|
||||||
|
&& !magic[3]
|
||||||
|
&& (entryPoint >= 0x80000000)
|
||||||
|
&& (textOffset >= 0x80000000);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutableLoader::ExecutableLoader(
|
ExecutableLoader::ExecutableLoader(
|
||||||
@ -610,19 +623,30 @@ ExecutableLoader::ExecutableLoader(
|
|||||||
_currentStackPtr = reinterpret_cast<char *>(_argListPtr);
|
_currentStackPtr = reinterpret_cast<char *>(_argListPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecutableLoader::copyArgument(const char *arg, size_t length) {
|
bool ExecutableLoader::addArgument(const char *arg) {
|
||||||
|
if (_numArgs >= MAX_EXECUTABLE_ARGS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_argListPtr[_numArgs++] = arg;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExecutableLoader::copyArgument(const char *arg, size_t length) {
|
||||||
|
if (_numArgs >= MAX_EXECUTABLE_ARGS)
|
||||||
|
return false;
|
||||||
|
|
||||||
// Command-line arguments must be copied to the top of the new stack in
|
// Command-line arguments must be copied to the top of the new stack in
|
||||||
// order to ensure the executable is going to be able to access them at any
|
// order to ensure the executable is going to be able to access them at any
|
||||||
// time.
|
// time.
|
||||||
length++;
|
length++;
|
||||||
_currentStackPtr -= (length + 7) & ~7;
|
_currentStackPtr -= (length + 7) & ~7;
|
||||||
|
_argListPtr[_numArgs++] = _currentStackPtr;
|
||||||
|
|
||||||
addArgument(_currentStackPtr);
|
|
||||||
__builtin_memcpy(_currentStackPtr, arg, length);
|
__builtin_memcpy(_currentStackPtr, arg, length);
|
||||||
//assert(_argCount <= MAX_EXECUTABLE_ARGS);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecutableLoader::formatArgument(const char *format, ...) {
|
bool ExecutableLoader::formatArgument(const char *format, ...) {
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
@ -630,7 +654,7 @@ void ExecutableLoader::formatArgument(const char *format, ...) {
|
|||||||
int length = vsnprintf(buffer, sizeof(buffer), format, ap);
|
int length = vsnprintf(buffer, sizeof(buffer), format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
copyArgument(buffer, length + 1);
|
return copyArgument(buffer, length + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] void ExecutableLoader::run(
|
[[noreturn]] void ExecutableLoader::run(
|
||||||
|
@ -290,7 +290,7 @@ static constexpr size_t MAX_EXECUTABLE_ARGS = 32;
|
|||||||
|
|
||||||
class ExecutableHeader {
|
class ExecutableHeader {
|
||||||
public:
|
public:
|
||||||
uint8_t magic[8], _pad[8];
|
uint32_t magic[4];
|
||||||
|
|
||||||
uint32_t entryPoint, initialGP;
|
uint32_t entryPoint, initialGP;
|
||||||
uint32_t textOffset, textLength;
|
uint32_t textOffset, textLength;
|
||||||
@ -311,6 +311,9 @@ public:
|
|||||||
inline void *getStackPtr(void) const {
|
inline void *getStackPtr(void) const {
|
||||||
return reinterpret_cast<void *>(stackOffset + stackLength);
|
return reinterpret_cast<void *>(stackOffset + stackLength);
|
||||||
}
|
}
|
||||||
|
inline const char *getRegionString(void) const {
|
||||||
|
return reinterpret_cast<const char *>(&this[1]);
|
||||||
|
}
|
||||||
inline void relocateText(const void *source) const {
|
inline void relocateText(const void *source) const {
|
||||||
__builtin_memcpy(getTextPtr(), source, textLength);
|
__builtin_memcpy(getTextPtr(), source, textLength);
|
||||||
}
|
}
|
||||||
@ -322,24 +325,22 @@ class ExecutableLoader {
|
|||||||
private:
|
private:
|
||||||
void *_entryPoint, *_initialGP;
|
void *_entryPoint, *_initialGP;
|
||||||
|
|
||||||
int _numArgs;
|
size_t _numArgs;
|
||||||
const char **_argListPtr;
|
const char **_argListPtr;
|
||||||
char *_currentStackPtr;
|
char *_currentStackPtr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline void addArgument(const char *arg) {
|
inline bool copyArgument(const char *arg) {
|
||||||
_argListPtr[_numArgs++] = arg;
|
return copyArgument(arg, __builtin_strlen(arg));
|
||||||
}
|
|
||||||
inline void copyArgument(const char *arg) {
|
|
||||||
copyArgument(arg, __builtin_strlen(arg));
|
|
||||||
}
|
}
|
||||||
[[noreturn]] inline void run(void) {
|
[[noreturn]] inline void run(void) {
|
||||||
run(_numArgs, _argListPtr);
|
run(_numArgs, _argListPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutableLoader(void *entryPoint, void *initialGP, void *stackTop);
|
ExecutableLoader(void *entryPoint, void *initialGP, void *stackTop);
|
||||||
void copyArgument(const char *arg, size_t length);
|
bool addArgument(const char *arg);
|
||||||
void formatArgument(const char *format, ...);
|
bool copyArgument(const char *arg, size_t length);
|
||||||
|
bool formatArgument(const char *format, ...);
|
||||||
[[noreturn]] void run(int rawArgc, const char *const *rawArgv);
|
[[noreturn]] void run(int rawArgc, const char *const *rawArgv);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -117,8 +117,10 @@ int main(int argc, const char **argv) {
|
|||||||
|
|
||||||
auto executableArg = args.executableArgs;
|
auto executableArg = args.executableArgs;
|
||||||
|
|
||||||
for (size_t i = args.numArgs; i; i--)
|
for (size_t i = args.numArgs; i; i--) {
|
||||||
loader.copyArgument(*(executableArg++));
|
if (!loader.copyArgument(*(executableArg++)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
loader.run();
|
loader.run();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -82,7 +82,6 @@ void FileIOManager::initIDE(void) {
|
|||||||
|
|
||||||
for (size_t i = 0; i < util::countOf(ide::devices); i++) {
|
for (size_t i = 0; i < util::countOf(ide::devices); i++) {
|
||||||
auto &dev = ide::devices[i];
|
auto &dev = ide::devices[i];
|
||||||
name[3] = i + '0';
|
|
||||||
|
|
||||||
if (!(dev.flags & ide::DEVICE_READY))
|
if (!(dev.flags & ide::DEVICE_READY))
|
||||||
continue;
|
continue;
|
||||||
@ -112,6 +111,7 @@ void FileIOManager::initIDE(void) {
|
|||||||
vfs.mount("hdd:", fat);
|
vfs.mount("hdd:", fat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name[3] = i + '0';
|
||||||
vfs.mount(name, ide[i], true);
|
vfs.mount(name, ide[i], true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,15 +120,19 @@ void FileIOManager::closeIDE(void) {
|
|||||||
char name[8]{ "ide#:\0" };
|
char name[8]{ "ide#:\0" };
|
||||||
|
|
||||||
for (size_t i = 0; i < util::countOf(ide::devices); i++) {
|
for (size_t i = 0; i < util::countOf(ide::devices); i++) {
|
||||||
if (ide[i]) {
|
if (!ide[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
ide[i]->close();
|
ide[i]->close();
|
||||||
delete ide[i];
|
delete ide[i];
|
||||||
ide[i] = nullptr;
|
ide[i] = nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
name[3] = i + '0';
|
name[3] = i + '0';
|
||||||
vfs.unmount(name);
|
vfs.unmount(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs.unmount("cdrom:");
|
||||||
|
vfs.unmount("hdd:");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileIOManager::loadResourceFile(const char *path) {
|
bool FileIOManager::loadResourceFile(const char *path) {
|
||||||
@ -161,17 +165,6 @@ void FileIOManager::closeResourceFile(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileIOManager::close(void) {
|
|
||||||
vfs.close();
|
|
||||||
resource.close();
|
|
||||||
#ifdef ENABLE_PCDRV
|
|
||||||
host.close();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
closeResourceFile();
|
|
||||||
closeIDE();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* App class */
|
/* App class */
|
||||||
|
|
||||||
static constexpr size_t _WORKER_STACK_SIZE = 0x20000;
|
static constexpr size_t _WORKER_STACK_SIZE = 0x20000;
|
||||||
@ -186,7 +179,7 @@ _ctx(ctx), _cartDriver(nullptr), _cartParser(nullptr), _identified(nullptr) {}
|
|||||||
|
|
||||||
App::~App(void) {
|
App::~App(void) {
|
||||||
_unloadCartData();
|
_unloadCartData();
|
||||||
_fileIO.close();
|
_workerStack.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::_unloadCartData(void) {
|
void App::_unloadCartData(void) {
|
||||||
@ -308,10 +301,10 @@ void App::_runWorker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void App::_worker(void) {
|
void App::_worker(void) {
|
||||||
if (_workerFunction) {
|
if (_workerFunction)
|
||||||
(this->*_workerFunction)();
|
(this->*_workerFunction)();
|
||||||
|
|
||||||
_workerStatus.setStatus(WORKER_DONE);
|
_workerStatus.setStatus(WORKER_DONE);
|
||||||
}
|
|
||||||
|
|
||||||
// Do nothing while waiting for vblank once the task is done.
|
// Do nothing while waiting for vblank once the task is done.
|
||||||
for (;;)
|
for (;;)
|
||||||
@ -359,7 +352,13 @@ void App::_interruptHandler(void) {
|
|||||||
#endif
|
#endif
|
||||||
_ctx.overlays[1] = &_screenshotOverlay;
|
_ctx.overlays[1] = &_screenshotOverlay;
|
||||||
|
|
||||||
|
#ifdef ENABLE_AUTOBOOT
|
||||||
_runWorker(&App::_ideInitWorker, _warningScreen);
|
_runWorker(&App::_ideInitWorker, _warningScreen);
|
||||||
|
#else
|
||||||
|
// If autoboot is disabled, show the warning screen before initializing the
|
||||||
|
// drives in order to give them enough time to spin up.
|
||||||
|
_runWorker(nullptr, _warningScreen);
|
||||||
|
#endif
|
||||||
_setupInterrupts();
|
_setupInterrupts();
|
||||||
_ctx.sounds[ui::SOUND_STARTUP].play();
|
_ctx.sounds[ui::SOUND_STARTUP].play();
|
||||||
|
|
||||||
|
@ -65,7 +65,8 @@ public:
|
|||||||
file::VFSProvider vfs;
|
file::VFSProvider vfs;
|
||||||
|
|
||||||
inline ~FileIOManager(void) {
|
inline ~FileIOManager(void) {
|
||||||
close();
|
closeResourceFile();
|
||||||
|
closeIDE();
|
||||||
}
|
}
|
||||||
|
|
||||||
FileIOManager(void);
|
FileIOManager(void);
|
||||||
@ -74,7 +75,6 @@ public:
|
|||||||
void closeIDE(void);
|
void closeIDE(void);
|
||||||
bool loadResourceFile(const char *path);
|
bool loadResourceFile(const char *path);
|
||||||
void closeResourceFile(void);
|
void closeResourceFile(void);
|
||||||
void close(void);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* App class */
|
/* App class */
|
||||||
|
@ -47,7 +47,13 @@ void WarningScreen::update(ui::Context &ctx) {
|
|||||||
_buttons[0] = STR("WarningScreen.ok");
|
_buttons[0] = STR("WarningScreen.ok");
|
||||||
|
|
||||||
if (ctx.buttons.pressed(ui::BTN_START))
|
if (ctx.buttons.pressed(ui::BTN_START))
|
||||||
|
#ifdef ENABLE_AUTOBOOT
|
||||||
ctx.show(APP->_buttonMappingScreen, false, true);
|
ctx.show(APP->_buttonMappingScreen, false, true);
|
||||||
|
#else
|
||||||
|
APP->_runWorker(
|
||||||
|
&App::_ideInitWorker, APP->_buttonMappingScreen, false, true
|
||||||
|
);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutobootScreen::show(ui::Context &ctx, bool goBack) {
|
void AutobootScreen::show(ui::Context &ctx, bool goBack) {
|
||||||
|
@ -64,7 +64,7 @@ bool App::_ideInitWorker(void) {
|
|||||||
bool App::_fileInitWorker(void) {
|
bool App::_fileInitWorker(void) {
|
||||||
_workerStatus.update(0, 3, WSTR("App.fileInitWorker.unmount"));
|
_workerStatus.update(0, 3, WSTR("App.fileInitWorker.unmount"));
|
||||||
_fileIO.closeResourceFile();
|
_fileIO.closeResourceFile();
|
||||||
_fileIO.close();
|
_fileIO.closeIDE();
|
||||||
|
|
||||||
_workerStatus.update(1, 3, WSTR("App.fileInitWorker.mount"));
|
_workerStatus.update(1, 3, WSTR("App.fileInitWorker.mount"));
|
||||||
_fileIO.initIDE();
|
_fileIO.initIDE();
|
||||||
@ -99,6 +99,8 @@ bool App::_executableWorker(void) {
|
|||||||
_workerStatus.update(0, 1, WSTR("App.executableWorker.init"));
|
_workerStatus.update(0, 1, WSTR("App.executableWorker.init"));
|
||||||
|
|
||||||
const char *path = _fileBrowserScreen.selectedPath;
|
const char *path = _fileBrowserScreen.selectedPath;
|
||||||
|
|
||||||
|
int device = -(path[3] - '0' + 1); // ide#: -> -1 or -2
|
||||||
auto _file = _fileIO.vfs.openFile(path, file::READ);
|
auto _file = _fileIO.vfs.openFile(path, file::READ);
|
||||||
|
|
||||||
util::ExecutableHeader header;
|
util::ExecutableHeader header;
|
||||||
@ -168,25 +170,38 @@ bool App::_executableWorker(void) {
|
|||||||
loader.formatArgument("entry.gp=%08x", header.getInitialGP());
|
loader.formatArgument("entry.gp=%08x", header.getInitialGP());
|
||||||
loader.formatArgument("entry.sp=%08x", header.getStackPtr());
|
loader.formatArgument("entry.sp=%08x", header.getStackPtr());
|
||||||
loader.formatArgument("load=%08x", header.getTextPtr());
|
loader.formatArgument("load=%08x", header.getTextPtr());
|
||||||
loader.formatArgument("drive=%c", path[3]); // ide#:...
|
loader.formatArgument("device=%d", device);
|
||||||
|
|
||||||
file::FileFragmentTable fragments;
|
file::FileFragmentTable fragments;
|
||||||
|
|
||||||
_fileIO.vfs.getFileFragments(fragments, path);
|
_fileIO.vfs.getFileFragments(fragments, path);
|
||||||
|
|
||||||
auto fragment = fragments.as<const file::FileFragment>();
|
auto fragment = fragments.as<const file::FileFragment>();
|
||||||
|
auto count = fragments.getNumFragments();
|
||||||
|
|
||||||
for (size_t i = fragments.getNumFragments(); i; i--, fragment++)
|
for (size_t i = count; i; i--, fragment++) {
|
||||||
loader.formatArgument(
|
if (loader.formatArgument(
|
||||||
"frag=%llx,%llx", fragment->lba, fragment->length
|
"frag=%llx,%llx", fragment->lba, fragment->length
|
||||||
|
))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fragments.destroy();
|
||||||
|
|
||||||
|
_messageScreen.setMessage(
|
||||||
|
MESSAGE_ERROR, WSTR("App.executableWorker.fragmentError"), path,
|
||||||
|
count, i
|
||||||
);
|
);
|
||||||
|
_workerStatus.setNextScreen(_messageScreen);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
fragments.destroy();
|
fragments.destroy();
|
||||||
|
|
||||||
// All destructors must be invoked manually as we are not returning to
|
// All destructors must be invoked manually as we are not returning to
|
||||||
// main() before starting the new executable.
|
// main() before starting the new executable.
|
||||||
_unloadCartData();
|
_unloadCartData();
|
||||||
_fileIO.close();
|
_fileIO.closeResourceFile();
|
||||||
|
_fileIO.closeIDE();
|
||||||
|
|
||||||
uninstallExceptionHandler();
|
uninstallExceptionHandler();
|
||||||
loader.run();
|
loader.run();
|
||||||
@ -233,7 +248,8 @@ bool App::_rebootWorker(void) {
|
|||||||
_workerStatus.update(0, 1, WSTR("App.rebootWorker.reboot"));
|
_workerStatus.update(0, 1, WSTR("App.rebootWorker.reboot"));
|
||||||
|
|
||||||
_unloadCartData();
|
_unloadCartData();
|
||||||
_fileIO.close();
|
_fileIO.closeResourceFile();
|
||||||
|
_fileIO.closeIDE();
|
||||||
_workerStatus.setStatus(WORKER_REBOOT);
|
_workerStatus.setStatus(WORKER_REBOOT);
|
||||||
|
|
||||||
// Fall back to a soft reboot if the watchdog fails to reset the system.
|
// Fall back to a soft reboot if the watchdog fails to reset the system.
|
||||||
|
@ -38,15 +38,19 @@ void StorageInfoScreen::show(ui::Context &ctx, bool goBack) {
|
|||||||
_PRINT(STR("StorageInfoScreen.bios.kernelInfo.unknown"));
|
_PRINT(STR("StorageInfoScreen.bios.kernelInfo.unknown"));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto shell = rom::getShellInfo();
|
rom::ShellInfo shell;
|
||||||
|
|
||||||
if (shell)
|
if (rom::getShellInfo(shell)) {
|
||||||
|
if (shell.bootFileName)
|
||||||
_PRINT(
|
_PRINT(
|
||||||
STR("StorageInfoScreen.bios.shellInfo.konami"), shell->name,
|
STR("StorageInfoScreen.bios.shellInfo.konami"), shell.name,
|
||||||
shell->bootFileName
|
shell.bootFileName
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
|
_PRINT(STR("StorageInfoScreen.bios.shellInfo.custom"), shell.name);
|
||||||
|
} else {
|
||||||
_PRINT(STR("StorageInfoScreen.bios.shellInfo.unknown"));
|
_PRINT(STR("StorageInfoScreen.bios.shellInfo.unknown"));
|
||||||
|
}
|
||||||
|
|
||||||
_PRINTLN();
|
_PRINTLN();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user