MECC and Laureate support

This commit is contained in:
4am 2018-07-06 18:35:57 -04:00
parent 64bf4e237a
commit 6b54b035cf
8 changed files with 297 additions and 11 deletions

View File

@ -3,6 +3,7 @@
from passport import eddimage, wozimage from passport import eddimage, wozimage
from passport import DefaultLogger, DebugLogger from passport import DefaultLogger, DebugLogger
from passport import Crack, Verify, EDDToWoz from passport import Crack, Verify, EDDToWoz
from passport.strings import STRINGS
import os.path import os.path
import sys import sys

View File

@ -64,10 +64,7 @@ class PassportGlobals:
self.possible_gamco = False self.possible_gamco = False
self.is_optimum = False self.is_optimum = False
self.is_mecc_fastloader = False self.is_mecc_fastloader = False
self.is_mecc1 = False self.mecc_variant = 0
self.is_mecc2 = False
self.is_mecc3 = False
self.is_mecc4 = False
self.possible_d5d5f7 = False self.possible_d5d5f7 = False
self.is_8b3 = False self.is_8b3 = False
self.is_milliken1 = False self.is_milliken1 = False
@ -355,6 +352,7 @@ class Track00RWTS(UniversalRWTSIgnoreEpilogues):
class DOS33RWTS(RWTS): class DOS33RWTS(RWTS):
def __init__(self, logical_sectors, g): def __init__(self, logical_sectors, g):
self.g = g
self.reset(logical_sectors) self.reset(logical_sectors)
RWTS.__init__(self, RWTS.__init__(self,
g, g,
@ -495,6 +493,66 @@ class BECARWTS(DOS33RWTS):
return True return True
return DOS33RWTS.verify_data_epilogue_at_point(self, track, track_num, physical_sector_num) return DOS33RWTS.verify_data_epilogue_at_point(self, track, track_num, physical_sector_num)
class LaureateRWTS(DOS33RWTS):
# nibble table is in T00,S06
# address prologue is T00,S05 A$55,A$5F,A$6A
# address epilogue is T00,S05 A$91,A$9B
# data prologue is T00,S04 A$E7,A$F1,A$FC
# data epilogue is T00,S05 A$35,A$3F
def reset(self, logical_sectors):
self.address_prologue = (logical_sectors[5][0x55],
logical_sectors[5][0x5F],
logical_sectors[5][0x6A])
self.address_epilogue = (logical_sectors[5][0x91],
logical_sectors[5][0x9B])
self.data_prologue = (logical_sectors[4][0xE7],
logical_sectors[4][0xF1],
logical_sectors[4][0xFC])
self.data_epilogue = (logical_sectors[5][0x35],
logical_sectors[5][0x3F])
self.nibble_translate_table = {}
for nibble in range(0x96, 0x100):
self.nibble_translate_table[nibble] = logical_sectors[6][nibble]
class MECCRWTS(DOS33RWTS):
# MECC fastloaders
def __init__(self, mecc_variant, logical_sectors, g):
g.mecc_variant = mecc_variant
DOS33RWTS.__init__(self, logical_sectors, g)
def reset(self, logical_sectors):
self.nibble_translate_table = self.kDefaultNibbleTranslationTable16
self.address_epilogue = (0xDE, 0xAA)
self.data_epilogue = (0xDE, 0xAA)
if self.g.mecc_variant == 1:
self.address_prologue = (logical_sectors[0x0B][0x08],
logical_sectors[0x0B][0x12],
logical_sectors[0x0B][0x1D])
self.data_prologue = (logical_sectors[0x0B][0x8F],
logical_sectors[0x0B][0x99],
logical_sectors[0x0B][0xA3])
elif self.g.mecc_variant == 2:
self.address_prologue = (logical_sectors[7][0x83],
logical_sectors[7][0x8D],
logical_sectors[7][0x98])
self.data_prologue = (logical_sectors[7][0x15],
logical_sectors[7][0x1F],
logical_sectors[7][0x2A])
elif self.g.mecc_variant == 3:
self.address_prologue = (logical_sectors[0x0A][0xE8],
logical_sectors[0x0A][0xF2],
logical_sectors[0x0A][0xFD])
self.data_prologue = (logical_sectors[0x0B][0x6F],
logical_sectors[0x0B][0x79],
logical_sectors[0x0B][0x83])
elif self.g.mecc_variant == 4:
self.address_prologue = (logical_sectors[8][0x83],
logical_sectors[8][0x8D],
logical_sectors[8][0x98])
self.data_prologue = (logical_sectors[8][0x15],
logical_sectors[8][0x1F],
logical_sectors[8][0x2A])
class BasePassportProcessor: # base class class BasePassportProcessor: # base class
def __init__(self, disk_image, logger_class=DefaultLogger): def __init__(self, disk_image, logger_class=DefaultLogger):
self.g = PassportGlobals() self.g = PassportGlobals()
@ -516,10 +574,10 @@ class BasePassportProcessor: # base class
bademu2.BadEmu2Patcher, bademu2.BadEmu2Patcher,
rwts.RWTSPatcher, rwts.RWTSPatcher,
#RWTSLogPatcher, #RWTSLogPatcher,
#MECC1Patcher, mecc1.MECC1Patcher,
#MECC2Patcher, mecc2.MECC2Patcher,
#MECC3Patcher, mecc3.MECC3Patcher,
#MECC4Patcher, mecc4.MECC4Patcher,
#ROL1EPatcher, #ROL1EPatcher,
#JSRBB03Patcher, #JSRBB03Patcher,
#DavidBB03Patcher, #DavidBB03Patcher,
@ -775,6 +833,127 @@ class BasePassportProcessor: # base class
b'\xAD\xCB\xB5' b'\xAD\xCB\xB5'
b'\x85\x42') b'\x85\x42')
def IDLaureate(self, t00s00):
"""returns True if T00S00 is Laureate bootloader, or False otherwise"""
if not find.at(0x2E, t00s00,
b'\xAE\xFF\x08'
b'\x30\x1E'
b'\xE0\x02'
b'\xD0\x05'
b'\xA9\xBF'
b'\x8D\xFE\x08'): return False
return find.at(0xF8, t00s00,
b'\x4C\x00\xB7'
b'\x00\x00\x00\xFF\x0B')
def IDMECC(self, t00s00):
"""returns True if T00S00 is MECC bootloader, or False otherwise"""
return find.at(0x00, t00s00,
b'\x01'
b'\x4C\x1A\x08'
b'\x17\x0F\x00'
b'\x00\x0D\x0B\x09\x07\x05\x03\x01'
b'\x0E\x0C\x0A\x08\x06\x04\x02\x0F')
def IDMECCVariant(self, logical_sectors):
"""returns int (1-4) of MECC bootloader variant, or 0 if no known variant is detected"""
# variant 1 (labeled "M8" on original disks)
if find.wild_at(0x02, logical_sectors[0x0B],
b'\xBD\x8C\xC0'
b'\x10\xFB'
b'\xC9' + find.WILDCARD + \
b'\xD0\xEF'
b'\xEA'
b'\xBD\x8C\xC0'
b'\x10\xFB'
b'\xC9' + find.WILDCARD + \
b'\xD0\xE5'
b'\xA0\x03'
b'\xBD\x8C\xC0'
b'\x10\xFB'
b'\xC9'):
if find.wild_at(0x89, logical_sectors[0x0B],
b'\xBD\x8C\xC0'
b'\x10\xFB'
b'\xC9' + find.WILDCARD + \
b'\xD0\xF4'
b'\xEA'
b'\xBD\x8C\xC0'
b'\x10\xFB'
b'\xC9' + find.WILDCARD + \
b'\xD0\xF2'
b'\xEA'
b'\xBD\x8C\xC0'
b'\x10\xFB'
b'\xC9'):
return 1
# variant 2 (labeled "M7" on original disks)
m7a = b'\xBD\x8C\xC0' \
b'\x10\xFB' \
b'\xC9' + find.WILDCARD + \
b'\xD0\xF0' \
b'\xEA' \
b'\xBD\x8C\xC0' \
b'\x10\xFB' \
b'\xC9' + find.WILDCARD + \
b'\xD0\xF2' \
b'\xA0\x03' \
b'\xBD\x8C\xC0' \
b'\x10\xFB' \
b'\xC9'
m7b = b'\xBD\x8C\xC0' \
b'\x10\xFB' \
b'\x49'
m7c = b'\xEA' \
b'\xBD\x8C\xC0' \
b'\x10\xFB' \
b'\xC9' + find.WILDCARD + \
b'\xD0\xF2' \
b'\xA0\x56' \
b'\xBD\x8C\xC0' \
b'\x10\xFB' \
b'\xC9'
if find.wild_at(0x7D, logical_sectors[7], m7a):
if find.at(0x0F, logical_sectors[7], m7b):
if find.wild_at(0x18, logical_sectors[7], m7c):
return 2
# variant 3 ("M7" variant found in Word Muncher 1.1 and others)
if find.wild_at(0xE2, logical_sectors[0x0A],
b'\xBD\x8C\xC0'
b'\x10\xFB'
b'\xC9' + find.WILDCARD + \
b'\xD0\xEF'
b'\xEA'
b'\xBD\x8C\xC0'
b'\x10\xFB'
b'\xC9' + find.WILDCARD + \
b'\xD0\xF2'
b'\xA0\x03'
b'\xBD\x8C\xC0'
b'\x10\xFB'
b'\xC9'):
if find.wild_at(0x69, logical_sectors[0x0B],
b'\xBD\x8C\xC0'
b'\x10\xFB'
b'\xC9' + find.WILDCARD + \
b'\xD0\xF4'
b'\xEA'
b'\xBD\x8C\xC0'
b'\x10\xFB'
b'\xC9' + find.WILDCARD + \
b'\xD0\xF2'
b'\xEA'
b'\xBD\x8C\xC0'
b'\x10\xFB'
b'\xC9'):
return 3
# variant 4 (same as variant 2 but everything is on sector 8 instead of 7)
if find.wild_at(0x7D, logical_sectors[8], m7a):
if find.at(0x0F, logical_sectors[8], m7b):
if find.wild_at(0x18, logical_sectors[8], m7c):
return 2
return 0 # unknown variant
def IDBootloader(self, t00): def IDBootloader(self, t00):
"""returns RWTS object that can (hopefully) read the rest of the disk""" """returns RWTS object that can (hopefully) read the rest of the disk"""
temporary_rwts_for_t00 = Track00RWTS(self.g) temporary_rwts_for_t00 = Track00RWTS(self.g)
@ -783,6 +962,7 @@ class BasePassportProcessor: # base class
self.g.logger.PrintByID("fatal0000") self.g.logger.PrintByID("fatal0000")
return None return None
t00s00 = physical_sectors[0].decoded t00s00 = physical_sectors[0].decoded
logical_sectors = temporary_rwts_for_t00.reorder_to_logical_sectors(physical_sectors)
if self.IDDOS33(t00s00): if self.IDDOS33(t00s00):
self.g.is_boot0 = True self.g.is_boot0 = True
@ -792,14 +972,22 @@ class BasePassportProcessor: # base class
self.g.logger.PrintByID("prontodos") self.g.logger.PrintByID("prontodos")
else: else:
self.g.logger.PrintByID("dos33boot0") self.g.logger.PrintByID("dos33boot0")
logical_sectors = temporary_rwts_for_t00.reorder_to_logical_sectors(physical_sectors)
if border.BorderPatcher(self.g).run(logical_sectors, 0): if border.BorderPatcher(self.g).run(logical_sectors, 0):
return BorderRWTS(logical_sectors, self.g) return BorderRWTS(logical_sectors, self.g)
return self.TraceDOS33(logical_sectors) return self.TraceDOS33(logical_sectors)
# TODO JSR08B3 # TODO JSR08B3
if self.IDMECC(t00s00):
self.g.is_mecc_fastloader = True
self.g.logger.PrintByID("mecc")
mecc_variant = self.IDMECCVariant(logical_sectors)
self.g.logger.debug("mecc_variant = %d" % mecc_variant)
if mecc_variant:
return MECCRWTS(mecc_variant, logical_sectors, self.g)
# TODO MECC fastloader # TODO MECC fastloader
# TODO DOS 3.3P # TODO DOS 3.3P
# TODO Laureate if self.IDLaureate(t00s00):
self.g.logger.PrintByID("laureate")
return LaureateRWTS(logical_sectors, self.g)
# TODO Electronic Arts # TODO Electronic Arts
# TODO DOS 3.2 # TODO DOS 3.2
# TODO IDEncoded44 # TODO IDEncoded44

