Skip to content

Commit

Permalink
SecuROM v3 support, preserve incorrect subcode store, refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
superg committed Oct 10, 2023
1 parent 3ba3204 commit 0666fa2
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 148 deletions.
10 changes: 6 additions & 4 deletions cd/cd_dump.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ struct LeadInEntry
bool verified;
};

constexpr uint32_t SLOW_SECTOR_TIMEOUT = 5;


uint32_t plextor_leadin_compare(const std::vector<uint8_t> &leadin1, const std::vector<uint8_t> &leadin2)
{
Expand Down Expand Up @@ -756,7 +758,7 @@ export bool redumper_dump_cd(Context &ctx, const Options &options, bool refine)
// refine subchannel (based on Q crc)
if(options.refine_subchannel && subcode && !read)
{
read_entry(fs_sub, (uint8_t *)sector_subcode.data(), CD_SUBCODE_SIZE, lba_index + subcode_shift, 1, 0, 0);
read_entry(fs_sub, (uint8_t *)sector_subcode.data(), CD_SUBCODE_SIZE, lba_index, 1, 0, 0);
ChannelQ Q;
subcode_extract_channel((uint8_t *)&Q, sector_subcode.data(), Subchannel::Q);
if(!Q.isValid())
Expand Down Expand Up @@ -951,12 +953,12 @@ export bool redumper_dump_cd(Context &ctx, const Options &options, bool refine)
if(Q.isValid())
{
std::vector<uint8_t> sector_subcode_file(CD_SUBCODE_SIZE);
read_entry(fs_sub, (uint8_t *)sector_subcode_file.data(), CD_SUBCODE_SIZE, lba_index + subcode_shift, 1, 0, 0);
read_entry(fs_sub, (uint8_t *)sector_subcode_file.data(), CD_SUBCODE_SIZE, lba_index, 1, 0, 0);
ChannelQ Q_file;
subcode_extract_channel((uint8_t *)&Q_file, sector_subcode_file.data(), Subchannel::Q);
if(!Q_file.isValid())
{
write_entry(fs_sub, sector_subcode.data(), CD_SUBCODE_SIZE, lba_index + subcode_shift, 1, 0);
write_entry(fs_sub, sector_subcode.data(), CD_SUBCODE_SIZE, lba_index, 1, 0);
if(inside_range(lba, error_ranges) == nullptr)
--errors_q;
}
Expand All @@ -969,7 +971,7 @@ export bool redumper_dump_cd(Context &ctx, const Options &options, bool refine)

if(subcode)
{
write_entry(fs_sub, sector_subcode.data(), CD_SUBCODE_SIZE, lba_index + subcode_shift, 1, 0);
write_entry(fs_sub, sector_subcode.data(), CD_SUBCODE_SIZE, lba_index, 1, 0);

ChannelQ Q;
subcode_extract_channel((uint8_t *)&Q, sector_subcode.data(), Subchannel::Q);
Expand Down
127 changes: 10 additions & 117 deletions cd/subcode.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export module cd.subcode;
import cd.cd;
import crc.crc16_gsm;
import utils.endian;
import utils.misc;



Expand Down Expand Up @@ -80,6 +79,16 @@ export struct ChannelQ
return CRC16_GSM().update(raw, sizeof(raw)).final() == endian_swap(crc);
}


bool isValid(int32_t lba)
{
bool valid = isValid();

if(valid && adr == 1 && mode1.tno && lba != BCDMSF_to_LBA(mode1.a_msf))
valid = false;

return valid;
}

std::string Decode() const
{
Expand Down Expand Up @@ -157,120 +166,4 @@ export void subcode_extract_channel(uint8_t *subchannel, const uint8_t *subcode,
}
}


export bool subcode_correct_subq(ChannelQ *subq, uint32_t sectors_count)
{
uint32_t mcn = sectors_count;
std::map<uint8_t, uint32_t> isrc;
ChannelQ q_empty;
memset(&q_empty, 0, sizeof(q_empty));

bool invalid_subq = true;
uint8_t tno = 0;
for(uint32_t lba_index = 0; lba_index < sectors_count; ++lba_index)
{
if(!subq[lba_index].isValid())
continue;

invalid_subq = false;

if(subq[lba_index].adr == 1)
tno = subq[lba_index].mode1.tno;
else if(subq[lba_index].adr == 2 && mcn == sectors_count)
mcn = lba_index;
else if(subq[lba_index].adr == 3 && tno && isrc.find(tno) == isrc.end())
isrc[tno] = lba_index;
}

if(invalid_subq)
return false;

uint32_t q_prev = sectors_count;
uint32_t q_next = 0;
for(uint32_t lba_index = 0; lba_index < sectors_count; ++lba_index)
{
if(!memcmp(&subq[lba_index], &q_empty, sizeof(q_empty)))
continue;

if(subq[lba_index].isValid())
{
if(subq[lba_index].adr == 1)
{
if(subq[lba_index].mode1.tno)
q_prev = lba_index;
else
q_prev = sectors_count;
}
}
else
{
// find next valid Q
if(lba_index >= q_next && q_next != sectors_count)
{
q_next = lba_index + 1;
for(; q_next < sectors_count; ++q_next)
if(subq[q_next].isValid())
{
if(subq[q_next].adr == 1)
{
if(!subq[q_next].mode1.tno)
q_next = 0;

break;
}
}
}

std::vector<ChannelQ> candidates;
if(q_prev < lba_index)
{
// mode 1
candidates.emplace_back(subq[q_prev].generateMode1(lba_index - q_prev));

// mode 2
if(mcn != sectors_count)
candidates.emplace_back(subq[q_prev].generateMode23(subq[mcn], lba_index - q_prev));

// mode 3
if(!isrc.empty())
{
auto it = isrc.find(subq[q_prev].mode1.tno);
if(it != isrc.end())
candidates.emplace_back(subq[q_prev].generateMode23(subq[it->second], lba_index - q_prev));
}
}

if(q_next > lba_index && q_next != sectors_count)
{
// mode 1
candidates.emplace_back(subq[q_next].generateMode1(lba_index - q_next));

// mode 2
if(mcn != sectors_count)
candidates.emplace_back(subq[q_next].generateMode23(subq[mcn], lba_index - q_next));

// mode 3
if(!isrc.empty())
{
auto it = isrc.find(subq[q_next].mode1.tno);
if(it != isrc.end())
candidates.emplace_back(subq[q_next].generateMode23(subq[it->second], lba_index - q_next));
}
}

if(!candidates.empty())
{
uint32_t c = 0;
for(uint32_t j = 0; j < (uint32_t)candidates.size(); ++j)
if(bit_diff((uint32_t *)&subq[lba_index], (uint32_t *)&candidates[j], sizeof(ChannelQ) / sizeof(uint32_t)) < bit_diff((uint32_t *)&subq[lba_index], (uint32_t *)&candidates[c], sizeof(ChannelQ) / sizeof(uint32_t)))
c = j;

subq[lba_index] = candidates[c];
}
}
}

return true;
}

}
135 changes: 119 additions & 16 deletions dump.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module;
#include <filesystem>
#include <format>
#include <fstream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
Expand All @@ -20,6 +21,7 @@ import scsi.sptd;
import utils.endian;
import utils.file_io;
import utils.logger;
import utils.misc;



Expand Down Expand Up @@ -58,23 +60,7 @@ export enum class DumpMode
};


export constexpr uint32_t SLOW_SECTOR_TIMEOUT = 5;
#if 1
export constexpr int32_t LBA_START = -45150; //MSVC internal compiler error: MSF_to_LBA(MSF_LEADIN_START); // -45150
#else
// easier debugging, LBA starts with 0, plextor lead-in and asus cache are disabled
export constexpr int32_t LBA_START = 0;
// GS2v3 13922 .. 17080-17090
// GS2_1.1 12762 .. 17075
// GS2_5.5 12859 .. 17130-17140
// GS2_1.2 12739 .. 16930-16940
// SC DISC 8546 .. 17100-17125
// SC BOX 10547 .. 16940-16950
// CB4 6407-7114 .. 9200- 9220
// GS GCD 9162 .. 17000-17010 // F05 0004
// XPLO FM 7770 .. 10700-10704
//static constexpr int32_t LBA_START = MSF_to_LBA(MSF_LEADIN_START);
#endif


export enum class State : uint8_t
Expand Down Expand Up @@ -136,6 +122,123 @@ export std::vector<ChannelQ> load_subq(const std::filesystem::path &sub_path)
}


