Fix BIOS ROM crash and ATAPI error polling

This commit is contained in:
spicyjpeg 2024-05-30 00:27:46 +02:00
parent 7702ef2258
commit 818ef7bdf1
No known key found for this signature in database
GPG Key ID: 5CC87404C01DF393
15 changed files with 147 additions and 98 deletions

View File

@ -50,7 +50,7 @@ jobs:
with:
name: build
if-no-files-found: error
path: cart-tool-*/**
path: cart-tool-*.zip
- name: Publish release
if: ${{ github.ref_type == 'tag' }}

View File

@ -218,6 +218,7 @@ function(addBootStub name resourceName)
${name} 80010000 0
src/boot/crt0.s
src/boot/main.cpp
src/common/io.cpp
src/common/util.cpp
)
addBinaryFile(

View File

@ -27,7 +27,7 @@ public:
};
int main(int argc, const char **argv) {
//io::init();
io::init();
// Parse the header of the archive's first entry manually. This avoids
// pulling in miniz and bloating the binary.

View File

@ -41,7 +41,14 @@ static size_t _comparePath(const ISORecord &record, const char *path) {
auto recordName = record.getName();
auto nameLength = record.nameLength;
for (; nameLength && (*recordName != ';'); nameLength--) {
for (; nameLength; nameLength--) {
// Files with no extension still have a trailing period, which needs to
// be stripped.
if (*recordName == ';')
break;
if ((recordName[0] == '.') && (recordName[1] == ';'))
break;
if (__builtin_toupper(*(recordName++)) != __builtin_toupper(*(ptr++)))
return 0;
}
@ -60,8 +67,14 @@ static bool _recordToFileInfo(FileInfo &output, const ISORecord &record) {
auto outputName = output.name;
for (; nameLength && (*recordName != ';'); nameLength--)
for (; nameLength; nameLength--) {
if (*recordName == ';')
break;
if ((recordName[0] == '.') && (recordName[1] == ';'))
break;
*(outputName++) = *(recordName++);
}
*outputName = 0;
@ -93,13 +106,14 @@ bool ISO9660File::_loadSector(uint32_t lba) {
}
size_t ISO9660File::read(void *output, size_t length) {
auto offset = uint32_t(_offset);
auto offset = uint32_t(_offset);
auto fileSize = size_t(size);
// Do not read any data past the end of the file.
if (offset > (size_t(size) - length))
length = size_t(size) - _offset;
if (!length)
if (!length || (offset >= fileSize))
return 0;
if (offset > (fileSize - length))
length = fileSize - offset;
auto ptr = reinterpret_cast<uintptr_t>(output);
auto remaining = length;
@ -203,7 +217,7 @@ bool ISO9660Provider::_getRecord(
return false;
if (!(*path)) {
output.copyFrom(&root);
__builtin_memcpy(&output, &root, root.getRecordLength());
return true;
}
@ -245,7 +259,7 @@ bool ISO9660Provider::_getRecord(
}
records.destroy();
LOG("%s not found", path);
LOG("not found: %s", path);
return false;
}
@ -285,7 +299,7 @@ bool ISO9660Provider::init(int drive) {
type = ISO9660;
capacity = uint64_t(pvd.volumeLength.le) * ide::ATAPI_SECTOR_SIZE;
LOG("mounted ISO: %s, drive=%d:", volumeLabel, drive);
LOG("mounted ISO: %d", drive);
return true;
}
@ -341,7 +355,7 @@ Directory *ISO9660Provider::openDirectory(const char *path) {
(record.length.le + ide::ATAPI_SECTOR_SIZE - 1) / ide::ATAPI_SECTOR_SIZE;
if (!_readData(dir->_records, record.lba.le, dirLength)) {
LOG("read failed, path=%s", path);
LOG("read failed: %s", path);
delete dir;
return nullptr;
}

View File

@ -54,14 +54,11 @@ public:
return (recordLength + 1) & ~1;
}
inline const ISOCharD *getName(void) const {
return &(this->recordLength) + sizeof(ISORecord);
return &(this->nameLength) + 1;
}
inline const uint8_t *getSystemUseData(void) const {
return getName() + ((nameLength + 1) & ~1);
}
inline void copyFrom(const void *source) {
__builtin_memcpy(this, source, sizeof(ISORecord));
}
};
class [[gnu::packed]] ISORecordBuffer : public ISORecord {

View File

@ -41,7 +41,7 @@ size_t FATFile::read(void *output, size_t length) {
auto error = f_read(&_fd, output, length, &actualLength);
if (error) {
LOG("%s, file=0x%08x", _FATFS_ERROR_NAMES[error], this);
LOG("%s", _FATFS_ERROR_NAMES[error]);
return 0;
}
@ -53,7 +53,7 @@ size_t FATFile::write(const void *input, size_t length) {
auto error = f_write(&_fd, input, length, &actualLength);
if (error) {
LOG("%s, file=0x%08x", _FATFS_ERROR_NAMES[error], this);
LOG("%s", _FATFS_ERROR_NAMES[error]);
return 0;
}
@ -64,7 +64,7 @@ uint64_t FATFile::seek(uint64_t offset) {
auto error = f_lseek(&_fd, offset);
if (error) {
LOG("%s, file=0x%08x", _FATFS_ERROR_NAMES[error], this);
LOG("%s", _FATFS_ERROR_NAMES[error]);
return 0;
}
@ -109,7 +109,7 @@ bool FATProvider::init(int drive) {
auto error = f_mount(&_fs, _drive, 1);
if (error) {
LOG("%s, drive=%s", _FATFS_ERROR_NAMES[error], _drive);
LOG("%s: %s", _FATFS_ERROR_NAMES[error], _drive);
return false;
}
@ -118,7 +118,7 @@ bool FATProvider::init(int drive) {
f_getlabel(_drive, volumeLabel, &serialNumber);
LOG("mounted FAT: %s, drive=%s", volumeLabel, _drive);
LOG("mounted FAT: %s", _drive);
return true;
}
@ -126,14 +126,14 @@ void FATProvider::close(void) {
auto error = f_unmount(_drive);
if (error) {
LOG("%s, drive=%s", _FATFS_ERROR_NAMES[error], _drive);
LOG("%s: %s", _FATFS_ERROR_NAMES[error], _drive);
return;
}
type = NONE;
capacity = 0;
LOG("FAT unmount ok, drive=%s", _drive);
LOG("unmounted FAT: %s", _drive);
}
uint64_t FATProvider::getFreeSpace(void) {
@ -145,7 +145,7 @@ uint64_t FATProvider::getFreeSpace(void) {
auto error = f_getfree(_drive, &count, &dummy);
if (error) {
LOG("%s, drive=%s", _FATFS_ERROR_NAMES[error], _drive);
LOG("%s: %s", _FATFS_ERROR_NAMES[error], _drive);
return 0;
}
@ -169,7 +169,7 @@ bool FATProvider::getFileInfo(FileInfo &output, const char *path) {
auto error = f_stat(path, &info);
if (error) {
LOG("%s, drive=%s", _FATFS_ERROR_NAMES[error], _drive);
LOG("%s: %s%s", _FATFS_ERROR_NAMES[error], _drive, path);
return false;
}
@ -211,7 +211,7 @@ bool FATProvider::getFileFragments(
_fileError:
f_close(&fd);
_openError:
LOG("%s, drive=%s", _FATFS_ERROR_NAMES[error], _drive);
LOG("%s, %s%s", _FATFS_ERROR_NAMES[error], _drive, path);
return false;
}
@ -223,7 +223,7 @@ Directory *FATProvider::openDirectory(const char *path) {
auto error = f_opendir(&(dir->_fd), path);
if (error) {
LOG("%s, drive=%s", _FATFS_ERROR_NAMES[error], _drive);
LOG("%s: %s%s", _FATFS_ERROR_NAMES[error], _drive, path);
delete dir;
return nullptr;
}
@ -238,7 +238,7 @@ bool FATProvider::createDirectory(const char *path) {
auto error = f_mkdir(path);
if (error) {
LOG("%s, drive=%s", _FATFS_ERROR_NAMES[error], _drive);
LOG("%s: %s%s", _FATFS_ERROR_NAMES[error], _drive, path);
return false;
}
@ -253,7 +253,7 @@ File *FATProvider::openFile(const char *path, uint32_t flags) {
auto error = f_open(&(_file->_fd), path, uint8_t(flags));
if (error) {
LOG("%s, drive=%s", _FATFS_ERROR_NAMES[error], _drive);
LOG("%s: %s%s", _FATFS_ERROR_NAMES[error], _drive, path);
delete _file;
return nullptr;
}

View File

@ -22,7 +22,7 @@ size_t HostFile::read(void *output, size_t length) {
int actualLength = pcdrvRead(_fd, output, length);
if (actualLength < 0) {
LOG("PCDRV error, code=%d, file=0x%08x", actualLength, this);
LOG("PCDRV error %d, fd=%d", actualLength, _fd);
return 0;
}
@ -33,7 +33,7 @@ size_t HostFile::write(const void *input, size_t length) {
int actualLength = pcdrvWrite(_fd, input, length);
if (actualLength < 0) {
LOG("PCDRV error, code=%d, file=0x%08x", actualLength, this);
LOG("PCDRV error %d, fd=%d", actualLength, _fd);
return 0;
}
@ -44,7 +44,7 @@ uint64_t HostFile::seek(uint64_t offset) {
int actualOffset = pcdrvSeek(_fd, int(offset), PCDRV_SEEK_SET);
if (actualOffset < 0) {
LOG("PCDRV error, code=%d, file=0x%08x", actualOffset, this);
LOG("PCDRV error %d, fd=%d", actualOffset, _fd);
return 0;
}
@ -55,7 +55,7 @@ uint64_t HostFile::tell(void) const {
int actualOffset = pcdrvSeek(_fd, 0, PCDRV_SEEK_CUR);
if (actualOffset < 0) {
LOG("PCDRV error, code=%d, file=0x%08x", actualOffset, this);
LOG("PCDRV error %d, fd=%d", actualOffset, _fd);
return 0;
}
@ -84,7 +84,7 @@ bool HostProvider::init(void) {
int error = pcdrvInit();
if (error < 0) {
LOG("PCDRV error, code=%d", error);
LOG("PCDRV error %d", error);
return false;
}
@ -98,7 +98,7 @@ bool HostProvider::getFileInfo(FileInfo &output, const char *path) {
int fd = pcdrvFindFirst(path, &entry);
if (fd < 0) {
LOG("PCDRV error, code=%d", fd);
LOG("PCDRV error %d: %s", fd, path);
return false;
}
@ -121,7 +121,7 @@ Directory *HostProvider::openDirectory(const char *path) {
int fd = pcdrvFindFirst(pattern, &(dir->_entry));
if (fd < 0) {
LOG("PCDRV error, code=%d", fd);
LOG("PCDRV error %d: %s", fd, path);
delete dir;
return nullptr;
}
@ -133,7 +133,7 @@ bool HostProvider::createDirectory(const char *path) {
int error = pcdrvCreateDir(path);
if (error < 0) {
LOG("PCDRV error, code=%d", error);
LOG("PCDRV error %d: %s", error, path);
return false;
}
@ -151,7 +151,7 @@ File *HostProvider::openFile(const char *path, uint32_t flags) {
int fd = pcdrvOpen(path, mode);
if (fd < 0) {
LOG("PCDRV error, code=%d", fd);
LOG("PCDRV error %d: %s", fd, path);
return nullptr;
}
@ -173,27 +173,27 @@ VFSMountPoint *VFSProvider::_getMounted(const char *path) {
return &mp;
}
LOG("unknown device: %s", path);
return nullptr;
}
bool VFSProvider::mount(const char *prefix, Provider *provider, bool force) {
auto hash = util::hash(prefix, VFS_PREFIX_SEPARATOR);
for (auto &mp : _mountPoints) {
if (force) {
if (mp.provider && (mp.provider != provider))
if (mp.prefix && (mp.prefix != hash))
continue;
} else {
if (mp.provider)
if (mp.prefix)
continue;
}
mp.prefix = util::hash(prefix, VFS_PREFIX_SEPARATOR);
mp.pathOffset = 0;
mp.prefix = hash;
mp.pathOffset = __builtin_strlen(prefix);
mp.provider = provider;
while (prefix[mp.pathOffset] != VFS_PREFIX_SEPARATOR)
mp.pathOffset++;
mp.pathOffset++;
LOG("mapped %s, dev=0x%08x", prefix, provider);
return true;
}
@ -210,6 +210,8 @@ bool VFSProvider::unmount(const char *prefix) {
mp.prefix = 0;
mp.pathOffset = 0;
mp.provider = nullptr;
LOG("unmapped %s", prefix);
return true;
}

View File

@ -116,14 +116,14 @@ bool ZIPProvider::init(File *file) {
if (!mz_zip_reader_init(&_zip, file->size, _ZIP_FLAGS)) {
auto error = mz_zip_get_last_error(&_zip);
LOG("%s, file=0x%08x", _MINIZ_ZIP_ERROR_NAMES[error], file);
LOG("%s", _MINIZ_ZIP_ERROR_NAMES[error]);
return false;
}
type = ZIP_FILE;
capacity = _zip.m_archive_size;
LOG("mounted ZIP, file=0x%08x", file);
LOG("mounted ZIP file");
return true;
}
@ -134,14 +134,14 @@ bool ZIPProvider::init(const void *zipData, size_t length) {
if (!mz_zip_reader_init_mem(&_zip, zipData, length, _ZIP_FLAGS)) {
auto error = mz_zip_get_last_error(&_zip);
LOG("%s, ptr=0x%08x", _MINIZ_ZIP_ERROR_NAMES[error], zipData);
LOG("%s: 0x%08x", _MINIZ_ZIP_ERROR_NAMES[error], zipData);
return false;
}
type = ZIP_MEMORY;
capacity = _zip.m_archive_size;
LOG("mounted ZIP, ptr=0x%08x", zipData);
LOG("mounted ZIP: 0x%08x", zipData);
return true;
}
@ -200,7 +200,7 @@ size_t ZIPProvider::loadData(util::Data &output, const char *path) {
if (!output.ptr) {
auto error = mz_zip_get_last_error(&_zip);
LOG("%s, zip=0x%08x", _MINIZ_ZIP_ERROR_NAMES[error], this);
LOG("%s: %s", _MINIZ_ZIP_ERROR_NAMES[error], path);
return 0;
}
@ -214,7 +214,7 @@ size_t ZIPProvider::loadData(void *output, size_t length, const char *path) {
if (!mz_zip_reader_extract_file_to_mem(&_zip, path, output, length, 0)) {
auto error = mz_zip_get_last_error(&_zip);
LOG("%s, zip=0x%08x", _MINIZ_ZIP_ERROR_NAMES[error], this);
LOG("%s: %s", _MINIZ_ZIP_ERROR_NAMES[error], path);
return 0;
}

View File

@ -22,7 +22,7 @@
namespace ide {
static constexpr int _STATUS_TIMEOUT = 30000000;
static constexpr int _WAIT_TIMEOUT = 30000000;
static constexpr int _DETECT_TIMEOUT = 500000;
static constexpr int _DMA_TIMEOUT = 10000;
static constexpr int _SRST_DELAY = 5000;
@ -144,14 +144,16 @@ void Device::_setLBA(uint64_t lba, size_t count) {
_write(CS0_CYLINDER_H, (lba >> 16) & 0xff);
}
DeviceError Device::_waitForStatus(uint8_t mask, uint8_t value, int timeout) {
DeviceError Device::_waitForStatus(
uint8_t mask, uint8_t value, int timeout, bool ignoreErrors
) {
if (!timeout)
timeout = _STATUS_TIMEOUT;
timeout = _WAIT_TIMEOUT;
for (; timeout > 0; timeout -= 10) {
uint8_t status = _read(CS0_STATUS);
if (status & CS0_STATUS_ERR) {
if (!ignoreErrors && (status & CS0_STATUS_ERR)) {
LOG(
"IDE error, stat=0x%02x, err=0x%02x", _read(CS0_STATUS),
_read(CS0_ERROR)
@ -160,6 +162,7 @@ DeviceError Device::_waitForStatus(uint8_t mask, uint8_t value, int timeout) {
_write(CS0_COMMAND, ATA_DEVICE_RESET);
return DRIVE_ERROR;
}
if ((status & mask) == value)
return NO_ERROR;
@ -178,8 +181,12 @@ DeviceError Device::_waitForStatus(uint8_t mask, uint8_t value, int timeout) {
return STATUS_TIMEOUT;
}
DeviceError Device::_command(uint8_t cmd, uint8_t status, int timeout) {
auto error = _waitForStatus(CS0_STATUS_BSY | status, status, timeout);
DeviceError Device::_command(
uint8_t cmd, uint8_t status, int timeout, bool ignoreErrors
) {
auto error = _waitForStatus(
CS0_STATUS_BSY | status, status, timeout, ignoreErrors
);
if (error)
return error;
@ -479,41 +486,47 @@ DeviceError Device::atapiPacket(const Packet &packet, size_t transferLength) {
auto error = _command(ATA_PACKET, 0);
if (error)
return error;
if (!error)
error = _writePIO(&packet, (flags & DEVICE_HAS_PACKET16) ? 16 : 12);
if (!error)
return _waitForStatus(CS0_STATUS_BSY, 0);
error = _writePIO(&packet, (flags & DEVICE_HAS_PACKET16) ? 16 : 12);
if (error)
return error;
return _waitForStatus(CS0_STATUS_BSY, 0);
return atapiPoll();
}
DeviceError Device::atapiPoll(void) {
Packet packet;
int senseKey = -1;
Packet packet;
SenseData data;
packet.setRequestSense();
if (!atapiPacket(packet)) {
SenseData data;
// If an error occurs, the error flag in the status register will be set but
// the drive will still accept a request sense command.
auto error = _command(ATA_PACKET, 0, 0, true);
if (!_readPIO(&data, sizeof(data))) {
senseKey = data.senseKey & 15;
LOG(
"key=0x%02x, asc=0x%02x, ascq=0x%02x", data.senseKey, data.asc,
data.ascQualifier
);
}
if (!error)
error = _writePIO(&packet, (flags & DEVICE_HAS_PACKET16) ? 16 : 12);
if (!error)
error = _waitForStatus(CS0_STATUS_BSY, 0);
if (!error)
error = _readPIO(&data, sizeof(data));
int senseKey;
if (error) {
// If the request sense command fails, fall back to reading the sense
// key from the IDE error register.
senseKey = (_read(CS0_ERROR) >> 4) & 15;
LOG("request sense failed");
} else {
senseKey = data.senseKey & 15;
LOG(
"key=0x%02x, asc=0x%02x, ascq=0x%02x", data.senseKey, data.asc,
data.ascQualifier
);
}
// If the request sense command fails, fall back to reading the sense key
// from the IDE error register.
if (senseKey < 0)
senseKey = (_read(CS0_ERROR) >> 4) & 15;
LOG("%s, key=%d", _SENSE_KEY_NAMES[senseKey], senseKey);
LOG("%s (%d)", _SENSE_KEY_NAMES[senseKey], senseKey);
switch (senseKey) {
case SENSE_KEY_NO_SENSE:

View File

@ -378,8 +378,12 @@ private:
}
void _setLBA(uint64_t lba, size_t count);
DeviceError _waitForStatus(uint8_t mask, uint8_t value, int timeout = 0);
DeviceError _command(uint8_t cmd, uint8_t status, int timeout = 0);
DeviceError _waitForStatus(
uint8_t mask, uint8_t value, int timeout = 0, bool ignoreErrors = false
);
DeviceError _command(
uint8_t cmd, uint8_t status, int timeout = 0, bool ignoreErrors = false
);
DeviceError _detectDrive(void);
DeviceError _readPIO(void *data, size_t length, int timeout = 0);

View File

@ -12,14 +12,6 @@ namespace io {
uint16_t _bankSwitchReg, _cartOutputReg, _miscOutputReg;
void init(void) {
_bankSwitchReg = 0;
_cartOutputReg = 0;
_miscOutputReg = 0
| SYS573_MISC_OUT_ADC_MOSI
| SYS573_MISC_OUT_ADC_CS
| SYS573_MISC_OUT_ADC_SCK
| SYS573_MISC_OUT_JVS_RESET;
// Remapping the base address is required in order for IDE DMA to work
// properly, as the BIU will output it over the address lines during a DMA
// transfer. It does not affect non-DMA access since the BIU will replace
@ -39,11 +31,29 @@ void init(void) {
| ( 4 << 24) // DMA read/write delay
| BIU_CTRL_DMA_DELAY;
SYS573_WATCHDOG = 0;
// 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
// bank. Normally the kernel takes care of setting up the memory controller
// appropriately, but this makes sure the configuration is correct if e.g.
// the tool is booted through OpenBIOS instead.
DRAM_CTRL = isDualBankRAM() ? 0x0c80 : 0x4788;
_bankSwitchReg = 0;
_cartOutputReg = 0;
_miscOutputReg = 0
| SYS573_MISC_OUT_ADC_MOSI
| SYS573_MISC_OUT_ADC_CS
| SYS573_MISC_OUT_ADC_SCK
| SYS573_MISC_OUT_JVS_RESET;
SYS573_BANK_CTRL = _bankSwitchReg;
SYS573_CART_OUT = _cartOutputReg;
SYS573_MISC_OUT = _miscOutputReg;
clearWatchdog();
}
void initIOBoard(void) {
// Some of the digital I/O board's light outputs are controlled by the FPGA
// and cannot be turned off until the FPGA is initialized.
if (isDigitalIOPresent()) {

View File

@ -40,7 +40,7 @@ enum JAMMAInput : uint32_t {
// SYS573_JAMMA_EXT2
JAMMA_P2_BUTTON4 = 1 << 20,
JAMMA_P2_BUTTON5 = 1 << 21,
JAMMA_UNKNOWN = 1 << 22,
JAMMA_RAM_LAYOUT = 1 << 22,
JAMMA_P2_BUTTON6 = 1 << 23,
// SYS573_MISC_IN
@ -72,7 +72,7 @@ enum MiscOutputPin {
MISC_AMP_ENABLE = 5,
MISC_CDDA_ENABLE = 6,
MISC_SPU_ENABLE = 7,
MISC_JVS_STAT = 8
MISC_JVS_RESET = 8
};
/* Inputs */
@ -81,6 +81,10 @@ static inline void clearWatchdog(void) {
SYS573_WATCHDOG = 0;
}
static inline bool isDualBankRAM(void) {
return (SYS573_JAMMA_EXT2 >> 10) & 1;
}
static inline bool getDIPSwitch(int bit) {
return !((SYS573_DIP_CART >> bit) & 1);
}
@ -159,6 +163,7 @@ static inline void setDIO1Wire(bool value) {
/* Other APIs */
void init(void);
void initIOBoard(void);
uint32_t getJAMMAInputs(void);
void getRTCTime(util::Date &output);
void setRTCTime(const util::Date &value, bool stop = false);

View File

@ -10,13 +10,13 @@
#include "ps1/system.h"
static const char *const _AUTOBOOT_PATHS[][2]{
{ "hdd:/noboot.txt", "hdd:/psx.exe" },
{ "cdrom:/noboot.txt", "cdrom:/psx.exe" },
{ "cdrom:/noboot.txt", "cdrom:/qsy.dxd" },
{ "cdrom:/noboot.txt", "cdrom:/ssw.bxf" },
{ "cdrom:/noboot.txt", "cdrom:/tsv.axg" },
{ "cdrom:/noboot.txt", "cdrom:/gse.nxx" },
{ "cdrom:/noboot.txt", "cdrom:/nse.gxx" }
{ "cdrom:/noboot.txt", "cdrom:/nse.gxx" },
{ "hdd:/noboot.txt", "hdd:/psx.exe" }
};
bool App::_ideInitWorker(void) {

View File

@ -185,6 +185,7 @@ static const Action _ACTIONS[]{
.prompt = "StorageActionsScreen.resetFlashHeader.prompt"_h,
.region = rom::flash,
.target = &StorageActionsScreen::resetFlashHeader
#if 0
}, {
.name = "StorageActionsScreen.matchFlashHeader.name"_h,
.prompt = "StorageActionsScreen.matchFlashHeader.prompt"_h,
@ -195,6 +196,7 @@ static const Action _ACTIONS[]{
.prompt = "StorageActionsScreen.editFlashHeader.prompt"_h,
.region = rom::flash,
.target = &StorageActionsScreen::editFlashHeader
#endif
}
};

View File

@ -14,6 +14,7 @@ int main(int argc, const char **argv) {
gpu::init();
spu::init();
io::init();
io::initIOBoard();
util::initZipCRC32();
args::MainArgs args;