1 /***************************************************************************
2 * Copyright (C) 2007 by Arep *
3 * Support is provided through the forums at *
4 * http://wii.console-tribe.com *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
20 ***************************************************************************/
23 * \brief Analyser and dumper for Nintendo GameCube/Wii discs.
25 * The functions in this file can be used to retrieve information about a Nintendo GameCube/Wii optical disc. Information is both structural (i.e.: Number of
26 * sectors, partitions, etc) and game-related (i.e.: Game Title, version, etc). This is the main object that should be used by applications.
28 * Most of the disc structure information used in this file comes from http://www.gc-linux.org/docs/yagcd.html and
29 * http://www.wiili.org/index.php/GameCube_Optical_Disc .
43 #include "constants.h"
44 #include "byteorder.h"
46 #include "dvd_drive.h"
47 #include "nintendo_disc_header.h"
48 #include "xbox_ref/xbox_ref_log.h"
50 static void hlds_e7_visible_probe_log (const char *fmt, ...) {
51 static bool started = false;
54 fprintf (stderr, "\n");
58 vfprintf (stderr, fmt, ap);
60 fprintf (stderr, "\n");
63 #include "unscrambler.h"
65 // #define cachedebug(...) debug (__VA_ARGS__);
66 #define cachedebug(...)
69 /* Cache always deals with 16-sector blocks. All numbers refer to the 16-sector blocks */
70 #define DISC_MINIMUM_CACHE_SIZE 5
71 #define DISC_DEFAULT_CACHE_SIZE 40
72 #define CACHE_ENTRY_INVALID ((u_int32_t) -1)
75 #define DISC_GAMECUBE_SECTORS_NO 0x0AE0B0 /* 712880 */
76 #define DISC_WII_SECTORS_NO_SL 0x230480 /* 2294912 */
77 #define DISC_WII_SECTORS_NO_DL 0x3F69C0 /* 4155840 */
78 #define DISC_XBOX_GDR8050L_UNLOCKED_SECTORS_NO 0x345B60 /* 3431264 */
81 #define MAX_READ_RETRIES 5
83 #define DEFAULT_READ_METHOD 0
84 #define DEFAULT_READ_SECTOR disc_read_sector_0
87 typedef int (*disc_read_sector_func) (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata);
89 u_int8_t buf[1024*1024*4];
90 u_int8_t buf_unscrambled[1024*1024*4];
95 /*! \brief A structure that represents a Nintendo GameCube/Wii optical disc.
98 dvd_drive *dvd; //!< The structure for the DVD-drive the disc is inserted in.
99 disc_type type; //!< The disc type.
100 char system_id; //!< A letter identifying the target system.
101 char game_id[2 + 1]; //!< Two letters identifying the game.
102 disc_region region; //!< The disc region.
103 char maker[3]; //!< Two letters identifying the maker of the game.
104 u_int8_t version; //!< A number identifying the game version.
105 char *version_string; //!< The same as <code>version</code>, in a more human-understandable format.
106 char *title; //!< The game title.
107 bool has_update; //!< True if the game contains a system update (Only possible for Wii discs).
108 u_int32_t sectors_no; //!< The number of sectors of the disc.
109 u_int32_t layerbreak; //!< For dual-layer DVDs.
116 /* Read function & stuff */
117 int command; //!< Buffer access command ID.
118 int read_method; //!< The read method ID.
119 // int def_read_method; //!< Default read method ID.
120 disc_read_sector_func read_sector; //!< The actual function that will be used to perform read operations, corresponding to <code>read_method</code>.
121 bool unscrambling; //!< If true, raw data read from the disc will be unscrambled to assure it is error-free. Disabling this is only useful for raw performance tests.
122 unscrambler *u; //!< The unscrambler structure that will be used to perform the unscrambling.
125 u_int32_t cache_size; //!< The number of blocks that will be cached when read.
126 bool hlds_e7_read_schedule_logged; //!< True once the selected HLDS 0xE7 read schedule has been logged for this run.
127 bool seed_diagnostic_active; //!< True while the initial 20 Nintendo seed blocks are being acquired.
128 unsigned int seed_diagnostic_block; //!< Zero-based seed-block index currently being acquired.
129 disc_seed_diagnostic seed_diagnostic; //!< Last actionable seed/cache failure evidence.
130 u_int8_t **raw_cache; //!< Memory area for raw sectors cache.
131 u_int8_t **cache; //!< Memory area for unscrambled sectors cache.
132 u_int32_t *cache_map; //!< Data structure used by the caching system to know which blocks are in memory.
137 static void disc_seed_diag_clear (disc *d) {
140 memset (&d -> seed_diagnostic, 0, sizeof (d -> seed_diagnostic));
143 static void disc_seed_diag_log (disc *d, const char *fmt, ...) {
145 if (!d || !d -> seed_diagnostic_active || !fmt)
147 xbox_ref_log_fprintf (stderr, "[SEED-DIAG] ");
149 /* xbox_ref_log_fprintf is variadic rather than vfprintf-based, so format
150 * into a bounded buffer before sending the line to both console and log. */
153 vsnprintf (line, sizeof (line), fmt, ap);
154 xbox_ref_log_fprintf (stderr, "%s\n", line);
159 static void disc_seed_diag_fail (
161 u_int32_t sector_start,
162 u_int32_t sector_end,
166 int transport_result,
169 dvd_command_diagnostic command;
170 char cdb_text[3 * 12 + 1];
174 if (!d || !d -> seed_diagnostic_active)
176 disc_seed_diag_clear (d);
177 d -> seed_diagnostic.valid = true;
178 d -> seed_diagnostic.seed_block_index = d -> seed_diagnostic_block;
179 d -> seed_diagnostic.sector_start = sector_start;
180 d -> seed_diagnostic.sector_end = sector_end;
181 d -> seed_diagnostic.retry = retry;
182 snprintf (d -> seed_diagnostic.stage, sizeof (d -> seed_diagnostic.stage), "%s", stage ? stage : "unknown");
183 snprintf (d -> seed_diagnostic.detail, sizeof (d -> seed_diagnostic.detail), "%s", detail ? detail : "");
184 d -> seed_diagnostic.transport_result = transport_result;
186 memset (&command, 0, sizeof (command));
187 if (capture_command && dvd_get_last_command_diagnostic (d -> dvd, &command)) {
188 d -> seed_diagnostic.transport_result = command.transport_result;
189 d -> seed_diagnostic.os_error = command.os_error;
190 d -> seed_diagnostic.scsi_status = command.scsi_status;
191 d -> seed_diagnostic.sense_key = command.sense_key;
192 d -> seed_diagnostic.asc = command.asc;
193 d -> seed_diagnostic.ascq = command.ascq;
194 d -> seed_diagnostic.cdb_length = command.cdb_length;
195 memcpy (d -> seed_diagnostic.cdb, command.cdb, sizeof (d -> seed_diagnostic.cdb));
200 for (i = 0; i < d -> seed_diagnostic.cdb_length && i < 12; i++) {
201 int wrote = snprintf (cdb_text + used, sizeof (cdb_text) - (size_t) used,
202 "%s%02X", i ? " " : "", d -> seed_diagnostic.cdb[i]);
203 if (wrote < 0 || wrote >= (int) (sizeof (cdb_text) - (size_t) used))
208 disc_seed_diag_log (d,
209 "block=%u/20 sectors=%u..%u retry=%d stage=%s result=FAIL rc=%d os=%d scsi=0x%02X sense=%02X/%02X/%02X cdb=[%s] detail=%s",
210 d -> seed_diagnostic.seed_block_index + 1,
211 sector_start, sector_end, retry,
212 d -> seed_diagnostic.stage,
213 d -> seed_diagnostic.transport_result,
214 d -> seed_diagnostic.os_error,
215 d -> seed_diagnostic.scsi_status & 0xff,
216 d -> seed_diagnostic.sense_key & 0xff,
217 d -> seed_diagnostic.asc & 0xff,
218 d -> seed_diagnostic.ascq & 0xff,
219 cdb_text[0] ? cdb_text : "none",
220 d -> seed_diagnostic.detail[0] ? d -> seed_diagnostic.detail : "none");
223 bool disc_get_seed_diagnostic (disc *d, disc_seed_diagnostic *out) {
224 if (!d || !out || !d -> seed_diagnostic.valid)
226 *out = d -> seed_diagnostic;
230 static void disc_cache_init (disc *d, u_int32_t size) {
233 if (size < DISC_MINIMUM_CACHE_SIZE) {
234 error ("Invalid cache size %u (must be >= %u)", size, DISC_MINIMUM_CACHE_SIZE);
237 d -> cache_size = size;
238 d -> cache = (u_int8_t **) malloc (sizeof (u_int8_t *) * size);
239 d -> raw_cache = (u_int8_t **) malloc (sizeof (u_int8_t *) * size);
240 for (i = 0; i < size; i++) {
241 d -> cache[i] = (u_int8_t *) malloc (sizeof (u_int8_t) * BLOCK_SIZE);
242 d -> raw_cache[i] = (u_int8_t *) malloc (sizeof (u_int8_t) * RAW_BLOCK_SIZE);
245 d -> cache_map = (u_int32_t *) malloc (sizeof (u_int32_t) * size);
246 for (i = 0; i < size; i++)
247 d -> cache_map[i] = CACHE_ENTRY_INVALID;
254 static void disc_cache_destroy (disc *d) {
257 my_free (d -> cache_map);
259 for (i = 0; i < d -> cache_size; i++) {
260 my_free (d -> cache[i]);
261 my_free (d -> raw_cache[i]);
263 my_free (d -> cache);
264 my_free (d -> raw_cache);
270 static void disc_cache_clear (disc *d) {
273 if (!d || !d -> cache_map)
275 for (i = 0; i < d -> cache_size; i++)
276 d -> cache_map[i] = CACHE_ENTRY_INVALID;
280 void disc_cache_add_block (disc *d, u_int32_t block, u_int8_t *data, u_int8_t *rawdata) {
284 pos = block % d -> cache_size;
285 //uniform unscrambled output
286 memcpy (d -> cache[pos], data, BLOCK_SIZE);
287 if (d -> type == DISC_TYPE_DVD || d -> type == DISC_TYPE_XBOX) {
288 for (cnt = 0; cnt < SECTORS_PER_BLOCK; cnt++) {
289 memcpy (rawdata+(cnt*RAW_SECTOR_SIZE)+12, data+(cnt*SECTOR_SIZE), SECTOR_SIZE);
292 for (cnt = 0; cnt < SECTORS_PER_BLOCK; cnt++) {
293 memcpy (rawdata+(cnt*RAW_SECTOR_SIZE)+6, data+(cnt*SECTOR_SIZE), SECTOR_SIZE);
296 memcpy (d -> raw_cache[pos], rawdata, RAW_BLOCK_SIZE);
297 d -> cache_map[pos] = block;
299 cachedebug ("Cached block %u (sectors %u-%u) at position %u", block, block * SECTORS_PER_BLOCK, (block + 1) * SECTORS_PER_BLOCK - 1, pos);
305 static bool disc_cache_lookup_block (disc *d, u_int32_t block, u_int8_t **data, u_int8_t **rawdata) {
309 pos = block % d -> cache_size;
311 if (d -> cache_map[pos] == block) {
312 cachedebug ("Cache HIT for block %u", block);
314 *data = d -> cache[pos];
316 *rawdata = d -> raw_cache[pos];
319 cachedebug ("Cache MISS for block %u", block);
331 static int disc_read_sector_generic (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata, u_int32_t method) {
333 u_int32_t start_block;
335 u_int32_t step, cnt, max_cnt, max_blk;
336 u_int32_t block_len, block_size, _block_size, last_block_size, block_cnt;
337 //fprintf (stdout,"disc_read_sector_%d", method);
338 start_block = sector_no / SECTORS_PER_BLOCK;
342 max_cnt = d->max_cnt;
343 max_blk = d->max_blk;
345 block_size = step*2064;
346 last_block_size = block_size;
348 if (block_size > 27 * 2064) {
349 block_len = block_size / (27*2064);
350 if (block_size % (27*2064) != 0) block_len += 1;
351 block_size = 27*2064;
352 last_block_size = (step*2064) - (27*2064*(block_len-1));
354 _block_size=block_size;
356 for (retry = 0; !out && retry < MAX_READ_RETRIES; retry++) {
357 /* Assume everything will turn out well */
363 while (cnt <= max_cnt){
365 _block_size=block_size;
366 if (method == 0 || method == 1 || method == 4) {
367 if (sector_no+(cnt*step) +992 +16 <= d -> sectors_no) //smaller than last sector
368 dvd_read_sector_dummy (d -> dvd, sector_no+(cnt*step) +992, 16, NULL, NULL, 0);
369 else if (sector_no+(cnt*step) -992 >= 0) //larger than first sector
370 dvd_read_sector_dummy (d -> dvd, sector_no+(cnt*step) -992, 16, NULL, NULL, 0);
371 else dvd_flush_cache_READ12 (d -> dvd, sector_no+(cnt*step), NULL);
374 if (method == 0 || method == 2 || method == 5) dvd_flush_cache_READ12 (d -> dvd, sector_no+(cnt*step), NULL);
375 if (method == 0 || method == 1 || method == 2 || method == 3) ret = dvd_read_sector_dummy (d -> dvd, sector_no+(cnt*step), d->sec_disc, NULL, &buf_unscrambled[0], 2064*step);
376 if (method == 4 || method == 5 || method == 6) ret = dvd_read_streaming (d -> dvd, sector_no+(cnt*step), d->sec_disc, NULL, &buf_unscrambled[0], 2064*step);
378 for (block_cnt=0; block_cnt<block_len; block_cnt++) {
379 if (dvd_memdump (d -> dvd, block_cnt*27*2064, 1, _block_size, &buf[(cnt*(2064 * step))+(block_cnt*27*2064)]) < 0) {
380 error ("Memdump failed");
381 //retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */ //no it's not!
385 if (block_cnt==block_len-1) _block_size = last_block_size;
388 //do this check only on 1st layer
389 else if (((buf[cnt*(2064*step)] & 1) == 0) && ((buf[cnt*(2064*step)+1]<<16)+(buf[cnt*(2064*step)+2]<<8)+(buf[cnt*(2064*step)+3]) != 0x30000 + sector_no+(cnt*step))) {
395 error ("dvd_read_streaming() failed with %d", ret);
402 if (cnt < max_cnt) out = false;
405 if (d -> unscrambling) {
407 /* Try to unscramble all data to see if EDC fails */
408 //for(cnt=0; cnt <= 4; cnt++) {
409 for(cnt=max_blk; cnt--;) {
410 if (!unscrambler_unscramble_16sectors (d -> u, sector_no+(cnt*16), &buf[cnt*(2064*16)], &buf_unscrambled[cnt*(2048*16)]))
418 /* If data were unscrambled correctly, add them to the cache */
419 //for(cnt = 0; cnt <= 4; cnt++) {
420 for(cnt=max_blk; cnt--;) {
421 disc_cache_add_block (d, start_block+cnt, &buf_unscrambled[cnt*(2048*16)], &buf[cnt*(2064*16)]);
426 //Simple read on 4rth try
428 if (sector_no +992 +16 <= d -> sectors_no) //smaller than last sector
429 dvd_read_sector_dummy (d -> dvd, sector_no +992, 16, NULL, NULL, 0);
430 else if (sector_no -992 >= 0) //larger than first sector
431 dvd_read_sector_dummy (d -> dvd, sector_no -992, 16, NULL, NULL, 0);
432 else dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL);
434 dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL);
435 ret = dvd_read_sector_dummy (d -> dvd, sector_no, SECTORS_PER_BLOCK, NULL, NULL, 0);
437 if (dvd_memdump (d -> dvd, 0, 1, RAW_BLOCK_SIZE, buf) < 0) {
438 error ("Memdump failed");
439 //retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */
442 else if ( ((*(buf) & 1) == 0) && ((*(buf+1)<<16)+(*(buf+2)<<8)+(*(buf+3)) != 0x30000+sector_no) ) out = false;
445 if (d -> unscrambling) {
447 /* Try to unscramble all data to see if EDC fails */
448 if (!unscrambler_unscramble_16sectors (d -> u, sector_no, buf, buf_unscrambled))
455 /* If data were unscrambled correctly, add them to the cache */
456 disc_cache_add_block (d, start_block, buf_unscrambled, buf);
459 error ("dvd_read_sector_dummy() failed with %d", ret);
466 error ("Too many retries, giving up");
472 static int disc_read_sector_xbox (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
474 u_int32_t start_block, block_start, sectors_to_read;
475 u_int8_t readbuf[BLOCK_SIZE];
476 u_int8_t rawbuf[RAW_BLOCK_SIZE];
481 start_block = sector_no / SECTORS_PER_BLOCK;
482 block_start = start_block * SECTORS_PER_BLOCK;
483 if (block_start >= d -> sectors_no)
486 sectors_to_read = SECTORS_PER_BLOCK;
487 if (block_start + sectors_to_read > d -> sectors_no)
488 sectors_to_read = d -> sectors_no - block_start;
490 memset (readbuf, 0, sizeof (readbuf));
491 memset (rawbuf, 0, sizeof (rawbuf));
493 out = dvd_read_10 (d -> dvd, block_start, sectors_to_read, NULL, readbuf, sizeof (readbuf)) >= 0;
495 disc_cache_add_block (d, start_block, readbuf, rawbuf);
497 error ("Xbox READ(10) failed at sector %u", block_start);
503 ///////////////////////////// General /////////////////////////////
504 static int disc_read_sector_0 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
505 return disc_read_sector_generic (d, sector_no, data, rawdata, 0);
510 ////////////////////////// Non-Streaming //////////////////////////
511 static int disc_read_sector_1 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
512 return disc_read_sector_generic (d, sector_no, data, rawdata, 1);
516 static int disc_read_sector_2 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
517 return disc_read_sector_generic (d, sector_no, data, rawdata, 2);
522 static int disc_read_sector_3 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
523 return disc_read_sector_generic (d, sector_no, data, rawdata, 3);
529 //////////////////////////// Streaming ////////////////////////////
530 static int disc_read_sector_4 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
531 return disc_read_sector_generic (d, sector_no, data, rawdata, 4);
535 static int disc_read_sector_5 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
536 return disc_read_sector_generic (d, sector_no, data, rawdata, 5);
540 static int disc_read_sector_6 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
541 return disc_read_sector_generic (d, sector_no, data, rawdata, 6);
546 ///////////////////////////// Hitachi /////////////////////////////
547 static int disc_read_sector_7 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
549 u_int32_t start_block;
551 u_int8_t buf[5][16 * 2064];
552 u_int8_t buf_unscrambled[5][16 * 2048];
553 //fprintf (stdout,"disc_read_sector_7");
554 start_block = sector_no / SECTORS_PER_BLOCK;
557 for (retry = 0; !out && retry < MAX_READ_RETRIES; retry++) {
558 /* Assume everything will turn out well */
562 warning ("Read retry %d for sector %u", retry, sector_no);
564 /* Try to reset in-memory data by seeking to a distant sector */
565 // if (sector_no > 1000)
566 // dvd_read_sector_streaming (d -> dvd, 0, NULL, NULL, 0);
568 // dvd_read_sector_streaming (d -> dvd, 1500, NULL, NULL, 0);
569 if (sector_no +992 +16 <= d -> sectors_no) //smaller than last sector
570 dvd_read_sector_dummy (d -> dvd, sector_no +992, 16, NULL, NULL, 0);
571 else if (sector_no -992 >= 0) //larger than first sector
572 dvd_read_sector_dummy (d -> dvd, sector_no -992, 16, NULL, NULL, 0);
573 else dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL);
576 if ((ret = dvd_read_sector_streaming (d -> dvd, sector_no, NULL, NULL, 0)) >= 0) {
577 for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no && out; j++) {
578 if (dvd_memdump (d -> dvd, 0 + (j * 16 * 2064), 1, 16 * 2064, buf[j]) < 0) { /* Dumping in a single block is faster */
579 error ("Memdump failed");
581 retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */
584 if (d -> unscrambling) {
586 /* Try to unscramble all data to see if EDC fails */
587 if (!unscrambler_unscramble_16sectors (d -> u, sector_no + (j * 16), buf[j], buf_unscrambled[j]))
596 /* It seems all data was unscrambled correctly, so cache them out */
597 for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no; j++)
598 disc_cache_add_block (d, start_block + j, buf_unscrambled[j], buf[j]);
602 error ("dvd_read_sector_streaming() failed with %d", ret);
608 error ("Too many retries, giving up");
615 static bool disc_read_sector_8_split_recover_block (disc *d, u_int32_t block_sector) {
616 static const int chunk_sizes[] = { 8, 4, 2, 1 };
618 int c, chunk_len, chunk_start, k, ret;
619 u_int32_t ram_offset, block_no;
621 u_int8_t raw_block[RAW_BLOCK_SIZE];
622 u_int8_t iso_block[BLOCK_SIZE];
623 u_int8_t readbuf[BLOCK_SIZE];
627 block_no = block_sector / SECTORS_PER_BLOCK;
629 for (c = 0; c < (int) (sizeof (chunk_sizes) / sizeof (chunk_sizes[0])); c++) {
630 chunk_len = chunk_sizes[c];
631 memset (raw_block, 0, sizeof (raw_block));
632 memset (iso_block, 0, sizeof (iso_block));
634 disc_seed_diag_clear (d);
636 warning ("Method 8 split recovery: trying %d-sector chunks for sectors %u..%u", chunk_len, block_sector, block_sector + SECTORS_PER_BLOCK - 1);
637 disc_seed_diag_log (d,
638 "block=%u/20 sectors=%u..%u retry=%d stage=split-profile result=BEGIN detail=chunk-sectors-%d",
639 d -> seed_diagnostic_block + 1, block_sector,
640 block_sector + SECTORS_PER_BLOCK - 1, c, chunk_len);
642 for (chunk_start = 0; chunk_start < SECTORS_PER_BLOCK && out; chunk_start += chunk_len) {
643 u_int32_t chunk_sector = block_sector + (u_int32_t) chunk_start;
644 memset (readbuf, 0, sizeof (readbuf));
646 memset (&sense, 0, sizeof (sense));
647 if (chunk_sector + 992 + 16 <= d -> sectors_no)
648 ret = dvd_read_sector_dummy (d -> dvd, chunk_sector + 992, 16, &sense, NULL, 0);
649 else if (chunk_sector >= 992)
650 ret = dvd_read_sector_dummy (d -> dvd, chunk_sector - 992, 16, &sense, NULL, 0);
652 ret = dvd_flush_cache_READ12 (d -> dvd, chunk_sector, &sense);
654 disc_seed_diag_log (d,
655 "block=%u/20 sectors=%u..%u retry=%d stage=split-prefetch result=NONFATAL-FAIL rc=%d sense=%02X/%02X/%02X detail=chunk-sectors-%d",
656 d -> seed_diagnostic_block + 1, chunk_sector,
657 chunk_sector + (u_int32_t) chunk_len - 1, c, ret,
658 sense.sense_key & 0xff, sense.asc & 0xff, sense.ascq & 0xff, chunk_len);
661 memset (&sense, 0, sizeof (sense));
662 ret = dvd_read_streaming (d -> dvd, chunk_sector, (u_int32_t) chunk_len,
663 &sense, readbuf, (size_t) chunk_len * SECTOR_SIZE);
665 snprintf (detail, sizeof (detail), "chunk-sectors=%d sense=%02X/%02X/%02X",
666 chunk_len, sense.sense_key & 0xff, sense.asc & 0xff, sense.ascq & 0xff);
667 disc_seed_diag_fail (d, chunk_sector,
668 chunk_sector + (u_int32_t) chunk_len - 1, c,
669 "split-streaming-read", detail, ret, true);
670 warning ("Method 8 split recovery: READ12 streaming failed for sectors %u..%u with %d", chunk_sector, chunk_sector + (u_int32_t) chunk_len - 1, ret);
675 for (k = 0; k < chunk_len; k++) {
676 sect = &raw_block[(chunk_start + k) * RAW_SECTOR_SIZE];
677 ram_offset = (u_int32_t) k * RAW_SECTOR_SIZE;
679 ret = dvd_memdump (d -> dvd, ram_offset, 1, 12, sect);
681 snprintf (detail, sizeof (detail), "chunk-sectors=%d raw-offset=%u sector-index=%d",
682 chunk_len, ram_offset, k);
683 disc_seed_diag_fail (d, chunk_sector + (u_int32_t) k,
684 chunk_sector + (u_int32_t) k, c,
685 "split-header-memdump", detail, ret, true);
686 warning ("Method 8 split recovery: header memdump failed at sector %u", chunk_sector + (u_int32_t) k);
690 ret = dvd_memdump (d -> dvd, ram_offset + 2060, 1, 4, sect + 2060);
692 snprintf (detail, sizeof (detail), "chunk-sectors=%d raw-offset=%u sector-index=%d",
693 chunk_len, ram_offset + 2060, k);
694 disc_seed_diag_fail (d, chunk_sector + (u_int32_t) k,
695 chunk_sector + (u_int32_t) k, c,
696 "split-edc-memdump", detail, ret, true);
697 warning ("Method 8 split recovery: EDC memdump failed at sector %u", chunk_sector + (u_int32_t) k);
702 memcpy (sect + 12, readbuf + ((size_t) k * SECTOR_SIZE), SECTOR_SIZE);
706 if (out && !unscrambler_unscramble_16sectors (d -> u, block_sector, raw_block, iso_block)) {
707 snprintf (detail, sizeof (detail), "chunk-sectors=%d", chunk_len);
708 disc_seed_diag_fail (d, block_sector,
709 block_sector + SECTORS_PER_BLOCK - 1, c,
710 "split-edc-unscramble-validation", detail, -1, false);
711 warning ("Method 8 split recovery: EDC/unscramble validation failed for %d-sector chunks at sectors %u..%u", chunk_len, block_sector, block_sector + SECTORS_PER_BLOCK - 1);
716 disc_cache_add_block (d, block_no, iso_block, raw_block);
717 warning ("Method 8 split recovery: recovered sectors %u..%u using %d-sector chunks", block_sector, block_sector + SECTORS_PER_BLOCK - 1, chunk_len);
718 disc_seed_diag_log (d,
719 "block=%u/20 sectors=%u..%u retry=%d stage=split-profile result=PASS detail=chunk-sectors-%d",
720 d -> seed_diagnostic_block + 1, block_sector,
721 block_sector + SECTORS_PER_BLOCK - 1, c, chunk_len);
726 warning ("Method 8 split recovery: all chunk sizes failed for sectors %u..%u", block_sector, block_sector + SECTORS_PER_BLOCK - 1);
730 static bool disc_hlds_type_is_gdr8050l_accel (u_int32_t type) {
731 return type == 442 || type == 443 || type == 445;
734 static bool disc_hlds_type_is_gdr8050l_no_prefetch (u_int32_t type) {
735 return type == 44 || type == 45 || disc_hlds_type_is_gdr8050l_accel (type);
739 static bool disc_hlds_type_is_gdr8081n_search_guided (u_int32_t type) {
743 static bool hlds_e7_find_exact_raw_header_offset (const u_int8_t *dumpbuf, size_t dump_len, u_int32_t sector_no, size_t *out_off) {
749 *out_off = (size_t) -1;
750 if (!dumpbuf || dump_len < RAW_SECTOR_SIZE)
752 expected = 0x30000U + sector_no;
753 for (off = 0; off + RAW_SECTOR_SIZE <= dump_len; off++) {
754 got = ((u_int32_t) dumpbuf[off + 1] << 16) | ((u_int32_t) dumpbuf[off + 2] << 8) | (u_int32_t) dumpbuf[off + 3];
757 /* Avoid all-zero/all-ff false positives. Raw headers observed on HLDS
758 * families can have different first-byte control bits, so do not require
759 * exact parity here; the final unscrambler/EDC pass is the authority. */
760 if (((dumpbuf[off] | dumpbuf[off + 1] | dumpbuf[off + 2] | dumpbuf[off + 3]) == 0x00) ||
761 ((dumpbuf[off] & dumpbuf[off + 1] & dumpbuf[off + 2] & dumpbuf[off + 3]) == 0xFF))
770 static int hlds_e7_count_exact_raw_headers_for_block (const u_int8_t *dumpbuf, size_t dump_len, u_int32_t block_sector, size_t offsets[SECTORS_PER_BLOCK]) {
776 for (k = 0; k < SECTORS_PER_BLOCK; k++)
777 offsets[k] = (size_t) -1;
779 for (k = 0; k < SECTORS_PER_BLOCK; k++) {
780 if (hlds_e7_find_exact_raw_header_offset (dumpbuf, dump_len, block_sector + (u_int32_t) k, &off)) {
789 static bool hlds_e7_raw_header_offsets_are_sector_shaped (const size_t offsets[SECTORS_PER_BLOCK]) {
795 for (k = 0; k < SECTORS_PER_BLOCK; k++) {
796 if (offsets[k] == (size_t) -1)
799 /* A real raw cache block has one 2064-byte raw sector per logical sector.
800 * False positives observed on GDR-8081N v4 looked like SRAM/tables with
801 * sector-number patterns only 4 bytes apart, so require a sane 2064-byte
802 * sector stride before treating matches as real cache sectors. */
804 for (k = 1; k < SECTORS_PER_BLOCK; k++) {
805 expected = offsets[0] + ((size_t) k * RAW_SECTOR_SIZE);
806 if (offsets[k] == expected)
809 return stride_matches >= 12;
812 static size_t hlds_e7_find_command_echo_offset (const u_int8_t *buf, size_t len) {
813 static const u_int8_t sig[] = {0xE7, 0x48, 0x49, 0x54, 0x01};
815 if (!buf || len < sizeof (sig))
817 for (off = 0; off + sizeof (sig) <= len; off++) {
818 if (memcmp (buf + off, sig, sizeof (sig)) == 0)
824 static int disc_read_sector_8_gdr8081n_search_guided (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
825 static bool logged = false;
827 u_int32_t block_sector;
828 u_int32_t start_block;
829 u_int32_t profile_blocks;
837 size_t offsets[SECTORS_PER_BLOCK];
840 u_int8_t raw_block[RAW_BLOCK_SIZE];
841 u_int8_t iso_block[BLOCK_SIZE];
842 u_int8_t readbuf[BLOCK_SIZE];
844 start_block = sector_no / SECTORS_PER_BLOCK;
845 block_sector = start_block * SECTORS_PER_BLOCK;
846 profile_blocks = dvd_get_hlds_e7_mem_blocks (d -> dvd);
847 if (profile_blocks < 1 || profile_blocks > 5)
849 scan_len = profile_blocks * RAW_BLOCK_SIZE;
850 scanbuf = (u_int8_t *) malloc (scan_len);
852 error ("GDR-8081N scan-guided Method 8: unable to allocate %u-byte scan buffer", scan_len);
856 hlds_e7_visible_probe_log ("GDR-8081N 0xE7: using scan-guided single-block Method 8 profile at 0x%08x, scan windows=%u", dvd_get_hlds_e7_cache_base (d -> dvd), profile_blocks);
861 for (retry = 0; !out && retry < 1; retry++) {
864 warning ("GDR-8081N scan-guided Method 8 retry %d for sectors %u..%u", retry, block_sector, block_sector + SECTORS_PER_BLOCK - 1);
866 /* Keep this conservative: the v2 scanner showed sector-cache material inside
867 * the 0x80000000 five-window range, but not necessarily in the exact Type4
868 * j/k slot map. For now, reconstruct only the requested 16-sector block
869 * from a full-window search. Do not require all five cached windows to map;
870 * that made v3 reject useful data before seed cracking could start. */
871 if (block_sector > d -> sectors_no - 1000)
872 dvd_read_sector_streaming (d -> dvd, block_sector - 16 * 5 * 2, NULL, NULL, 0);
874 dvd_read_sector_streaming (d -> dvd, block_sector + 16 * 5, NULL, NULL, 0);
876 if ((ret = dvd_read_sector_streaming (d -> dvd, block_sector, NULL, readbuf, sizeof (readbuf))) < 0) {
877 error ("GDR-8081N scan-guided Method 8: dvd_read_sector_streaming(%u) failed with %d", block_sector, ret);
882 memset (scanbuf, 0, scan_len);
883 if (dvd_memdump (d -> dvd, 0, profile_blocks, RAW_BLOCK_SIZE, scanbuf) < 0) {
884 error ("GDR-8081N scan-guided Method 8: full-window memdump failed");
889 found_count = hlds_e7_count_exact_raw_headers_for_block (scanbuf, scan_len, block_sector, offsets);
890 sector_shaped = hlds_e7_raw_header_offsets_are_sector_shaped (offsets);
891 if (found_count == SECTORS_PER_BLOCK && !sector_shaped) {
892 warning ("GDR-8081N scan-guided Method 8: found 16/16 sector-number patterns for sectors %u..%u, but offsets are not 2064-byte sector-shaped; treating as SRAM/table false positive",
893 block_sector, block_sector + SECTORS_PER_BLOCK - 1);
897 if (found_count != SECTORS_PER_BLOCK) {
899 for (k = 0; k < SECTORS_PER_BLOCK; k++) {
900 if (offsets[k] == (size_t) -1) {
905 warning ("GDR-8081N scan-guided Method 8: found %d/16 exact raw headers for sectors %u..%u; first missing sector %u",
906 found_count, block_sector, block_sector + SECTORS_PER_BLOCK - 1,
907 first_missing >= 0 ? block_sector + (u_int32_t) first_missing : block_sector);
912 for (k = 0; k < SECTORS_PER_BLOCK; k++) {
913 sect = &raw_block[k * RAW_SECTOR_SIZE];
914 memcpy (sect, scanbuf + offsets[k], 12);
915 memcpy (sect + 12, readbuf + ((size_t) k * SECTOR_SIZE), SECTOR_SIZE);
916 memcpy (sect + 2060, scanbuf + offsets[k] + 2060, 4);
919 if (!unscrambler_unscramble_16sectors (d -> u, block_sector, raw_block, iso_block)) {
920 warning ("GDR-8081N scan-guided Method 8: EDC/unscramble validation failed for sectors %u..%u after finding all 16 headers", block_sector, block_sector + SECTORS_PER_BLOCK - 1);
925 disc_cache_add_block (d, start_block, iso_block, raw_block);
930 error ("GDR-8081N scan-guided Method 8: strict sector-layout validation failed");
934 static int disc_read_sector_8 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
936 u_int32_t ram_offset;
937 u_int32_t start_block;
938 u_int32_t profile_blocks;
939 u_int32_t prefetch_sector;
940 int j, k, ret, retry;
942 u_int8_t *sect, buf[5][RAW_BLOCK_SIZE];
943 u_int8_t readbuf[BLOCK_SIZE];
944 u_int8_t buf_unscrambled[5][BLOCK_SIZE];
948 if (disc_hlds_type_is_gdr8081n_search_guided (dvd_get_hlds_e7_type (d -> dvd)))
949 return disc_read_sector_8_gdr8081n_search_guided (d, sector_no, data, rawdata);
951 start_block = sector_no / SECTORS_PER_BLOCK;
952 profile_blocks = dvd_get_hlds_e7_mem_blocks (d -> dvd);
953 if (profile_blocks < 1 || profile_blocks > 5)
957 for (retry = 0; !out && retry < MAX_READ_RETRIES; retry++) {
959 disc_seed_diag_clear (d);
960 disc_seed_diag_log (d,
961 "block=%u/20 sectors=%u..%u retry=%d stage=normal-profile result=BEGIN detail=windows-%u",
962 d -> seed_diagnostic_block + 1, sector_no,
963 sector_no + SECTORS_PER_BLOCK - 1, retry, profile_blocks);
966 warning ("Read retry %d for sector %u", retry, sector_no);
967 memset (&sense, 0, sizeof (sense));
968 if (sector_no + 992 + 16 <= d -> sectors_no)
969 ret = dvd_read_sector_dummy (d -> dvd, sector_no + 992, 16, &sense, NULL, 0);
970 else if (sector_no >= 992)
971 ret = dvd_read_sector_dummy (d -> dvd, sector_no - 992, 16, &sense, NULL, 0);
973 ret = dvd_flush_cache_READ12 (d -> dvd, sector_no, &sense);
975 disc_seed_diag_log (d,
976 "block=%u/20 sectors=%u..%u retry=%d stage=retry-cache-reset result=NONFATAL-FAIL rc=%d sense=%02X/%02X/%02X",
977 d -> seed_diagnostic_block + 1, sector_no,
978 sector_no + SECTORS_PER_BLOCK - 1, retry, ret,
979 sense.sense_key & 0xff, sense.asc & 0xff, sense.ascq & 0xff);
983 /* Prime the volatile cache, then immediately consume it. */
984 memset (&sense, 0, sizeof (sense));
985 if (disc_hlds_type_is_gdr8050l_no_prefetch (dvd_get_hlds_e7_type (d -> dvd))) {
986 prefetch_sector = sector_no;
987 prefetch_ret = dvd_flush_cache_READ12 (d -> dvd, sector_no, &sense);
989 if (sector_no > d -> sectors_no - 1000)
990 prefetch_sector = sector_no - 16 * 5 * 2;
992 prefetch_sector = sector_no + 16 * 5;
993 prefetch_ret = dvd_read_sector_streaming (d -> dvd, prefetch_sector, &sense, NULL, 0);
995 if (prefetch_ret < 0) {
996 disc_seed_diag_log (d,
997 "block=%u/20 sectors=%u..%u retry=%d stage=prefetch result=NONFATAL-FAIL rc=%d sense=%02X/%02X/%02X detail=prefetch-lba-%u",
998 d -> seed_diagnostic_block + 1, sector_no,
999 sector_no + SECTORS_PER_BLOCK - 1, retry, prefetch_ret,
1000 sense.sense_key & 0xff, sense.asc & 0xff, sense.ascq & 0xff,
1004 memset (&sense, 0, sizeof (sense));
1005 ret = dvd_read_sector_streaming (d -> dvd, sector_no, &sense, readbuf, sizeof (readbuf));
1007 for (j = 0; j < (int) profile_blocks && sector_no + j * 16 < d -> sectors_no && out; j++) {
1008 for (k = 0; k < 16; k++) {
1009 sect = &buf[j][k * RAW_SECTOR_SIZE];
1010 ram_offset = (j * RAW_BLOCK_SIZE) + k * RAW_SECTOR_SIZE;
1011 ret = dvd_memdump (d -> dvd, ram_offset, 1, 12, sect);
1013 snprintf (detail, sizeof (detail),
1014 "window=%d sector-index=%d raw-offset=%u", j, k, ram_offset);
1015 disc_seed_diag_fail (d, sector_no + (u_int32_t) (j * 16 + k),
1016 sector_no + (u_int32_t) (j * 16 + k), retry,
1017 "header-memdump", detail, ret, true);
1018 error ("Memdump (1) failed");
1020 retry = MAX_READ_RETRIES;
1022 ret = dvd_memdump (d -> dvd, ram_offset + 2060, 1, 4, sect + 2060);
1024 snprintf (detail, sizeof (detail),
1025 "window=%d sector-index=%d raw-offset=%u", j, k, ram_offset + 2060);
1026 disc_seed_diag_fail (d, sector_no + (u_int32_t) (j * 16 + k),
1027 sector_no + (u_int32_t) (j * 16 + k), retry,
1028 "edc-memdump", detail, ret, true);
1029 error ("Memdump (2) failed");
1036 for (j = 0; j < (int) profile_blocks && sector_no + j * 16 < d -> sectors_no && out; j++) {
1038 memset (&sense, 0, sizeof (sense));
1039 ret = dvd_read_sector_streaming (d -> dvd, sector_no + (u_int32_t) j * 16,
1040 &sense, readbuf, sizeof (readbuf));
1042 snprintf (detail, sizeof (detail),
1043 "window=%d sense=%02X/%02X/%02X", j,
1044 sense.sense_key & 0xff, sense.asc & 0xff, sense.ascq & 0xff);
1045 disc_seed_diag_fail (d, sector_no + (u_int32_t) j * 16,
1046 sector_no + (u_int32_t) j * 16 + SECTORS_PER_BLOCK - 1,
1047 retry, "cached-window-streaming-read", detail, ret, true);
1048 error ("dvd_read_sector_streaming() failed with %d", ret);
1054 for (k = 0; k < 16; k++) {
1055 sect = &buf[j][k * RAW_SECTOR_SIZE];
1056 memcpy (sect + 12, readbuf + k * SECTOR_SIZE, SECTOR_SIZE);
1059 if (d -> unscrambling) {
1061 if (!unscrambler_unscramble_16sectors (d -> u,
1062 sector_no + (u_int32_t) (j * 16), buf[j], buf_unscrambled[j])) {
1063 snprintf (detail, sizeof (detail), "window=%d", j);
1064 disc_seed_diag_fail (d,
1065 sector_no + (u_int32_t) j * 16,
1066 sector_no + (u_int32_t) j * 16 + SECTORS_PER_BLOCK - 1,
1067 retry, "edc-unscramble-validation", detail, -1, false);
1076 for (j = 0; j < (int) profile_blocks && sector_no + j * SECTORS_PER_BLOCK < d -> sectors_no; j++)
1077 disc_cache_add_block (d, start_block + j, buf_unscrambled[j], buf[j]);
1078 disc_seed_diag_clear (d);
1079 disc_seed_diag_log (d,
1080 "block=%u/20 sectors=%u..%u retry=%d stage=normal-profile result=PASS detail=windows-%u",
1081 d -> seed_diagnostic_block + 1, sector_no,
1082 sector_no + SECTORS_PER_BLOCK - 1, retry, profile_blocks);
1085 snprintf (detail, sizeof (detail), "sense=%02X/%02X/%02X",
1086 sense.sense_key & 0xff, sense.asc & 0xff, sense.ascq & 0xff);
1087 disc_seed_diag_fail (d, sector_no,
1088 sector_no + SECTORS_PER_BLOCK - 1, retry,
1089 "streaming-read", detail, ret, true);
1090 error ("dvd_read_sector_streaming() failed with %d", ret);
1095 if (!out && disc_hlds_type_is_gdr8050l_accel (dvd_get_hlds_e7_type (d -> dvd))) {
1096 u_int32_t failed_type = dvd_get_hlds_e7_type (d -> dvd);
1097 warning ("GDR-8050L modified 0xE7: accelerated profile %s failed at sector %u; falling back to proven single-window profile for this run",
1098 dvd_get_hlds_e7_profile_name (d -> dvd), sector_no);
1099 dvd_set_hlds_e7_runtime_profile (d -> dvd, 44, 0x80000000U, 1);
1100 d -> hlds_e7_read_schedule_logged = false;
1101 disc_cache_clear (d);
1102 out = disc_read_sector_8 (d, sector_no, data, rawdata);
1104 warning ("GDR-8050L modified 0xE7: fallback from accelerated profile %u also failed", failed_type);
1108 u_int32_t block_sector = start_block * SECTORS_PER_BLOCK;
1109 warning ("Method 8 normal profile read failed at sectors %u..%u; entering split recovery", block_sector, block_sector + SECTORS_PER_BLOCK - 1);
1110 disc_seed_diag_log (d,
1111 "block=%u/20 sectors=%u..%u retry=%d stage=normal-profile result=EXHAUSTED detail=entering-split-recovery",
1112 d -> seed_diagnostic_block + 1, block_sector,
1113 block_sector + SECTORS_PER_BLOCK - 1, MAX_READ_RETRIES - 1);
1114 out = disc_read_sector_8_split_recover_block (d, block_sector);
1118 error ("Too many retries, giving up");
1124 static int disc_read_sector_9 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
1126 u_int32_t ram_offset;
1127 int j, k, ret, retry;
1128 u_int8_t *sect, buf[5][RAW_BLOCK_SIZE];
1129 u_int8_t readbuf[BLOCK_SIZE], tmp[16];
1130 u_int8_t buf_unscrambled[5][BLOCK_SIZE];
1131 u_int32_t start_block;
1132 //fprintf (stdout,"disc_read_sector_9");
1133 start_block = sector_no / SECTORS_PER_BLOCK;
1136 for (retry = 0; !out && retry < MAX_READ_RETRIES; retry++) {
1137 /* Assume everything will turn out well */
1141 warning ("Read retry %d for sector %u", retry, sector_no);
1143 /* Try to reset in-memory data by seeking to a distant sector */
1144 // if (sector_no > 1000)
1145 // dvd_read_sector_streaming (d -> dvd, 0, NULL, NULL, 0);
1147 // dvd_read_sector_streaming (d -> dvd, 1500, NULL, NULL, 0);
1148 if (sector_no +992 +16 <= d -> sectors_no) //smaller than last sector
1149 dvd_read_sector_dummy (d -> dvd, sector_no +992, 16, NULL, NULL, 0);
1150 else if (sector_no -992 >= 0) //larger than first sector
1151 dvd_read_sector_dummy (d -> dvd, sector_no -992, 16, NULL, NULL, 0);
1152 else dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL);
1155 /* First READ command, this will cache 5 16-sector blocks. Immediately dump relevant data */
1156 if (sector_no > d -> sectors_no - 1000)
1157 dvd_read_sector_streaming (d -> dvd, sector_no - 16 * 5 * 2, NULL, NULL, 0);
1159 dvd_read_sector_streaming (d -> dvd, sector_no + 16 * 5, NULL, NULL, 0);
1160 if ((ret = dvd_read_sector_streaming (d -> dvd, sector_no, NULL, readbuf, BLOCK_SIZE)) >= 0) {
1161 for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no && out; j++) {
1162 /* Reconstruct raw sectors */
1163 for (k = 0; k < 16; k++) {
1164 sect = &buf[j][k * RAW_SECTOR_SIZE];
1165 ram_offset = (j * RAW_BLOCK_SIZE) + k * RAW_SECTOR_SIZE;
1166 /* Get first 12 bytes (ID. IED and CPR_MAI fields) and last 4 bytes (EDC field) with memdump */
1167 if (j == 0 && k == 0) {
1168 if (dvd_memdump (d -> dvd, ram_offset, 1, 12, sect) < 0) {
1169 error ("Memdump (1) failed");
1171 retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */
1174 memcpy (sect, tmp + 4, 12);
1177 if (out && dvd_memdump (d -> dvd, ram_offset + 2060, 1, 16, tmp) < 0) { /* Dumping in a single block is faster */
1178 error ("Memdump (2) failed");
1181 memcpy (sect + 2060, tmp, 4);
1186 /* Now the same for remaining 4 16-sector blocks */
1187 for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no && out; j++) {
1188 if (j == 0 || (ret = dvd_read_sector_streaming (d -> dvd, sector_no + j * 16, NULL, readbuf, BLOCK_SIZE)) >= 0) {
1189 /* Copy "user data" field which has been incorrectly unscrambled by the DVD drive firmware */
1190 for (k = 0; k < 16; k++) {
1191 sect = &buf[j][k * RAW_SECTOR_SIZE];
1192 memcpy (sect + 12, readbuf + k * SECTOR_SIZE, SECTOR_SIZE);
1195 if (d -> unscrambling) {
1197 /* Try to unscramble all data to see if EDC fails */
1198 if (!unscrambler_unscramble_16sectors (d -> u, sector_no + (j * 16), buf[j], buf_unscrambled[j]))
1204 error ("dvd_read_sector_streaming() failed with %d", ret);
1210 /* It seems all data were unscrambled correctly, so cache them out */
1211 for (j = 0; j < 5 && sector_no + j * SECTORS_PER_BLOCK < d -> sectors_no; j++)
1212 disc_cache_add_block (d, start_block + j, buf_unscrambled[j], buf[j]);
1215 error ("dvd_read_sector_streaming() failed with %d", ret);
1221 error ("Too many retries, giving up");
1227 /* We could also use the 'System ID' (first byte of the image) to tell the discs apart */
1228 static disc_type disc_detect_type (disc *d, u_int32_t forced_type, u_int32_t sectors_no) {
1231 if (forced_type==0) {
1232 d -> type = DISC_TYPE_GAMECUBE;
1233 d -> sectors_no = DISC_GAMECUBE_SECTORS_NO;
1234 } else if (forced_type==1) {
1235 d -> type = DISC_TYPE_WII;
1236 d -> sectors_no = DISC_WII_SECTORS_NO_SL;
1237 } else if (forced_type==2) {
1238 d -> type = DISC_TYPE_WII_DL;
1239 d -> sectors_no = DISC_WII_SECTORS_NO_DL;
1240 //dvd_get_layerbreak(d->dvd, &(d -> layerbreak), NULL);
1241 } else if (forced_type==3) {
1242 d -> type = DISC_TYPE_DVD;
1243 if (sectors_no == -1) dvd_get_size(d->dvd, &(d -> sectors_no), NULL);
1244 dvd_get_layerbreak(d->dvd, &(d -> layerbreak), NULL);
1245 } else if (forced_type==4) {
1246 d -> type = DISC_TYPE_XBOX;
1247 d -> read_sector = disc_read_sector_xbox;
1248 d -> read_method = 10;
1249 if (sectors_no == -1) {
1250 u_int32_t sector_size = 0;
1251 /* Do not run the GDR-8050L handshake during type detection.
1252 * Redump-style Xbox output must capture the visible DVD-video view
1253 * before switching the drive into the unlocked game view. */
1254 if (dvd_read_capacity_10(d->dvd, &(d -> sectors_no), §or_size, NULL) < 0 || sector_size != SECTOR_SIZE)
1255 d -> sectors_no = DISC_XBOX_GDR8050L_UNLOCKED_SECTORS_NO;
1259 if (dvd_is_xbox_drive(d->dvd)) {
1260 d -> type = DISC_TYPE_XBOX;
1261 d -> read_sector = disc_read_sector_xbox;
1262 d -> read_method = 10;
1264 u_int32_t sector_size = 0;
1265 /* Keep the drive in its current/locked view for dump planning.
1266 * The Xbox dumper explicitly unlocks only when it needs the
1267 * game/XDVDFS view. */
1268 if (dvd_read_capacity_10(d->dvd, &(d -> sectors_no), §or_size, NULL) < 0 || sector_size != SECTOR_SIZE)
1269 d -> sectors_no = DISC_XBOX_GDR8050L_UNLOCKED_SECTORS_NO;
1271 if (sectors_no != -1) d -> sectors_no = sectors_no;
1275 /* Try to read a sector beyond the end of GameCube discs */
1276 if (!dvd_read_sector_dummy (d -> dvd, DISC_GAMECUBE_SECTORS_NO + 100, SECTORS_PER_BLOCK, &sense, NULL, 0) && sense.sense_key == 0x05 && sense.asc == 0x21) {
1277 d -> type = DISC_TYPE_GAMECUBE;
1278 d -> sectors_no = DISC_GAMECUBE_SECTORS_NO;
1280 if (!dvd_read_sector_dummy (d -> dvd, DISC_WII_SECTORS_NO_SL + 100, SECTORS_PER_BLOCK, &sense, NULL, 0) && sense.sense_key == 0x05 && sense.asc == 0x21) {
1281 d -> type = DISC_TYPE_WII;
1282 d -> sectors_no = DISC_WII_SECTORS_NO_SL;
1284 d -> type = DISC_TYPE_WII_DL;
1285 d -> sectors_no = DISC_WII_SECTORS_NO_DL;
1286 //dvd_get_layerbreak(d->dvd, &(d -> layerbreak), NULL);
1291 if (sectors_no != -1) d -> sectors_no = sectors_no;
1298 * Reads a sector from the disc (or from the cache), using the preset read method.
1299 * @param d The disc structure.
1300 * @param sector_no The requested sector number.
1301 * @param data A buffer to hold the unscrambled sector data (or NULL).
1302 * @param rawdata A buffer to hold the raw sector data (or NULL).
1305 int disc_read_sector (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) {
1307 u_int8_t *cdata, *crawdata;
1310 /* Unscrambled data cannot be requested if unscrambling was disabled */
1311 MY_ASSERT (!(data && !d -> unscrambling && d -> type != DISC_TYPE_XBOX));
1313 block = sector_no / SECTORS_PER_BLOCK;
1315 /* See if sector is in cache */
1316 if (!(out = disc_cache_lookup_block (d, block, &cdata, &crawdata))) {
1317 /* Requested block is not in cache, try to read it from media */
1318 out = d -> read_sector (d, sector_no, data, rawdata);
1320 /* Now requested sector is in cache, for sure ;) */
1322 MY_ASSERT (disc_cache_lookup_block (d, block, &cdata, &crawdata));
1327 *data = cdata + (sector_no % SECTORS_PER_BLOCK) * SECTOR_SIZE;
1329 *rawdata = crawdata + (sector_no % SECTORS_PER_BLOCK) * RAW_SECTOR_SIZE;
1341 static const char *disc_detected_type_name (disc_type type) {
1343 case DISC_TYPE_GAMECUBE:
1347 case DISC_TYPE_WII_DL:
1351 case DISC_TYPE_XBOX:
1359 static bool disc_analyze (disc *d, bool allow_type_correction, bool allow_size_correction) {
1361 char tmp[0x03E0 + 1];
1362 bool unscramble_old, out;
1363 nintendo_disc_header_type header_type;
1364 disc_type previous_type;
1366 /* Force unscrambling for this read */
1367 unscramble_old = d -> unscrambling;
1368 disc_set_unscrambling (d, true);
1370 if (disc_read_sector (d, 0, &buf, NULL)) {
1372 d -> system_id = buf[0];
1375 * The legacy capacity probe can misclassify GameCube media on some
1376 * HLDS drives because an out-of-range dummy read does not always
1377 * return the expected ILLEGAL REQUEST / LBA OUT OF RANGE sense data.
1378 * Once sector 0 has been unscrambled, its platform magic is the
1379 * authoritative discriminator.
1381 * Explicit -T selections remain authoritative and are not changed.
1382 * Explicit -S geometry also remains authoritative.
1384 header_type = nintendo_disc_header_detect (buf, SECTOR_SIZE);
1385 previous_type = d -> type;
1387 if (allow_type_correction &&
1388 header_type == NINTENDO_DISC_HEADER_GAMECUBE) {
1389 d -> type = DISC_TYPE_GAMECUBE;
1390 if (allow_size_correction)
1391 d -> sectors_no = DISC_GAMECUBE_SECTORS_NO;
1392 } else if (allow_type_correction &&
1393 header_type == NINTENDO_DISC_HEADER_WII &&
1394 d -> type != DISC_TYPE_WII &&
1395 d -> type != DISC_TYPE_WII_DL) {
1396 d -> type = DISC_TYPE_WII;
1397 if (allow_size_correction)
1398 d -> sectors_no = DISC_WII_SECTORS_NO_SL;
1401 if (allow_type_correction &&
1402 header_type != NINTENDO_DISC_HEADER_UNKNOWN &&
1403 previous_type != d -> type) {
1404 warning ("Disc type corrected from %s to %s using sector-0 platform magic",
1405 disc_detected_type_name (previous_type),
1406 disc_detected_type_name (d -> type));
1410 strncpy (d -> game_id, (char *) buf + 1, 2);
1411 d -> game_id[2] = '\0';
1416 d -> region = DISC_REGION_PAL;
1419 d -> region = DISC_REGION_NTSC;
1422 d -> region = DISC_REGION_JAPAN;
1425 d -> region = DISC_REGION_AUSTRALIA;
1428 d -> region = DISC_REGION_FRANCE;
1431 d -> region = DISC_REGION_GERMANY;
1434 d -> region = DISC_REGION_ITALY;
1437 d -> region = DISC_REGION_SPAIN;
1440 d -> region = DISC_REGION_PAL_X;
1443 d -> region = DISC_REGION_PAL_Y;
1446 d -> region = DISC_REGION_UNKNOWN;
1451 strncpy (d -> maker, (char *) buf + 4, 2);
1452 d -> maker[2] = '\0';
1455 d -> version = buf[7];
1456 snprintf (tmp, sizeof (tmp), "1.%02u", d -> version);
1457 my_strdup (d -> version_string, tmp);
1460 memcpy (tmp, buf + 0x0020, sizeof (tmp) - 1);
1461 tmp[sizeof (tmp) - 1] = '\0';
1463 my_strdup (d -> title, tmp);
1467 error ("Cannot analyze disc");
1471 disc_set_unscrambling (d, unscramble_old);
1477 static char disc_type_strings[5][15] = {
1486 * Retrieves the disc type.
1487 * @param d The disc structure.
1488 * @param dt This will be set to the disc type.
1489 * @param dt_s This will point to a string describing the disc type.
1490 * @return A string describing the disc type.
1492 char *disc_get_type (disc *d, disc_type *dt, char **dt_s) {
1497 if (d -> type <= DISC_TYPE_XBOX)
1498 *dt_s = disc_type_strings[d -> type];
1500 *dt_s = disc_type_strings[DISC_TYPE_DVD];
1508 * Retrieves the disc game ID.
1509 * @param d The disc structure.
1510 * @param gid_s This will point to a string containing the game ID.
1511 * @return A string containing the game ID.
1513 char *disc_get_gameid (disc *d, char **gid_s) {
1515 *gid_s = d -> game_id;
1521 static char disc_region_strings[11][15] = {
1536 * Retrieves the disc region.
1537 * @param d The disc structure.
1538 * @param dr This will be set to the disc region.
1539 * @param dr_s This will point to a string describing the disc region.
1540 * @return A string describing the disc region.
1542 char *disc_get_region (disc *d, disc_region *dr, char **dr_s) {
1547 if (d -> region < DISC_REGION_UNKNOWN)
1548 *dr_s = disc_region_strings[d -> region];
1550 *dr_s = disc_region_strings[DISC_REGION_UNKNOWN];
1557 /* The following list has been derived from http://wiitdb.com/Company/HomePage */
1563 {"0B", "Coconuts Japan"},
1564 {"0C", "Coconuts Japan / G.X.Media"},
1567 {"0F", "Mebio Software"},
1568 {"0G", "Shouei System"},
1570 {"0J", "Mitsui Fudosan / Dentsu"},
1571 {"0L", "Warashi Inc."},
1573 {"0P", "Game Village"},
1574 {"0Q", "IE Institute"},
1576 {"02", "Rocket Games / Ajinomoto"},
1577 {"03", "Imagineer-Zoom"},
1578 {"04", "Gray Matter"},
1583 {"09", "Hot B Co."},
1585 {"1C", "Tecmo Products"},
1586 {"1D", "Japan Glary Business"},
1587 {"1E", "Forum / OpenSystem"},
1588 {"1F", "Virgin Games (Japan)"},
1590 {"1J", "Daikokudenki"},
1591 {"1P", "Creatures Inc."},
1592 {"1Q", "TDK Deep Impresion"},
1593 {"2A", "Culture Brain"},
1595 {"2D", "Visit Co.,Ltd."},
1597 {"2F", "System Sacom"},
1599 {"2H", "Ubisoft Japan"},
1600 {"2J", "Media Works"},
1601 {"2K", "NEC InterChannel"},
1604 {"2N", "Smilesoft / Rocket"},
1605 {"2Q", "Mediakite"},
1606 {"3B", "Arcade Zone Ltd"},
1607 {"3C", "Entertainment International / Empire Software"},
1609 {"3E", "Gremlin Graphics"},
1610 {"3F", "K.Amusement Leasing Co."},
1611 {"4B", "Raya Systems"},
1612 {"4C", "Renovation Products"},
1613 {"4D", "Malibu Games"},
1615 {"4G", "Playmates Interactive"},
1616 {"4J", "Fox Interactive"},
1617 {"4K", "Time Warner Interactive"},
1618 {"4Q", "Disney Interactive"},
1619 {"4S", "Black Pearl"},
1620 {"4U", "Advanced Productions"},
1621 {"4X", "GT Interactive"},
1623 {"4Z", "Crave Entertainment"},
1624 {"5A", "Mindscape / Red Orb Entertainment"},
1627 {"5D", "Midway / Tradewest"},
1628 {"5F", "American Softworks"},
1629 {"5G", "Majesco Sales Inc"},
1633 {"5M", "Telegames"},
1635 {"5P", "Vatical Entertainment"},
1636 {"5Q", "LEGO Media"},
1637 {"5S", "Xicat Interactive"},
1638 {"5T", "Cryo Interactive"},
1639 {"5W", "Red Storm Entertainment"},
1641 {"5Z", "Data Design / Conspiracy / Swing"},
1642 {"6B", "Laser Beam"},
1643 {"6E", "Elite Systems"},
1644 {"6F", "Electro Brain"},
1645 {"6G", "The Learning Company"},
1647 {"6J", "Software 2000"},
1648 {"6K", "UFO Interactive Games"},
1649 {"6L", "BAM! Entertainment"},
1651 {"6Q", "Classified Games"},
1652 {"6S", "TDK Mediactive"},
1653 {"6U", "DreamCatcher"},
1654 {"6V", "JoWood Produtions"},
1656 {"6X", "Wannado Edition"},
1657 {"6Y", "LSP (Light & Shadow Prod.)"},
1658 {"6Z", "ITE Media"},
1659 {"7A", "Triffix Entertainment"},
1660 {"7C", "Microprose Software"},
1661 {"7D", "Sierra / Universal Interactive"},
1663 {"7G", "Rage Software"},
1667 {"7L", "Simon & Schuster Interactive"},
1668 {"7M", "Asmik Ace Entertainment Inc."},
1669 {"7N", "Empire Interactive"},
1670 {"7Q", "Jester Interactive"},
1671 {"7S", "Rockstar Games"},
1672 {"7T", "Scholastic"},
1673 {"7U", "Ignition Entertainment"},
1674 {"7V", "Summitsoft"},
1675 {"7W", "Stadlbauer"},
1676 {"8B", "BulletProof Software (BPS)"},
1677 {"8C", "Vic Tokai Inc."},
1678 {"8E", "Character Soft"},
1681 {"8J", "General Entertainment"},
1683 {"8P", "Sega Japan"},
1684 {"9A", "Nichibutsu / Nihon Bussan"},
1686 {"9C", "Imagineer"},
1688 {"9G", "Take2 / Den'Z / Global Star"},
1689 {"9H", "Bottom Up"},
1690 {"9J", "TGL (Technical Group Laboratory)"},
1691 {"9L", "Hasbro Japan"},
1692 {"9N", "Marvelous Entertainment"},
1693 {"9P", "Keynet Inc."},
1694 {"9Q", "Hands-On Entertainment"},
1696 {"13", "Electronic Arts Japan"},
1697 {"15", "Cobra Team"},
1698 {"16", "Human / Field"},
1700 {"18", "Hudson Soft"},
1702 {"20", "Destination Software / Zoo Games / KSS"},
1703 {"21", "Sunsoft / Tokai Engineering"},
1704 {"22", "POW (Planning Office Wada) / VR1 Japan"},
1705 {"23", "Micro World"},
1708 {"27", "Loriciel / Electro Brain"},
1709 {"28", "Kemco Japan"},
1712 {"31", "Carrozzeria"},
1716 {"36", "Codemasters"},
1717 {"37", "Taito / GAGA Communications"},
1719 {"39", "Telstar / Event / Taito"},
1720 {"40", "Seika Corp."},
1721 {"41", "Ubi Soft Entertainment"},
1722 {"42", "Sunsoft US"},
1723 {"44", "Life Fitness"},
1725 {"47", "Spectrum Holobyte"},
1727 {"50", "Absolute Entertainment"},
1729 {"52", "Activision"},
1730 {"53", "American Sammy"},
1731 {"54", "Take 2 Interactive / GameTek"},
1736 {"61", "Virgin Interactive"},
1738 {"64", "LucasArts Entertainment"},
1740 {"68", "Bethesda Softworks"},
1741 {"69", "Electronic Arts"},
1742 {"70", "Atari (Infogrames)"},
1743 {"71", "Interplay"},
1745 {"73", "Parker Brothers"},
1746 {"75", "Sales Curve (Storm / SCI)"},
1751 {"82", "Namco Ltd."},
1754 {"86", "Tokuma Shoten Intermedia"},
1755 {"87", "Tsukuda Original"},
1756 {"88", "DATAM-Polystar"},
1757 {"90", "Takara Amusement"},
1758 {"91", "Chun Soft"},
1759 {"92", "Video System / Mc O' River"},
1762 {"96", "Yonezawa / S'pal"},
1764 {"99", "Marvelous Entertainment"},
1768 {"A5", "K.Amusement Leasing Co."},
1771 {"A9", "Technos Japan Corp."},
1772 {"AA", "JVC / Victor"},
1773 {"AC", "Toei Animation"},
1776 {"AG", "Media Rings Corporation"},
1778 {"AJ", "Pioneer LDC"},
1780 {"AL", "Mediafactory"},
1781 {"AP", "Infogrames / Hudson"},
1782 {"AQ", "Kiratto. Ludic Inc"},
1783 {"B0", "Acclaim Japan"},
1787 {"B6", "HAL Laboratory"},
1789 {"B9", "Pony Canyon"},
1790 {"BA", "Culture Brain"},
1792 {"BC", "Toshiba EMI"},
1793 {"BD", "Sony Imagesoft"},
1799 {"BN", "Sunrise Interactive"},
1800 {"BP", "Global A Entertainment"},
1805 {"C4", "Tokuma Shoten"},
1806 {"C5", "Data East"},
1807 {"C6", "Tonkin House / Tokyo Shoseki"},
1809 {"CA", "Konami / Ultra / Palcom"},
1810 {"CB", "NTVIC / VAP"},
1811 {"CC", "Use Co.,Ltd."},
1813 {"CE", "Pony Canyon / FCI"},
1814 {"CF", "Angel / Sotsu Agency / Sunrise"},
1815 {"CG", "Yumedia / Aroma Co., Ltd"},
1817 {"CK", "Axela / Crea-Tech"},
1818 {"CL", "Sekaibunka-Sha / Sumire Kobo / Marigul Management Inc."},
1819 {"CM", "Konami Computer Entertainment Osaka"},
1820 {"CN", "NEC Interchannel"},
1821 {"CP", "Enterbrain"},
1822 {"CQ", "From Software"},
1823 {"D0", "Taito / Disco"},
1825 {"D2", "Quest / Bothtec"},
1827 {"D4", "Ask Kodansha"},
1829 {"D7", "Copya System"},
1830 {"D8", "Capcom Co., Ltd."},
1831 {"D9", "Banpresto"},
1833 {"DB", "LJN Japan"},
1835 {"DE", "Human Entertainment"},
1838 {"DH", "Gaps Inc."},
1840 {"DQ", "Compile Heart"},
1849 {"EA", "King Records"},
1851 {"EC", "Epic / Sony Records"},
1852 {"EE", "IGS (Information Global Service)"},
1854 {"EH", "Right Stuff"},
1856 {"EM", "Konami Computer Entertainment Tokyo"},
1857 {"EN", "Alphadream Corporation"},
1859 {"ES", "Star-Fish"},
1861 {"F1", "Motown Software"},
1862 {"F2", "Left Field Entertainment"},
1863 {"F3", "Extreme Ent. Grp."},
1865 {"F9", "Cybersoft"},
1866 {"FB", "Psygnosis"},
1867 {"FE", "Davidson / Western Tech."},
1868 {"FK", "The Game Factory"},
1869 {"FL", "Hip Games"},
1873 {"FR", "Digital Tainment Pool"},
1874 {"FS", "XS Games / Jack Of All Games"},
1876 {"G0", "Alpha Unit"},
1877 {"G1", "PCCW Japan"},
1878 {"G2", "Yuke's Media Creations"},
1879 {"G4", "KiKi Co Ltd"},
1880 {"G5", "Open Sesame Inc"},
1884 {"G9", "D3 Publisher"},
1885 {"GB", "Konami Computer Entertainment Japan"},
1886 {"GD", "Square-Enix"},
1888 {"GF", "Micott & Basara Inc."},
1889 {"GH", "Orbital Media"},
1890 {"GJ", "Detn8 Games"},
1891 {"GL", "Gameloft / Ubi Soft"},
1892 {"GM", "Gamecock Media Group"},
1893 {"GN", "Oxygen Games"},
1894 {"GT", "505 Games"},
1895 {"GY", "The Game Factory"},
1899 {"H4", "SNK Playmore"},
1900 {"HJ", "Genius Products"},
1901 {"HY", "Reef Entertainment"},
1902 {"HZ", "Nordcurrent"},
1904 {"J9", "AQ Interactive"},
1905 {"JF", "Arc System Works"},
1907 {"K6", "Nihon System"},
1908 {"KB", "NIS America"},
1909 {"KM", "Deep Silver"},
1910 {"LH", "Trend Verlag / East Entertainment"},
1911 {"LT", "Legacy Interactive"},
1912 {"MJ", "Mumbo Jumbo"},
1913 {"MR", "Mindscape"},
1914 {"MS", "Milestone / UFO Interactive"},
1917 {"NK", "Neko Entertainment / Diffusion / Naps team"},
1919 {"NR", "Data Design / Destineer Studios"},
1920 {"PL", "Playlogic"},
1921 {"RM", "Rondomedia"},
1922 {"RS", "Warner Bros. Interactive Entertainment Inc."},
1923 {"RT", "RTL Games"},
1924 {"RW", "RealNetworks"},
1925 {"S5", "Southpeak Interactive"},
1926 {"SP", "Blade Interactive Studios"},
1927 {"SV", "SevenGames"},
1928 {"TK", "Tasuke / Works"},
1929 {"UG", "Metro 3D / Data Design"},
1930 {"VN", "Valcon Games"},
1931 {"VP", "Virgin Play"},
1932 {"WR", "Warner Bros. Interactive Entertainment Inc."},
1933 {"XJ", "Xseed Games"},
1934 {"XS", "Aksys Games"},
1939 * Retrieves the disk maker.
1940 * @param d The disc structure.
1941 * @param m This will point to a string containing the disc maker ID.
1942 * @param m_s This will point to a string describing the disc maker.
1943 * @return A string describing the disc maker.
1945 char *disc_get_maker (disc *d, char **m, char **m_s) {
1952 for (i = 0; makers[i].code; i++) {
1953 if (strcasecmp (d -> maker, makers[i].code) == 0) {
1954 *m_s = makers[i].name;
1958 if (!makers[i].code) {
1968 * Retrieves the disc version.
1969 * @param d The disc structure.
1970 * @param v This will contain the version ID.
1971 * @param v_s This will point to a string describing the disc version.
1972 * @return A string describing the disc version.
1974 char *disc_get_version (disc *d, u_int8_t *v, char **v_s) {
1979 *v_s = d -> version_string;
1986 * Retrieves the disc game title.
1987 * @param d The disc structure.
1988 * @param t_s This will point to a string describing the disc title.
1989 * @return A string describing the disc title.
1991 char *disc_get_title (disc *d, char **t_s) {
2000 * Retrieves if the disc has an update.
2001 * @param d The disc structure.
2002 * @return True if the disc contains an update, false otherwise.
2004 bool disc_get_update (disc *d) {
2005 return (d -> has_update);
2010 * Retrieves the number of sectors of the disc.
2011 * @param d The disc structure.
2012 * @return The number of sectors.
2014 u_int32_t disc_get_sectors_no (disc *d) {
2015 return (d -> sectors_no);
2018 u_int32_t disc_get_layerbreak (disc *d) {
2019 return (d -> layerbreak);
2022 u_int32_t disc_get_command (disc *d) {
2023 return (d -> command);
2026 u_int32_t disc_get_method (disc *d) {
2027 return (d -> read_method);
2030 u_int32_t disc_get_def_method (disc *d) {
2031 return dvd_get_def_method(d -> dvd);//(d -> def_read_method);
2034 u_int32_t disc_get_sec_disc (disc *d) {
2035 return (d -> sec_disc);
2038 u_int32_t disc_get_sec_mem (disc *d) {
2039 return (d -> sec_mem);
2042 /* wiidevel@stacktic.org */
2043 static bool disc_check_update (disc *d) {
2046 bool unscramble_old;
2048 if (d -> type == DISC_TYPE_WII || d -> type == DISC_TYPE_WII_DL) {
2049 /* Force unscrambling for this read */
2050 unscramble_old = d -> unscrambling;
2051 disc_set_unscrambling (d, true);
2053 /* We need to read offset 0x50004 of the disc. Sector 160 has offset 0x50000 */
2054 if (disc_read_sector (d, 160, &buf, NULL)) {
2055 x = my_ntohl (*(u_int32_t *) (buf + 4));
2056 if (x == 0xA5BED6AE)
2057 d -> has_update = false;
2059 d -> has_update = true;
2061 error ("disc_check_update() failed");
2064 disc_set_unscrambling (d, unscramble_old);
2066 /* GameCube discs never have an update, as actually the GC firmware cannot be upgrade */
2067 d -> has_update = false;
2070 return (d -> has_update);
2075 * Sets the disc read method.
2076 * @param d The disc structure.
2077 * @param method The requested method.
2078 * @return True if the method was set correctly, false otherwise (i. e.: method too small/big).
2080 bool disc_set_read_method (disc *d, int method) {
2082 u_int32_t deviation;
2086 d -> command = dvd_get_command(d -> dvd);
2087 // d -> def_read_method = dvd_get_def_method(d -> dvd);
2088 d -> read_method = method;
2093 d -> read_sector = disc_read_sector_0;
2096 d -> read_sector = disc_read_sector_1;
2099 d -> read_sector = disc_read_sector_2;
2102 d -> read_sector = disc_read_sector_3;
2105 d -> read_sector = disc_read_sector_4;
2108 d -> read_sector = disc_read_sector_5;
2111 d -> read_sector = disc_read_sector_6;
2114 d -> read_sector = disc_read_sector_7;
2117 d -> read_sector = disc_read_sector_8;
2120 d -> read_sector = disc_read_sector_9;
2123 d -> read_sector = disc_read_sector_xbox;
2126 switch (dvd_get_def_method(d -> dvd)) {
2128 d -> read_method = 0;
2129 d -> read_sector = disc_read_sector_0;
2132 d -> read_method = 1;
2133 d -> read_sector = disc_read_sector_1;
2136 d -> read_method = 2;
2137 d -> read_sector = disc_read_sector_2;
2140 d -> read_method = 3;
2141 d -> read_sector = disc_read_sector_3;
2144 d -> read_method = 4;
2145 d -> read_sector = disc_read_sector_4;
2148 d -> read_method = 5;
2149 d -> read_sector = disc_read_sector_5;
2152 d -> read_method = 6;
2153 d -> read_sector = disc_read_sector_6;
2156 d -> read_method = 7;
2157 d -> read_sector = disc_read_sector_7;
2160 d -> read_method = 8;
2161 d -> read_sector = disc_read_sector_8;
2164 d -> read_method = 9;
2165 d -> read_sector = disc_read_sector_9;
2168 d -> read_method = 10;
2169 d -> read_sector = disc_read_sector_xbox;
2172 d -> read_method = DEFAULT_READ_METHOD;
2173 d -> read_sector = DEFAULT_READ_SECTOR;
2178 if (d->sec_disc==-1) {
2179 if ((d->read_method == 4) || (d->read_method == 5) || (d->read_method == 6))
2184 if (d->sec_mem==-1) {
2185 if ((d->read_method == 4) || (d->read_method == 5) || (d->read_method == 6))
2191 deviation = d->sec_mem % SECTORS_PER_BLOCK;
2199 if (cnt1%SECTORS_PER_BLOCK<=1) break;
2202 d -> max_cnt = counter;
2203 d -> max_blk = ((d->sec_mem*(d->max_cnt+1))-((d->sec_mem*(d->max_cnt+1)) % SECTORS_PER_BLOCK)) / 16;
2206 debug ("Read method set to %d", d -> read_method);
2208 error ("Cannot set read method\n");
2216 * Controls the unscrambling process.
2217 * @param d The disc structure.
2218 * @param unscramble If true, every raw sectors read will be unscrambled to check if they are error-free, otherwise read data will be returned as-is.
2220 void disc_set_unscrambling (disc *d, bool unscramble) {
2221 d -> unscrambling = unscramble;
2222 debug ("Sectors unscrambling %s", unscramble ? "enabled" : "disabled");
2229 static unsigned int hlds_e7_sector_header_value (const u_int8_t *hdr) {
2232 return ((unsigned int) hdr[1] << 16) | ((unsigned int) hdr[2] << 8) | (unsigned int) hdr[3];
2235 static int hlds_e7_score_sector_header (const u_int8_t *hdr, u_int32_t sector_no) {
2237 unsigned int expected;
2242 got = hlds_e7_sector_header_value (hdr);
2243 expected = 0x30000U + sector_no;
2245 if ((hdr[0] & 1) == 0)
2247 if (got == expected)
2249 if ((hdr[0] | hdr[1] | hdr[2] | hdr[3]) == 0x00)
2251 if ((hdr[0] & hdr[1] & hdr[2] & hdr[3]) == 0xFF)
2256 static void hlds_e7_json_escape (FILE *f, const char *s) {
2257 const unsigned char *p;
2262 for (p = (const unsigned char *) s; *p; p++) {
2263 if (*p == '"' || *p == '\\')
2264 fprintf (f, "\\%c", *p);
2265 else if (*p == '\n')
2267 else if (*p == '\r')
2269 else if (*p == '\t')
2272 fprintf (f, "\\u%04x", (unsigned int) *p);
2278 static void hlds_e7_json_bytes (FILE *f, const u_int8_t *b, size_t n) {
2282 for (i = 0; i < n; i++) {
2285 fprintf (f, "%02x", (unsigned int) b[i]);
2291 static u_int32_t hlds_e7_fnv1a32 (const u_int8_t *buf, size_t len) {
2297 for (i = 0; i < len; i++) {
2298 h ^= (u_int32_t) buf[i];
2304 static size_t hlds_e7_count_byte_diffs (const u_int8_t *a, const u_int8_t *b, size_t len) {
2310 for (i = 0; i < len; i++) {
2317 static bool hlds_e7_probe_bytes_useful (const u_int8_t *p, size_t len) {
2325 for (i = 0; i < len; i++) {
2329 return !(orv == 0x00 || andv == 0xFF);
2332 static int hlds_e7_find_raw_header_match (const u_int8_t *buf, size_t len, u_int32_t block_sector, size_t *match_offset, u_int32_t *match_sector) {
2340 *match_offset = (size_t) -1;
2342 *match_sector = 0xFFFFFFFFU;
2343 if (!buf || len < 4)
2345 for (off = 0; off + 4 <= len; off++) {
2346 for (k = 0; k < SECTORS_PER_BLOCK; k++) {
2347 expected = 0x30000U + block_sector + (u_int32_t) k;
2348 if (((u_int32_t) buf[off + 1] << 16 | (u_int32_t) buf[off + 2] << 8 | (u_int32_t) buf[off + 3]) == expected) {
2350 if ((buf[off] & 1) == 0)
2352 if ((off % RAW_SECTOR_SIZE) == (size_t) (k * RAW_SECTOR_SIZE))
2354 else if ((off % RAW_SECTOR_SIZE) == 0)
2356 if (score > best_score) {
2359 *match_offset = off;
2361 *match_sector = block_sector + (u_int32_t) k;
2369 static int hlds_e7_find_user_data_match (const u_int8_t *dumpbuf, size_t dump_len, const u_int8_t *readbuf, size_t read_len, size_t *match_offset, u_int32_t *match_sector, size_t *read_offset) {
2370 static const size_t probe_offsets[] = {0x00, 0x20, 0x80, 0x100, 0x400, 0x700};
2371 const size_t probe_len = 32;
2375 const u_int8_t *needle;
2377 *match_offset = (size_t) -1;
2379 *match_sector = 0xFFFFFFFFU;
2381 *read_offset = (size_t) -1;
2382 if (!dumpbuf || !readbuf || dump_len < probe_len || read_len < SECTOR_SIZE)
2384 for (k = 0; k < SECTORS_PER_BLOCK && ((k * SECTOR_SIZE) + SECTOR_SIZE) <= read_len; k++) {
2385 for (po = 0; po < sizeof (probe_offsets) / sizeof (probe_offsets[0]); po++) {
2386 if (probe_offsets[po] + probe_len > SECTOR_SIZE)
2388 needle = readbuf + k * SECTOR_SIZE + probe_offsets[po];
2389 if (!hlds_e7_probe_bytes_useful (needle, probe_len))
2391 for (off = 0; off + probe_len <= dump_len; off++) {
2392 if (memcmp (dumpbuf + off, needle, probe_len) == 0) {
2394 *match_offset = off;
2396 *match_sector = (u_int32_t) k;
2398 *read_offset = probe_offsets[po];
2412 } hlds_e7_probe_candidate;
2414 bool disc_hlds_e7_scan (disc *d, const char *json_path, const char *dump_prefix) {
2421 static const scan_candidate candidates[] = {
2422 {"type4_base_5win", 0x80000000U, 5, "known Type3/Type4 family base"},
2423 {"type4_base_1win", 0x80000000U, 1, "known Type3/Type4 base, conservative window"},
2424 {"type4_plus_0x8000", 0x80008000U, 1, "nearby +0x8000 alias candidate"},
2425 {"type4_plus_0x10000", 0x80010000U, 1, "nearby +0x10000 alias candidate"},
2426 {"type4_plus_0x20000", 0x80020000U, 1, "nearby +0x20000 alias candidate"},
2427 {"type4_plus_0x30000", 0x80030000U, 1, "nearby +0x30000 alias candidate"},
2428 {"type4_minus_0x8000", 0x7FFF8000U, 1, "moving/boundary candidate"},
2429 {"type4_minus_0x10000", 0x7FFF0000U, 1, "moving/boundary candidate"},
2430 {"type4_minus_0x18000", 0x7FFE8000U, 1, "moving/boundary candidate"},
2431 {"type1_a00000", 0x00A00000U, 1, "Type1 neighborhood"},
2432 {"type1_a13000", 0x00A13000U, 1, "GCC-4160N Type1 known base"},
2433 {"firmware_table_00380000",0x00380000U, 1, "observed 0x00380030 neighborhood, aligned down"},
2434 {"firmware_table_00380030",0x00380030U, 1, "observed stale/profile-garbage value; test only"},
2435 {"low_sram_00000000", 0x00000000U, 1, "low SRAM alias"},
2436 {"low_sram_00008000", 0x00008000U, 1, "low SRAM alias +0x8000"},
2437 {"low_sram_00010000", 0x00010000U, 1, "low SRAM alias +0x10000"},
2438 {"low_sram_00020000", 0x00020000U, 1, "low SRAM alias +0x20000"},
2439 {"firmware_sram_00001800", 0x00001800U, 1, "GDR-8081N plaintext firmware references 0x18xx SRAM/MMIO neighborhood"},
2440 {"firmware_sram_000018a8", 0x000018A8U, 1, "GDR-8081N plaintext firmware references 0x18a8"},
2441 {"firmware_sram_00009300", 0x00009300U, 1, "GDR-8081N plaintext firmware references 0x93xx"},
2442 {"firmware_sram_00009b00", 0x00009B00U, 1, "GDR-8081N plaintext firmware references 0x9bxx"},
2443 {"firmware_sram_0000a800", 0x0000A800U, 1, "GDR-8081N plaintext firmware references 0xa800"},
2444 {"firmware_alias_40000000",0x40000000U, 1, "firmware mapping base as alias sanity check"}
2446 static const u_int32_t probe_sectors[] = {0U, 320U};
2448 u_int8_t sample[16];
2449 u_int8_t readbuf[BLOCK_SIZE];
2451 u_int8_t *first_dump;
2454 u_int32_t old_windows;
2459 size_t max_scan_len;
2461 size_t exact_offsets[SECTORS_PER_BLOCK];
2464 size_t command_echo_offset;
2468 u_int32_t raw_sector;
2469 u_int32_t user_sector;
2476 char dump_path[512];
2480 u_int32_t best_base;
2481 u_int32_t best_windows;
2485 if (!d || !d -> dvd)
2487 path = (json_path && json_path[0]) ? json_path : "hlds_e7_scan.json";
2488 f = fopen (path, "wb");
2490 warning ("HLDS 0xE7 scan: could not open %s for writing", path);
2494 max_scan_len = 5U * RAW_BLOCK_SIZE;
2495 dumpbuf = (u_int8_t *) malloc (max_scan_len);
2496 first_dump = (u_int8_t *) malloc (max_scan_len);
2497 if (!dumpbuf || !first_dump) {
2503 warning ("HLDS 0xE7 scan: out of memory");
2507 old_type = dvd_get_hlds_e7_type (d -> dvd);
2508 old_base = dvd_get_hlds_e7_cache_base (d -> dvd);
2509 old_windows = dvd_get_hlds_e7_mem_blocks (d -> dvd);
2510 best_score = -999999;
2513 any_readable = false;
2515 fprintf (stderr, "\nHLDS 0xE7 scan mode v5: strict cache/memdump validation without seed cracking\n");
2516 fprintf (stderr, "HLDS 0xE7 scan mode v5: requiring 2064-byte raw-sector stride or READ payload echo; table/command echoes are not promoted\n");
2517 fprintf (stderr, "HLDS 0xE7 scan mode v5: writing JSON report to %s\n", path);
2520 fprintf (f, " \"scan_version\": \"v5_strict_sector_shape_command_echo\",\n");
2521 fprintf (f, " \"drive\": \"");
2522 hlds_e7_json_escape (f, disc_get_drive_model_string (d));
2523 fprintf (f, "\",\n");
2524 fprintf (f, " \"initial_profile\": \"");
2525 hlds_e7_json_escape (f, dvd_get_hlds_e7_profile_name (d -> dvd));
2526 fprintf (f, "\",\n");
2527 fprintf (f, " \"initial_cache_base\": \"0x%08x\",\n", old_base);
2528 fprintf (f, " \"initial_windows\": %u,\n", old_windows);
2529 fprintf (f, " \"probe_sectors\": [%u, %u],\n", probe_sectors[0], probe_sectors[1]);
2530 fprintf (f, " \"notes\": \"v5 does not promote sector-number table matches. It requires exact raw-sector IDs to be laid out with a 2064-byte stride or a direct READ payload echo. It also records HIT command-echo offsets because those indicate SRAM/command buffers, not proven sector cache.\",\n");
2531 fprintf (f, " \"candidates\": [\n");
2533 for (i = 0; i < sizeof (candidates) / sizeof (candidates[0]); i++) {
2534 scan_len = candidates[i].windows * RAW_BLOCK_SIZE;
2535 if (scan_len == 0 || scan_len > max_scan_len)
2536 scan_len = RAW_BLOCK_SIZE;
2539 dvd_set_hlds_e7_runtime_profile (d -> dvd, 9000U + (u_int32_t) i, candidates[i].base, candidates[i].windows);
2540 fprintf (stderr, " [%02u/%02u] %-25s base=0x%08x windows=%u scan=%lu... ",
2541 (unsigned int) (i + 1), (unsigned int) (sizeof (candidates) / sizeof (candidates[0])),
2542 candidates[i].label, candidates[i].base, candidates[i].windows, (unsigned long) scan_len);
2543 fprintf (f, " {\n");
2544 fprintf (f, " \"label\": \"");
2545 hlds_e7_json_escape (f, candidates[i].label);
2546 fprintf (f, "\",\n");
2547 fprintf (f, " \"base\": \"0x%08x\",\n", candidates[i].base);
2548 fprintf (f, " \"windows\": %u,\n", candidates[i].windows);
2549 fprintf (f, " \"scan_bytes\": %lu,\n", (unsigned long) scan_len);
2550 fprintf (f, " \"origin\": \"");
2551 hlds_e7_json_escape (f, candidates[i].origin);
2552 fprintf (f, "\",\n");
2553 fprintf (f, " \"sector_tests\": [\n");
2554 for (j = 0; j < sizeof (probe_sectors) / sizeof (probe_sectors[0]); j++) {
2555 memset (sample, 0, sizeof (sample));
2556 memset (readbuf, 0, sizeof (readbuf));
2557 memset (dumpbuf, 0, scan_len);
2558 dvd_flush_cache_READ12 (d -> dvd, probe_sectors[j], NULL);
2559 read_ret = dvd_read_sector_streaming (d -> dvd, probe_sectors[j], NULL, readbuf, sizeof (readbuf));
2560 dump_ret = dvd_memdump (d -> dvd, 0, candidates[i].windows ? candidates[i].windows : 1, RAW_BLOCK_SIZE, dumpbuf);
2561 if (dump_ret >= 0) {
2562 if (dump_prefix && dump_prefix[0]) {
2563 snprintf (dump_path, sizeof (dump_path), "%s_%02lu_%s_sector_%u.bin", dump_prefix, (unsigned long) (i + 1), candidates[i].label, probe_sectors[j]);
2564 df = fopen (dump_path, "wb");
2566 fwrite (dumpbuf, 1, scan_len, df);
2570 any_readable = true;
2571 memcpy (sample, dumpbuf, sizeof (sample));
2572 hash = hlds_e7_fnv1a32 (dumpbuf, scan_len);
2573 (void) hlds_e7_find_raw_header_match (dumpbuf, scan_len, probe_sectors[j], &raw_offset, &raw_sector);
2574 exact_count = hlds_e7_count_exact_raw_headers_for_block (dumpbuf, scan_len, probe_sectors[j], exact_offsets);
2575 sector_shaped = hlds_e7_raw_header_offsets_are_sector_shaped (exact_offsets);
2576 command_echo_offset = hlds_e7_find_command_echo_offset (dumpbuf, scan_len);
2579 else if (exact_count > 0)
2580 raw_score = exact_count;
2583 user_score = hlds_e7_find_user_data_match (dumpbuf, scan_len, readbuf, sizeof (readbuf), &user_offset, &user_sector, &read_offset);
2584 sector_score = raw_score + user_score;
2585 if (command_echo_offset != (size_t) -1 && !sector_shaped && user_score <= 0)
2588 memcpy (first_dump, dumpbuf, scan_len);
2590 window_diff = hlds_e7_count_byte_diffs (first_dump, dumpbuf, scan_len);
2591 if (window_diff > 4096)
2593 else if (window_diff > 512)
2595 else if (window_diff < 16)
2603 raw_offset = (size_t) -1;
2605 for (k = 0; k < SECTORS_PER_BLOCK; k++)
2606 exact_offsets[k] = (size_t) -1;
2607 raw_sector = 0xFFFFFFFFU;
2608 sector_shaped = false;
2609 command_echo_offset = (size_t) -1;
2610 user_offset = (size_t) -1;
2611 user_sector = 0xFFFFFFFFU;
2612 read_offset = (size_t) -1;
2616 total_score += sector_score;
2617 fprintf (f, " {\"sector\": %u, \"read_ret\": %d, \"window_memdump_ret\": %d, \"score\": %d, ",
2618 probe_sectors[j], read_ret, dump_ret, sector_score);
2619 fprintf (f, "\"raw_header_score\": %d, \"raw_header_offset\": ", raw_score);
2620 if (raw_offset == (size_t) -1)
2621 fprintf (f, "null, \"raw_header_sector\": null, ");
2623 fprintf (f, "%lu, \"raw_header_sector\": %u, ", (unsigned long) raw_offset, raw_sector);
2624 fprintf (f, "\"raw_header_found_count\": %d, \"raw_header_offsets\": [", exact_count);
2625 for (k = 0; k < SECTORS_PER_BLOCK; k++) {
2628 if (exact_offsets[k] == (size_t) -1)
2629 fprintf (f, "null");
2631 fprintf (f, "%lu", (unsigned long) exact_offsets[k]);
2634 fprintf (f, "\"raw_header_sector_shaped\": %s, ", sector_shaped ? "true" : "false");
2635 fprintf (f, "\"command_echo_offset\": ");
2636 if (command_echo_offset == (size_t) -1)
2637 fprintf (f, "null, ");
2639 fprintf (f, "%lu, ", (unsigned long) command_echo_offset);
2640 fprintf (f, "\"user_data_score\": %d, \"user_data_offset\": ", user_score);
2641 if (user_offset == (size_t) -1)
2642 fprintf (f, "null, \"user_data_sector_index\": null, \"read_probe_offset\": null, ");
2644 fprintf (f, "%lu, \"user_data_sector_index\": %u, \"read_probe_offset\": %lu, ", (unsigned long) user_offset, user_sector, (unsigned long) read_offset);
2645 fprintf (f, "\"window_hash_fnv1a32\": \"0x%08x\", \"sample\": ", hash);
2646 hlds_e7_json_bytes (f, sample, sizeof (sample));
2647 fprintf (f, "}%s\n", (j + 1 < sizeof (probe_sectors) / sizeof (probe_sectors[0])) ? "," : "");
2649 if (window_diff > 4096)
2651 else if (window_diff > 512)
2653 else if (window_diff < 16)
2655 fprintf (f, " ],\n");
2656 fprintf (f, " \"sector_window_diff_bytes\": %lu,\n", (unsigned long) window_diff);
2657 fprintf (f, " \"sector_window_diff_per_1000\": %lu,\n", scan_len ? (unsigned long) ((window_diff * 1000U) / scan_len) : 0UL);
2658 fprintf (f, " \"total_score\": %d,\n", total_score);
2659 fprintf (f, " \"classification\": \"%s\"\n", total_score >= 220 ? "strict_cache_candidate" : (total_score >= 80 ? "needs_more_candidates" : (total_score > 0 ? "sram_or_table_match" : "no_match")));
2660 fprintf (f, " }%s\n", (i + 1 < sizeof (candidates) / sizeof (candidates[0])) ? "," : "");
2661 fprintf (stderr, "score=%d diff=%lu%s\n", total_score, (unsigned long) window_diff, total_score >= 220 ? " STRICT" : (total_score >= 80 ? " REVIEW" : ""));
2662 if (total_score > best_score) {
2663 best_score = total_score;
2664 best_base = candidates[i].base;
2665 best_windows = candidates[i].windows;
2669 fprintf (f, " ],\n");
2670 fprintf (f, " \"best\": {\"base\": \"0x%08x\", \"windows\": %u, \"score\": %d, \"confidence\": \"%s\"},\n",
2671 best_base, best_windows, best_score, best_score >= 220 ? "strict" : (best_score >= 80 ? "review" : (best_score > 0 ? "weak" : "none")));
2672 fprintf (f, " \"sector_cache_candidate_found\": %s,\n", best_score >= 220 ? "true" : "false");
2673 fprintf (f, " \"promotion_recommendation\": \"%s\",\n", best_score >= 220 ? "candidate may be promoted into an experimental dump profile" : "do not promote; scan found command/SRAM/table echoes but no strict 2064-byte sector cache");
2674 fprintf (f, " \"next_recommended_action\": \"%s\",\n", best_score >= 220 ? "try the strict scan-guided normal probe" : "do not run normal seed retrieval yet; use firmware analysis or a wider address/subcommand sweep to find the real cache path");
2675 fprintf (f, " \"e7_memdump_command\": \"%s\"\n", any_readable ? "accepted_by_at_least_one_candidate" : "no_successful_window_memdump");
2679 dvd_set_hlds_e7_runtime_profile (d -> dvd, old_type, old_base, old_windows);
2680 fprintf (stderr, "HLDS 0xE7 scan mode v5 complete: best base=0x%08x windows=%u score=%d (%s; %s)\n",
2681 best_base, best_windows, best_score,
2682 best_score >= 220 ? "strict" : (best_score >= 80 ? "review" : (best_score > 0 ? "weak" : "no match")),
2683 best_score >= 220 ? "promotion allowed" : "do not promote");
2686 return best_score >= 80;
2690 static int hlds_e7_raw_hit_data_in (disc *d, u_int8_t subcmd, u_int32_t offset, u_int32_t length, u_int8_t *buf) {
2692 if (!d || !d -> dvd || !buf || length == 0 || length > 65535U)
2694 dvd_init_command (&mmc, buf, (int) length, NULL);
2696 mmc.cmd[1] = 0x48; /* H */
2697 mmc.cmd[2] = 0x49; /* I */
2698 mmc.cmd[3] = 0x54; /* T */
2699 mmc.cmd[4] = subcmd;
2700 mmc.cmd[6] = (u_int8_t) ((offset >> 24) & 0xFF);
2701 mmc.cmd[7] = (u_int8_t) ((offset >> 16) & 0xFF);
2702 mmc.cmd[8] = (u_int8_t) ((offset >> 8) & 0xFF);
2703 mmc.cmd[9] = (u_int8_t) (offset & 0xFF);
2704 mmc.cmd[10] = (u_int8_t) ((length >> 8) & 0xFF);
2705 mmc.cmd[11] = (u_int8_t) (length & 0xFF);
2706 return dvd_execute_cmd (d -> dvd, &mmc, true);
2712 } hlds_e7_subcmd_probe;
2717 } hlds_e7_raw_addr_probe;
2719 bool disc_hlds_e7_subcmd_sweep (disc *d, const char *json_path, const char *dump_prefix) {
2720 static const hlds_e7_subcmd_probe subcmds[] = {
2721 {0x00, "subcmd_00"}, {0x01, "subcmd_01_known_memdump"},
2722 {0x02, "subcmd_02"}, {0x03, "subcmd_03"},
2723 {0x04, "subcmd_04"}, {0x05, "subcmd_05"},
2724 {0x06, "subcmd_06"}, {0x07, "subcmd_07"},
2725 {0x08, "subcmd_08"}, {0x09, "subcmd_09"},
2726 {0x0A, "subcmd_0a"}, {0x0B, "subcmd_0b"},
2727 {0x0C, "subcmd_0c"}, {0x0D, "subcmd_0d"},
2728 {0x0E, "subcmd_0e"}, {0x0F, "subcmd_0f"}
2730 static const hlds_e7_raw_addr_probe addrs[] = {
2731 {0x80000000U, "type4_base"},
2732 {0x80008000U, "type4_plus_8000"},
2733 {0x80010000U, "type4_plus_10000"},
2734 {0x00000000U, "low_sram_0"},
2735 {0x00001800U, "firmware_sram_1800"},
2736 {0x000018A8U, "firmware_sram_18a8"},
2737 {0x00380000U, "table_00380000"},
2738 {0x40000000U, "firmware_alias_40000000"}
2740 static const u_int32_t probe_sectors[] = {0, 320};
2744 char dump_path[512];
2746 u_int8_t readbuf[BLOCK_SIZE];
2755 int total_promotable;
2759 size_t command_echo_offset;
2760 size_t offsets[SECTORS_PER_BLOCK];
2761 u_int32_t raw_sector;
2762 u_int32_t user_sector;
2765 u_int8_t sample[16];
2769 path = (json_path && json_path[0]) ? json_path : "hlds_e7_subcmd_sweep.json";
2770 len = RAW_BLOCK_SIZE; /* one 16-sector raw-cache-sized window; enough to find strict stride without huge runtimes */
2771 buf = (u_int8_t *) malloc (len);
2773 warning ("HLDS 0xE7 subcmd sweep: out of memory");
2776 f = fopen (path, "wb");
2779 warning ("HLDS 0xE7 subcmd sweep: could not open %s for writing", path);
2783 fprintf (stderr, "\nHLDS 0xE7 subcommand sweep v2: probing HIT subcommands 0x00..0x0f without seed cracking\n");
2784 fprintf (stderr, "HLDS 0xE7 subcommand sweep v2: data-in only, %u-byte reads, no dump attempt\n", len);
2785 fprintf (stderr, "HLDS 0xE7 subcommand sweep v2: writing JSON report to %s\n", path);
2787 best_score = -999999;
2788 total_promotable = 0;
2791 fprintf (f, " \"sweep_version\": \"v1_hlds_hit_subcmd_address_probe\",\n");
2792 fprintf (f, " \"drive\": \"");
2793 hlds_e7_json_escape (f, disc_get_drive_model_string (d));
2794 fprintf (f, "\",\n");
2795 fprintf (f, " \"notes\": \"This diagnostic sends HIT 0xE7 data-in commands with subcommands 0x00..0x0f over a small address set. It does not crack seeds or dump the disc. A promotable result requires sector-shaped 2064-byte raw headers or a direct READ-payload echo; command echoes alone are not promoted.\",\n");
2796 fprintf (f, " \"read_length\": %u,\n", len);
2797 fprintf (f, " \"probe_sectors\": [%u, %u],\n", probe_sectors[0], probe_sectors[1]);
2798 fprintf (f, " \"results\": [\n");
2800 for (i = 0; i < sizeof (subcmds) / sizeof (subcmds[0]); i++) {
2801 for (a = 0; a < sizeof (addrs) / sizeof (addrs[0]); a++) {
2802 int total_score = 0;
2804 fprintf (stderr, " subcmd=0x%02x %-24s addr=0x%08x... ",
2805 (unsigned int) subcmds[i].subcmd, subcmds[i].label, addrs[a].address);
2806 fprintf (f, " {\n");
2807 fprintf (f, " \"subcmd\": \"0x%02x\",\n", (unsigned int) subcmds[i].subcmd);
2808 fprintf (f, " \"subcmd_label\": \"");
2809 hlds_e7_json_escape (f, subcmds[i].label);
2810 fprintf (f, "\",\n");
2811 fprintf (f, " \"address\": \"0x%08x\",\n", addrs[a].address);
2812 fprintf (f, " \"address_label\": \"");
2813 hlds_e7_json_escape (f, addrs[a].label);
2814 fprintf (f, "\",\n");
2815 fprintf (f, " \"sector_tests\": [\n");
2816 for (j = 0; j < sizeof (probe_sectors) / sizeof (probe_sectors[0]); j++) {
2819 memset (buf, 0, len);
2820 memset (readbuf, 0, sizeof (readbuf));
2821 memset (sample, 0, sizeof (sample));
2822 read_ret = dvd_read_sector_streaming (d -> dvd, probe_sectors[j], NULL, readbuf, sizeof (readbuf));
2823 ret = hlds_e7_raw_hit_data_in (d, subcmds[i].subcmd, addrs[a].address, len, buf);
2824 raw_offset = (size_t) -1;
2825 user_offset = (size_t) -1;
2826 read_offset = (size_t) -1;
2827 command_echo_offset = (size_t) -1;
2828 raw_sector = 0xFFFFFFFFU;
2829 user_sector = 0xFFFFFFFFU;
2831 for (kk = 0; kk < SECTORS_PER_BLOCK; kk++)
2832 offsets[kk] = (size_t) -1;
2833 sector_shaped = false;
2838 memcpy (sample, buf, sizeof (sample));
2839 hash = hlds_e7_fnv1a32 (buf, len);
2840 (void) hlds_e7_find_raw_header_match (buf, len, probe_sectors[j], &raw_offset, &raw_sector);
2841 exact_count = hlds_e7_count_exact_raw_headers_for_block (buf, len, probe_sectors[j], offsets);
2842 sector_shaped = hlds_e7_raw_header_offsets_are_sector_shaped (offsets);
2843 command_echo_offset = hlds_e7_find_command_echo_offset (buf, len);
2844 user_score = hlds_e7_find_user_data_match (buf, len, readbuf, sizeof (readbuf), &user_offset, &user_sector, &read_offset);
2845 raw_score = sector_shaped ? 220 : exact_count;
2851 score += raw_score + user_score;
2852 if (command_echo_offset != (size_t) -1 && !sector_shaped && user_score <= 0)
2854 if (sector_shaped || user_score > 0)
2856 total_score += score;
2857 fprintf (f, " {\"sector\": %u, \"read_ret\": %d, \"e7_ret\": %d, \"score\": %d, ",
2858 probe_sectors[j], read_ret, ret, score);
2859 fprintf (f, "\"raw_header_found_count\": %d, \"raw_header_sector_shaped\": %s, ",
2860 exact_count, sector_shaped ? "true" : "false");
2861 fprintf (f, "\"raw_header_offset\": ");
2862 if (raw_offset == (size_t) -1)
2863 fprintf (f, "null, \"raw_header_sector\": null, ");
2865 fprintf (f, "%lu, \"raw_header_sector\": %u, ", (unsigned long) raw_offset, raw_sector);
2866 fprintf (f, "\"command_echo_offset\": ");
2867 if (command_echo_offset == (size_t) -1)
2868 fprintf (f, "null, ");
2870 fprintf (f, "%lu, ", (unsigned long) command_echo_offset);
2871 fprintf (f, "\"user_data_score\": %d, \"user_data_offset\": ", user_score);
2872 if (user_offset == (size_t) -1)
2873 fprintf (f, "null, \"user_data_sector_index\": null, \"read_probe_offset\": null, ");
2875 fprintf (f, "%lu, \"user_data_sector_index\": %u, \"read_probe_offset\": %lu, ",
2876 (unsigned long) user_offset, user_sector, (unsigned long) read_offset);
2877 fprintf (f, "\"window_hash_fnv1a32\": \"0x%08x\", \"sample\": ", hash);
2878 hlds_e7_json_bytes (f, sample, sizeof (sample));
2879 fprintf (f, "}%s\n", (j + 1 < sizeof (probe_sectors) / sizeof (probe_sectors[0])) ? "," : "");
2882 * If the caller requested raw sweep dumps, write every successful
2883 * HIT 0xE7 data-in response, not only promotable sector-cache hits.
2885 * v7 only dumped promotable windows. That meant a useful negative
2886 * sweep produced no gdr8081n_subcmd_*.bin files at all, even though
2887 * non-promotable command/SRAM echoes were exactly what we needed to
2890 if (dump_prefix && dump_prefix[0] && ret >= 0) {
2891 snprintf (dump_path, sizeof (dump_path), "%s_sub%02x_%s_sector_%u.bin",
2892 dump_prefix, (unsigned int) subcmds[i].subcmd, addrs[a].label, probe_sectors[j]);
2893 df = fopen (dump_path, "wb");
2895 fwrite (buf, 1, len, df);
2900 fprintf (f, " ],\n");
2901 fprintf (f, " \"total_score\": %d,\n", total_score);
2902 fprintf (f, " \"promotable_sector_tests\": %d,\n", promotable);
2903 fprintf (f, " \"classification\": \"%s\"\n", promotable > 0 ? "promotable_candidate" : (total_score > 0 ? "responds_nonpromotable" : "no_useful_response"));
2904 fprintf (f, " }%s\n",
2905 (i + 1 == sizeof (subcmds) / sizeof (subcmds[0]) && a + 1 == sizeof (addrs) / sizeof (addrs[0])) ? "" : ",");
2906 fprintf (stderr, "score=%d%s\n", total_score, promotable > 0 ? " PROMOTABLE" : "");
2907 if (total_score > best_score)
2908 best_score = total_score;
2909 total_promotable += promotable;
2913 fprintf (f, " ],\n");
2914 fprintf (f, " \"promotable_candidate_found\": %s,\n", total_promotable > 0 ? "true" : "false");
2915 fprintf (f, " \"promotion_recommendation\": \"%s\",\n", total_promotable > 0 ? "review promotable candidates and try a targeted profile" : "do not promote; no subcommand/address pair exposed sector-shaped cache or READ-payload echo");
2916 fprintf (f, " \"next_recommended_action\": \"%s\"\n", total_promotable > 0 ? "send the JSON and any dumped promotable windows" : "continue firmware handler analysis; avoid normal seed retrieval on GDR-8081N until a promotable candidate appears");
2921 fprintf (stderr, "HLDS 0xE7 subcommand sweep v2 complete: promotable candidates=%d (%s)\n",
2922 total_promotable, total_promotable > 0 ? "review JSON" : "none found");
2932 } hlds_e7_range_probe;
2934 bool disc_hlds_e7_memrange_sweep (disc *d, const char *json_path, const char *dump_prefix) {
2935 static const hlds_e7_range_probe ranges[] = {
2936 {0x7FFE0000U, 0x80080000U, 0x00000800U, "type4_dense_neighborhood"},
2937 {0x00000000U, 0x00040000U, 0x00000800U, "low_sram_dense"},
2938 {0x00370000U, 0x00390000U, 0x00000800U, "table_0038_dense"},
2939 {0x00A00000U, 0x00A40000U, 0x00000800U, "type1_dense_neighborhood"},
2940 {0x40000000U, 0x40010000U, 0x00000800U, "firmware_alias_dense"}
2942 static const u_int32_t probe_sectors[] = {0, 320};
2946 char dump_path[512];
2948 u_int8_t readbuf[BLOCK_SIZE];
2952 unsigned long tested;
2953 unsigned long nonzero_windows;
2954 unsigned long command_echo_windows;
2955 unsigned long raw_table_windows;
2956 unsigned long promotable_windows;
2958 u_int32_t best_addr;
2959 const char *best_range;
2963 path = (json_path && json_path[0]) ? json_path : "hlds_e7_memrange_sweep.json";
2964 len = RAW_BLOCK_SIZE;
2965 buf = (u_int8_t *) malloc (len);
2967 warning ("HLDS 0xE7 memrange sweep: out of memory");
2970 f = fopen (path, "wb");
2973 warning ("HLDS 0xE7 memrange sweep: could not open %s for writing", path);
2977 fprintf (stderr, "\nHLDS 0xE7 memory-range sweep v1: using known memdump subcmd 0x01 only\n");
2978 fprintf (stderr, "HLDS 0xE7 memory-range sweep v1: dense address stride, no seed cracking, no dump attempt\n");
2979 fprintf (stderr, "HLDS 0xE7 memory-range sweep v1: writing JSON report to %s\n", path);
2982 nonzero_windows = 0;
2983 command_echo_windows = 0;
2984 raw_table_windows = 0;
2985 promotable_windows = 0;
2986 best_score = -999999;
2988 best_range = "none";
2991 fprintf (f, " \"sweep_version\": \"v1_known_memdump_dense_address_range\",\n");
2992 fprintf (f, " \"drive\": \"");
2993 hlds_e7_json_escape (f, disc_get_drive_model_string (d));
2994 fprintf (f, "\",\n");
2995 fprintf (f, " \"notes\": \"This diagnostic uses only HIT 0xE7 subcmd 0x01, because the subcommand sweep showed only that subcommand returns nonzero data. It densely sweeps address ranges and promotes only sector-shaped 2064-byte raw headers or direct READ-payload echoes. Command echoes and sector-number table matches are recorded but not promoted.\",\n");
2996 fprintf (f, " \"read_length\": %u,\n", len);
2997 fprintf (f, " \"probe_sectors\": [%u, %u],\n", probe_sectors[0], probe_sectors[1]);
2998 fprintf (f, " \"ranges\": [\n");
2999 for (r = 0; r < sizeof (ranges) / sizeof (ranges[0]); r++) {
3000 fprintf (f, " {\"label\": \"");
3001 hlds_e7_json_escape (f, ranges[r].label);
3002 fprintf (f, "\", \"start\": \"0x%08x\", \"end\": \"0x%08x\", \"step\": \"0x%08x\"}%s\n",
3003 ranges[r].start, ranges[r].end, ranges[r].step,
3004 (r + 1 < sizeof (ranges) / sizeof (ranges[0])) ? "," : "");
3006 fprintf (f, " ],\n");
3007 fprintf (f, " \"results\": [\n");
3009 for (r = 0; r < sizeof (ranges) / sizeof (ranges[0]); r++) {
3010 fprintf (stderr, " range %-28s 0x%08x..0x%08x step=0x%04x\n",
3011 ranges[r].label, ranges[r].start, ranges[r].end, ranges[r].step);
3012 for (addr = ranges[r].start; addr < ranges[r].end; addr += ranges[r].step) {
3014 int addr_promotable = 0;
3015 int addr_nonzero = 0;
3016 int addr_command_echo = 0;
3017 int addr_raw_table = 0;
3018 bool first_result = (tested == 0);
3023 fprintf (f, " {\n");
3024 fprintf (f, " \"range\": \"");
3025 hlds_e7_json_escape (f, ranges[r].label);
3026 fprintf (f, "\",\n");
3027 fprintf (f, " \"address\": \"0x%08x\",\n", addr);
3028 fprintf (f, " \"sector_tests\": [\n");
3030 for (j = 0; j < sizeof (probe_sectors) / sizeof (probe_sectors[0]); j++) {
3034 int exact_count = 0;
3038 size_t raw_offset = (size_t) -1;
3039 size_t user_offset = (size_t) -1;
3040 size_t read_offset = (size_t) -1;
3041 size_t command_echo_offset = (size_t) -1;
3042 size_t offsets[SECTORS_PER_BLOCK];
3043 u_int32_t raw_sector = 0xFFFFFFFFU;
3044 u_int32_t user_sector = 0xFFFFFFFFU;
3046 bool sector_shaped = false;
3047 bool is_zero = true;
3048 u_int8_t sample[16];
3050 memset (buf, 0, len);
3051 memset (readbuf, 0, sizeof (readbuf));
3052 memset (sample, 0, sizeof (sample));
3053 for (kk = 0; kk < SECTORS_PER_BLOCK; kk++)
3054 offsets[kk] = (size_t) -1;
3055 read_ret = dvd_read_sector_streaming (d -> dvd, probe_sectors[j], NULL, readbuf, sizeof (readbuf));
3056 ret = hlds_e7_raw_hit_data_in (d, 0x01, addr, len, buf);
3059 memcpy (sample, buf, sizeof (sample));
3060 hash = hlds_e7_fnv1a32 (buf, len);
3061 for (zi = 0; zi < len; zi++) {
3067 (void) hlds_e7_find_raw_header_match (buf, len, probe_sectors[j], &raw_offset, &raw_sector);
3068 exact_count = hlds_e7_count_exact_raw_headers_for_block (buf, len, probe_sectors[j], offsets);
3069 sector_shaped = hlds_e7_raw_header_offsets_are_sector_shaped (offsets);
3070 command_echo_offset = hlds_e7_find_command_echo_offset (buf, len);
3071 user_score = hlds_e7_find_user_data_match (buf, len, readbuf, sizeof (readbuf), &user_offset, &user_sector, &read_offset);
3072 raw_score = sector_shaped ? 220 : exact_count;
3073 score += raw_score + user_score;
3074 if (command_echo_offset != (size_t) -1 && !sector_shaped && user_score <= 0)
3078 if (command_echo_offset != (size_t) -1)
3079 addr_command_echo++;
3080 if (exact_count > 0 && !sector_shaped)
3082 if (sector_shaped || user_score > 0)
3084 if (dump_prefix && dump_prefix[0] && !is_zero) {
3085 snprintf (dump_path, sizeof (dump_path), "%s_%s_0x%08x_sector_%u.bin",
3086 dump_prefix, ranges[r].label, addr, probe_sectors[j]);
3087 df = fopen (dump_path, "wb");
3089 fwrite (buf, 1, len, df);
3098 addr_score += score;
3100 fprintf (f, " {\"sector\": %u, \"read_ret\": %d, \"e7_ret\": %d, \"score\": %d, ",
3101 probe_sectors[j], read_ret, ret, score);
3102 fprintf (f, "\"nonzero\": %s, \"raw_header_found_count\": %d, \"raw_header_sector_shaped\": %s, ",
3103 is_zero ? "false" : "true", exact_count, sector_shaped ? "true" : "false");
3104 fprintf (f, "\"raw_header_offset\": ");
3105 if (raw_offset == (size_t) -1)
3106 fprintf (f, "null, \"raw_header_sector\": null, ");
3108 fprintf (f, "%lu, \"raw_header_sector\": %u, ", (unsigned long) raw_offset, raw_sector);
3109 fprintf (f, "\"command_echo_offset\": ");
3110 if (command_echo_offset == (size_t) -1)
3111 fprintf (f, "null, ");
3113 fprintf (f, "%lu, ", (unsigned long) command_echo_offset);
3114 fprintf (f, "\"user_data_score\": %d, \"user_data_offset\": ", user_score);
3115 if (user_offset == (size_t) -1)
3116 fprintf (f, "null, \"user_data_sector_index\": null, \"read_probe_offset\": null, ");
3118 fprintf (f, "%lu, \"user_data_sector_index\": %u, \"read_probe_offset\": %lu, ",
3119 (unsigned long) user_offset, user_sector, (unsigned long) read_offset);
3120 fprintf (f, "\"window_hash_fnv1a32\": \"0x%08x\", \"sample\": ", hash);
3121 hlds_e7_json_bytes (f, sample, sizeof (sample));
3122 fprintf (f, "}%s\n", (j + 1 < sizeof (probe_sectors) / sizeof (probe_sectors[0])) ? "," : "");
3126 nonzero_windows += addr_nonzero;
3127 if (addr_command_echo)
3128 command_echo_windows += addr_command_echo;
3130 raw_table_windows += addr_raw_table;
3131 if (addr_promotable)
3132 promotable_windows += addr_promotable;
3133 if (addr_score > best_score) {
3134 best_score = addr_score;
3136 best_range = ranges[r].label;
3139 fprintf (f, " ],\n");
3140 fprintf (f, " \"total_score\": %d,\n", addr_score);
3141 fprintf (f, " \"nonzero_sector_tests\": %d,\n", addr_nonzero);
3142 fprintf (f, " \"command_echo_sector_tests\": %d,\n", addr_command_echo);
3143 fprintf (f, " \"raw_table_like_sector_tests\": %d,\n", addr_raw_table);
3144 fprintf (f, " \"promotable_sector_tests\": %d,\n", addr_promotable);
3145 fprintf (f, " \"classification\": \"%s\"\n",
3146 addr_promotable > 0 ? "promotable_candidate" : (addr_raw_table || addr_command_echo ? "sram_or_table_match" : (addr_nonzero ? "nonzero_no_cache" : "zero_or_no_response")));
3151 fprintf (f, "\n ],\n");
3152 fprintf (f, " \"addresses_tested\": %lu,\n", tested);
3153 fprintf (f, " \"nonzero_windows\": %lu,\n", nonzero_windows);
3154 fprintf (f, " \"command_echo_windows\": %lu,\n", command_echo_windows);
3155 fprintf (f, " \"raw_table_like_windows\": %lu,\n", raw_table_windows);
3156 fprintf (f, " \"promotable_windows\": %lu,\n", promotable_windows);
3157 fprintf (f, " \"best\": {\"range\": \"");
3158 hlds_e7_json_escape (f, best_range);
3159 fprintf (f, "\", \"address\": \"0x%08x\", \"score\": %d},\n", best_addr, best_score);
3160 fprintf (f, " \"promotable_candidate_found\": %s,\n", promotable_windows ? "true" : "false");
3161 fprintf (f, " \"promotion_recommendation\": \"%s\",\n",
3162 promotable_windows ? "review promotable address and try a targeted profile" : "do not promote; dense subcmd 0x01 address sweep found no sector-shaped cache or READ-payload echo");
3163 fprintf (f, " \"next_recommended_action\": \"%s\"\n",
3164 promotable_windows ? "send JSON and matching dumped windows" : "focus on firmware handler/control-flow analysis or different pre-read/cache-fill sequences before another seed attempt");
3169 fprintf (stderr, "HLDS 0xE7 memory-range sweep v1 complete: addresses=%lu promotable_windows=%lu nonzero_windows=%lu command_echo_windows=%lu\n",
3170 tested, promotable_windows, nonzero_windows, command_echo_windows);
3175 static bool disc_probe_gdr8050l_e7_speed_profile (disc *d) {
3176 static const hlds_e7_probe_candidate candidates[] = {
3177 {443, 0x80000000U, 3, "Probe A 3-window no-prefetch: base 0x80000000, 3 windows"},
3178 {442, 0x80000000U, 2, "Probe B 2-window no-prefetch: base 0x80000000, 2 windows"},
3179 {445, 0x80000000U, 5, "Probe C 5-window guarded no-prefetch: base 0x80000000, 5 windows"},
3180 {44, 0x80000000U, 1, "Probe D proven fallback: base 0x80000000, 1 window"}
3182 static const u_int32_t probe_sectors[] = {0, 320};
3186 if (!d || (dvd_get_hlds_e7_type (d -> dvd) != 44 && dvd_get_hlds_e7_type (d -> dvd) != 45))
3189 hlds_e7_visible_probe_log ("GDR-8050L modified 0xE7 speed probe: single-window is proven; trying guarded no-prefetch multi-window profiles before seed cracking");
3190 for (i = 0; i < sizeof (candidates) / sizeof (candidates[0]); i++) {
3191 hlds_e7_visible_probe_log ("GDR-8050L modified 0xE7 speed probe: %s", candidates[i].label);
3192 dvd_set_hlds_e7_runtime_profile (d -> dvd, candidates[i].type, candidates[i].base, candidates[i].windows);
3194 for (j = 0; j < sizeof (probe_sectors) / sizeof (probe_sectors[0]); j++) {
3195 disc_cache_clear (d);
3196 if (!disc_read_sector (d, probe_sectors[j], NULL, NULL) || dvd_get_hlds_e7_type (d -> dvd) != candidates[i].type) {
3201 disc_cache_clear (d);
3203 hlds_e7_visible_probe_log ("GDR-8050L modified 0xE7 speed probe: selected %s", candidates[i].label);
3206 hlds_e7_visible_probe_log ("GDR-8050L modified 0xE7 speed probe: failed %s", candidates[i].label);
3209 dvd_set_hlds_e7_runtime_profile (d -> dvd, 44, 0x80000000U, 1);
3210 disc_cache_clear (d);
3211 hlds_e7_visible_probe_log ("GDR-8050L modified 0xE7 speed probe: all accelerated profiles failed; using proven single-window fallback");
3215 static bool disc_probe_gdr8081n_e7_profile (disc *d) {
3216 static const hlds_e7_probe_candidate candidates[] = {
3217 {815, 0x80000000U, 5, "Probe A strict scan-guided Type4-derived: base 0x80000000, 5 windows"}
3221 if (!d || dvd_get_hlds_e7_type (d -> dvd) != 81)
3224 hlds_e7_visible_probe_log ("GDR-8081N 0xE7 profile probe: drive is experimental; trying strict scan-guided profile only; exact-offset fallbacks were removed to avoid 10-minute false-negative loops");
3225 for (i = 0; i < sizeof (candidates) / sizeof (candidates[0]); i++) {
3226 hlds_e7_visible_probe_log ("GDR-8081N 0xE7 profile probe: %s", candidates[i].label);
3227 dvd_set_hlds_e7_runtime_profile (d -> dvd, candidates[i].type, candidates[i].base, candidates[i].windows);
3228 disc_cache_clear (d);
3229 if (disc_read_sector (d, 0, NULL, NULL)) {
3230 hlds_e7_visible_probe_log ("GDR-8081N 0xE7 profile probe: selected %s", candidates[i].label);
3233 hlds_e7_visible_probe_log ("GDR-8081N 0xE7 profile probe: failed %s", candidates[i].label);
3236 dvd_set_hlds_e7_runtime_profile (d -> dvd, 81, 0x80000000U, 5);
3237 disc_cache_clear (d);
3238 hlds_e7_visible_probe_log ("GDR-8081N 0xE7 profile probe: strict scan-guided candidate failed; run --hlds-e7-scan with --scan-dump-prefix and inspect strict/user-data fields before another seed attempt");
3242 static bool disc_crack_seeds (disc *d) {
3245 /* As a Nintendo GameCube/Wii disc should not have too many keys, 20 should be enough. */
3246 debug ("Retrieving all DVD seeds");
3247 disc_seed_diag_clear (d);
3248 d -> seed_diagnostic_active = true;
3249 d -> seed_diagnostic_block = 0;
3250 xbox_ref_log_fprintf (stderr, "\n");
3251 disc_seed_diag_log (d,
3252 "campaign=begin blocks=20 method=%d profile=%s cache-base=0x%08X windows=%u",
3254 dvd_get_hlds_e7_profile_name (d -> dvd),
3255 dvd_get_hlds_e7_cache_base (d -> dvd),
3256 dvd_get_hlds_e7_mem_blocks (d -> dvd));
3258 if (!disc_probe_gdr8050l_e7_speed_profile (d)) {
3259 disc_seed_diag_fail (d, 0, 15, 0, "profile-probe",
3260 "GDR-8050L runtime profile probe failed", -1, false);
3261 d -> seed_diagnostic_active = false;
3264 if (!disc_probe_gdr8081n_e7_profile (d)) {
3265 disc_seed_diag_fail (d, 0, 15, 0, "profile-probe",
3266 "GDR-8081N runtime profile probe failed", -1, false);
3267 d -> seed_diagnostic_active = false;
3271 for (i = 0; i < 20 * 16; i += 16) {
3272 d -> seed_diagnostic_block = (unsigned int) (i / 16);
3273 disc_seed_diag_clear (d);
3274 disc_seed_diag_log (d,
3275 "block=%u/20 sectors=%d..%d stage=seed-block result=BEGIN",
3276 d -> seed_diagnostic_block + 1, i, i + 15);
3277 if (!disc_read_sector (d, (u_int32_t) i, NULL, NULL)) {
3278 if (!d -> seed_diagnostic.valid)
3279 disc_seed_diag_fail (d, (u_int32_t) i, (u_int32_t) i + 15,
3280 0, "seed-block-read", "disc_read_sector returned failure without a classified sub-stage", -1, false);
3281 disc_seed_diag_log (d,
3282 "campaign=fail block=%u/20 sectors=%d..%d",
3283 d -> seed_diagnostic_block + 1, i, i + 15);
3284 d -> seed_diagnostic_active = false;
3287 disc_seed_diag_log (d,
3288 "block=%u/20 sectors=%d..%d stage=seed-block result=PASS",
3289 d -> seed_diagnostic_block + 1, i, i + 15);
3292 disc_seed_diag_clear (d);
3293 disc_seed_diag_log (d, "campaign=pass blocks=20");
3294 d -> seed_diagnostic_active = false;
3300 * Creates a new structure representing a Nintendo GameCube/Wii optical disc.
3301 * @param dvd_device The CD/DVD-ROM device, in OS-dependent format (i.e.: /dev/something on Unix, x: on Windows).
3302 * @return The newly-created structure, to be used with the other commands.
3304 disc *disc_new (char *dvd_device, u_int32_t command) {
3308 if ((dvd = dvd_drive_new (dvd_device, command))) {
3309 d = (disc *) malloc (sizeof (disc));
3310 memset (d, 0, sizeof (disc));
3312 d -> u = unscrambler_new ();
3313 disc_set_unscrambling (d, true); // Unscramble by default
3314 disc_set_read_method (d, DEFAULT_READ_METHOD);
3315 disc_cache_init (d, DISC_DEFAULT_CACHE_SIZE);
3324 int disc_media_preflight (disc *d, unsigned int timeout_ms, int *sense_key, int *asc, int *ascq) {
3326 unsigned int elapsed = 0;
3327 const unsigned int interval_ms = 500;
3330 if (sense_key) *sense_key = 0;
3332 if (ascq) *ascq = 0;
3333 if (!d || !d -> dvd)
3337 u_int32_t sectors = 0, sector_size = 0;
3339 memset (&sense, 0, sizeof (sense));
3340 rc = dvd_test_unit_ready (d -> dvd, &sense);
3342 /* Some optical drives and USB bridges report TEST UNIT READY=GOOD
3343 * with an empty tray. Require a second, media-dependent command
3344 * before allowing vendor seed/cache reads. */
3345 memset (&sense, 0, sizeof (sense));
3346 rc = dvd_read_capacity_10 (d -> dvd, §ors, §or_size, &sense);
3347 if (rc >= 0 && sectors > 1 && sector_size == SECTOR_SIZE)
3349 /* A successful command with zero/invalid capacity is not proof of media. */
3351 if (sense_key) *sense_key = 0;
3353 if (ascq) *ascq = 0;
3358 if (sense_key) *sense_key = sense.sense_key;
3359 if (asc) *asc = sense.asc;
3360 if (ascq) *ascq = sense.ascq;
3362 /* SPC/MMC: NOT READY / MEDIUM NOT PRESENT. */
3363 if ((sense.sense_key & 0x0f) == 0x02 && sense.asc == 0x3a)
3366 /* Retry transient becoming-ready / unit-attention states. */
3367 if (!(((sense.sense_key & 0x0f) == 0x02 && sense.asc == 0x04) ||
3368 ((sense.sense_key & 0x0f) == 0x06 && (sense.asc == 0x28 || sense.asc == 0x29))))
3370 if (elapsed >= timeout_ms)
3373 Sleep (interval_ms);
3375 usleep ((useconds_t) interval_ms * 1000);
3377 elapsed += interval_ms;
3381 bool disc_init (disc *d, u_int32_t disctype, u_int32_t sectors_no) {
3384 d -> sectors_no = 1000; // TODO
3385 disc_detect_type (d, disctype, sectors_no);
3386 if (d -> type != DISC_TYPE_XBOX && !disc_crack_seeds (d))
3388 // unscrambler_set_bruteforce (d -> u, false); // Disabling bruteforcing will allow us to detect errors more quickly
3389 unscrambler_set_bruteforce (d -> u, true);
3390 if (d -> type==DISC_TYPE_DVD) {
3391 my_strdup (d -> title, "DVD");
3394 else if (d -> type==DISC_TYPE_XBOX) {
3395 my_strdup (d -> title, "Xbox DVD");
3396 d -> system_id = 'X';
3397 strncpy (d -> game_id, "XB", sizeof (d -> game_id));
3398 strncpy (d -> maker, "MS", sizeof (d -> maker));
3399 my_strdup (d -> version_string, "N/A");
3400 d -> has_update = false;
3401 disc_set_unscrambling (d, false);
3404 else if (disc_analyze (
3407 sectors_no == (u_int32_t) -1
3409 disc_check_update (d);
3420 * Frees resources used by a disc structure and destroys it.
3421 * @param d The disc structure.
3424 void *disc_destroy (disc *d) {
3425 disc_cache_destroy (d);
3426 unscrambler_destroy (d -> u);
3427 my_free (d -> version_string);
3428 my_free (d -> title);
3429 dvd_drive_destroy (d -> dvd);
3436 bool disc_is_xbox_unlock_drive (disc *d) {
3437 return d && dvd_is_xbox_unlock_drive (d -> dvd);
3440 bool disc_is_xbox_challenge_drive (disc *d) {
3441 return d && dvd_is_xbox_challenge_drive (d -> dvd);
3444 bool disc_is_xbox_vendor_unlock_drive (disc *d) {
3445 return d && dvd_is_xbox_vendor_unlock_drive (d -> dvd);
3448 int disc_xbox_lock (disc *d) {
3449 u_int32_t sectors = 0;
3450 u_int32_t sector_size = 0;
3452 if (!d || d -> type != DISC_TYPE_XBOX)
3455 if (dvd_is_xbox_vendor_unlock_drive (d -> dvd)) {
3456 if (dvd_xbox_vendor_lock (d -> dvd) < 0)
3460 if (dvd_read_capacity_10 (d -> dvd, §ors, §or_size, NULL) == 0 && sector_size == SECTOR_SIZE)
3461 d -> sectors_no = sectors;
3466 int disc_xbox_unlock (disc *d) {
3467 u_int32_t sectors = 0;
3468 u_int32_t sector_size = 0;
3470 if (!d || d -> type != DISC_TYPE_XBOX)
3473 if (dvd_is_xbox_challenge_drive (d -> dvd)) {
3474 if (dvd_xbox_gdr8050l_unlock (d -> dvd, §ors) < 0)
3476 d -> sectors_no = sectors;
3480 if (dvd_is_xbox_vendor_unlock_drive (d -> dvd)) {
3481 if (dvd_xbox_vendor_unlock_wxripper (d -> dvd, §ors) < 0)
3483 d -> sectors_no = sectors;
3487 /* Forced Xbox mode on an unknown drive keeps FriiDump's direct READ(10)
3488 * experiment path, but no model-specific unlock is applied. */
3489 if (dvd_read_capacity_10 (d -> dvd, §ors, §or_size, NULL) == 0 && sector_size == SECTOR_SIZE)
3490 d -> sectors_no = sectors;
3496 int disc_xbox_read_10 (disc *d, u_int32_t sector, u_int32_t sectors, u_int8_t *buf, size_t bufsize) {
3497 if (!d || d -> type != DISC_TYPE_XBOX || !buf)
3499 return dvd_read_10 (d -> dvd, sector, sectors, NULL, buf, bufsize);
3503 int disc_xbox_read_dvd_structure (disc *d, u_int8_t format, u_int8_t layer, u_int8_t *buf, size_t bufsize) {
3504 if (!d || d -> type != DISC_TYPE_XBOX || !buf)
3506 return dvd_read_dvd_structure (d -> dvd, format, layer, buf, bufsize, NULL);
3510 int disc_xbox_read_capacity_10 (disc *d, u_int32_t *sectors, u_int32_t *sector_size) {
3511 if (!d || d -> type != DISC_TYPE_XBOX)
3513 return dvd_read_capacity_10 (d -> dvd, sectors, sector_size, NULL);
3518 int disc_xbox_prepare_game_view (disc *d, u_int32_t *sectors, u_int32_t *sector_size) {
3520 if (!d || d -> type != DISC_TYPE_XBOX)
3522 out = dvd_xbox_prepare_game_view (d -> dvd, sectors, sector_size);
3523 if (out == 0 && sectors)
3524 d -> sectors_no = *sectors;
3528 int disc_refresh_volume (disc *d) {
3531 return dvd_refresh_volume (d -> dvd);
3534 int disc_lock_volume (disc *d) {
3537 return dvd_lock_volume (d -> dvd);
3540 int disc_xbox_refresh_volume (disc *d) {
3541 if (!d || d -> type != DISC_TYPE_XBOX)
3543 return dvd_xbox_refresh_volume (d -> dvd);
3546 int disc_xbox_lock_volume (disc *d) {
3547 if (!d || d -> type != DISC_TYPE_XBOX)
3549 return dvd_xbox_lock_volume (d -> dvd);
3552 int disc_xbox_media_cycle (disc *d) {
3553 if (!d || d -> type != DISC_TYPE_XBOX)
3555 return dvd_media_cycle (d -> dvd, NULL);
3558 int disc_xbox_wait_ready (disc *d, unsigned int timeout_ms) {
3559 if (!d || d -> type != DISC_TYPE_XBOX)
3561 return dvd_wait_ready (d -> dvd, timeout_ms);
3564 char *disc_get_drive_vendor (disc *d) {
3565 return d ? dvd_get_vendor (d -> dvd) : NULL;
3568 char *disc_get_drive_product_id (disc *d) {
3569 return d ? dvd_get_product_id (d -> dvd) : NULL;
3572 char *disc_get_drive_firmware_revision (disc *d) {
3573 return d ? dvd_get_product_revision (d -> dvd) : NULL;
3576 char *disc_get_drive_model_string (disc *d) {
3577 return d ? dvd_get_model_string (d -> dvd) : NULL;
3581 char *disc_get_device (disc *d) {
3582 return (dvd_get_device (d -> dvd));
3585 void *disc_get_native_handle (disc *d) {
3586 if (!d) return NULL;
3587 return dvd_get_native_handle (d -> dvd);
3591 bool disc_get_drive_support_status (disc *d) {
3592 return (dvd_get_support_status (d -> dvd));
3595 const char *disc_get_hlds_e7_profile_name (disc *d) {
3596 return d ? dvd_get_hlds_e7_profile_name (d -> dvd) : "none";
3599 const char *disc_get_hlds_e7_support_tier (disc *d) {
3600 return d ? dvd_get_hlds_e7_support_tier (d -> dvd) : "none";
3603 const char *disc_get_hlds_e7_family (disc *d) {
3604 return d ? dvd_get_hlds_e7_family (d -> dvd) : "none";
3607 const char *disc_get_hlds_e7_tokens (disc *d) {
3608 return d ? dvd_get_hlds_e7_tokens (d -> dvd) : "";
3611 const char *disc_get_hlds_e7_record_id (disc *d) {
3612 return d ? dvd_get_hlds_e7_record_id (d -> dvd) : "";
3615 const char *disc_get_hlds_e7_notes (disc *d) {
3616 return d ? dvd_get_hlds_e7_notes (d -> dvd) : "";
3619 u_int32_t disc_get_hlds_e7_type (disc *d) {
3620 return d ? dvd_get_hlds_e7_type (d -> dvd) : 0;
3623 u_int32_t disc_get_hlds_e7_cache_base (disc *d) {
3624 return d ? dvd_get_hlds_e7_cache_base (d -> dvd) : 0;
3627 u_int32_t disc_get_hlds_e7_mem_blocks (disc *d) {
3628 return d ? dvd_get_hlds_e7_mem_blocks (d -> dvd) : 0;
3631 u_int32_t disc_get_hlds_e7_static_cdb_base (disc *d) {
3632 return d ? dvd_get_hlds_e7_static_cdb_base (d -> dvd) : 0;
3635 u_int32_t disc_get_hlds_e7_static_gate (disc *d) {
3636 return d ? dvd_get_hlds_e7_static_gate (d -> dvd) : 0;
3639 int disc_get_hlds_e7_preferred_method (disc *d) {
3640 return d ? dvd_get_hlds_e7_preferred_method (d -> dvd) : -1;
3643 void disc_set_speed (disc *d, u_int32_t speed) {
3644 if (speed != -1) dvd_set_speed (d -> dvd, speed, NULL);
3647 void disc_set_streaming_speed (disc *d, u_int32_t speed) {
3648 if (speed != -1) dvd_set_streaming (d -> dvd, speed, NULL);
3651 bool disc_stop_unit (disc *d, bool start) {
3652 if (dvd_stop_unit (d -> dvd, start, NULL) == 0) return true;
3656 void init_range (disc *d, u_int32_t sec_disc, u_int32_t sec_mem) {
3657 if ((sec_disc>=1)&&(sec_disc<=100)) d->sec_disc = sec_disc;
3658 else d->sec_disc = -1;
3659 if ((sec_mem>=16)&&(sec_mem<=100)) d->sec_mem = sec_mem;
3660 else d->sec_mem = -1;