View File

@ -8,6 +8,10 @@ __all__ = [
"bootcounter", "bootcounter",
"border", "border",
"d5d5f7", "d5d5f7",
"mecc1",
"mecc2",
"mecc3",
"mecc4",
"microfun", "microfun",
"rwts", "rwts",
"universale7", "universale7",

View File

@ -0,0 +1,23 @@
from passport.patchers import Patch, Patcher
from passport.util import *
class MECC1Patcher(Patcher):
"""MECC fastloader variant 1
tested on
- A-153 Word Munchers 1.4
"""
def should_run(self, track_num):
return self.g.mecc_variant == 1 and track_num == 0
def run(self, logical_sectors, track_num):
patches = []
for a, x, v in ((0x0B, 0x08, b'\xD5'),
(0x0B, 0x12, b'\xAA'),
(0x0B, 0x1D, b'\x96'),
(0x0B, 0x8F, b'\xD5'),
(0x0B, 0x99, b'\xAA'),
(0x0B, 0xA3, b'\xAD')):
if logical_sectors[a][x] != v[0]:
patches.append(Patch(0, a, x, v))
return patches

View File

@ -0,0 +1,25 @@
from passport.patchers import Patch, Patcher
from passport.util import *
class MECC2Patcher(Patcher):
"""MECC fastloader variant 2
tested on
- A-175 Phonics Prime Time - Initial Consonants 1.0
- A-176 Phonics Prime Time - Final Consonants 1.0
- A-179 Phonics Prime Time - Blends and Digraphs 1.0
"""
def should_run(self, track_num):
return self.g.mecc_variant == 2 and track_num == 0
def run(self, logical_sectors, track_num):
patches = []
for a, x, v in ((7, 0x83, b'\xD5'),
(7, 0x8D, b'\xAA'),
(7, 0x98, b'\x96'),
(7, 0x15, b'\xD5'),
(7, 0x1F, b'\xAA'),
(7, 0x2A, b'\xAD')):
if logical_sectors[a][x] != v[0]:
patches.append(Patch(0, a, x, v))
return patches

View File

@ -0,0 +1,23 @@
from passport.patchers import Patch, Patcher
from passport.util import *
class MECC3Patcher(Patcher):
"""MECC fastloader variant 3
tested on
- A-153 Word Munchers 1.1
"""
def should_run(self, track_num):
return self.g.mecc_variant == 3 and track_num == 0
def run(self, logical_sectors, track_num):
patches = []
for a, x, v in ((0x0A, 0xE8, b'\xD5'),
(0x0A, 0xF2, b'\xAA'),
(0x0A, 0xFD, b'\x96'),
(0x0B, 0x6F, b'\xD5'),
(0x0B, 0x79, b'\xAA'),
(0x0B, 0x83, b'\xAD')):
if logical_sectors[a][x] != v[0]:
patches.append(Patch(0, a, x, v))
return patches

View File

@ -0,0 +1,22 @@
from passport.patchers import Patch, Patcher
from passport.util import *
class MECC4Patcher(Patcher):
"""MECC fastloader variant 4
tested on
"""
def should_run(self, track_num):
return self.g.mecc_variant == 4 and track_num == 0
def run(self, logical_sectors, track_num):
patches = []
for a, x, v in ((8, 0x83, b'\xD5'),
(8, 0x8D, b'\xAA'),
(8, 0x98, b'\x96'),
(8, 0x15, b'\xD5'),
(8, 0x1F, b'\xAA'),
(8, 0x2A, b'\xAD')):
if logical_sectors[a][x] != v[0]:
patches.append(Patch(0, a, x, v))
return patches

View File

@ -1,5 +1,5 @@
STRINGS = { STRINGS = {
"header": "Passport.py by 4am (2018-06-06)\n", # max 32 characters "header": "Passport.py by 4am (2018-07-03)\n", # max 32 characters
"reading": "Reading from {filename}\n", "reading": "Reading from {filename}\n",
"diskrwts": "Using disk's own RWTS\n", "diskrwts": "Using disk's own RWTS\n",
"bb00": "T00,S05 Found $BB00 protection check\n" "bb00": "T00,S05 Found $BB00 protection check\n"