Conversation
* Initial OmniDrive support * Count SCSI errors in dumpable range during refine * Initial Xbox support * Raw BD support * revert bd * revert one more * Code review
📝 WalkthroughWalkthroughAdds DVD subsystem and OmniDrive/raw read support: new dvd modules (framing, EDC, scrambler), GF(256) utilities, OmniDrive SCSI opcode/command, drive reserved5 and OmniDrive detection, per-sector DVD dump refactor with read_dvd_sectors, signed LBA/range API changes, OVERREAD_COUNT and CHUNK_1MB, and build/test updates. Changes
Sequence DiagramsequenceDiagram
participant App as Redumper
participant Drive as Drive (inquiry / reserved5)
participant SCSI as SPTD / SCSI
participant Dump as DumpConfig
participant DVD as dvd module
participant EDC as DVD_EDC
participant FS as File I/O
App->>Drive: query drive (inquiry -> DriveConfig)
Drive-->>App: DriveConfig + optional OmniDrive version
App->>Dump: dump_get_config(disc_type, raw)
Dump-->>App: sector_size, image_extension, lba_start/end
alt OmniDrive + raw
App->>SCSI: cmd_read_omnidrive(buffer, block_size, lba, count, disc_type, ...)
SCSI-->>App: raw sector data
else standard read
App->>SCSI: standard read command
SCSI-->>App: sector data
end
App->>DVD: read_dvd_sectors(buffer, sector_size, lba, count, raw)
DVD->>DVD: descramble / parity / validate_id
DVD->>EDC: compute/verify EDC
EDC-->>DVD: validation result
DVD-->>App: processed sector
App->>FS: write to image file (.iso/.sdram)
FS-->>App: write complete
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Fix all issues with AI agents
In `@cd/protection.ixx`:
- Around line 287-290: The existence check uses the wrong extension: change the
check that currently tests for image_prefix + ".sdram" to instead test for
image_prefix + ".scram" so it matches the file opened later; update the
condition that checks std::filesystem::exists(image_prefix + ".sdram") to
std::filesystem::exists(image_prefix + ".scram") (working with image_prefix
built from options.image_path and options.image_name).
In `@dvd/dvd_scrambler.ixx`:
- Around line 45-48: The current offset calculation mixes floating point by
using +7.5; change it to pure integer math: compute the nibble value (e.g.,
uint32_t nibble = (*key) ^ ((psn >> 4) & 0xF)) and then compute offset using the
integer equivalent of +7.5 as (15/2), i.e. offset = ((2 * nibble + 15) *
FORM1_DATA_SIZE) / 2, ensuring offset and intermediate values are uint32_t to
avoid any implicit floating-point conversions.
In `@systems/gc.ixx`:
- Around line 2-37: The code in SystemGC::printInfo currently casts
header_data.data() to Header* which breaks strict aliasing and can misalign
fields; add `#include` <cstring> and replace the cast with a local Header variable
(e.g., Header header{}), then std::memcpy(&header, header_data.data(),
sizeof(Header)); and update all uses of header->... to header.... Ensure
comparisons using _GC_MAGIC and subsequent field accesses reference the copied
header instance.
In `@systems/wii.ixx`:
- Around line 2-37: The code in SystemWII::printInfo currently casts
header_data.data() to Header*, which is undefined on architectures with stricter
alignment; instead allocate a local Header variable, call data_reader->read into
header_data as before, then use std::memcpy to copy sizeof(Header) bytes from
header_data.data() into the local Header, and use that local Header for checks
(e.g., comparing header.wii_magic to _WII_MAGIC) and subsequent accesses to
avoid misaligned reads.
In `@utils/misc.ixx`:
- Around line 274-278: The function digits_count(T value) can invoke undefined
behavior when negating the smallest signed value; instead compute the absolute
magnitude by converting value to an unsigned type: use std::make_unsigned_t<T>
(or a safe fixed unsigned type) to hold the magnitude, assign magnitude =
static_cast<std::make_unsigned_t<T>>(value < 0 ?
-static_cast<std::make_unsigned_t<T>>(value) : value), then compute and return
(magnitude ? log10(magnitude) : 0) + 1; update digits_count to use that unsigned
magnitude and add the needed <type_traits> include.
🧹 Nitpick comments (6)
dvd/xbox.ixx (2)
346-354: TODO comment indicates incomplete implementation for OmniDrive error handling.The TODO at Line 352 notes that retry/recovery logic is needed when status code is non-zero, ID is invalid, or EDC fails. This may cause silent data corruption if the initial read fails but doesn't raise an error.
Consider implementing the retry mechanism before release, or at minimum logging a warning when the raw sector data may be unreliable.
Would you like me to help draft the retry logic for reading from
XGD_SS_LEADOUT_SECTOR_PSN + 0x40?
382-387: OmniDrive security sector marked as "invalid" without user guidance.The TODO indicates SS rebuild requires cryptography. Users will see "security sector: invalid" in logs without understanding why or what limitations this creates. Consider adding a LOG statement explaining that OmniDrive SS reconstruction is pending implementation.
dvd/dvd_raw.ixx (2)
3-5: Remove unused includes.
<cstring>,<vector>, and"throw_line.hh"appear to be unused in this file. Removing them would reduce compilation dependencies.🧹 Proposed cleanup
module; `#include` <cstdint> -#include <cstring> -#include <vector> -#include "throw_line.hh" export module dvd.raw;
27-27: Consider simplifying the address adjustment.
address += -DVD_LBA_STARTcan be simplified toaddress -= DVD_LBA_STARTfor better readability.✨ Proposed simplification
if(address < 0) { raw_addressing = true; - address += -DVD_LBA_START; + address -= DVD_LBA_START; }dvd/dvd_split.ixx (2)
135-136: Consider adding error handling for file open failures.The file streams are opened without checking if the operations succeeded. If
sdram_pathexists but cannot be read (permissions, etc.), or ifiso_pathcannot be created, the subsequent operations will silently fail.💡 Suggested improvement
std::ifstream sdram_fs(sdram_path, std::ofstream::binary); + if(!sdram_fs) + throw_line("failed to open sdram file for reading ({})", sdram_path.filename().string()); std::ofstream iso_fs(iso_path, std::ofstream::binary); + if(!iso_fs) + throw_line("failed to create iso file for writing ({})", iso_path.filename().string());
176-191: Infinite loop relies on EOF detection via partial read.The
while(true)loop exits whenbytesRead != sector.size(), which handles normal EOF. However, if a read error occurs (not EOF), the loop will also exit butsuccessstate from the lastdescramblecall may be misleading. Consider distinguishing between EOF and actual read errors for better diagnostics.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@dvd/dvd_dump.ixx`:
- Around line 491-496: In progress_output, avoid division-by-zero when computing
percent_dumped: compute int64_t denom = (int64_t)lba_end - (int64_t)lba_start
and if denom == 0 set percent_dumped to a safe value (e.g., 100 when lba ==
lba_end else 0) otherwise compute percent_dumped = (int64_t)(lba - lba_start) *
100 / denom; update the logic in progress_output to use these checks and the
denom variable to prevent divide-by-zero while keeping the existing
spinner_animation and LOGC_RF call.
CR feedback Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@dvd/dvd_dump.ixx`:
- Around line 882-889: The vector allocation under std::vector<State>
state_buffer(lba_end - lba_start) can underflow when lba_end <= lba_start; guard
the allocation and subsequent read_entry/count logic by checking that lba_end >
lba_start (e.g. only construct state_buffer and call read_entry when the range
length is positive), otherwise skip allocation and ensure errors.scsi remains
zero; update the block around dump_mode / DumpMode::DUMP to perform this range
check before touching state_buffer, read_entry, or computing errors.scsi.
- Around line 828-858: The dvd_raw option must only affect DVD media: change the
computation and use of the local raw flag so it is true only when
options.dvd_raw is set, omnidrive_firmware is present, and the current disc type
(ctx.disc_type) is actually DVD; use that guarded raw everywhere (including the
dump_get_config(ctx.disc_type, raw) call and the branch that sets rom_update =
false / fs_ctx.search = false) so Blu‑ray or other media won’t have metadata/ROM
update disabled by the dvd_raw option.
🧹 Nitpick comments (1)
dvd/dvd_dump.ixx (1)
511-534: Usesector_sizefor buffer indexing to keep the raw path future-proof.
The loop currently indexessectorsbysizeof(RecordingFrame)which can drift fromsector_sizeif config evolves.♻️ Proposed tweak
- for(uint32_t i = 0; i < sectors_count; ++i) - { - auto &recording_frame = (RecordingFrame &)sectors[i * sizeof(RecordingFrame)]; - recording_frame = DataFrame_to_RecordingFrame(data_frames[i]); - } + for(uint32_t i = 0; i < sectors_count; ++i) + { + auto &recording_frame = (RecordingFrame &)sectors[i * sector_size]; + recording_frame = DataFrame_to_RecordingFrame(data_frames[i]); + }
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@dvd/dvd_scrambler.ixx`:
- Around line 47-76: In descramble, avoid reading frame->edc or computing the
EDC when the provided buffer is smaller than a full DataFrame: add a guard
(check size >= sizeof(DataFrame)) before the code that accesses frame->edc and
calls DVD_EDC().update(...).final(), and only compare the EDC (and set
unscrambled / call the fallback process to re-scramble) when that size check
passes; keep all other validation and the process(...) calls for partial buffers
unchanged. Ensure references to DataFrame, descramble, DVD_EDC::update, and
offsetof(DataFrame, edc) are used to locate and gate the EDC access.
🧹 Nitpick comments (1)
dvd/dvd_dump.ixx (1)
528-532: Consider usingreinterpret_castfor clarity.The C-style cast to
RecordingFrame &works correctly but is less explicit. Usingreinterpret_castwould better communicate the intentional memory reinterpretation.♻️ Suggested refactor
for(uint32_t i = 0; i < sectors_count; ++i) { - auto &recording_frame = (RecordingFrame &)sectors[i * sizeof(RecordingFrame)]; - recording_frame = DataFrame_to_RecordingFrame(data_frames[i]); + auto *recording_frame = reinterpret_cast<RecordingFrame *>(sectors + i * sizeof(RecordingFrame)); + *recording_frame = DataFrame_to_RecordingFrame(data_frames[i]); }
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@dvd/dvd_dump.ixx`:
- Around line 874-884: The code currently throws when lba_start >= lba_end;
instead preserve the previous no-op behavior by removing the throw_line and
guarding allocations and read_entry so they only run when lba_end > lba_start
and dump_mode != DumpMode::DUMP; specifically, in the block using Errors,
std::vector<State> state_buffer, and read_entry, wrap the allocation/read in an
if (lba_end > lba_start) check (or skip allocation when the computed size would
be zero/negative), ensure errors.scsi is set appropriately (e.g. zero) when
skipped, and leave the FIXME about chunking for separate follow-up work
(references: lba_start, lba_end, DumpMode::DUMP, state_buffer, read_entry,
cfg.lba_zero, State::ERROR_SKIP).
- Around line 512-525: The code allocates std::vector<DataFrame> data_frames but
passes sector_size bytes per sector to cmd_read_omnidrive, which can overflow
when sector_size > sizeof(DataFrame); replace the DataFrame vector with a byte
buffer sized sectors_count * sector_size (e.g., std::vector<uint8_t>
raw_buf(sectors_count * sector_size)), call cmd_read_omnidrive(...,
raw_buf.data(), sector_size, ...), then in the loop for each i reinterpret a
DataFrame from raw_buf.data() + i*sector_size (or memcpy into a DataFrame
instance) and convert it with DataFrame_to_RecordingFrame into the output buffer
at sectors + i*sector_size (avoid the current incorrect cast using sectors[i *
sizeof(RecordingFrame)]). Ensure all pointer arithmetic uses sector_size and no
buffer overrun occurs.
🧹 Nitpick comments (1)
dvd/dvd.ixx (1)
28-105: Add size/layout guards for raw frame structs.
These types are serialized via byte copies; astatic_assertmakes layout drift obvious.♻️ Suggested guard rails
export struct RecordingFrame { struct { uint8_t main_data[172]; uint8_t parity_inner[10]; } row[12]; uint8_t parity_outer[182]; }; + +static_assert(sizeof(DataFrame) == FORM1_DATA_SIZE + 16, "DataFrame size mismatch"); +static_assert(sizeof(RecordingFrame) == 12 * (172 + 10) + 182, "RecordingFrame size mismatch");
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@dvd/dvd_dump.ixx`:
- Around line 512-529: The loop in read_dvd_sectors casts the byte buffer to
RecordingFrame& when writing converted frames; replace that with a memcpy
pattern: for each i, create a RecordingFrame tmp =
DataFrame_to_RecordingFrame(data_frames[i]) (or construct the RecordingFrame),
then memcpy the bytes into the destination buffer at sectors + i *
sizeof(RecordingFrame) using sizeof(RecordingFrame). This keeps behavior
identical to DataFrame_to_RecordingFrame while following the codebase's
established memcpy pattern and avoiding direct reference casting.
* Skip all sectors after a subcode desync instead of just the first (superg#341) * Initial OmniDrive support (superg#336) (superg#340) * Initial OmniDrive support (superg#336) * Initial OmniDrive support * Count SCSI errors in dumpable range during refine * Initial Xbox support * Raw BD support * revert bd * revert one more * Code review * changed dvd scrambler table init to construction (temporary?) * revert code that will come in other PRs * refactoring * rework drive info output * recording/data frame conversion, dvd dump loop refactored * Apply suggestions from code review CR feedback Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * added parity generation * commonize overread count, dvd overread configuration, PSN refactoring * chunk refactoring, addressed CR review * removed unnecessary code * addressed CR issue --------- Co-authored-by: Deterous <138427222+Deterous@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * reverted to --rings option, removed desync stats (superg#342) --------- Co-authored-by: Sazpaimon <sazpaimon@x-cult.org> Co-authored-by: Hennadiy Brych <gennadiy.brich@gmail.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Initial OmniDrive support
Count SCSI errors in dumpable range during refine
Initial Xbox support
Raw BD support
revert bd
revert one more
Code review
Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Tests