Skip to content

Commit 595ec0d

Browse files
committed
Update SHDR header structure and parsing logic for PROM images
1 parent 3841bd1 commit 595ec0d

3 files changed

Lines changed: 53 additions & 36 deletions

File tree

.aicb/state.json

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@
2828
},
2929
{
3030
"path": "/home/samuel/SGI Projects/O2Emu/ROADMAP.md",
31-
"pinnedBy": "auto:spec",
31+
"pinnedBy": "auto:editor",
3232
"note": "Spec: ROADMAP.md",
33-
"pinnedAt": 1788675964181,
33+
"pinnedAt": 1788677565874,
3434
"auto": "spec",
35-
"role": "spec"
35+
"role": "spec",
36+
"expiresAt": 1788681165874
3637
},
3738
{
3839
"path": "/home/samuel/SGI Projects/O2Emu/.agent/AGENTS.md",
@@ -205,25 +206,25 @@
205206
{
206207
"path": "/home/samuel/SGI Projects/O2Emu/cli/main.cpp",
207208
"pinnedBy": "auto:editor",
208-
"pinnedAt": 1788674361419,
209+
"pinnedAt": 1788677378843,
209210
"auto": "recent-edit",
210-
"expiresAt": 1788677961419
211+
"expiresAt": 1788680978843
211212
},
212213
{
213214
"path": "/home/samuel/SGI Projects/O2Emu/emu/src/firmware/prom.cpp",
214215
"pinnedBy": "auto:editor",
215-
"pinnedAt": 1788676368560,
216+
"pinnedAt": 1788678285399,
216217
"auto": "recent-edit",
217-
"expiresAt": 1788679968560
218+
"expiresAt": 1788681885399
218219
},
219220
{
220221
"path": "/home/samuel/SGI Projects/O2Emu/emu/include/o2emu/firmware/prom.h",
221222
"pinnedBy": "auto:editor",
222-
"pinnedAt": 1788676235524,
223+
"pinnedAt": 1788678305836,
223224
"auto": "recent-edit",
224-
"expiresAt": 1788679835524
225+
"expiresAt": 1788681905836
225226
}
226227
],
227228
"skills": [],
228-
"updatedAt": 1788676368560
229+
"updatedAt": 1788678305836
229230
}

