Fix crashes and autobooting, clean up struct attributes

This commit is contained in:
spicyjpeg 2024-06-02 22:07:50 +02:00
parent 10ed088011
commit 6083c0cbe6
No known key found for this signature in database
GPG Key ID: 5CC87404C01DF393
18 changed files with 154 additions and 92 deletions

View File

@ -106,8 +106,8 @@
},
"atapiEjectWorker": {
"eject": "Sending eject command...",
"noDrive": "No ATAPI CD-ROM drive has been found on the IDE bus or could be successfully initialized. Your drive might be incompatible with the ATAPI driver used by this tool.\n\nPress the Test button to view debug logs.",
"ejectError": "Failed to open the drive's tray. Your drive might be incompatible with the ATAPI driver used by this tool.\n\nError code: %s\nPress the Test button to view debug logs."
"noDrive": "No ATAPI CD-ROM drive has been found on the IDE bus or could be successfully initialized. Your drive may be incompatible with the ATAPI driver used by this tool.\n\nPress the Test button to view debug logs.",
"ejectError": "Failed to open the drive's tray. Make sure the drive's front panel is not blocked off by the 573's case. Your drive may also be incompatible with the ATAPI driver used by this tool.\n\nError code: %s\nPress the Test button to view debug logs."
},
"rebootWorker": {
"reboot": "Rebooting system..."
@ -308,9 +308,10 @@
"itemPrompt": "{RIGHT_ARROW} Press {START_BUTTON} to select, hold {LEFT_BUTTON}{RIGHT_BUTTON} + {START_BUTTON} to go back",
"host": "{HOST_ICON} Host filesystem (PCDRV)",
"noFS": "no disc or unsupported FS",
"noDeviceError": "No drives have been found and successfully initialized on the IDE bus. Make sure the drives are appropriately configured as primary or secondary and are receiving power.\n\nPress the Test button to view debug logs.",
"atapiError": "Failed to initialize the CD-ROM drive or access the filesystem on it. Your drive might be incompatible with the ATAPI driver used by this tool.\n\nPress the Test button to view debug logs.",
"atapiError": "Failed to initialize the CD-ROM drive or access the filesystem on it. Ensure a disc is inserted and formatted with a valid ISO9660 filesystem. Your drive may also be incompatible with the ATAPI driver used by this tool.\n\nPress the Test button to view debug logs.",
"ideError": "Failed to initialize the drive or access the filesystem on it. Turn off the system and make sure the drive is connected to the IDE bus properly, set as secondary (if a CD-ROM drive is also present) and formatted with a single FAT16, FAT32 or exFAT partition.\n\nPress the Test button to view debug logs.",
"noFilesError": "No files or directories have been found in the root of the selected drive's filesystem."
},

View File

