diff --git a/passport/__init__.py b/passport/__init__.py index e6b9e12..2ff1299 100755 --- a/passport/__init__.py +++ b/passport/__init__.py @@ -162,6 +162,7 @@ class BasePassportProcessor: # base class self.g.logger.PrintByID("sync") return True # TODO IsUnformatted nibble test and other tests + # (still need these for disks like Crime Wave and Thunder Bombs) return False def IDDiversi(self, t00s00): @@ -179,103 +180,32 @@ class BasePassportProcessor: # base class def IDDavidDOS(self, t00s00): """returns True if T00S00 is David-DOS II bootloader, or False otherwise""" - if not find.at(0x01, t00s00, - b'\xA5\x27' - b'\xC9\x09' - b'\xD0\x17'): - return False - return find.wild_at(0x4A, t00s00, - b'\xA2' + find.WILDCARD + \ - b'\xBD' + find.WILDCARD + b'\x08' + \ - b'\x9D' + find.WILDCARD + b'\x04' + \ - b'\xCA' - b'\x10\xF7') + return find.at(0x01, t00s00, kIDDavidDOS1) and \ + find.wild_at(0x4A, t00s00, kIDDavidDOS2) def IDDatasoft(self, t00s00): """returns True if T00S00 is encrypted Datasoft bootloader, or False otherwise""" - return find.at(0x00, t00s00, - b'\x01\x4C\x7E\x08\x04\x8A\x0C\xB8' - b'\x00\x56\x10\x7A\x00\x00\x1A\x16' - b'\x12\x0E\x0A\x06\x53\x18\x9A\x02' - b'\x10\x1B\x02\x10\x4D\x56\x15\x0B' - b'\xBF\x14\x14\x54\x54\x54\x92\x81' - b'\x1B\x10\x10\x41\x06\x73\x0A\x10' - b'\x33\x4E\x00\x73\x12\x10\x33\x7C' - b'\x00\x11\x20\xE3\x49\x50\x73\x1A' - b'\x10\x41\x00\x23\x80\x5B\x0A\x10' - b'\x0B\x4E\x9D\x0A\x10\x9D\x0C\x10' - b'\x60\x1E\x53\x10\x90\x53\xBC\x90' - b'\x53\x00\x90\xD8\x52\x00\xD8\x7C' - b'\x00\x53\x80\x0B\x06\x41\x00\x09' - b'\x04\x45\x0C\x63\x04\x90\x94\xD0' - b'\xD4\x23\x04\x91\xA1\xEB\xCD\x06' - b'\x95\xA1\xE1\x98\x97\x86') + return find.at(0x00, t00s00, kIDDatasoft) def IDMicrograms(self, t00s00): """returns True if T00S00 is Micrograms bootloader, or False otherwise""" - if not find.at(0x01, t00s00, - b'\xA5\x27' - b'\xC9\x09' - b'\xD0\x12' - b'\xA9\xC6' - b'\x85\x3F'): - return False - return find.at(0x42, t00s00, b'\x4C\x00') + return find.at(0x01, t00s00, kIDMicrograms1) and \ + find.at(0x42, t00s00, kIDMicrograms2) def IDQuickDOS(self, t00s00): """returns True if T00S00 is Quick-DOS bootloader, or False otherwise""" - return find.at(0x01, t00s00, - b'\xA5\x27' - b'\xC9\x09' - b'\xD0\x27' - b'\x78' - b'\xAD\x83\xC0') + return find.at(0x01, t00s00, kIDQuickDOS) def IDRDOS(self, t00s00): """returns True if T00S00 is Quick-DOS bootloader, or False otherwise""" - return find.at(0x00, t00s00, - b'\x01' - b'\xA9\x60' - b'\x8D\x01\x08' - b'\xA2\x00' - b'\xA0\x1F' - b'\xB9\x00\x08' - b'\x49') + return find.at(0x00, t00s00, kIDRDOS) def IDDOS33(self, t00s00): """returns True if T00S00 is DOS bootloader or some variation that can be safely boot traced, or False otherwise""" # Code at $0801 must be standard (with one exception) - if not find.wild_at(0x00, t00s00, - b'\x01' - b'\xA5\x27' - b'\xC9\x09' - b'\xD0\x18' - b'\xA5\x2B' - b'\x4A' - b'\x4A' - b'\x4A' - b'\x4A' - b'\x09\xC0' - b'\x85\x3F' - b'\xA9\x5C' - b'\x85\x3E' - b'\x18' - b'\xAD\xFE\x08' - b'\x6D\xFF\x08' + \ - find.WILDCARD + find.WILDCARD + find.WILDCARD + \ - b'\xAE\xFF\x08' - b'\x30\x15' - b'\xBD\x4D\x08' - b'\x85\x3D' - b'\xCE\xFF\x08' - b'\xAD\xFE\x08' - b'\x85\x27' - b'\xCE\xFE\x08' - b'\xA6\x2B' - b'\x6C\x3E\x00' - b'\xEE\xFE\x08' - b'\xEE\xFE\x08'): return False + if not find.wild_at(0x00, t00s00, kIDDOS33a): + return False # DOS 3.3 has JSR $FE89 / JSR $FE93 / JSR $FB2F # some Sierra have STA $C050 / STA $C057 / STA $C055 instead # with the unpleasant side-effect of showing text-mode garbage @@ -661,43 +591,53 @@ class BasePassportProcessor: # base class # main loop - loop through disk from track $22 down to track $00 for logical_track_num in range(0x22, -1, -1): self.g.track = logical_track_num # for display purposes only + self.g.logger.debug("Seeking to track %s" % hex(self.g.track)) + # distinguish between logical and physical track numbers to deal with # disks like Sunburst that store logical track 0x11+ on physical track 0x11.5+ physical_track_num = self.rwts.seek(logical_track_num) + # self.tracks must be indexed by physical track number so we can write out # .woz files correctly self.tracks[physical_track_num] = self.g.disk_image.seek(physical_track_num) - self.g.logger.debug("Seeking to track %s" % hex(self.g.track)) + tried_reseek = False + physical_sectors = OrderedDict() while True: - physical_sectors = self.rwts.decode_track(self.tracks[physical_track_num], logical_track_num, self.burn) + physical_sectors.update(self.rwts.decode_track(self.tracks[physical_track_num], logical_track_num, self.burn)) if self.rwts.enough(logical_track_num, physical_sectors): break + if supports_reseek and not tried_reseek: self.tracks[physical_track_num] = self.g.disk_image.reseek(physical_track_num) self.g.logger.debug("Reseeking to track %s" % hex(self.g.track)) tried_reseek = True continue + self.g.logger.debug("found %d sectors" % len(physical_sectors)) if (0x0F not in physical_sectors) and self.SkipTrack(logical_track_num, self.tracks[physical_track_num]): physical_sectors = None break + if self.g.tried_univ: if logical_track_num == 0x22 and (0x0F not in physical_sectors): self.g.logger.PrintByID("fail") self.g.logger.PrintByID("fatal220f") return False else: - # TODO wrong in case where we switch mid-track. - # Need to save the sectors that worked with the original RWTS - # then append the ones that worked with the universal RWTS - self.g.logger.PrintByID("switch", {"sector":0x0F}) # TODO find exact sector + transition_sector = 0x0F + if physical_sectors: + temp_logical_sectors = self.rwts.reorder_to_logical_sectors(physical_sectors) + transition_sector = min(temp_logical_sectors.keys()) + self.g.logger.PrintByID("switch", {"sector":transition_sector}) self.rwts = UniversalRWTS(self.g) self.g.tried_univ = True continue + if logical_track_num == 0 and type(self.rwts) != UniversalRWTSIgnoreEpilogues: self.rwts = UniversalRWTSIgnoreEpilogues(self.g) continue + self.g.logger.PrintByID("fail") return False self.save_track(physical_track_num, logical_track_num, physical_sectors) @@ -711,37 +651,14 @@ class BasePassportProcessor: # base class class Verify(BasePassportProcessor): def AnalyzeT00(self, logical_sectors): - self.g.is_boot1 = find.at(0x00, logical_sectors[1], - b'\x8E\xE9\xB7\x8E\xF7\xB7\xA9\x01' - b'\x8D\xF8\xB7\x8D\xEA\xB7\xAD\xE0' - b'\xB7\x8D\xE1\xB7\xA9\x02\x8D\xEC' - b'\xB7\xA9\x04\x8D\xED\xB7\xAC\xE7' - b'\xB7\x88\x8C\xF1\xB7\xA9\x01\x8D' - b'\xF4\xB7\x8A\x4A\x4A\x4A\x4A\xAA' - b'\xA9\x00\x9D\xF8\x04\x9D\x78\x04') - self.g.is_master = find.at(0x00, logical_sectors[1], - b'\x8E\xE9\x37\x8E\xF7\x37\xA9\x01' - b'\x8D\xF8\x37\x8D\xEA\x37\xAD\xE0' - b'\x37\x8D\xE1\x37\xA9\x02\x8D\xEC' - b'\x37\xA9\x04\x8D\xED\x37\xAC\xE7' - b'\x37\x88\x8C\xF1\x37\xA9\x01\x8D' - b'\xF4\x37\x8A\x4A\x4A\x4A\x4A\xAA' - b'\xA9\x00\x9D\xF8\x04\x9D\x78\x04') - self.g.is_rwts = find.wild_at(0x00, logical_sectors[7], - b'\x84\x48\x85\x49\xA0\x02\x8C' + find.WILDCARD + \ - find.WILDCARD + b'\xA0\x04\x8C' + find.WILDCARD + find.WILDCARD + b'\xA0\x01' + \ - b'\xB1\x48\xAA\xA0\x0F\xD1\x48\xF0' - b'\x1B\x8A\x48\xB1\x48\xAA\x68\x48' - b'\x91\x48\xBD\x8E\xC0\xA0\x08\xBD' - b'\x8C\xC0\xDD\x8C\xC0\xD0\xF6\x88' - b'\xD0\xF8\x68\xAA\xBD\x8E\xC0\xBD' - b'\x8C\xC0\xA0\x08\xBD\x8C\xC0\x48') + self.g.is_boot1 = find.at(0x00, logical_sectors[1], kIDBoot1) + self.g.is_master = find.at(0x00, logical_sectors[1], kIDMaster) + self.g.is_rwts = find.wild_at(0x00, logical_sectors[7], kIDRWTS) def save_track(self, physical_track_num, logical_track_num, physical_sectors): if not physical_sectors: return {} logical_sectors = self.rwts.reorder_to_logical_sectors(physical_sectors) - should_run_patchers = (len(physical_sectors) == 16) # TODO - if should_run_patchers: + if self.rwts.enough(logical_track_num, physical_sectors): # patchers operate on logical tracks if logical_track_num == 0: # set additional globals for patchers to use diff --git a/passport/constants.py b/passport/constants.py index e03f7f6..2e57389 100644 --- a/passport/constants.py +++ b/passport/constants.py @@ -1,5 +1,94 @@ from passport.util import * +kIDBoot1 = bytes.fromhex( + "8E E9 B7" + "8E F7 B7" + "A9 01" + "8D F8 B7" + "8D EA B7" + "AD E0 B7" + "8D E1 B7" + "A9 02" + "8D EC B7" + "A9 04" + "8D ED B7" + "AC E7 B7" + "88" + "8C F1 B7" + "A9 01" + "8D F4 B7" + "8A" + "4A" + "4A" + "4A" + "4A" + "AA" + "A9 00" + "9D F8 04" + "9D 78 04") + +kIDMaster = bytes.fromhex( + "8E E9 37" + "8E F7 37" + "A9 01" + "8D F8 37" + "8D EA 37" + "AD E0 37" + "8D E1 37" + "A9 02" + "8D EC 37" + "A9 04" + "8D ED 37" + "AC E7 37" + "88" + "8C F1 37" + "A9 01" + "8D F4 37" + "8A" + "4A" + "4A" + "4A" + "4A" + "AA" + "A9 00" + "9D F8 04" + "9D 78 04") + +kIDRWTS = bytes.fromhex( + "84 48" + "85 49" + "A0 02" + "8C" + find.WILDSTR + find.WILDSTR + \ + "A0 04" + "8C" + find.WILDSTR + find.WILDSTR + \ + "A0 01" + "B1 48" + "AA" + "A0 0F" + "D1 48" + "F0 1B" + "8A" + "48" + "B1 48" + "AA" + "68" + "48" + "91 48" + "BD 8E C0" + "A0 08" + "BD 8C C0" + "DD 8C C0" + "D0 F6" + "88" + "D0 F8" + "68" + "AA" + "BD 8E C0" + "BD 8C C0" + "A0 08" + "BD 8C C0" + "48") + kIDDiversiDOSBootloader = bytes.fromhex("B3 A3 A0 D2 CF D2 D2 C5 8D 87 8D") kIDProDOSBootloader = bytes.fromhex( @@ -20,3 +109,89 @@ kIDPascalBootloader2 = bytes.fromhex( "B0 04" # BCS +4 "E0 40" # CPX #$40 "B0") # BCS + +kIDDavidDOS1 = bytes.fromhex( + "A5 27" + "C9 09" + "D0 17") + +kIDDavidDOS2 = bytes.fromhex( + "A2" + find.WILDSTR + \ + "BD" + find.WILDSTR + " 08" + \ + "9D" + find.WILDSTR + " 04" + \ + "CA" + "10 F7") + +kIDDatasoft = bytes.fromhex( + "01 4C 7E 08 04 8A 0C B8" + "00 56 10 7A 00 00 1A 16" + "12 0E 0A 06 53 18 9A 02" + "10 1B 02 10 4D 56 15 0B" + "BF 14 14 54 54 54 92 81" + "1B 10 10 41 06 73 0A 10" + "33 4E 00 73 12 10 33 7C" + "00 11 20 E3 49 50 73 1A" + "10 41 00 23 80 5B 0A 10" + "0B 4E 9D 0A 10 9D 0C 10" + "60 1E 53 10 90 53 BC 90" + "53 00 90 D8 52 00 D8 7C" + "00 53 80 0B 06 41 00 09" + "04 45 0C 63 04 90 94 D0" + "D4 23 04 91 A1 EB CD 06" + "95 A1 E1 98 97 86") + +kIDMicrograms1 = bytes.fromhex( + "A5 27" + "C9 09" + "D0 12" + "A9 C6" + "85 3F") + +kIDMicrograms2 = bytes.fromhex("4C 00") + +kIDQuickDOS = bytes.fromhex( + "A5 27" + "C9 09" + "D0 27" + "78" + "AD 83 C0") + +kIDRDOS = bytes.fromhex( + "01" + "A9 60" + "8D 01 08" + "A2 00" + "A0 1F" + "B9 00 08" + "49") + +kIDDOS33a = bytes.fromhex( + "01" + "A5 27" + "C9 09" + "D0 18" + "A5 2B" + "4A" + "4A" + "4A" + "4A" + "09 C0" + "85 3F" + "A9 5C" + "85 3E" + "18" + "AD FE 08" + "6D FF 08" + \ + find.WILDSTR + find.WILDSTR + find.WILDSTR + \ + "AE FF 08" + "30 15" + "BD 4D 08" + "85 3D" + "CE FF 08" + "AD FE 08" + "85 27" + "CE FE 08" + "A6 2B" + "6C 3E 00" + "EE FE 08" + "EE FE 08")