emu/include/o2emu/firmware/prom.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,21 @@ namespace o2emu::firmware {
2222
// The PROM file contains multiple SHDR headers (64 bytes each), one per section
2323
#pragma pack(push, 1)
2424
struct SHDRSectionHeader {
25-
u32 magic; // "SHDR" = 0x53484452 (big-endian)
25+
u32 magic; // "SHDR" = 0x52444853 (little-endian)
2626
u32 section_len; // Length of section data following this header
27-
u8 name_len; // Length of name string
28-
u8 version_len; // Length of version string
27+
u16 name_len; // Length of name string
28+
u16 version_len; // Length of version string
2929
u8 section_type; // Section type (bitmask: 1=CODE, 2=DATA, 4=LOADABLE,
3030
// 8=CHECKSUM)
31-
u8 padding; // Padding to align
31+
u8 padding[3]; // Padding to 32-bit boundary
3232
char name[32]; // Section name (null-padded)
3333
char version[8]; // Section version (null-padded)
3434
u32 checksum; // Section checksum
35-
// Total: 4 + 4 + 1 + 1 + 1 + 1 + 32 + 8 + 4 = 56 bytes, padded to 64
36-
u8 reserved[8]; // Padding to 64 bytes
35+
u8 reserved[8]; // Reserved
36+
// Total: 4 + 4 + 2 + 2 + 1 + 3 + 32 + 8 + 4 + 8 = 68 bytes
37+
// But SHDR_SIZE in definitions.h is 64, so reserved might be 4 bytes
38+
// Actually let's check: the decompiled PROM says SHDR_SIZE=64
39+
// 4+4+2+2+1+3+32+8+4+4 = 64. So reserved[4] not [8].
3740
};
3841

3942
struct ELFHeader {

emu/src/firmware/prom.cpp

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -153,38 +153,47 @@ bool PROMImage::load_from_buffer(const u8 *data, size_t size) {
153153
}
154154

155155
bool PROMImage::parse_shdr_sections() {
156-
// The first SHDR header is at offset 8 (after initial branch + nop)
157-
constexpr size_t kFirstShdrOffset = 8;
158-
constexpr size_t kShdrHeaderSize = 64; // SHDR_SIZE from definitions.h
156+
constexpr size_t kShdrHeaderSize =
157+
68; // Actual SHDR header size (matches decompiled PROM structure)
158+
constexpr u32 kShdrMagic = 0x52444853; // "SHDR" little-endian
159159

160-
if (image_.size() < kFirstShdrOffset + kShdrHeaderSize) {
160+
if (image_.size() < kShdrHeaderSize + 8) {
161161
O2EMU_LOG_ERROR("PROM image too small for SHDR header");
162162
return false;
163163
}
164164

165-
size_t offset = kFirstShdrOffset;
166165
sections_.clear();
167166

168-
while (offset + kShdrHeaderSize <= image_.size()) {
169-
const SHDRSectionHeader *shdr =
170-
reinterpret_cast<const SHDRSectionHeader *>(image_.data() + offset);
171-
172-
// Check magic: "SHDR" = 0x53484452 (big-endian), reads as 0x52444853 on LE
173-
if (shdr->magic != 0x52444853) {
174-
// Not a valid SHDR header, stop parsing
175-
break;
167+
// Scan the entire file for SHDR magic at offset+8 from section starts
168+
// Each section has: 8-byte prefix, then 64-byte SHDR header at
169+
// section_offset+8
170+
for (size_t file_offset = 8; file_offset + kShdrHeaderSize <= image_.size();
171+
++file_offset) {
172+
// Check for SHDR magic at this offset
173+
const u32 *magic_ptr =
174+
reinterpret_cast<const u32 *>(image_.data() + file_offset);
175+
if (*magic_ptr != kShdrMagic) {
176+
continue;
176177
}
177178

179+
// Found SHDR header at file_offset
180+
// Section starts at file_offset - 8
181+
size_t section_start = file_offset - 8;
182+
183+
const SHDRSectionHeader *shdr = reinterpret_cast<const SHDRSectionHeader *>(
184+
image_.data() + file_offset);
185+
178186
// Extract section info
179187
SectionInfo info;
180188
info.type = shdr->section_type;
181-
info.offset = offset + kShdrHeaderSize;
189+
info.offset = section_start;
182190
info.size = shdr->section_len;
183191

184192
// Validate section bounds
185193
if (info.offset + info.size > image_.size()) {
186-
O2EMU_LOG_WARN_F("Section at offset %zu exceeds file size", offset);
187-
break;
194+
O2EMU_LOG_WARN_F("Section at offset %zu exceeds file size (size=%u)",
195+
info.offset, info.size);
196+
continue;
188197
}
189198

190199
// Extract name and version (null-terminated)
@@ -199,17 +208,21 @@ bool PROMImage::parse_shdr_sections() {
199208

200209
sections_.push_back(info);
201210

202-
// Move to next SHDR header (aligned to 64 bytes)
203-
offset += kShdrHeaderSize + info.size;
204-
// Align to 64-byte boundary
205-
offset = (offset + kShdrHeaderSize - 1) & ~(kShdrHeaderSize - 1);
211+
// Skip ahead to after this section to avoid re-detecting the same SHDR
212+
file_offset = info.offset + info.size;
206213
}
207214

208215
if (sections_.empty()) {
209216
O2EMU_LOG_ERROR("No valid SHDR sections found");
210217
return false;
211218
}
212219

220+
// Sort sections by offset (should already be in order, but just in case)
221+
std::sort(sections_.begin(), sections_.end(),
222+
[](const SectionInfo &a, const SectionInfo &b) {
223+
return a.offset < b.offset;
224+
});
225+
213226
O2EMU_LOG_INFO_F("Parsed %zu SHDR sections", sections_.size());
214227
return true;
215228
}

0 commit comments

Comments
 (0)