export bool subcode_correct_subq(ChannelQ *subq, uint32_t sectors_count)
{
uint32_t mcn = sectors_count;
std::map<uint8_t, uint32_t> isrc;
ChannelQ q_empty;
memset(&q_empty, 0, sizeof(q_empty));

bool invalid_subq = true;
uint8_t tno = 0;
for(uint32_t lba_index = 0; lba_index < sectors_count; ++lba_index)
{
if(!subq[lba_index].isValid())
continue;

invalid_subq = false;

if(subq[lba_index].adr == 1)
tno = subq[lba_index].mode1.tno;
else if(subq[lba_index].adr == 2 && mcn == sectors_count)
mcn = lba_index;
else if(subq[lba_index].adr == 3 && tno && isrc.find(tno) == isrc.end())
isrc[tno] = lba_index;
}

if(invalid_subq)
return false;

uint32_t q_prev = sectors_count;
uint32_t q_next = 0;
for(uint32_t lba_index = 0; lba_index < sectors_count; ++lba_index)
{
if(!memcmp(&subq[lba_index], &q_empty, sizeof(q_empty)))
continue;

// treat unexpected MSF as invalid (SecuROM)
if(subq[lba_index].isValid(lba_index + LBA_START))
{
if(subq[lba_index].adr == 1)
{
if(subq[lba_index].mode1.tno)
q_prev = lba_index;
else
q_prev = sectors_count;
}
}
else
{
// find next valid Q
if(lba_index >= q_next && q_next != sectors_count)
{
q_next = lba_index + 1;
for(; q_next < sectors_count; ++q_next)
if(subq[q_next].isValid(q_next + LBA_START))
{
if(subq[q_next].adr == 1)
{
if(!subq[q_next].mode1.tno)
q_next = 0;

break;
}
}
}

std::vector<ChannelQ> candidates;
if(q_prev < lba_index)
{
// mode 1
candidates.emplace_back(subq[q_prev].generateMode1(lba_index - q_prev));

// mode 2
if(mcn != sectors_count)
candidates.emplace_back(subq[q_prev].generateMode23(subq[mcn], lba_index - q_prev));

// mode 3
if(!isrc.empty())
{
auto it = isrc.find(subq[q_prev].mode1.tno);
if(it != isrc.end())
candidates.emplace_back(subq[q_prev].generateMode23(subq[it->second], lba_index - q_prev));
}
}

if(q_next > lba_index && q_next != sectors_count)
{
// mode 1
candidates.emplace_back(subq[q_next].generateMode1(lba_index - q_next));

// mode 2
if(mcn != sectors_count)
candidates.emplace_back(subq[q_next].generateMode23(subq[mcn], lba_index - q_next));

// mode 3
if(!isrc.empty())
{
auto it = isrc.find(subq[q_next].mode1.tno);
if(it != isrc.end())
candidates.emplace_back(subq[q_next].generateMode23(subq[it->second], lba_index - q_next));
}
}

if(!candidates.empty())
{
uint32_t c = 0;
for(uint32_t j = 0; j < (uint32_t)candidates.size(); ++j)
if(bit_diff((uint32_t *)&subq[lba_index], (uint32_t *)&candidates[j], sizeof(ChannelQ) / sizeof(uint32_t)) < bit_diff((uint32_t *)&subq[lba_index], (uint32_t *)&candidates[c], sizeof(ChannelQ) / sizeof(uint32_t)))
c = j;

subq[lba_index] = candidates[c];
}
}
}

return true;
}