@ -144,7 +144,7 @@ public:
static constexpr int TABLE_BUCKET_COUNT = 256;
struct [[gnu::packed]] StringTableEntry {
struct StringTableEntry {
public:
uint32_t hash;
uint16_t offset, chained;

View File

@ -159,12 +159,12 @@ public:
/* Image class */
struct [[gnu::packed]] TIMHeader {
struct TIMHeader {
public:
uint32_t magic, flags;
};
struct [[gnu::packed]] TIMSectionHeader {
struct TIMSectionHeader {
public:
uint32_t length;
RectWH vram;

View File

@ -10,7 +10,7 @@ namespace gpu {
static constexpr char FONT_INVALID_CHAR = 0x7f;
class [[gnu::packed]] FontMetrics {
class FontMetrics {
public:
uint8_t spaceWidth, tabWidth, lineHeight, _reserved;
uint32_t characterSizes[256];

View File

@ -165,7 +165,8 @@ static constexpr int _DMA_TIMEOUT = 10000;
Device devices[2]{ (DEVICE_PRIMARY), (DEVICE_SECONDARY) };
Device::Device(uint32_t flags)
: flags(flags), capacity(0), lastStatusReg(0), lastErrorReg(0) {
: flags(flags), capacity(0), lastStatusReg(0), lastErrorReg(0), lastCountReg(0)
{
util::clear(lastSenseData);
}
@ -299,10 +300,11 @@ DeviceError Device::_waitForDRQ(int timeout, bool ignoreError) {
void Device::_handleError(void) {
lastStatusReg = _read(CS0_STATUS);
lastErrorReg = _read(CS0_ERROR);
lastCountReg = _read(CS0_COUNT);
LOG_IDE(
"drive=%d, st=0x%02x, err=0x%02x", (flags / DEVICE_SECONDARY) & 1,
lastStatusReg, lastErrorReg
"%d, st=0x%02x, err=0x%02x, cnt=0x%02x", getDriveIndex(), lastStatusReg,
lastErrorReg, lastCountReg
);
// Issuing a device reset command to an ATAPI drive would result in the
@ -314,10 +316,11 @@ void Device::_handleError(void) {
void Device::_handleTimeout(void) {
lastStatusReg = _read(CS0_STATUS);
lastErrorReg = _read(CS0_ERROR);
lastCountReg = _read(CS0_COUNT);
LOG_IDE(
"drive=%d, st=0x%02x, err=0x%02x", (flags / DEVICE_SECONDARY) & 1,
lastStatusReg, lastErrorReg
"%d, st=0x%02x, err=0x%02x, cnt=0x%02x", getDriveIndex(), lastStatusReg,
lastErrorReg, lastCountReg
);
_write(CS0_COMMAND, ATA_DEVICE_RESET);
@ -333,7 +336,7 @@ DeviceError Device::_resetDrive(void) {
_select(0);
if (_waitForIdle(false, _DETECT_TIMEOUT, true)) {
LOG_IDE("drive %d select timeout", (flags / DEVICE_SECONDARY) & 1);
LOG_IDE("drive %d select timeout", getDriveIndex());
return NO_DRIVE;
}
@ -361,7 +364,7 @@ DeviceError Device::_resetDrive(void) {
#endif
}
LOG_IDE("drive %d not responding", (flags / DEVICE_SECONDARY) & 1);
LOG_IDE("drive %d not responding", getDriveIndex());
return NO_DRIVE;
}
@ -463,7 +466,12 @@ DeviceError Device::_atapiRequestSense(void) {
auto error = _waitForIdle(false, _REQ_SENSE_TIMEOUT, true);
if (!error) {
_write(CS0_FEATURES, 0);
#if 0
_setCylinder(sizeof(SenseData));
#else
_setCylinder(ATAPI_SECTOR_SIZE);
#endif
_write(CS0_COMMAND, ATA_PACKET);
error = _waitForDRQ(_REQ_SENSE_TIMEOUT, true);
@ -485,7 +493,9 @@ DeviceError Device::_atapiRequestSense(void) {
// If the request sense command fails, fall back to reading the sense
// key from the error register.
lastSenseData.senseKey = lastErrorReg >> 4;
LOG_IDE("%s", DEVICE_ERROR_NAMES[error]);
LOG_IDE("%s", getErrorString(error));
_write(CS0_COMMAND, ATA_DEVICE_RESET);
}
return _senseDataToError(lastSenseData);
@ -510,7 +520,12 @@ DeviceError Device::_atapiPacket(const Packet &packet, size_t dataLength) {
auto error = _waitForIdle();
if (!error) {
_write(CS0_FEATURES, 0);
#if 0
_setCylinder(dataLength);
#else
_setCylinder(ATAPI_SECTOR_SIZE);
#endif
_write(CS0_COMMAND, ATA_PACKET);
error = _waitForDRQ();
@ -527,12 +542,12 @@ DeviceError Device::_atapiPacket(const Packet &packet, size_t dataLength) {
// If an error occurred, fetch sense data to determine whether to resend
// the command.
LOG_IDE("%s, cmd=0x%02x", DEVICE_ERROR_NAMES[error], packet.command);
LOG_IDE("%s, cmd=0x%02x", getErrorString(error), packet.command);
error = _atapiRequestSense();
if (error && (error != NOT_YET_READY)) {
LOG_IDE("%s (from sense)", DEVICE_ERROR_NAMES[error]);
LOG_IDE("%s (from sense)", getErrorString(error));
return error;
}
@ -654,7 +669,7 @@ DeviceError Device::enumerate(void) {
if (error)
return error;
LOG_IDE("drive %d ready, mode=PIO%d", (flags / DEVICE_SECONDARY) & 1, mode);
LOG_IDE("drive %d ready, mode=PIO%d", getDriveIndex(), mode);
flags |= DEVICE_READY;
// Make sure any pending ATAPI sense data is cleared.

View File

@ -38,7 +38,7 @@ enum IdentifyCapabilitiesFlag : uint16_t {
IDENTIFY_CAP_FLAG_DMA_INTERLEAVE = 1 << 15
};
class IdentifyBlock {
class alignas(uint32_t) IdentifyBlock {
public:
uint16_t deviceFlags; // 0
uint16_t _reserved[9];
@ -100,7 +100,7 @@ public:
/* ATAPI data structures */
class SenseData {
class alignas(uint32_t) SenseData {
public:
uint8_t errorCode; // 0
uint8_t _reserved; // 1
@ -126,7 +126,7 @@ public:
}
};
class Packet {
class alignas(uint32_t) Packet {
public:
uint8_t command;
uint8_t param[11];
@ -268,9 +268,12 @@ public:
#endif
uint64_t capacity;
uint8_t lastStatusReg, lastErrorReg;
uint8_t lastStatusReg, lastErrorReg, lastCountReg;
SenseData lastSenseData;
inline int getDriveIndex(void) const {
return (flags / DEVICE_SECONDARY) & 1;
}
inline size_t getSectorSize(void) const {
return (flags & DEVICE_ATAPI) ? ATAPI_SECTOR_SIZE : ATA_SECTOR_SIZE;
}

View File

@ -48,6 +48,17 @@ enum CS1DeviceControlFlag : uint8_t {
CS1_DEVICE_CTRL_HOB = 1 << 7 // High-order bit (LBA48)
};
enum CS0FeaturesFlag : uint8_t {
CS0_FEATURES_DMA = 1 << 0, // Use DMA for data (ATAPI)
CS0_FEATURES_OVL = 1 << 1 // Overlap (ATAPI)
};
enum CS0CountFlag : uint8_t {
CS0_COUNT_CD = 1 << 0, // Command or data (ATAPI)
CS0_COUNT_IO = 1 << 1, // Input or output (ATAPI)
CS0_COUNT_REL = 1 << 2 // Bus release (ATAPI)
};
/* ATA command definitions */
enum ATACommand : uint8_t {

View File

@ -78,7 +78,7 @@ extern const FlashRegion flash, pcmcia[2];
/* BIOS ROM headers */
struct [[gnu::packed]] SonyKernelHeader {
struct SonyKernelHeader {
public:
uint8_t day, month;
uint16_t year;
@ -88,7 +88,7 @@ public:
bool validateMagic(void) const;
};
struct [[gnu::packed]] OpenBIOSHeader {
struct OpenBIOSHeader {
public:
uint8_t magic[8];
uint32_t idNameLength, idDescLength, idType;

View File

@ -40,7 +40,7 @@ size_t upload(uint32_t ramOffset, const void *data, size_t length, bool wait);
/* Sound class */
struct [[gnu::packed]] VAGHeader {
struct VAGHeader {
public:
uint32_t magic, version, interleave, length, sampleRate;
uint16_t _reserved[5], channels;

View File

@ -288,7 +288,7 @@ extern Logger logger;
static constexpr size_t EXECUTABLE_BODY_OFFSET = 2048;
static constexpr size_t MAX_EXECUTABLE_ARGS = 32;
class [[gnu::packed]] ExecutableHeader {
class ExecutableHeader {
public:
uint8_t magic[8], _pad[8];

View File

@ -15,19 +15,28 @@ int main(int argc, const char **argv) {
for (; argc > 0; argc--)
args.parseArgument(*(argv++));
#ifdef ENABLE_LOGGING
#if defined(ENABLE_APP_LOGGING) || defined(ENABLE_IDE_LOGGING)
util::logger.setupSyslog(args.baudRate);
#endif
if (!args.entryPoint || !args.loadAddress || !args.numFragments)
if (!args.entryPoint || !args.loadAddress || !args.numFragments) {
LOG_APP("required arguments missing");
return 1;
}
if (!args.stackTop)
args.stackTop = _textStart - 16;
auto &dev = ide::devices[args.drive];
auto &dev = ide::devices[args.drive];
auto error = dev.enumerate();
if (dev.enumerate())
while ((error == ide::NOT_YET_READY) || (error == ide::DISC_CHANGED))
error = dev.poll();
if (error) {
LOG_APP("drive %d initialization failed", args.drive);
return 2;
}
io::clearWatchdog();
@ -52,8 +61,10 @@ int main(int argc, const char **argv) {
length -= skipSectors;
}
if (dev.readData(reinterpret_cast<void *>(ptr), lba, length))
if (dev.readData(reinterpret_cast<void *>(ptr), lba, length)) {
LOG_APP("read failed, lba=0x%08x", lba);
return 3;
}
io::clearWatchdog();
ptr += length * sectorSize;

View File

@ -141,6 +141,10 @@ bool FileIOManager::loadResourceFile(const char *path) {
if (_resourceFile) {
if (resource.init(_resourceFile))
return true;
_resourceFile->close();
delete _resourceFile;
_resourceFile = nullptr;
}
resource.init(resourcePtr, resourceLength);

View File

@ -30,23 +30,16 @@ bool App::_ideInitWorker(void) {
_workerStatus.update(
i, util::countOf(ide::devices), WSTR("App.ideInitWorker.init")
);
dev.enumerate();
auto error = dev.enumerate();
while ((error == ide::NOT_YET_READY) || (error == ide::DISC_CHANGED))
error = dev.poll();
LOG_APP("drive %d: %s", i, ide::getErrorString(error));
}
return _fileInitWorker();
}
bool App::_fileInitWorker(void) {
_workerStatus.update(0, 4, WSTR("App.fileInitWorker.unmount"));
_fileIO.closeResourceFile();
_fileIO.close();
_workerStatus.update(1, 4, WSTR("App.fileInitWorker.mount"));
_fileIO.initIDE();
_workerStatus.update(2, 4, WSTR("App.fileInitWorker.loadResources"));
if (_fileIO.loadResourceFile(EXTERNAL_DATA_DIR "/resource.zip"))
_loadResources();
_fileInitWorker();
#ifdef ENABLE_AUTOBOOT
// Only try to autoboot if DIP switch 1 is on.
@ -71,6 +64,21 @@ bool App::_fileInitWorker(void) {
return true;
}
bool App::_fileInitWorker(void) {
_workerStatus.update(0, 4, WSTR("App.fileInitWorker.unmount"));
_fileIO.closeResourceFile();
_fileIO.close();
_workerStatus.update(1, 4, WSTR("App.fileInitWorker.mount"));
_fileIO.initIDE();
_workerStatus.update(2, 4, WSTR("App.fileInitWorker.loadResources"));
if (_fileIO.loadResourceFile(EXTERNAL_DATA_DIR "/resource.zip"))
_loadResources();
return true;
}
struct Launcher {
public:
const char *path;

View File

@ -135,20 +135,14 @@ const char *FilePickerScreen::_getItemName(ui::Context &ctx, int index) const {
auto &dev = ide::devices[drive];
auto fs = APP->_fileIO.ide[drive];
if (dev.flags & ide::DEVICE_ATAPI)
name[0] = CH_CDROM_ICON;
else
name[0] = CH_HDD_ICON;
name[1] = ' ';
if (fs)
snprintf(
&name[2], sizeof(name) - 2, "%s: %s", dev.model, fs->volumeLabel
);
else
__builtin_strncpy(&name[2], dev.model, sizeof(name) - 2);
auto icon = (dev.flags & ide::DEVICE_ATAPI)
? CH_CDROM_ICON
: CH_HDD_ICON;
auto label = fs
? fs->volumeLabel
: STR("FilePickerScreen.noFS");
snprintf(name, sizeof(name), "%c %s: %s", icon, dev.model, label);
return name;
}

View File

@ -33,7 +33,7 @@ static constexpr size_t MAX_QR_STRING_LENGTH = 0x600;
/* Identifier structure */
class [[gnu::packed]] Identifier {
class Identifier {
public:
uint8_t data[8];
@ -72,7 +72,7 @@ public:
extern const ChipSize CHIP_SIZES[NUM_CHIP_TYPES];
class [[gnu::packed]] CartDump {
class CartDump {
public:
uint16_t magic;
ChipType chipType;
@ -131,7 +131,7 @@ public:
/* Flash and RTC header dump structure */
class [[gnu::packed]] ROMHeaderDump {
class ROMHeaderDump {
public:
uint16_t magic;
uint8_t _reserved, flags;

View File

@ -53,7 +53,7 @@ static constexpr size_t REGION_MAX_LENGTH = 5;
/* Common data structures */
class [[gnu::packed]] IdentifierSet {
class IdentifierSet {
public:
Identifier traceID, cartID, installID, systemID; // aka TID, SID, MID, XID
@ -64,7 +64,7 @@ public:
);
};
class [[gnu::packed]] PublicIdentifierSet {
class PublicIdentifierSet {
public:
Identifier installID, systemID; // aka MID, XID
@ -72,12 +72,12 @@ public:
void setInstallID(uint8_t prefix);
};
class [[gnu::packed]] SimpleHeader {
class SimpleHeader {
public:
char region[4];
};
class [[gnu::packed]] BasicHeader {
class BasicHeader {
public:
char region[2], codePrefix[2];
uint8_t checksum, _pad[3];
@ -86,7 +86,7 @@ public:
bool validateChecksum(bool invert = false) const;
};
class [[gnu::packed]] ExtendedHeader {
class ExtendedHeader {
public:
char code[8];
uint16_t year; // BCD, can be little endian, big endian or zero
@ -245,7 +245,7 @@ ROMHeaderParser *newROMHeaderParser(ROMHeaderDump &dump);
/* Cartridge and flash header database */
class [[gnu::packed]] CartDBEntry {
class CartDBEntry {
public:
ChipType chipType;
FormatType formatType;
@ -287,7 +287,7 @@ public:
}
};
class [[gnu::packed]] ROMHeaderDBEntry {
class ROMHeaderDBEntry {
public:
FormatType formatType;
uint8_t flags;

View File

@ -21,9 +21,7 @@ int main(int argc, const char **argv) {
for (; argc > 0; argc--)
args.parseArgument(*(argv++));
#ifdef ENABLE_LOGGING
util::logger.setupSyslog(args.baudRate);
#endif
// A pointer to the resource archive is always provided on the command line
// by the boot stub.
@ -42,7 +40,7 @@ int main(int argc, const char **argv) {
io::resetIDEDevices();
gpu::enableDisplay(true);
spu::setMasterVolume(spu::MAX_VOLUME);
spu::setMasterVolume(spu::MAX_VOLUME / 2);
io::setMiscOutput(io::MISC_SPU_ENABLE, true);
app->run(args.resourcePtr, args.resourceLength);

View File

@ -13,40 +13,57 @@ namespace ui {
/* Button state manager */
static const uint32_t _BUTTON_MAPPINGS[NUM_BUTTON_MAPS][NUM_BUTTONS]{
{ // MAP_JOYSTICK
io::JAMMA_P1_LEFT | io::JAMMA_P1_UP | io::JAMMA_P2_LEFT | io::JAMMA_P2_UP,
io::JAMMA_P1_RIGHT | io::JAMMA_P1_DOWN | io::JAMMA_P2_RIGHT | io::JAMMA_P2_DOWN,
io::JAMMA_P1_START | io::JAMMA_P1_BUTTON1 | io::JAMMA_P2_START | io::JAMMA_P2_BUTTON1,
{
// MAP_JOYSTICK
0
| io::JAMMA_P1_LEFT
| io::JAMMA_P2_LEFT
| io::JAMMA_P1_UP
| io::JAMMA_P2_UP,
0
| io::JAMMA_P1_RIGHT
| io::JAMMA_P2_RIGHT
| io::JAMMA_P1_DOWN
| io::JAMMA_P2_DOWN,
0
| io::JAMMA_P1_START
| io::JAMMA_P2_START
| io::JAMMA_P1_BUTTON1
| io::JAMMA_P2_BUTTON1,
io::JAMMA_TEST | io::JAMMA_SERVICE
},
{ // MAP_DDR_CAB
}, {
// MAP_DDR_CAB
io::JAMMA_P1_BUTTON2 | io::JAMMA_P2_BUTTON2,
io::JAMMA_P1_BUTTON3 | io::JAMMA_P2_BUTTON3,
io::JAMMA_P1_START | io::JAMMA_P2_START,
io::JAMMA_TEST | io::JAMMA_SERVICE
},
{ // MAP_DDR_SOLO_CAB
io::JAMMA_P1_START | io::JAMMA_P2_START,
io::JAMMA_TEST | io::JAMMA_SERVICE
}, {
// MAP_DDR_SOLO_CAB
io::JAMMA_P1_BUTTON5,
io::JAMMA_P2_BUTTON5,
io::JAMMA_P1_START,
io::JAMMA_TEST | io::JAMMA_SERVICE
},
{ // MAP_DM_CAB
}, {
// MAP_DM_CAB
io::JAMMA_P2_LEFT,
io::JAMMA_P2_RIGHT,
io::JAMMA_P1_START,
io::JAMMA_TEST | io::JAMMA_SERVICE
},
{ // MAP_DMX_CAB (more or less redundant with MAP_JOYSTICK)
io::JAMMA_P1_UP | io::JAMMA_P2_UP,
io::JAMMA_P1_DOWN | io::JAMMA_P2_DOWN,
}, {
// MAP_DMX_CAB (more or less redundant with MAP_JOYSTICK)
io::JAMMA_P1_UP | io::JAMMA_P2_UP,
io::JAMMA_P1_DOWN | io::JAMMA_P2_DOWN,
io::JAMMA_P1_START | io::JAMMA_P2_START,
io::JAMMA_TEST | io::JAMMA_SERVICE
},
{ // MAP_SINGLE_BUTTON
io::JAMMA_TEST | io::JAMMA_SERVICE
}, {
// MAP_SINGLE_BUTTON
0,
0,
io::JAMMA_P1_START | io::JAMMA_P2_START | io::JAMMA_TEST | io::JAMMA_SERVICE,
0
| io::JAMMA_P1_START
| io::JAMMA_P2_START
| io::JAMMA_TEST
| io::JAMMA_SERVICE,
0
}
};