root/tools/firmware_load.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. addBufRange
  2. findRanges
  3. idx_valid
  4. idx2adr
  5. adr2idx
  6. adr2ptr
  7. idxcorr
  8. set_ignore_errors
  9. fwadr
  10. fwval
  11. fwRd
  12. fwRn
  13. fwRnMOV
  14. fwOp2
  15. LDR2adr
  16. LDR2idx
  17. LDR2val
  18. ADR2adr
  19. ALUop2
  20. ALUop2a
  21. idxFollowBranch
  22. followBranch
  23. followBranch2
  24. isLDR_PC
  25. isLDR_PC_cond
  26. isLDR_SP
  27. isLDR
  28. isLDR_cond
  29. isADR_PC
  30. isADR_PC_cond
  31. isADR
  32. isLDMFD
  33. isLDMFD_PC
  34. isSTMFD
  35. isSTMFD_LR
  36. isSTR
  37. isSTR_cond
  38. isBX
  39. isBX_cond
  40. isBX_LR
  41. isBLX
  42. isBL
  43. isBL_cond
  44. isBLEQ
  45. isB
  46. isBorBL
  47. isCMP
  48. isMOV
  49. isMOV_immed
  50. isORR
  51. isADD
  52. isSUB
  53. isASCIIstring
  54. find_Nth_str
  55. find_str
  56. find_str_bytes
  57. find_inst
  58. find_inst_rev
  59. find_Nth_inst
  60. find_Nth_inst_rev
  61. find_strptr_ref
  62. find_str_ref
  63. find_nxt_str_ref
  64. find_nxt_str_ref_alt
  65. find_BL
  66. find_B
  67. search_fw
  68. search_fw_bytes
  69. load_firmware

   1 
   2 // Firmware file handling for Canon camera firmware dumps
   3 // Note: only supports DryOS based cameras and ARM32 code.
   4 //       the cameras operate in little endian mode, this code assumes it will
   5 //       be compiled and run on a little endian CPU.
   6 //       It won't work on anything else.
   7 
   8 //------------------------------------------------------------------------------------------------------------
   9 
  10 #include <stdlib.h>
  11 #include <stdio.h>
  12 #include <stdint.h>
  13 #include <string.h>
  14 #include <time.h>
  15 #include <stdarg.h>
  16 
  17 #include "dancingbits.h"
  18 #include "stubs_load.h"
  19 #include "firmware_load.h"
  20 
  21 //------------------------------------------------------------------------------------------------------------
  22 
  23 // These must be supplied elsewhere
  24 extern void error(char*, int);
  25 extern void usage(char *err);
  26 
  27 //------------------------------------------------------------------------------------------------------------
  28 
  29 // Firmware handling
  30 
  31 // Currently used by:
  32 //      finsig_dryos.c for generating stubs_entry.S
  33 //      code_gen.c for generating CHDK source code
  34 
  35 // The firmware dump is loaded into an array of 'uint32_t' 32 bit unsigned integer values
  36 // this simpifies the access and analysis of the data (all ARM32 instructions are 32 bits long and 32 bit aligned)
  37 
  38 // The functions that analyse the firmware work with either memory addresses (uint32_t) or indexes (int)
  39 // The indexes are to the memory array where the firmware is loaded.
  40 // So for a firmware that loads at address 0xFF810000, the index of this instruction in the array will be 0.
  41 // The index for 0xFF810004 = 1, etc.
  42 
  43 // Functions take a pointer to a 'firmware' structure as the first parameter and operate on the contents
  44 // of this structure. Can be used to load and compare multiple dumps.
  45 
  46 //------------------------------------------------------------------------------------------------------------
  47 
  48 // Most firmware dumps contain large blocks that have a value of only 0xFFFFFFFF.
  49 // The BufRange structure and list stores the valid ranges so these empty blocks can be skipped when
  50 // searching for stuff.
  51 
  52 // Add a valid range to the list
  53 void addBufRange(firmware *fw, int o, int l)
  54 {
  55     BufRange *n = malloc(sizeof(BufRange));
  56     n->p = fw->buf + o;
  57     n->off = o;
  58     n->len = l;
  59     n->next = 0;
  60     if (fw->br == 0)
  61     {
  62         fw->br = n;
  63     }
  64     else
  65     {
  66         fw->last->next = n;
  67     }
  68     fw->last = n;
  69 }
  70 
  71 // Find valid ranges for the firmware dump
  72 void findRanges(firmware *fw)
  73 {
  74     int i, j, k;
  75 
  76     // Find all the valid ranges for checking (skips over large blocks of 0xFFFFFFFF)
  77     fw->br = 0; fw->last = 0;
  78     k = -1; j = 0;
  79     for (i = 0; i < fw->size; i++)
  80     {
  81         if (fw->buf[i] == 0xFFFFFFFF)   // Possible start of block to skip
  82         {
  83             if (k == -1)            // Mark start of possible skip block
  84             {
  85                 k = i;
  86             }
  87         }
  88         else                        // Found end of block ?
  89         {
  90             if (k != -1)
  91             {
  92                 if (i - k > 32)     // If block more than 32 words then we want to skip it
  93                 {
  94                     if (k - j > 8)
  95                     {
  96                         // Add a range record for the previous valid range (ignore short ranges)
  97                         addBufRange(fw,j,k - j);
  98                     }
  99                     j = i;          // Reset valid range start to current position
 100                 }
 101                 k = -1;             // Reset marker for skip block
 102             }
 103         }
 104     }
 105     // Add range for last valid block
 106     if (k != -1)
 107     {
 108         if (k - j > 8)
 109         {
 110             addBufRange(fw,j,k - j);
 111         }
 112     }
 113     else
 114     {
 115         if (i - j > 8)
 116         {
 117             addBufRange(fw,j,i - j);
 118         }
 119     }
 120 }
 121 
 122 //------------------------------------------------------------------------------------------------------------
 123 
 124 // Check if the supplied index 'i' is valid for the firmware dump
 125 // Takes into account cameras with 'alternate' firmware base addresses (S110)
 126 // and those that copy a block of the firmware code to RAM (DryOS 50 and up)
 127 
 128 // Assumptions
 129 //  The 'alternate' copy of the firmware is loaded at a higher address than the base copy
 130 //      e.g. base address = 0xF8000000, alt address = 0xFF000000
 131 //          --> i > fw->size
 132 //  The firmware is always loaded at a memory address higher than the RAM that code is
 133 //  copied to.
 134 //          --> i < 0
 135 
 136 int idx_valid(firmware *fw, int i)
 137 {
 138     if ((i >= 0) && (i < fw->size))
 139         return 1;
 140     if ((fw->dryos_ver >= 51) && (fw->alt_base) && (i >= fw->size))
 141     {
 142         i = ((i * 4) - (fw->alt_base - fw->base)) / 4;
 143         if ((i >= 0) && (i < fw->size))
 144             return 1;
 145     }
 146     if (fw->dryos_ver >= 50)
 147     {
 148         int i2 = ((i * 4) + (fw->base - fw->base2)) / 4;
 149         if ((i2 >= 0) && (i2 < fw->size2))
 150             return 1;
 151         // RAM code can also reference ROM, check for that
 152         if (idx2adr(fw,i)>=fw->base && idx2adr(fw,i)<(fw->base+fw->size*4))
 153             return 1;
 154     }
 155     return 0;
 156 }
 157 
 158 // Convert an instruction index to a memory address (see above regarding RAM and 'alternate' values)
 159 uint32_t idx2adr(firmware *fw, int idx)
 160 {
 161     return fw->base + (idx << 2);
 162 }
 163 
 164 // Convert a memory address to an instruction index (see above regarding RAM and 'alternate' values)
 165 int adr2idx(firmware *fw, uint32_t adr)
 166 {
 167     if (adr < fw->base)
 168         return -((fw->base - adr) >> 2);
 169     else
 170         return (adr - fw->base) >> 2;
 171 }
 172 
 173 // Convert a memory address to a pointer into the firmware memory buffer
 174 char* adr2ptr(firmware *fw, uint32_t adr)
 175 {
 176     if ((fw->dryos_ver >= 51) && (fw->alt_base) && (adr >= fw->alt_base))
 177     {
 178         return ((char*)fw->buf) + (adr - fw->alt_base);
 179     }
 180     if ((fw->dryos_ver >= 50) && (adr < fw->base))
 181     {
 182         adr = (adr - fw->base2) + fw->base_copied;
 183     }
 184     return ((char*)fw->buf) + (adr - fw->base);
 185 }
 186 
 187 // check for code copied to RAM, correct idx if needed
 188 int idxcorr(firmware *fw, int idx)
 189 {
 190     static int inited = 0;
 191     static int b2oidx, b2idx;
 192     if (!inited)
 193     {
 194         b2oidx = adr2idx(fw, fw->base_copied);
 195         b2idx = adr2idx(fw, fw->base2);
 196         inited = 1;
 197     }
 198 
 199     if (fw->base2)
 200     {
 201         if ((idx >= b2oidx) && (idx < b2oidx + fw->size2))
 202         {
 203             idx = idx - b2oidx + b2idx;
 204         }
 205     }
 206     return idx;
 207 }
 208 //------------------------------------------------------------------------------------------------------------
 209 
 210 static int ignore_errors = 0;
 211 
 212 void set_ignore_errors(int n)
 213 {
 214     ignore_errors = n;
 215 }
 216 
 217 // These functions should be used to get data & instructions in the firmware dump
 218 // This will ensure that everything works correctly for code / data referenced in RAM
 219 // or the 'alternate' base address for the firmware.
 220 
 221 // Return a pointer to the instruction/data in the memory array at the specified index
 222 // Takes care of converting RAM and 'alternate' indexes and addresses
 223 uint32_t* fwadr(firmware *fw, int i)
 224 {
 225     if ((i >= 0) && (i < fw->size))
 226         return &fw->buf[i];
 227     if ((fw->dryos_ver >= 51) && (fw->alt_base) && (i >= fw->size))
 228     {
 229         i = ((i * 4) - (fw->alt_base - fw->base)) / 4;
 230         if ((i >= 0) && (i < fw->size))
 231             return &fw->buf[i];
 232     }
 233     if ((fw->dryos_ver >= 50) && (i < 0))
 234     {
 235         i = ((i * 4) + (fw->base - fw->base2)) / 4;
 236         if ((i >= 0) && (i < fw->size2))
 237             return &fw->buf2[i];
 238     }
 239     if (ignore_errors)
 240     {
 241         return &fw->buf[0];
 242     }
 243     fprintf(stderr,"Invalid firmware offset %d.\n",i);
 244     error("\nInvalid firmware offset %d. Possible corrupt firmware or incorrect start address.\n",i);
 245     return 0;
 246 }
 247 
 248 // Return the instruction / data at the specified index
 249 uint32_t fwval(firmware *fw, int i)
 250 {
 251     return *fwadr(fw,i);
 252 }
 253 
 254 // Return the destination register of the instruction at the specified index
 255 int fwRd(firmware *fw, int i)
 256 {
 257     // Destination register - Rd
 258     return (*fwadr(fw,i) & 0x0000F000) >> 12;
 259 }
 260 
 261 // Return the source register of the instruction at the specified index
 262 int fwRn(firmware *fw, int i)
 263 {
 264     // Source register - Rn
 265     return (*fwadr(fw,i) & 0x000F0000) >> 16;
 266 }
 267 
 268 // Return the source register of the instruction at the specified index
 269 int fwRnMOV(firmware *fw, int i)
 270 {
 271     // Source register - Rn
 272     return (*fwadr(fw,i) & 0x0000000F);
 273 }
 274 
 275 // Return the operand2 value of the instruction at the specified index
 276 int fwOp2(firmware *fw, int i)
 277 {
 278     // Operand2
 279     return (*fwadr(fw,i) & 0x00000FFF);
 280 }
 281 
 282 //------------------------------------------------------------------------------------------------------------
 283 
 284 // decode LDR instruction at offset and return firmware address pointed to
 285 uint32_t LDR2adr(firmware *fw, int offset)
 286 {
 287     uint32_t inst = fwval(fw,offset);
 288     int offst = (inst & 0xFFF);
 289     uint32_t fadr = (inst & 0x00800000)?idx2adr(fw,offset+2)+offst:idx2adr(fw,offset+2)-offst;
 290     return fadr;
 291 }
 292 
 293 // decode LDR instruction at offset and return firmware buffer index of the new address
 294 uint32_t LDR2idx(firmware *fw, int offset)
 295 {
 296     return adr2idx(fw,LDR2adr(fw,offset));
 297 }
 298 
 299 // decode LDR instruction at offset and return firmware value stored at the address
 300 uint32_t LDR2val(firmware *fw, int offset)
 301 {
 302     return fwval(fw,adr2idx(fw,LDR2adr(fw,offset)));
 303 }
 304 
 305 //------------------------------------------------------------------------------------------------------------
 306 
 307 // decode ADR instruction at offset and return firmware address pointed to
 308 // NOT COMPLETE
 309 uint32_t ADR2adr(firmware *fw, int offset)
 310 {
 311     uint32_t inst = fwval(fw,offset);
 312     int rot = 32 - ((inst & 0xF00) >> 7);
 313     int offst = (inst & 0xFF) <<rot;
 314     uint32_t fadr = 0;
 315     switch (inst & 0x01E00000)
 316     {
 317         case 0x00400000:    // SUB
 318             fadr = idx2adr(fw,offset+2)-offst;
 319             break;
 320         case 0x00800000:    // ADD
 321             fadr = idx2adr(fw,offset+2)+offst;
 322             break;
 323         case 0x01A00000:    // MOV
 324             //fprintf(stderr,"***** ADR2adr MOV\n");
 325             break;
 326         case 0x01E00000:    // MVN
 327             //fprintf(stderr,"***** ADR2adr MVN\n");
 328             break;
 329     }
 330     return fadr;
 331 }
 332 
 333 // decode operand2 from ALU inst (not complete!)
 334 uint32_t ALUop2(firmware *fw, int offset)
 335 {
 336     uint32_t inst = fwval(fw,offset);
 337     int rot = 32 - ((inst & 0xF00) >> 7);
 338     int offst = (inst & 0xFF) <<rot;
 339     uint32_t fadr = 0;
 340     switch (inst & 0x03E00000)
 341     {
 342         case 0x02400000:    // SUB Immed
 343         case 0x02800000:    // ADD Immed
 344         case 0x03400000:    // CMP Immed
 345         case 0x03A00000:    // MOV Immed
 346         case 0x03C00000:    // BIC Immed
 347             fadr = offst;
 348             break;
 349     }
 350     return fadr;
 351 }
 352 
 353 // decode operand2 from ALU inst (not complete, try2 - based on chdk_dasm code)
 354 uint32_t ALUop2a(firmware *fw, int offset)
 355 {
 356     uint32_t inst = fwval(fw,offset);
 357     uint32_t rot = (inst>>7)&0x1e;
 358     uint32_t imm8 = inst & 0xff;
 359     uint32_t offst = (imm8>>rot) | (imm8<<(32-rot));
 360     uint32_t fadr = 0;
 361     switch (inst & 0x03E00000)
 362     {
 363         case 0x02400000:    // SUB Immed
 364         case 0x02800000:    // ADD Immed
 365         case 0x03A00000:    // MOV Immed
 366         case 0x03C00000:    // BIC Immed
 367         case 0x03800000:    // ORR Immed
 368             fadr = offst;
 369             break;
 370     }
 371     return fadr;
 372 }
 373 
 374 //------------------------------------------------------------------------------------------------------------
 375 
 376 // Follow the B / BL / LDR PC instruction at the specified index and return the index of the new location
 377 // Notes:
 378 //      If offset == 0 returns the original index (fidx)
 379 //      The B / BL instruction is at 'fidx + (offset & 0xFFFFFF) - 1'
 380 //      The '(offset & 0xFF000000)' value is a mask that determines instruction matching
 381 //          offset & 0xFF000000 == 0x00000000 --> match B only
 382 //          offset & 0xFF000000 == 0x01000000 --> match B or BL
 383 int idxFollowBranch(firmware *fw, int fidx, int offset)
 384 {
 385     if (offset)
 386     {
 387         uint32_t msk = ~(offset & 0xFF000000);
 388         fidx += ((offset & 0x00FFFFFF) - 1);
 389         uint32_t inst = fwval(fw,fidx);
 390         if ((inst & (0xFF000000&msk)) == (0xEA000000&msk))  // Branch (B or BL depending on msk)
 391         {
 392             int o = inst & 0x00FFFFFF;
 393             if (o & 0x00800000) o |= 0xFF000000;
 394             fidx = fidx + o + 2;
 395         }
 396         else if ((inst & (0xFFFFF000)) == (0xE51FF000))     // LDR PC,=...
 397         {
 398             fidx = adr2idx(fw,LDR2val(fw,fidx));
 399         }
 400     }
 401     return fidx;
 402 }
 403 
 404 // Follow the B / BL / LDR PC instruction at the specified address and return the address of the new location
 405 // Notes as per above.
 406 uint32_t followBranch(firmware *fw, uint32_t fadr, int offset)
 407 {
 408     if (offset)
 409     {
 410         uint32_t msk = ~(offset & 0xFF000000);
 411         uint32_t fidx = adr2idx(fw,fadr);  // function index
 412         fidx += ((offset & 0x00FFFFFF) - 1);
 413         uint32_t inst = fwval(fw,fidx);
 414         if ((inst & (0xFF000000&msk)) == (0xEA000000&msk))  // Branch (B or BL depending on msk)
 415         {
 416             int o = inst & 0x00FFFFFF;
 417             if (o & 0x00800000) o |= 0xFF000000;
 418             if (idx_valid(fw,fidx+o+2))
 419                 fadr = idx2adr(fw,fidx+o+2);
 420         }
 421         else if ((inst & (0xFFFFF000)) == (0xE51FF000))     // LDR PC,=...
 422         {
 423             fadr = LDR2val(fw,fidx);
 424         }
 425     }
 426     return fadr;
 427 }
 428 
 429 // As above; but if offset == 1 then follow any branch at the new location
 430 uint32_t followBranch2(firmware *fw, uint32_t fadr, int offset)
 431 {
 432     fadr = followBranch(fw, fadr, offset);
 433     if ((offset & 0x00FFFFFF) == 1)
 434         fadr = followBranch(fw, fadr, offset);
 435     return fadr;
 436 }
 437 
 438 //------------------------------------------------------------------------------------------------------------
 439 
 440 // These functions test the instruction at the supplied 'offset' index to see if they match specific types
 441 
 442 // LDR Rx, =...
 443 int isLDR_PC(firmware *fw, int offset)
 444 {
 445     return ((fwval(fw,offset) & 0xFE1F0000) == 0xE41F0000);
 446 }
 447 
 448 // LDRnn Rx, =...
 449 int isLDR_PC_cond(firmware *fw, int offset)
 450 {
 451     return ((fwval(fw,offset) & 0x0E1F0000) == 0x041F0000);
 452 }
 453 
 454 // LDR Rx,[SP,...]
 455 int isLDR_SP(firmware *fw, int offset)
 456 {
 457     return ((fwval(fw,offset) & 0xFFFF0000) == 0xE59D0000);
 458 }
 459 
 460 // LDR
 461 int isLDR(firmware *fw, int offset)
 462 {
 463     return ((fwval(fw,offset) & 0xFE100000) == 0xE4100000);
 464 }
 465 
 466 // LDRnn
 467 int isLDR_cond(firmware *fw, int offset)
 468 {
 469     return ((fwval(fw,offset) & 0x0E100000) == 0x04100000);
 470 }
 471 
 472 // ADR Rx, value
 473 int isADR_PC(firmware *fw, int offset)
 474 {
 475     return ((fwval(fw,offset) & 0xFE0F0000) == 0xE20F0000);
 476 }
 477 
 478 // ADRnn Rx, value
 479 int isADR_PC_cond(firmware *fw, int offset)
 480 {
 481     return ((fwval(fw,offset) & 0x0E0F0000) == 0x020F0000);
 482 }
 483 
 484 // ADR or MOV
 485 int isADR(firmware *fw, int offset)
 486 {
 487     return ((fwval(fw,offset) & 0xFE000000) == 0xE2000000);
 488 }
 489 
 490 // LDMFD
 491 int isLDMFD(firmware *fw, int offset)
 492 {
 493     return ((fwval(fw,offset) & 0xFFFF0000) == 0xE8BD0000);
 494 }
 495 
 496 // LDMFD SP!, {..., PC}
 497 int isLDMFD_PC(firmware *fw, int offset)
 498 {
 499     return ((fwval(fw,offset) & 0xFFFF8000) == 0xE8BD8000);
 500 }
 501 
 502 // STMFD SP!,
 503 int isSTMFD(firmware *fw, int offset)
 504 {
 505     return ((fwval(fw,offset) & 0xFFFF0000) == 0xE92D0000);
 506 }
 507 
 508 // STMFD SP!, {..,LR}
 509 int isSTMFD_LR(firmware *fw, int offset)
 510 {
 511     return ((fwval(fw,offset) & 0xFFFF4000) == 0xE92D4000);
 512 }
 513 
 514 // STR
 515 int isSTR(firmware *fw, int offset)
 516 {
 517     return ((fwval(fw,offset) & 0xFE100000) == 0xE4000000);
 518 }
 519 
 520 // STRnn
 521 int isSTR_cond(firmware *fw, int offset)
 522 {
 523     return ((fwval(fw,offset) & 0x0E100000) == 0x04000000);
 524 }
 525 
 526 // BX
 527 int isBX(firmware *fw, int offset)
 528 {
 529     return ((fwval(fw,offset) & 0xFFFFFFF0) == 0xE12FFF10);
 530 }
 531 
 532 // BX
 533 int isBX_cond(firmware *fw, int offset)
 534 {
 535     return ((fwval(fw,offset) & 0x0FFFFFF0) == 0x012FFF10);
 536 }
 537 
 538 // BX LR
 539 int isBX_LR(firmware *fw, int offset)
 540 {
 541     return (fwval(fw,offset) == 0xE12FFF1E);
 542 }
 543 
 544 // BLX
 545 int isBLX(firmware *fw, int offset)
 546 {
 547     return ((fwval(fw,offset) & 0xFFFFFFF0) == 0xE12FFF30);
 548 }
 549 
 550 // BL
 551 int isBL(firmware *fw, int offset)
 552 {
 553     return ((fwval(fw,offset) & 0xFF000000) == 0xEB000000);
 554 }
 555 
 556 // BLxx
 557 int isBL_cond(firmware *fw, int offset)
 558 {
 559     return ((fwval(fw,offset) & 0x0F000000) == 0x0B000000);
 560 }
 561 
 562 // BLEQ
 563 int isBLEQ(firmware *fw, int offset)
 564 {
 565     return ((fwval(fw,offset) & 0xFF000000) == 0x0B000000);
 566 }
 567 
 568 // B
 569 int isB(firmware *fw, int offset)
 570 {
 571     return ((fwval(fw,offset) & 0xFF000000) == 0xEA000000);
 572 }
 573 
 574 // B or BL
 575 int isBorBL(firmware *fw, int offset)
 576 {
 577     return ((fwval(fw,offset) & 0xFE000000) == 0xEA000000);
 578 }
 579 
 580 // CMP
 581 int isCMP(firmware *fw, int offset)
 582 {
 583     return ((fwval(fw,offset) & 0xFFF00000) == 0xE3500000);
 584 }
 585 
 586 // MOV
 587 int isMOV(firmware *fw, int offset)
 588 {
 589     return ((fwval(fw,offset) & 0xFFF00000) == 0xE1A00000);
 590 }
 591 
 592 // MOV Rd, #
 593 int isMOV_immed(firmware *fw, int offset)
 594 {
 595     return ((fwval(fw,offset) & 0xFFF00000) == 0xE3A00000);
 596 }
 597 
 598 // ORR Rd, Rn, #
 599 int isORR(firmware *fw, int offset)
 600 {
 601     return ((fwval(fw,offset) & 0xFFF00000) == 0xE3800000);
 602 }
 603 
 604 // ADD
 605 int isADD(firmware *fw, int offset)
 606 {
 607     return ((fwval(fw,offset) & 0xfff00000) == 0xe2800000);
 608 }
 609 
 610 // SUB
 611 int isSUB(firmware *fw, int offset)
 612 {
 613     return ((fwval(fw,offset) & 0xfff00000) == 0xe2400000);
 614 }
 615 
 616 //------------------------------------------------------------------------------------------------------------
 617 
 618 int isASCIIstring(firmware *fw, uint32_t adr)
 619 {
 620     if (idx_valid(fw, adr2idx(fw, adr)))
 621     {
 622         unsigned char *p = (unsigned char*)adr2ptr(fw, adr);
 623         int i;
 624         for (i = 0; (i < 100) && (p[i] != 0); i++)
 625         {
 626             if (!((p[i] == '\r') || (p[i] == '\n') || (p[i] == '\t') || ((p[i] >= 0x20) && (p[i] <= 0x7f))))
 627             {
 628                 return 0;
 629             }
 630         }
 631         if ((i >= 2) && (p[i] == 0))
 632             return 1;
 633     }
 634     return 0;
 635 }
 636 //------------------------------------------------------------------------------------------------------------
 637 
 638 // Find the index of a string in the firmware
 639 // Assumes the string starts on a 32bit boundary.
 640 // String + terminating zero byte should be at least 4 bytes long
 641 // Handles multiple string instances
 642 int find_Nth_str(firmware *fw, char *str, int N)
 643 {
 644     int nlen = strlen(str);
 645     uint32_t nm0 = *((uint32_t*)str);
 646     uint32_t *p;
 647     int j;
 648 
 649     BufRange *br = fw->br;
 650     while (br)
 651     {
 652         for (p = br->p, j = 0; j < br->len - nlen/4; j++, p++)
 653         {
 654             if ((nm0 == *p) && ((nlen<=4) || (memcmp(p+1,str+4,nlen-4) == 0)) )
 655             {
 656                 if (--N == 0)
 657                     return j+br->off;
 658             }
 659         }
 660         br = br->next;
 661     }
 662 
 663     return -1;
 664 }
 665 
 666 int find_str(firmware *fw, char *str)
 667 {
 668     return find_Nth_str(fw, str, 1);
 669 }
 670 
 671 // Find the index of a string in the firmware, can start at any address
 672 // returns firmware address, not index
 673 uint32_t find_str_bytes(firmware *fw, char *str)
 674 {
 675     BufRange *p = fw->br;
 676     while (p)
 677     {
 678         int k;
 679         for (k = p->off*4; k < (p->off + p->len)*4; k++)
 680         {
 681             if (strcmp(((char*)fw->buf)+k,str) == 0)
 682                 return fw->base+k;
 683         }
 684         p = p->next;
 685     }
 686 
 687     return 0;
 688 }
 689 
 690 // Find the next instance of the instruction matched by the 'inst' function (from the isXXX functions above)
 691 // Starts searching at 'idx' for a max of 'len' instructions
 692 int find_inst(firmware *fw, int (*inst)(firmware*,int), int idx, int len)
 693 {
 694     int k;
 695     for (k = idx; (k < fw->size) && (k < idx + len); k++)
 696     {
 697         if (inst(fw, k))
 698             return k;
 699     }
 700     return -1;
 701 }
 702 
 703 // Find the previous instance of the instruction matched by the 'inst' function (from the isXXX functions above)
 704 // Starts searching at 'idx' for a max of 'len' instructions
 705 int find_inst_rev(firmware *fw, int (*inst)(firmware*,int), int idx, int len)
 706 {
 707     int k;
 708     for (k = idx; (k > 0) && (k > idx - len); k--)
 709     {
 710         if (inst(fw, k))
 711             return k;
 712     }
 713     return -1;
 714 }
 715 
 716 // Find the Nth instance of the instruction matched by the 'inst' function
 717 // Modified version of find_inst()
 718 int find_Nth_inst(firmware *fw, int (*inst)(firmware*,int), int idx, int len, int N)
 719 {
 720     int k;
 721     for (k = idx; (k < fw->size) && (k < idx + len); k++)
 722     {
 723         if (inst(fw, k))
 724             N--;
 725         if (N <= 0)
 726             return k;
 727     }
 728     return -1;
 729 }
 730 
 731 // Find the Nth previous instance of the instruction matched by the 'inst' function
 732 // Modified version of find_inst_rev()
 733 int find_Nth_inst_rev(firmware *fw, int (*inst)(firmware*,int), int idx, int len, int N)
 734 {
 735     int k;
 736     for (k = idx; (k > 0) && (k > idx - len); k--)
 737     {
 738         if (inst(fw, k))
 739             N--;
 740         if (N <= 0)
 741             return k;
 742     }
 743     return -1;
 744 }
 745 
 746 //------------------------------------------------------------------------------------------------------------
 747 
 748 // Finds the first instance of an instruction that references a pointer to the specified string in the firmware.
 749 //  e.g.
 750 //          LDR R0, =p_str  <-- returns index of this instruction
 751 //  p_str   DCD abcdef
 752 //  abcdef  DCB "abcdef",0
 753 int find_strptr_ref(firmware *fw, char *str)
 754 {
 755     uint32_t sadr = find_str_bytes(fw, str);    // string address
 756     if (sadr > 0)
 757     {
 758         int k;
 759         for (k=0; k<fw->size; k++)
 760         {
 761             if (fwval(fw,k) == sadr)
 762             {
 763                 uint32_t fadr = idx2adr(fw,k);  // string pointer address
 764                 int j;
 765                 for (j=0; j<fw->size; j++)
 766                 {
 767                     if (isADR_PC_cond(fw,j) && (ADR2adr(fw,j) == fadr))
 768                     {
 769                         return j;
 770                     }
 771                     else if (isLDR_PC_cond(fw,j) && (LDR2val(fw,j) == fadr))
 772                     {
 773                         return j;
 774                     }
 775                 }
 776             }
 777         }
 778     }
 779     return -1;
 780 }
 781 
 782 // Finds the first instance of an instruction that references the specified string in the firmware.
 783 //  e.g.
 784 //          LDR R0, =abcdef     <-- returns index of this instruction
 785 //  abcdef  DCB "abcdef",0
 786 int find_str_ref(firmware *fw, char *str)
 787 {
 788     int k = find_str(fw, str);
 789     if (k >= fw->lowest_idx)
 790     {
 791         uint32_t sadr = idx2adr(fw,k);        // string address
 792         for (k=0; k<fw->size; k++)
 793         {
 794             if (isADR_PC_cond(fw,k) && (ADR2adr(fw,k) == sadr))
 795             {
 796                 return k;
 797             }
 798             else if (isLDR_PC_cond(fw,k) && (LDR2val(fw,k) == sadr))
 799             {
 800                 return k;
 801             }
 802         }
 803     }
 804     return -1;
 805 }
 806 
 807 // Finds the next reference to a string
 808 int find_nxt_str_ref(firmware *fw, int str_adr, int ofst)
 809 {
 810     if (str_adr >= fw->lowest_idx)
 811     {
 812         int k;
 813         uint32_t sadr = idx2adr(fw,str_adr);        // string address
 814         for (k=ofst+1; k<fw->size; k++)
 815         {
 816             if (isADR_PC_cond(fw,k) && (ADR2adr(fw,k) == sadr))
 817             {
 818                 return k;
 819             }
 820             else if (isLDR_PC_cond(fw,k) && (LDR2val(fw,k) == sadr))
 821             {
 822                 return k;
 823             }
 824         }
 825     }
 826     return -1;
 827 }
 828 
 829 // Finds the next reference to a string
 830 int find_nxt_str_ref_alt(firmware *fw, char *str, int ofst, int limit)
 831 {
 832     int k;
 833     for (k=ofst; k<ofst+limit; k++)
 834     {
 835         if (isADR_PC_cond(fw,k) && idx_valid(fw,adr2idx(fw,ADR2adr(fw,k))) && (strcmp(str,adr2ptr(fw,ADR2adr(fw,k))) == 0))
 836         {
 837             return k;
 838         }
 839         else if (isLDR_PC_cond(fw,k) && idx_valid(fw,adr2idx(fw,LDR2val(fw,k))) && (strcmp(str,adr2ptr(fw,LDR2val(fw,k))) == 0))
 840         {
 841             return k;
 842         }
 843     }
 844     return -1;
 845 }
 846 
 847 //------------------------------------------------------------------------------------------------------------
 848 
 849 // Checks if the instruction at index 'k' is a BL to address 'v1'
 850 // Used with the 'search_fw' below
 851 int find_BL(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2)
 852 {
 853     if (isBL(fw,k))
 854     {
 855         uint32_t n = idxFollowBranch(fw, k, 0x01000001);
 856         if (n == v1)
 857             return k;
 858     }
 859     return 0;
 860 }
 861 
 862 // Checks if the instruction at index 'k' is a BL to address 'v1'
 863 // Used with the 'search_fw' below
 864 int find_B(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2)
 865 {
 866     if (isB(fw,k))
 867     {
 868         uint32_t n = idxFollowBranch(fw, k, 0x00000001);
 869         if (n == v1)
 870             return k;
 871     }
 872     return 0;
 873 }
 874 
 875 //------------------------------------------------------------------------------------------------------------
 876 
 877 // Search the firmware for something. The desired matching is performed using the supplied 'func' function.
 878 // Continues searching until 'func' returns non-zero - then returns the value returned by 'func'
 879 // otherwise returns 0.
 880 // Uses the BufRange structs to speed up searching
 881 int search_fw(firmware *fw, int (*func)(firmware*, int, uint32_t, uint32_t), uint32_t v1, uint32_t v2, int len)
 882 {
 883     BufRange *p = fw->br;
 884     while (p)
 885     {
 886         int k;
 887         for (k = p->off; k <= p->off + p->len - len; k++)
 888         {
 889             int rv = func(fw,k,v1,v2);
 890             if (rv != 0)
 891                 return rv;
 892         }
 893         p = p->next;
 894     }
 895     return 0;
 896 }
 897 
 898 // Search the firmware for something. The desired matching is performed using the supplied 'func' function.
 899 // Continues searching until 'func' returns non-zero - then returns 1
 900 // otherwise returns 0.
 901 // Uses the BufRange structs to speed up searching
 902 // Note: this version searches byte by byte in the firmware dump instead of by words
 903 int search_fw_bytes(firmware *fw, int (*func)(firmware*, int))
 904 {
 905     BufRange *p = fw->br;
 906     while (p)
 907     {
 908         int k;
 909         for (k = p->off*4; k < (p->off + p->len)*4; k++)
 910         {
 911             if (func(fw,k))
 912                 return 1;
 913         }
 914         p = p->next;
 915     }
 916     return 0;
 917 }
 918 
 919 //------------------------------------------------------------------------------------------------------------
 920 
 921 // Load the named firmware file, using the supplied base and alternate base addresses
 922 // Once loaded searches the firmware for information
 923 void load_firmware(firmware *fw, const char *filename, const char *base_addr, const char *alt_base_addr, int os_type)
 924 {
 925     // Open file.
 926     FILE *f = fopen(filename, "rb");
 927     int i, j, k;
 928 
 929     if (f == NULL)
 930     {
 931         fprintf(stderr,"Error opening %s\n",filename);
 932         usage("firmware open");
 933     }
 934 
 935     // these are used regardless of camera generation, have to be initialized here
 936     fw->buf2 = 0;
 937     fw->base2 = 0;
 938     fw->size2 = 0;
 939 
 940     fw->os_type = os_type;
 941 
 942     // File length
 943     fseek(f,0,SEEK_END);
 944     fw->size = (ftell(f)+3)/4;
 945     fseek(f,0,SEEK_SET);
 946 
 947     // Save base addresses
 948     fw->base = strtoul(base_addr, NULL, 0);
 949     if (alt_base_addr)
 950         fw->alt_base = strtoul(alt_base_addr, NULL, 0);
 951     else
 952         fw->alt_base = 0;
 953 
 954     // Max (old) sig size is 32, add extra space at end of buffer and fill with 0xFFFFFFFF
 955     // Allows sig matching past end of firmware without checking each time in the inner loop
 956     fw->buf = malloc((fw->size+32)*4);
 957     k = fread(fw->buf, 4, fw->size, f);
 958     fclose(f);
 959 
 960     // fill extra space in buffer
 961     memset(&fw->buf[fw->size],0xff,32*4);
 962 
 963     // Find all the valid ranges for checking (skips over large blocks of 0xFFFFFFFF)
 964     findRanges(fw);
 965 
 966     // Check for DIGIC 4+ dump
 967     // assumes dump starting with either the main firmware or the bootloader
 968     fw->main_offs = 0;
 969     if (os_type == OS_DRYOS)
 970     {
 971         k = find_str(fw, "gaonisoy");
 972         if (k != 1)
 973         {
 974             fw->main_offs = 0x10000 / 4;
 975         }
 976     }
 977     // Get DRYOS version
 978     fw->real_dryos_ver = fw->dryos_ver = 0;
 979     if (os_type == OS_DRYOS)
 980     {
 981         k = find_str(fw, "DRYOS version 2.3, release #");
 982         if (k != -1)
 983         {
 984             fw->real_dryos_ver = fw->dryos_ver = atoi(((char*)&fw->buf[k])+28);
 985             fw->dryos_ver_str = (char*)&fw->buf[k];
 986         }
 987     }
 988 
 989     // Get firmware version info
 990     fw->firmware_ver_str = 0;
 991     k = find_str(fw, "Firmware Ver ");
 992     if (os_type == OS_VXWORKS)
 993     {
 994         if (k < 0)
 995         {
 996             k = find_str(fw, "Firmware Version GM");    // ixus700
 997         }
 998         if (k < 0)
 999         {
1000             k = find_str(fw, "Firmware Version ");      // ixus30/40
1001         }
1002     }
1003     if (k != -1)
1004     {
1005         fw->firmware_ver_str = (char*)&fw->buf[k];
1006         fw->fwver_idx = k;
1007     }
1008 
1009     // Get camera name & platformid     ***** UPDATE for new each new DryOS version *****
1010     fw->fsize = -((int)fw->base)/4;
1011     if (fw->alt_base) fw->fsize = -((int)fw->alt_base)/4;
1012     fw->cam_idx = -1;
1013     fw->pid_adr = 0xffffffff;
1014     fw->cam = 0;
1015     fw->pid = 0;
1016     if (os_type == OS_DRYOS)
1017     {
1018         if (fw->dryos_ver > 59) fw->dryos_ver = 59; // UPDATE when support is added for higher DryOS versions
1019         switch (fw->dryos_ver)
1020         {
1021             case 20:
1022             case 23:
1023             case 31:
1024             case 39:
1025                 fw->cam_idx = adr2idx(fw,0xFFFE0110);
1026                 fw->pid_adr = 0xFFFE0130;
1027                 break;
1028             case 43:
1029             case 45:
1030                 fw->cam_idx = adr2idx(fw,0xFFFE00D0);
1031                 fw->pid_adr = 0xFFFE0130;
1032                 break;
1033             case 47:
1034                 fw->cam_idx = adr2idx(fw,(fw->base==0xFF000000)?0xFFF40170:0xFFFE0170);
1035                 fw->pid_adr = (fw->base==0xFF000000)?0xFFF40040:0xFFFE0040;
1036                 break;
1037             case 49:
1038             case 50:
1039             case 51:
1040             case 52:
1041                 if (fw->alt_base)
1042                 {
1043                     fw->cam_idx = adr2idx(fw,(fw->alt_base==0xFF000000)?0xFFF40190:0xFFFE0170);
1044                     fw->pid_adr = (fw->alt_base==0xFF000000)?0xFFF40040:0xFFFE0040;
1045                     if (idx_valid(fw,fw->cam_idx) && (strncmp((char*)fwadr(fw,fw->cam_idx),"Canon ",6) != 0))
1046                         fw->cam_idx = adr2idx(fw,(fw->alt_base==0xFF000000)?0xFFF40170:0xFFFE0170);
1047                 }
1048                 else
1049                 {
1050                     fw->cam_idx = adr2idx(fw,(fw->base==0xFF000000)?0xFFF40190:0xFFFE0170);
1051                     fw->pid_adr = (fw->base==0xFF000000)?0xFFF40040:0xFFFE0040;
1052                     if (idx_valid(fw,fw->cam_idx) && (strncmp((char*)fwadr(fw,fw->cam_idx),"Canon ",6) != 0))
1053                         fw->cam_idx = adr2idx(fw,(fw->base==0xFF000000)?0xFFF40170:0xFFFE0170);
1054                 }
1055                 break;
1056             case 54:
1057                 fw->cam_idx = adr2idx(fw,(fw->base==0xFF010000)?0xFFF40170:0xFFFF0170);
1058                 fw->pid_adr = (fw->base==0xFF010000)?0xFFF40040:0xFFFF0040;
1059                 break;
1060             case 55:
1061             case 57: // TODO: based on a single fw dump (ixus275)
1062                 fw->cam_idx = adr2idx(fw,(fw->base==0xFF010000)?0xFFFE0170:0xFFFF0170);
1063                 fw->pid_adr = (fw->base==0xFF010000)?0xFFFE0040:0xFFFF0040;
1064                 break;
1065             case 58:
1066             case 59:
1067                 fw->cam_idx = adr2idx(fw,(fw->base==0xFF010000)?0xFFFE03A0:0xFFFF03A0);
1068                 fw->pid_adr = (fw->base==0xFF010000)?0xFFFE0270:0xFFFF0270;
1069                 break;
1070         }
1071     }
1072     else
1073     {
1074         //                             IXUS 700    IXUS 30/40  IXUS 50     Other
1075         uint32_t vx_name_offsets[] = { 0xFFD70110, 0xFFD70120, 0xFFF80110, 0xFFFE0110 };
1076         uint32_t vx_pid_offsets[] =  { 0xFFD70130, 0xFFD7014E, 0xFFF80130, 0xFFFE0130 };
1077         for (i=0; i<(int)(sizeof(vx_name_offsets)/sizeof(vx_name_offsets[0])); i++)
1078         {
1079             int k = adr2idx(fw,vx_name_offsets[i]);
1080             if (idx_valid(fw,k) && (strncmp((char*)fwadr(fw,k),"Canon ",6) == 0))
1081             {
1082                 fw->cam_idx = k;
1083                 fw->pid_adr = vx_pid_offsets[i];
1084                 break;
1085             }
1086         }
1087     }
1088 
1089     // Extact camera name if found
1090     if (idx_valid(fw,fw->cam_idx) && (strncmp((char*)fwadr(fw,fw->cam_idx),"Canon ",6) == 0))
1091     {
1092         fw->cam = (char*)fwadr(fw,fw->cam_idx);
1093     }
1094 
1095     // Set ID if found
1096     if (idx_valid(fw,adr2idx(fw,fw->pid_adr)) && (fw->pid_adr != 0xffffffff))
1097     {
1098         // get the correct halfword
1099         fw->pid = (fwval(fw,adr2idx(fw,fw->pid_adr)) >> ((fw->pid_adr & 2)?16:0)) & 0xFFFF;
1100     }
1101 
1102     // Calc MAXRAMADDR
1103     fw->maxram = 0;
1104     if (os_type == OS_DRYOS)
1105     {
1106         if (((fw->buf[0x10 + fw->main_offs] & 0xFFFFFF00) == 0xE3A00000) && (fw->buf[0x11 + fw->main_offs] == 0xEE060F12))
1107         {
1108             fw->maxram = (1 << (((fw->buf[0x10 + fw->main_offs] & 0x3E) >> 1) + 1)) - 1;
1109         }
1110         else if (((fw->buf[0x14 + fw->main_offs] & 0xFFFFFF00) == 0xE3A00000) && (fw->buf[0x15 + fw->main_offs] == 0xEE060F12))
1111         {
1112             fw->maxram = (1 << (((fw->buf[0x14 + fw->main_offs] & 0x3E) >> 1) + 1)) - 1;
1113         }
1114     }
1115     else if (os_type == OS_VXWORKS)
1116     {
1117         for (k=16; k<100; k++)
1118         {
1119             if ((fw->buf[k] & 0xFFFF0FFF) == 0xEE060F12) // mcr 15, 0, rx, cr6, cr2, {0}
1120             {
1121                 fw->maxram = (1 << (((fw->buf[k-1] & 0x3E) >> 1) + 1)) - 1;
1122                 break;
1123             }
1124         }
1125     }
1126 
1127     // Find MEMISOSTART
1128     fw->memisostart = 0;
1129     if (os_type == OS_DRYOS)
1130     {
1131         for (k=0 + fw->main_offs; k<(100 + fw->main_offs); k++)
1132         {
1133             if (isLDR_PC(fw,k) && (LDR2val(fw,k) == 0x1900) && isLDR_PC(fw,k+6))
1134             {
1135                 fw->memisostart = LDR2val(fw,k+6);
1136             }
1137         }
1138     }
1139     else if (os_type == OS_VXWORKS)
1140     {
1141         for (k=16; k<100; k++)
1142         {
1143             if (isMOV_immed(fw,k) && (ALUop2(fw,k) == 0x1900) && isLDR_PC(fw,k+11))
1144             {
1145                 fw->memisostart = LDR2val(fw,k+11);
1146                 // Find DATA section info
1147                 if (isLDR_PC(fw,k-1) && isLDR_PC(fw,k-4) && ((fwval(fw,k-2) & 0xFFF0FFF0) == 0xE1500000))
1148                 {
1149                     uint32_t fadr = LDR2val(fw,k-1);
1150                     uint32_t dadr = 0x1900;
1151                     uint32_t eadr = LDR2val(fw,k-4);
1152                     if ((fadr > fw->base) && (dadr < fw->base))
1153                     {
1154                         fw->data_start = dadr;
1155                         fw->data_init_start = fadr;
1156                         fw->data_len = eadr / 4;
1157                     }
1158                 }
1159                 break;
1160             }
1161             else if (isMOV_immed(fw,k) && (ALUop2(fw,k) == 0x1900) && isLDR_PC(fw,k-2) && isLDR_PC(fw,k-3))
1162             {
1163                 // special case ixus30/40
1164                 fw->maxram = 0x1FFFFFF; // 32MB, difficult to find
1165                 fw->memisostart = 0x1900 + LDR2val(fw,k-3);
1166                 // Find DATA section info
1167                 fw->data_init_start = LDR2val(fw,k-2);
1168                 fw->data_start = 0x1900;
1169                 j = idxFollowBranch(fw, k+6, 1);
1170                 if (j != k+6)
1171                 {
1172                     k = idxFollowBranch(fw, j+1, 0x01000001);
1173                     if (k != j+1)
1174                     {
1175                         if ( isLDR_PC(fw,k+3) )
1176                         {
1177                             uint32_t eadr = LDR2val(fw,k+3);
1178                             if ( (eadr>0x1000) && (eadr< fw->memisostart - 0x1900) )
1179                             {
1180                                 fw->data_len = (eadr - 0x1900) / 4;
1181                             }
1182                         }
1183                     }
1184                 }
1185                 break;
1186             }
1187             else if (isMOV_immed(fw,k) && (ALUop2(fw,k) == 0x1900) && isLDR_PC(fw,k-2) &&
1188                         ((fwval(fw,k-1) & 0xFFFF0F00) == 0xE50B0000) && isLDR_PC(fw,k+28) && isLDR_PC(fw,k+4)
1189                     )
1190             {
1191                 // special case ixusW
1192                 fw->memisostart = LDR2val(fw,k+28);
1193                 // Find DATA section info
1194                 fw->data_init_start = LDR2val(fw,k-2);
1195                 fw->data_start = 0x1900;
1196                 fw->data_len = (LDR2val(fw,k+4) - 0x1900) / 4;
1197                 break;
1198             }
1199         }
1200     }
1201 
1202     // Find encryption key & dancing bits
1203     fw->ksys_idx = 0;
1204     fw->ksys = 0;
1205     fw->dancing_bits_idx = 0;
1206     fw->dancing_bits = 0;
1207     if (os_type == OS_DRYOS)
1208     {
1209         uint32_t ofst = (fw->main_offs)?0:adr2idx(fw,0xFFFF0000); // Offset of area to find dancing bits
1210         if (idx_valid(fw,ofst) && isB(fw,ofst) && isLDR_PC(fw,ofst+1))
1211         {
1212             // Get KEYSYS value
1213             ofst = adr2idx(fw,LDR2val(fw,ofst+1));     // Address of firmware encryption key
1214             if (idx_valid(fw,ofst))
1215             {
1216                 fw->ksys_idx = ofst;
1217                 fw->ksys = "? Not found, possible new firmware encryption key.";
1218                 switch (fwval(fw,ofst))
1219                 {
1220                     // Note: only check first word of key (assumes Canon won't release a new key with the same initial value as an existing one)
1221                     // (Avoid storing full encryption key in this source code).
1222                     case 0x70726964:    fw->ksys = "d3"; break;
1223                     case 0x646C726F:    fw->ksys = "d3enc"; break;
1224                     case 0x774D450B:    fw->ksys = "d4"; break;
1225                     case 0x80751A95:    fw->ksys = "d4a"; break;
1226                     case 0x76894368:    fw->ksys = "d4b"; break;
1227                     case 0x50838EF7:    fw->ksys = "d4c"; break;
1228                     case 0xCCE4D2E6:    fw->ksys = "d4d"; break;
1229                     case 0x66E0C6D2:    fw->ksys = "d4e"; break;
1230                     case 0xE1268DB4:    fw->ksys = "d4f"; break;
1231                     case 0x216EA8C8:    fw->ksys = "d4g"; break;
1232                     case 0x45264974:    fw->ksys = "d4h"; break;
1233                                         case 0x666363FC:    fw->ksys = "d4i"; break;
1234                                         case 0xAE8DB5AF:    fw->ksys = "d4j"; break;
1235                 }
1236             }
1237 
1238             // Get NEED_ENCODED_DISKBOOT value
1239             ofst = ofst + 4; // Address of dancing bits data (try after firmware key)
1240             if (idx_valid(fw,ofst))
1241             {
1242                 for (i=0; i<VITALY && !fw->dancing_bits; i++)
1243                 {
1244                     fw->dancing_bits = i+1;
1245                     for (j=0; j<8 && fw->dancing_bits; j++)
1246                     {
1247                         if ((fwval(fw,ofst+j) & 0xFF) != _chr_[i][j])
1248                         {
1249                             fw->dancing_bits = 0;
1250                         }
1251                     }
1252                 }
1253                 if (!fw->dancing_bits)
1254                 {
1255                     // Try before firmware key
1256                     ofst = ofst - 12;
1257                     for (i=0; i<VITALY && !fw->dancing_bits; i++)
1258                     {
1259                         fw->dancing_bits = i+1;
1260                         for (j=0; j<8 && fw->dancing_bits; j++)
1261                         {
1262                             if ((fwval(fw,ofst+j) & 0xFF) != _chr_[i][j])
1263                             {
1264                                 fw->dancing_bits = 0;
1265                             }
1266                         }
1267                     }
1268                 }
1269                 if (fw->dancing_bits != 0)
1270                 {
1271                     // Make sure LoadBootFile actually fails on files that are not encoded
1272                     // E.G. G9 - will load and run an un-encoded DISKBOOT.BIN file
1273                     int need_dance = 1;
1274                     for (k = ofst; (k>adr2idx(fw,0xFFFF0000)) && need_dance; k--)
1275                     {
1276                         if (isLDR_PC(fw,k) && (LDR2val(fw,k) == idx2adr(fw,ofst)))
1277                         {
1278                             j = find_inst_rev(fw,isSTMFD_LR,k-1,10);
1279                             if (j >= 0)
1280                             {
1281                                 uint32_t fadr = idx2adr(fw,j);
1282                                 for (i=j-200; i<j+200 && need_dance; i++)
1283                                 {
1284                                     if (isB(fw,i))
1285                                     {
1286                                         uint32_t badr = followBranch(fw,idx2adr(fw,i),1);
1287                                         if (badr == fadr)
1288                                         {
1289                                             int l;
1290                                             for (l=i-1; l>i-50; l--)
1291                                             {
1292                                                 if (isLDR(fw,l) && isCMP(fw,l+1) && isBX_cond(fw,l+2))
1293                                                 {
1294                                                     need_dance = 0;
1295                                                     break;
1296                                                 }
1297                                             }
1298                                         }
1299                                     }
1300                                 }
1301                             }
1302                         }
1303                     }
1304                     if (need_dance)
1305                         fw->dancing_bits_idx = ofst;
1306                     else
1307                         fw->dancing_bits = 0;
1308                 }
1309             }
1310         }
1311     }
1312 
1313     int dx = 3;
1314 
1315     fw->lowest_idx = 0;
1316 
1317     // DryOS R50/R51/R52 etc. copies a block of ROM to RAM and then uses that copy
1318     // Need to allow for this in finding addresses
1319     // Seen on SX260HS
1320     if (fw->dryos_ver >= 50)
1321     {
1322 
1323         // Try and find ROM address copied, and location copied to
1324         for (i=3 + fw->main_offs; i<(100 + fw->main_offs); i++)
1325         {
1326             if (isLDR_PC(fw,i) && isLDR_PC(fw,i+1) && (isLDR_PC(fw,i+2)))
1327             {
1328                 uint32_t fadr = LDR2val(fw,i);
1329                 uint32_t dadr = LDR2val(fw,i+1);
1330                 uint32_t eadr = LDR2val(fw,i+2);
1331                 if ((fadr > fw->base) && (dadr < fw->base))
1332                 {
1333                     fw->buf2 = &fw->buf[adr2idx(fw,fadr)];
1334                     fw->base2 = dadr;
1335                     fw->base_copied = fadr;
1336                     fw->size2 = (eadr - dadr) / 4;
1337                     fw->lowest_idx = adr2idx(fw,fw->base2);
1338                     dx = i+3;
1339                     break;
1340                 }
1341             }
1342         }
1343     }
1344 
1345     // Find DATA section info
1346     if (os_type == OS_DRYOS)
1347     {
1348         for (i=dx; i<(100 + fw->main_offs); i++)
1349         {
1350             if (isLDR_PC(fw,i) && isLDR_PC(fw,i+1) && (isLDR_PC(fw,i+2)))
1351             {
1352                 uint32_t fadr = LDR2val(fw,i);
1353                 uint32_t dadr = LDR2val(fw,i+1);
1354                 uint32_t eadr = LDR2val(fw,i+2);
1355                 if ((fadr > fw->base) && (dadr < fw->base))
1356                 {
1357                     fw->data_start = dadr;
1358                     fw->data_init_start = fadr;
1359                     fw->data_len = (eadr - dadr) / 4;
1360                     break;
1361                 }
1362             }
1363         }
1364     }
1365 }
1366 
1367 //------------------------------------------------------------------------------------------------------------

/* [<][>][^][v][top][bottom][index][help] */