export std::ostream &redump_print_subq(std::ostream &os, int32_t lba, const ChannelQ &Q)
{
MSF msf = LBA_to_MSF(lba);
Expand Down
32 changes: 21 additions & 11 deletions systems/securom.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,24 @@ public:

for(uint32_t lba_index = 0; lba_index < subq_fixed.size(); ++lba_index)
{
if(!subq_fixed[lba_index].isValid() || subq[lba_index].isValid())
continue;

int32_t lba = lba_index + LBA_START;

uint16_t crc_current = endian_swap(subq[lba_index].crc);
uint16_t crc_expected = CRC16_GSM().update(subq[lba_index].raw, sizeof(subq[lba_index].raw)).final();
uint16_t crc_fixed = endian_swap(subq_fixed[lba_index].crc);

if((crc_current ^ 0x0080) == crc_expected)
candidates.push_back(lba);
else if((crc_current ^ 0x8001) == crc_fixed)
candidates_8001.push_back(lba);
if(subq[lba_index].isValid())
{
if(!subq[lba_index].isValid(lba))
candidates_8001.push_back(lba);
}
else if(subq_fixed[lba_index].isValid())
{
uint16_t crc_current = endian_swap(subq[lba_index].crc);
uint16_t crc_expected = CRC16_GSM().update(subq[lba_index].raw, sizeof(subq[lba_index].raw)).final();
uint16_t crc_fixed = endian_swap(subq_fixed[lba_index].crc);

if((crc_current ^ 0x0080) == crc_expected)
candidates.push_back(lba);
else if((crc_current ^ 0x8001) == crc_fixed)
candidates_8001.push_back(lba);
}
}

uint32_t version = 0;
Expand All @@ -75,6 +80,11 @@ public:
candidates.swap(candidates_8001);
version = 4;
}
else if(candidates_8001.size() == 98 || candidates_8001.size() == 99 && candidates_8001.front() == -1)
{
candidates.swap(candidates_8001);
version = 3;
}

if(version)
{
Expand Down

0 comments on commit 0666fa2

Please sign in to comment.