From 2cadaf5c68b631ffefcee5ba0018b0cd6c8ff8af Mon Sep 17 00:00:00 2001 From: Deterous <138427222+Deterous@users.noreply.github.com> Date: Sat, 6 Jun 2026 01:15:33 +0900 Subject: [PATCH 1/5] Print PS3 firmware version --- systems/ps3.ixx | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/systems/ps3.ixx b/systems/ps3.ixx index 7d948e26..e8c61661 100644 --- a/systems/ps3.ixx +++ b/systems/ps3.ixx @@ -5,6 +5,7 @@ module; #include #include #include +#include #include "system.hh" #include "throw_line.hh" @@ -77,9 +78,14 @@ public: if(!serial.empty()) os << std::format(" serial: {}", serial) << std::endl; + + auto firmware_version = pupVersion(data_reader, root_directory->subEntry("PS3_UPDATE/PS3UPDAT.PUP")); + if(!firmware_version.empty()) + os << std::format(" firmware version: {}", firmware_version) << std::endl; } private: + static constexpr uint32_t PUP_FILE_OFFSET = 0x3E; struct SFBHeader { uint8_t magic[4]; @@ -152,6 +158,32 @@ private: return sfb; } + std::string pupVersion(DataReader *data_reader, std::shared_ptr pup_file) const + { + std::string firmware_version; + + if(!pup_file) + return firmware_version; + + std::vector sector_buffer(data_reader->sectorSize()); + if(data_reader->read(sector_buffer.data(), pup_file->sectorsLBA(), 1) != 1) + return firmware_version; + + uint32_t version_offset = ((uint32_t)sector_buffer[PUP_FILE_OFFSET] << 8) | sector_buffer[PUP_FILE_OFFSET + 1]; + if(version_offset >= data_reader->sectorSize()) + { + uint32_t target_sector = pup_file->sectorsLBA() + version_offset / data_reader->sectorSize(); + if(data_reader->read(sector_buffer.data(), target_sector, 1) != 1) + return firmware_version; + } + + uint32_t relative_offset = version_offset % data_reader->sectorSize(); + if(relative_offset + 4 <= sector_buffer.size()) + firmware_version.assign((char *)§or_buffer[relative_offset], 4); + + return firmware_version; + } + protected: std::map parseSFO(std::span sfo_raw) const { From 0643be2ddeb2c849a2d0ffb2e7c50bcfa3e84be6 Mon Sep 17 00:00:00 2001 From: Deterous <138427222+Deterous@users.noreply.github.com> Date: Sat, 6 Jun 2026 01:48:25 +0900 Subject: [PATCH 2/5] Account for empty firmware update file --- systems/ps3.ixx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/systems/ps3.ixx b/systems/ps3.ixx index e8c61661..9ce255e6 100644 --- a/systems/ps3.ixx +++ b/systems/ps3.ixx @@ -170,6 +170,9 @@ private: return firmware_version; uint32_t version_offset = ((uint32_t)sector_buffer[PUP_FILE_OFFSET] << 8) | sector_buffer[PUP_FILE_OFFSET + 1]; + if(version_offset == 0) + return firmware_version; + if(version_offset >= data_reader->sectorSize()) { uint32_t target_sector = pup_file->sectorsLBA() + version_offset / data_reader->sectorSize(); From d429f74cedaf78f3e6b8ae93f93a112de5ae895b Mon Sep 17 00:00:00 2001 From: Deterous <138427222+Deterous@users.noreply.github.com> Date: Sat, 6 Jun 2026 13:18:58 +0900 Subject: [PATCH 3/5] Read version.txt record offset --- systems/ps3.ixx | 61 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/systems/ps3.ixx b/systems/ps3.ixx index 9ce255e6..8a07e39f 100644 --- a/systems/ps3.ixx +++ b/systems/ps3.ixx @@ -1,4 +1,5 @@ module; +#include #include #include #include @@ -85,7 +86,20 @@ public: } private: - static constexpr uint32_t PUP_FILE_OFFSET = 0x3E; + static constexpr std::string_view _PUP_MAGIC = "SCEUF\0\0\0"; + static constexpr uint64_t _VERSION_ID = 0x100; + static constexpr uint32_t _VERSION_LENGTH = 4; + + struct PUPHeader + { + uint8_t magic[8]; + uint64_t version; + uint64_t build; + uint64_t records_count; + uint64_t header_size; + uint64_t data_size; + }; + struct SFBHeader { uint8_t magic[4]; @@ -169,20 +183,51 @@ private: if(data_reader->read(sector_buffer.data(), pup_file->sectorsLBA(), 1) != 1) return firmware_version; - uint32_t version_offset = ((uint32_t)sector_buffer[PUP_FILE_OFFSET] << 8) | sector_buffer[PUP_FILE_OFFSET + 1]; - if(version_offset == 0) + auto header = (PUPHeader *)sector_buffer.data(); + + // check for valid PUP file + if(memcmp(header->magic, _PUP_MAGIC.data(), _PUP_MAGIC.size())) return firmware_version; - if(version_offset >= data_reader->sectorSize()) + // find version record offset + uint64_t version_offset; + uint32_t sector_number = 0; + uint32_t cur = sizeof(PUPHeader); + uint64_t records_count = endian_swap(header->records_count); + for(uint64_t i = 0; i < records_count; ++i) + { + // read next sector if needed + if(cur + 4 * sizeof(uint64_t) >= data_reader->sectorSize()) + { + sector_number += 1; + uint32_t target_sector = pup_file->sectorsLBA() + sector_number; + if(data_reader->read(sector_buffer.data(), target_sector, 1) != 1) + return firmware_version; + cur = 0; + } + + uint64_t record_type = endian_swap(*(uint64_t *)§or_buffer[cur]); + if(record_type == _VERSION_ID) + { + version_offset = endian_swap(*(uint64_t *)§or_buffer[cur + sizeof(uint64_t)]); + break; + } + + cur += 4 * sizeof(uint64_t); + } + + // read sector that version.txt is in + uint32_t version_sector = version_offset / data_reader->sectorSize(); + if(version_sector != sector_number) { - uint32_t target_sector = pup_file->sectorsLBA() + version_offset / data_reader->sectorSize(); - if(data_reader->read(sector_buffer.data(), target_sector, 1) != 1) + if(data_reader->read(sector_buffer.data(), pup_file->sectorsLBA() + version_sector, 1) != 1) return firmware_version; } + // read 4-byte string from version.txt uint32_t relative_offset = version_offset % data_reader->sectorSize(); - if(relative_offset + 4 <= sector_buffer.size()) - firmware_version.assign((char *)§or_buffer[relative_offset], 4); + if(relative_offset + _VERSION_LENGTH <= sector_buffer.size()) + firmware_version.assign((char *)§or_buffer[relative_offset], _VERSION_LENGTH); return firmware_version; } From ee8cdc4e9913b6e9ba8e6c2df2a04fc18e632f79 Mon Sep 17 00:00:00 2001 From: Deterous <138427222+Deterous@users.noreply.github.com> Date: Fri, 12 Jun 2026 14:36:40 +0900 Subject: [PATCH 4/5] PUPFile struct --- systems/ps3.ixx | 59 ++++++++++++++++++------------------------------- 1 file changed, 21 insertions(+), 38 deletions(-) diff --git a/systems/ps3.ixx b/systems/ps3.ixx index 8a07e39f..b66f0001 100644 --- a/systems/ps3.ixx +++ b/systems/ps3.ixx @@ -100,6 +100,14 @@ private: uint64_t data_size; }; + struct PUPFile + { + uint64_t type; + uint64_t offset; + uint64_t size; + uint64_t padding; + }; + struct SFBHeader { uint8_t magic[4]; @@ -174,62 +182,37 @@ private: std::string pupVersion(DataReader *data_reader, std::shared_ptr pup_file) const { - std::string firmware_version; - if(!pup_file) - return firmware_version; + return ""; std::vector sector_buffer(data_reader->sectorSize()); if(data_reader->read(sector_buffer.data(), pup_file->sectorsLBA(), 1) != 1) - return firmware_version; + return ""; auto header = (PUPHeader *)sector_buffer.data(); - // check for valid PUP file if(memcmp(header->magic, _PUP_MAGIC.data(), _PUP_MAGIC.size())) - return firmware_version; + return ""; - // find version record offset - uint64_t version_offset; - uint32_t sector_number = 0; uint32_t cur = sizeof(PUPHeader); uint64_t records_count = endian_swap(header->records_count); for(uint64_t i = 0; i < records_count; ++i) { - // read next sector if needed - if(cur + 4 * sizeof(uint64_t) >= data_reader->sectorSize()) - { - sector_number += 1; - uint32_t target_sector = pup_file->sectorsLBA() + sector_number; - if(data_reader->read(sector_buffer.data(), target_sector, 1) != 1) - return firmware_version; - cur = 0; - } + if(cur + sizeof(PUPFile) > sector_buffer.size()) + return ""; - uint64_t record_type = endian_swap(*(uint64_t *)§or_buffer[cur]); - if(record_type == _VERSION_ID) + auto file = (PUPFile *)(sector_buffer.data() + cur); + cur += sizeof(PUPFile); + if(endian_swap(file->type) == 0x100) { - version_offset = endian_swap(*(uint64_t *)§or_buffer[cur + sizeof(uint64_t)]); - break; + uint64_t version_offset = endian_swap(file->offset); + if(version_offset + 4 > sector_buffer.size()) + return ""; + return std::string((char *)(sector_buffer.data() + version_offset), 4); } - - cur += 4 * sizeof(uint64_t); - } - - // read sector that version.txt is in - uint32_t version_sector = version_offset / data_reader->sectorSize(); - if(version_sector != sector_number) - { - if(data_reader->read(sector_buffer.data(), pup_file->sectorsLBA() + version_sector, 1) != 1) - return firmware_version; } - // read 4-byte string from version.txt - uint32_t relative_offset = version_offset % data_reader->sectorSize(); - if(relative_offset + _VERSION_LENGTH <= sector_buffer.size()) - firmware_version.assign((char *)§or_buffer[relative_offset], _VERSION_LENGTH); - - return firmware_version; + return ""; } protected: From 7ab94358fd7462434a51f9f8d14b4ce8669707a5 Mon Sep 17 00:00:00 2001 From: Deterous <138427222+Deterous@users.noreply.github.com> Date: Fri, 12 Jun 2026 14:51:24 +0900 Subject: [PATCH 5/5] Use constant --- systems/ps3.ixx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/systems/ps3.ixx b/systems/ps3.ixx index b66f0001..9cab02c4 100644 --- a/systems/ps3.ixx +++ b/systems/ps3.ixx @@ -206,9 +206,9 @@ private: if(endian_swap(file->type) == 0x100) { uint64_t version_offset = endian_swap(file->offset); - if(version_offset + 4 > sector_buffer.size()) + if(version_offset > sector_buffer.size() - _VERSION_LENGTH) return ""; - return std::string((char *)(sector_buffer.data() + version_offset), 4); + return std::string((char *)(sector_buffer.data() + version_offset), _VERSION_LENGTH); } }