mirror of
https://github.com/spicyjpeg/573in1.git
synced 2025-01-22 19:52:05 +01:00
Bump to 0.4.5, add flash executable loading, fix bugs
This commit is contained in:
parent
aac5f4abb1
commit
f4a8d16b20
@ -6,7 +6,7 @@ set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain.cmake")
|
|||||||
project(
|
project(
|
||||||
cart-tool
|
cart-tool
|
||||||
LANGUAGES C CXX ASM
|
LANGUAGES C CXX ASM
|
||||||
VERSION 0.4.4
|
VERSION 0.4.5
|
||||||
DESCRIPTION "Konami System 573 security cartridge tool"
|
DESCRIPTION "Konami System 573 security cartridge tool"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
extern "C" const uint8_t _resourceArchive[];
|
extern "C" const uint8_t _resourceArchive[];
|
||||||
extern "C" const size_t _resourceArchiveLength;
|
extern "C" const size_t _resourceArchiveLength;
|
||||||
|
|
||||||
static char _ptrArg[]{ "resource.ptr=xxxxxxxx" };
|
static char _ptrArg[]{ "resource.ptr=xxxxxxxx\0" };
|
||||||
static char _lengthArg[]{ "resource.length=xxxxxxxx" };
|
static char _lengthArg[]{ "resource.length=xxxxxxxx\0" };
|
||||||
|
|
||||||
struct [[gnu::packed]] ZIPFileHeader {
|
struct [[gnu::packed]] ZIPFileHeader {
|
||||||
public:
|
public:
|
||||||
|
@ -87,8 +87,8 @@ bool ExecutableLauncherArgs::parseArgument(const char *arg) {
|
|||||||
loadAddress = reinterpret_cast<void *>(strtol(&arg[5], nullptr, 16));
|
loadAddress = reinterpret_cast<void *>(strtol(&arg[5], nullptr, 16));
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case "drive"_h:
|
case "device"_h:
|
||||||
drive = int(strtol(&arg[6], nullptr, 0));
|
device = int(strtol(&arg[6], nullptr, 0));
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case "frag"_h:
|
case "frag"_h:
|
||||||
|
@ -52,7 +52,7 @@ public:
|
|||||||
void *entryPoint, *initialGP, *stackTop;
|
void *entryPoint, *initialGP, *stackTop;
|
||||||
|
|
||||||
void *loadAddress;
|
void *loadAddress;
|
||||||
int drive;
|
int device; // 0-63 = flash, -1 or -2 = IDE
|
||||||
|
|
||||||
size_t numArgs, numFragments;
|
size_t numArgs, numFragments;
|
||||||
const char *executableArgs[util::MAX_EXECUTABLE_ARGS];
|
const char *executableArgs[util::MAX_EXECUTABLE_ARGS];
|
||||||
@ -60,7 +60,7 @@ public:
|
|||||||
|
|
||||||
inline ExecutableLauncherArgs(void)
|
inline ExecutableLauncherArgs(void)
|
||||||
: entryPoint(nullptr), initialGP(nullptr), stackTop(nullptr),
|
: entryPoint(nullptr), initialGP(nullptr), stackTop(nullptr),
|
||||||
loadAddress(nullptr), drive(0), numArgs(0), numFragments(0) {}
|
loadAddress(nullptr), device(0), numArgs(0), numFragments(0) {}
|
||||||
|
|
||||||
bool parseArgument(const char *arg);
|
bool parseArgument(const char *arg);
|
||||||
};
|
};
|
||||||
|
@ -104,6 +104,9 @@ void FATDirectory::close(void) {
|
|||||||
/* FAT filesystem provider */
|
/* FAT filesystem provider */
|
||||||
|
|
||||||
bool FATProvider::init(int drive) {
|
bool FATProvider::init(int drive) {
|
||||||
|
if (type)
|
||||||
|
return false;
|
||||||
|
|
||||||
_drive[0] = drive + '0';
|
_drive[0] = drive + '0';
|
||||||
|
|
||||||
auto error = f_mount(&_fs, _drive, 1);
|
auto error = f_mount(&_fs, _drive, 1);
|
||||||
@ -123,6 +126,9 @@ bool FATProvider::init(int drive) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FATProvider::close(void) {
|
void FATProvider::close(void) {
|
||||||
|
if (!type)
|
||||||
|
return;
|
||||||
|
|
||||||
auto error = f_unmount(_drive);
|
auto error = f_unmount(_drive);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -20,11 +20,12 @@ enum FileSystemType {
|
|||||||
FAT12 = 1,
|
FAT12 = 1,
|
||||||
FAT16 = 2,
|
FAT16 = 2,
|
||||||
FAT32 = 3,
|
FAT32 = 3,
|
||||||
ISO9660 = 4,
|
EXFAT = 4,
|
||||||
ZIP_MEMORY = 5,
|
ISO9660 = 5,
|
||||||
ZIP_FILE = 6,
|
ZIP_MEMORY = 6,
|
||||||
HOST = 7,
|
ZIP_FILE = 7,
|
||||||
VFS = 8
|
HOST = 8,
|
||||||
|
VFS = 9
|
||||||
};
|
};
|
||||||
|
|
||||||
// These are functionally equivalent to the FA_* flags used by FatFs.
|
// These are functionally equivalent to the FA_* flags used by FatFs.
|
||||||
|
@ -180,24 +180,33 @@ VFSMountPoint *VFSProvider::_getMounted(const char *path) {
|
|||||||
bool VFSProvider::mount(const char *prefix, Provider *provider, bool force) {
|
bool VFSProvider::mount(const char *prefix, Provider *provider, bool force) {
|
||||||
auto hash = util::hash(prefix, VFS_PREFIX_SEPARATOR);
|
auto hash = util::hash(prefix, VFS_PREFIX_SEPARATOR);
|
||||||
|
|
||||||
|
VFSMountPoint *freeMP = nullptr;
|
||||||
|
|
||||||
for (auto &mp : _mountPoints) {
|
for (auto &mp : _mountPoints) {
|
||||||
if (force) {
|
if (!mp.prefix) {
|
||||||
if (mp.prefix && (mp.prefix != hash))
|
freeMP = ∓
|
||||||
continue;
|
} else if (mp.prefix == hash) {
|
||||||
} else {
|
if (force) {
|
||||||
if (mp.prefix)
|
freeMP = ∓
|
||||||
continue;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_FS("%s was already mapped", prefix);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mp.prefix = hash;
|
|
||||||
mp.pathOffset = __builtin_strlen(prefix);
|
|
||||||
mp.provider = provider;
|
|
||||||
|
|
||||||
LOG_FS("mapped %s", prefix);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
if (!freeMP) {
|
||||||
|
LOG_FS("no mount points left for %s", prefix);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeMP->prefix = hash;
|
||||||
|
freeMP->pathOffset = __builtin_strlen(prefix);
|
||||||
|
freeMP->provider = provider;
|
||||||
|
|
||||||
|
LOG_FS("mapped %s", prefix);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VFSProvider::unmount(const char *prefix) {
|
bool VFSProvider::unmount(const char *prefix) {
|
||||||
@ -215,6 +224,7 @@ bool VFSProvider::unmount(const char *prefix) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_FS("%s was not mapped", prefix);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +97,9 @@ static constexpr uint32_t _ZIP_FLAGS = 0
|
|||||||
| MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY;
|
| MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY;
|
||||||
|
|
||||||
bool ZIPProvider::init(File *file) {
|
bool ZIPProvider::init(File *file) {
|
||||||
|
if (type)
|
||||||
|
return false;
|
||||||
|
|
||||||
mz_zip_zero_struct(&_zip);
|
mz_zip_zero_struct(&_zip);
|
||||||
_file = file;
|
_file = file;
|
||||||
|
|
||||||
@ -128,6 +131,9 @@ bool ZIPProvider::init(File *file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ZIPProvider::init(const void *zipData, size_t length) {
|
bool ZIPProvider::init(const void *zipData, size_t length) {
|
||||||
|
if (type)
|
||||||
|
return false;
|
||||||
|
|
||||||
mz_zip_zero_struct(&_zip);
|
mz_zip_zero_struct(&_zip);
|
||||||
_file = nullptr;
|
_file = nullptr;
|
||||||
|
|
||||||
@ -146,6 +152,9 @@ bool ZIPProvider::init(const void *zipData, size_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ZIPProvider::close(void) {
|
void ZIPProvider::close(void) {
|
||||||
|
if (!type)
|
||||||
|
return;
|
||||||
|
|
||||||
mz_zip_reader_end(&_zip);
|
mz_zip_reader_end(&_zip);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -607,8 +607,9 @@ DeviceError Device::enumerate(void) {
|
|||||||
// actually present. A strict timeout is used in the commands below in order
|
// actually present. A strict timeout is used in the commands below in order
|
||||||
// to prevent blocking for too long.
|
// to prevent blocking for too long.
|
||||||
IdentifyBlock block;
|
IdentifyBlock block;
|
||||||
|
auto signature = _getCylinder();
|
||||||
|
|
||||||
if (_getCylinder() == _ATAPI_SIGNATURE) {
|
if (signature == _ATAPI_SIGNATURE) {
|
||||||
flags |= DEVICE_ATAPI;
|
flags |= DEVICE_ATAPI;
|
||||||
|
|
||||||
_write(CS0_COMMAND, ATA_IDENTIFY_PACKET);
|
_write(CS0_COMMAND, ATA_IDENTIFY_PACKET);
|
||||||
@ -660,6 +661,13 @@ DeviceError Device::enumerate(void) {
|
|||||||
// Find out the fastest PIO transfer mode supported and enable it.
|
// Find out the fastest PIO transfer mode supported and enable it.
|
||||||
int mode = block.getHighestPIOMode();
|
int mode = block.getHighestPIOMode();
|
||||||
|
|
||||||
|
_select(0);
|
||||||
|
|
||||||
|
error = _waitForIdle();
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
_write(CS0_FEATURES, FEATURE_TRANSFER_MODE);
|
_write(CS0_FEATURES, FEATURE_TRANSFER_MODE);
|
||||||
_write(CS0_COUNT, TRANSFER_MODE_PIO | mode);
|
_write(CS0_COUNT, TRANSFER_MODE_PIO | mode);
|
||||||
_write(CS0_COMMAND, ATA_SET_FEATURES);
|
_write(CS0_COMMAND, ATA_SET_FEATURES);
|
||||||
|
@ -36,12 +36,12 @@ void init(void) {
|
|||||||
| ( 4 << 24) // DMA read/write delay
|
| ( 4 << 24) // DMA read/write delay
|
||||||
| BIU_CTRL_DMA_DELAY;
|
| BIU_CTRL_DMA_DELAY;
|
||||||
|
|
||||||
|
#if 0
|
||||||
// Revision D of the main board has footprints for either eight 8-bit RAM
|
// Revision D of the main board has footprints for either eight 8-bit RAM
|
||||||
// chips wired as two 32-bit banks, or two 16-bit chips wired as a single
|
// chips wired as two 32-bit banks, or two 16-bit chips wired as a single
|
||||||
// bank. Normally the kernel takes care of setting up the memory controller
|
// bank.
|
||||||
// appropriately, but this makes sure the configuration is correct if e.g.
|
|
||||||
// the tool is booted through OpenBIOS instead.
|
|
||||||
DRAM_CTRL = isDualBankRAM() ? 0x0c80 : 0x4788;
|
DRAM_CTRL = isDualBankRAM() ? 0x0c80 : 0x4788;
|
||||||
|
#endif
|
||||||
|
|
||||||
_bankSwitchReg = 0;
|
_bankSwitchReg = 0;
|
||||||
_cartOutputReg = 0;
|
_cartOutputReg = 0;
|
||||||
|
@ -29,9 +29,21 @@ void Region::read(void *data, uint32_t offset, size_t length) const {
|
|||||||
auto source = reinterpret_cast<const uint32_t *>(ptr + offset);
|
auto source = reinterpret_cast<const uint32_t *>(ptr + offset);
|
||||||
auto dest = reinterpret_cast<uint32_t *>(data);
|
auto dest = reinterpret_cast<uint32_t *>(data);
|
||||||
|
|
||||||
|
// TODO: use memcpy() instead once an optimized implementation is added
|
||||||
util::assertAligned<uint32_t>(source);
|
util::assertAligned<uint32_t>(source);
|
||||||
util::assertAligned<uint32_t>(dest);
|
util::assertAligned<uint32_t>(dest);
|
||||||
|
|
||||||
|
for (; length >= 32; length -= 32, dest += 8, source += 8) {
|
||||||
|
dest[0] = source[0];
|
||||||
|
dest[1] = source[1];
|
||||||
|
dest[2] = source[2];
|
||||||
|
dest[3] = source[3];
|
||||||
|
dest[4] = source[4];
|
||||||
|
dest[5] = source[5];
|
||||||
|
dest[6] = source[6];
|
||||||
|
dest[7] = source[7];
|
||||||
|
}
|
||||||
|
|
||||||
for (; length; length -= 4)
|
for (; length; length -= 4)
|
||||||
*(dest++) = *(source++);
|
*(dest++) = *(source++);
|
||||||
}
|
}
|
||||||
@ -64,8 +76,19 @@ void RTCRegion::read(void *data, uint32_t offset, size_t length) const {
|
|||||||
|
|
||||||
// The RTC is an 8-bit device connected to a 16-bit bus, i.e. each byte must
|
// The RTC is an 8-bit device connected to a 16-bit bus, i.e. each byte must
|
||||||
// be read as a 16-bit value and then the upper 8 bits must be discarded.
|
// be read as a 16-bit value and then the upper 8 bits must be discarded.
|
||||||
|
for (; length >= 8; length -= 8, dest += 8, source += 8) {
|
||||||
|
dest[0] = uint8_t(source[0]);
|
||||||
|
dest[1] = uint8_t(source[1]);
|
||||||
|
dest[2] = uint8_t(source[2]);
|
||||||
|
dest[3] = uint8_t(source[3]);
|
||||||
|
dest[4] = uint8_t(source[4]);
|
||||||
|
dest[5] = uint8_t(source[5]);
|
||||||
|
dest[6] = uint8_t(source[6]);
|
||||||
|
dest[7] = uint8_t(source[7]);
|
||||||
|
}
|
||||||
|
|
||||||
for (; length; length--)
|
for (; length; length--)
|
||||||
*(dest++) = *(source++) & 0xff;
|
*(dest++) = uint8_t(*(source++));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t RTCRegion::zipCRC32(
|
uint32_t RTCRegion::zipCRC32(
|
||||||
@ -120,18 +143,11 @@ uint16_t *FlashRegion::getRawPtr(uint32_t offset, bool alignToChip) const {
|
|||||||
void FlashRegion::read(void *data, uint32_t offset, size_t length) const {
|
void FlashRegion::read(void *data, uint32_t offset, size_t length) const {
|
||||||
// FIXME: this implementation will not handle unaligned reads and reads that
|
// FIXME: this implementation will not handle unaligned reads and reads that
|
||||||
// cross bank boundaries properly
|
// cross bank boundaries properly
|
||||||
int bankOffset = offset / FLASH_BANK_LENGTH;
|
auto bankOffset = offset / FLASH_BANK_LENGTH;
|
||||||
int ptrOffset = offset % FLASH_BANK_LENGTH;
|
auto ptrOffset = offset % FLASH_BANK_LENGTH;
|
||||||
|
|
||||||
auto source = reinterpret_cast<const uint32_t *>(ptr + ptrOffset);
|
|
||||||
auto dest = reinterpret_cast<uint32_t *>(data);
|
|
||||||
|
|
||||||
util::assertAligned<uint32_t>(source);
|
|
||||||
util::assertAligned<uint32_t>(dest);
|
|
||||||
io::setFlashBank(bank + bankOffset);
|
io::setFlashBank(bank + bankOffset);
|
||||||
|
Region::read(data, ptrOffset, length);
|
||||||
for (; length; length -= 4)
|
|
||||||
*(dest++) = *(source++);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t FlashRegion::zipCRC32(
|
uint32_t FlashRegion::zipCRC32(
|
||||||
@ -139,8 +155,8 @@ uint32_t FlashRegion::zipCRC32(
|
|||||||
) const {
|
) const {
|
||||||
// FIXME: this implementation will not handle unaligned reads and reads that
|
// FIXME: this implementation will not handle unaligned reads and reads that
|
||||||
// cross bank boundaries properly
|
// cross bank boundaries properly
|
||||||
int bankOffset = offset / FLASH_BANK_LENGTH;
|
auto bankOffset = offset / FLASH_BANK_LENGTH;
|
||||||
int ptrOffset = offset % FLASH_BANK_LENGTH;
|
auto ptrOffset = offset % FLASH_BANK_LENGTH;
|
||||||
|
|
||||||
auto source = reinterpret_cast<const uint32_t *>(ptr + ptrOffset);
|
auto source = reinterpret_cast<const uint32_t *>(ptr + ptrOffset);
|
||||||
auto table = reinterpret_cast<const uint32_t *>(CACHE_BASE);
|
auto table = reinterpret_cast<const uint32_t *>(CACHE_BASE);
|
||||||
@ -176,7 +192,7 @@ enum FlashIdentifier : uint16_t {
|
|||||||
_ID_28F640J5 = 0x89 | (0x15 << 8)
|
_ID_28F640J5 = 0x89 | (0x15 << 8)
|
||||||
};
|
};
|
||||||
|
|
||||||
bool FlashRegion::hasBootExecutable(void) const {
|
const util::ExecutableHeader *FlashRegion::getBootExecutableHeader(void) const {
|
||||||
// FIXME: this implementation will not detect executables that cross bank
|
// FIXME: this implementation will not detect executables that cross bank
|
||||||
// boundaries (but it shouldn't matter as executables must be <4 MB anyway)
|
// boundaries (but it shouldn't matter as executables must be <4 MB anyway)
|
||||||
auto data = reinterpret_cast<const uint8_t *>(ptr + FLASH_EXECUTABLE_OFFSET);
|
auto data = reinterpret_cast<const uint8_t *>(ptr + FLASH_EXECUTABLE_OFFSET);
|
||||||
@ -185,10 +201,10 @@ bool FlashRegion::hasBootExecutable(void) const {
|
|||||||
|
|
||||||
io::setFlashBank(bank);
|
io::setFlashBank(bank);
|
||||||
|
|
||||||
auto &header = *reinterpret_cast<const util::ExecutableHeader *>(data);
|
auto header = reinterpret_cast<const util::ExecutableHeader *>(data);
|
||||||
|
|
||||||
if (!header.validateMagic())
|
if (!header->validateMagic())
|
||||||
return false;
|
return nullptr;
|
||||||
|
|
||||||
// The integrity of the executable is verified by calculating the CRC32 of
|
// The integrity of the executable is verified by calculating the CRC32 of
|
||||||
// its bytes whose offsets are powers of 2 (i.e. the bytes at indices 0, 1,
|
// its bytes whose offsets are powers of 2 (i.e. the bytes at indices 0, 1,
|
||||||
@ -196,7 +212,7 @@ bool FlashRegion::hasBootExecutable(void) const {
|
|||||||
// header.textLength + util::EXECUTABLE_BODY_OFFSET, as the CRC is also
|
// header.textLength + util::EXECUTABLE_BODY_OFFSET, as the CRC is also
|
||||||
// calculated on the header, but Konami's shell ignores the last 2048 bytes
|
// calculated on the header, but Konami's shell ignores the last 2048 bytes
|
||||||
// due to a bug.
|
// due to a bug.
|
||||||
size_t length = header.textLength;
|
size_t length = header->textLength;
|
||||||
uint32_t crc = ~0;
|
uint32_t crc = ~0;
|
||||||
|
|
||||||
crc = (crc >> 8) ^ table[(crc ^ *data) & 0xff];
|
crc = (crc >> 8) ^ table[(crc ^ *data) & 0xff];
|
||||||
@ -204,7 +220,10 @@ bool FlashRegion::hasBootExecutable(void) const {
|
|||||||
for (size_t i = 1; i < length; i <<= 1)
|
for (size_t i = 1; i < length; i <<= 1)
|
||||||
crc = (crc >> 8) ^ table[(crc ^ data[i]) & 0xff];
|
crc = (crc >> 8) ^ table[(crc ^ data[i]) & 0xff];
|
||||||
|
|
||||||
return (~crc == *crcPtr);
|
if (~crc != *crcPtr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t FlashRegion::getJEDECID(void) const {
|
uint32_t FlashRegion::getJEDECID(void) const {
|
||||||
|
@ -32,7 +32,9 @@ public:
|
|||||||
uint32_t offset, size_t length, uint32_t crc = 0
|
uint32_t offset, size_t length, uint32_t crc = 0
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
virtual bool hasBootExecutable(void) const { return false; }
|
virtual const util::ExecutableHeader *getBootExecutableHeader(void) const {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
virtual uint32_t getJEDECID(void) const { return 0; }
|
virtual uint32_t getJEDECID(void) const { return 0; }
|
||||||
virtual Driver *newDriver(void) const { return nullptr; }
|
virtual Driver *newDriver(void) const { return nullptr; }
|
||||||
};
|
};
|
||||||
@ -67,7 +69,7 @@ public:
|
|||||||
void read(void *data, uint32_t offset, size_t length) const;
|
void read(void *data, uint32_t offset, size_t length) const;
|
||||||
uint32_t zipCRC32(uint32_t offset, size_t length, uint32_t crc = 0) const;
|
uint32_t zipCRC32(uint32_t offset, size_t length, uint32_t crc = 0) const;
|
||||||
|
|
||||||
bool hasBootExecutable(void) const;
|
const util::ExecutableHeader *getBootExecutableHeader(void) const;
|
||||||
uint32_t getJEDECID(void) const;
|
uint32_t getJEDECID(void) const;
|
||||||
Driver *newDriver(void) const;
|
Driver *newDriver(void) const;
|
||||||
};
|
};
|
||||||
|
@ -7,30 +7,42 @@
|
|||||||
|
|
||||||
extern "C" uint8_t _textStart[];
|
extern "C" uint8_t _textStart[];
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
static constexpr size_t _LOAD_CHUNK_LENGTH = 0x8000;
|
||||||
io::init();
|
|
||||||
|
|
||||||
args::ExecutableLauncherArgs args;
|
static int _loadFromFlash(args::ExecutableLauncherArgs &args) {
|
||||||
|
io::setFlashBank(args.device);
|
||||||
|
|
||||||
for (; argc > 0; argc--)
|
// The executable's offset and length are always passed as a single
|
||||||
args.parseArgument(*(argv++));
|
// fragment.
|
||||||
|
auto ptr = reinterpret_cast<uintptr_t>(args.loadAddress);
|
||||||
|
auto source = uintptr_t(args.fragments[0].lba);
|
||||||
|
auto length = size_t(args.fragments[0].length);
|
||||||
|
|
||||||
#if defined(ENABLE_APP_LOGGING) || defined(ENABLE_IDE_LOGGING)
|
while (length) {
|
||||||
util::logger.setupSyslog(args.baudRate);
|
size_t chunkLength = util::min(length, _LOAD_CHUNK_LENGTH);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!args.entryPoint || !args.loadAddress || !args.numFragments) {
|
__builtin_memcpy(
|
||||||
LOG_APP("required arguments missing");
|
reinterpret_cast<void *>(ptr),
|
||||||
return 1;
|
reinterpret_cast<const void *>(source), chunkLength
|
||||||
|
);
|
||||||
|
io::clearWatchdog();
|
||||||
|
|
||||||
|
ptr += chunkLength;
|
||||||
|
source += chunkLength;
|
||||||
|
length -= chunkLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args.stackTop)
|
return 0;
|
||||||
args.stackTop = _textStart - 16;
|
}
|
||||||
|
|
||||||
auto &dev = ide::devices[args.drive];
|
static int _loadFromIDE(args::ExecutableLauncherArgs &args) {
|
||||||
|
int drive = -(args.device + 1);
|
||||||
|
auto &dev = ide::devices[drive];
|
||||||
|
|
||||||
if (dev.enumerate()) {
|
auto error = dev.enumerate();
|
||||||
LOG_APP("drive %d initialization failed", args.drive);
|
|
||||||
|
if (error) {
|
||||||
|
LOG_APP("drive %d: %s", drive, ide::getErrorString(error));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,8 +69,10 @@ int main(int argc, const char **argv) {
|
|||||||
length -= skipSectors;
|
length -= skipSectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev.readData(reinterpret_cast<void *>(ptr), lba, length)) {
|
error = dev.readData(reinterpret_cast<void *>(ptr), lba, length);
|
||||||
LOG_APP("read failed, lba=0x%08x", lba);
|
|
||||||
|
if (error) {
|
||||||
|
LOG_APP("drive %d: %s", drive, ide::getErrorString(error));
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,6 +80,36 @@ int main(int argc, const char **argv) {
|
|||||||
ptr += length * sectorSize;
|
ptr += length * sectorSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char **argv) {
|
||||||
|
io::init();
|
||||||
|
|
||||||
|
args::ExecutableLauncherArgs args;
|
||||||
|
|
||||||
|
for (; argc > 0; argc--)
|
||||||
|
args.parseArgument(*(argv++));
|
||||||
|
|
||||||
|
#if defined(ENABLE_APP_LOGGING) || defined(ENABLE_IDE_LOGGING)
|
||||||
|
util::logger.setupSyslog(args.baudRate);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!args.entryPoint || !args.loadAddress || !args.numFragments) {
|
||||||
|
LOG_APP("required arguments missing");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args.stackTop)
|
||||||
|
args.stackTop = _textStart - 16;
|
||||||
|
|
||||||
|
int error = (args.device >= 0)
|
||||||
|
? _loadFromFlash(args)
|
||||||
|
: _loadFromIDE(args);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
// Launch the executable.
|
// Launch the executable.
|
||||||
util::ExecutableLoader loader(
|
util::ExecutableLoader loader(
|
||||||
args.entryPoint, args.initialGP, args.stackTop
|
args.entryPoint, args.initialGP, args.stackTop
|
||||||
|
@ -78,7 +78,7 @@ FileIOManager::FileIOManager(void)
|
|||||||
void FileIOManager::initIDE(void) {
|
void FileIOManager::initIDE(void) {
|
||||||
closeIDE();
|
closeIDE();
|
||||||
|
|
||||||
char name[6]{ "ide#:" };
|
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++) {
|
||||||
auto &dev = ide::devices[i];
|
auto &dev = ide::devices[i];
|
||||||
@ -117,7 +117,7 @@ void FileIOManager::initIDE(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FileIOManager::closeIDE(void) {
|
void FileIOManager::closeIDE(void) {
|
||||||
char name[6]{ "ide#:" };
|
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]) {
|
||||||
|
@ -41,7 +41,7 @@ bool App::_ideInitWorker(void) {
|
|||||||
#ifdef ENABLE_AUTOBOOT
|
#ifdef ENABLE_AUTOBOOT
|
||||||
// Only try to autoboot if DIP switch 1 is on.
|
// Only try to autoboot if DIP switch 1 is on.
|
||||||
if (io::getDIPSwitch(0)) {
|
if (io::getDIPSwitch(0)) {
|
||||||
_workerStatus.update(3, 4, WSTR("App.fileInitWorker.autoboot"));
|
_workerStatus.update(3, 4, WSTR("App.ideInitWorker.autoboot"));
|
||||||
|
|
||||||
for (auto path : _AUTOBOOT_PATHS) {
|
for (auto path : _AUTOBOOT_PATHS) {
|
||||||
file::FileInfo info;
|
file::FileInfo info;
|
||||||
@ -62,14 +62,14 @@ bool App::_ideInitWorker(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool App::_fileInitWorker(void) {
|
bool App::_fileInitWorker(void) {
|
||||||
_workerStatus.update(0, 4, WSTR("App.fileInitWorker.unmount"));
|
_workerStatus.update(0, 3, WSTR("App.fileInitWorker.unmount"));
|
||||||
_fileIO.closeResourceFile();
|
_fileIO.closeResourceFile();
|
||||||
_fileIO.close();
|
_fileIO.close();
|
||||||
|
|
||||||
_workerStatus.update(1, 4, WSTR("App.fileInitWorker.mount"));
|
_workerStatus.update(1, 3, WSTR("App.fileInitWorker.mount"));
|
||||||
_fileIO.initIDE();
|
_fileIO.initIDE();
|
||||||
|
|
||||||
_workerStatus.update(2, 4, WSTR("App.fileInitWorker.loadResources"));
|
_workerStatus.update(2, 3, WSTR("App.fileInitWorker.loadResources"));
|
||||||
if (_fileIO.loadResourceFile(EXTERNAL_DATA_DIR "/resource.zip"))
|
if (_fileIO.loadResourceFile(EXTERNAL_DATA_DIR "/resource.zip"))
|
||||||
_loadResources();
|
_loadResources();
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ void FilePickerScreen::update(ui::Context &ctx) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char name[6]{ "ide#:" };
|
char name[8]{ "ide#:\0" };
|
||||||
|
|
||||||
int drive = _drives[index];
|
int drive = _drives[index];
|
||||||
auto &dev = ide::devices[drive];
|
auto &dev = ide::devices[drive];
|
||||||
|
@ -72,7 +72,7 @@ void StorageInfoScreen::show(ui::Context &ctx, bool goBack) {
|
|||||||
(id >> 24) & 0xff
|
(id >> 24) & 0xff
|
||||||
);
|
);
|
||||||
|
|
||||||
if (rom::flash.hasBootExecutable())
|
if (rom::flash.getBootExecutableHeader())
|
||||||
_PRINT(STR("StorageInfoScreen.flash.bootable"));
|
_PRINT(STR("StorageInfoScreen.flash.bootable"));
|
||||||
|
|
||||||
// TODO: show information about currently installed game
|
// TODO: show information about currently installed game
|
||||||
@ -96,7 +96,7 @@ void StorageInfoScreen::show(ui::Context &ctx, bool goBack) {
|
|||||||
(id >> 24) & 0xff
|
(id >> 24) & 0xff
|
||||||
);
|
);
|
||||||
|
|
||||||
if (card.hasBootExecutable())
|
if (card.getBootExecutableHeader())
|
||||||
_PRINT(STR("StorageInfoScreen.pcmcia.bootable"));
|
_PRINT(STR("StorageInfoScreen.pcmcia.bootable"));
|
||||||
} else {
|
} else {
|
||||||
_PRINT(STR("StorageInfoScreen.pcmcia.noCard"));
|
_PRINT(STR("StorageInfoScreen.pcmcia.noCard"));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user