From 9351898fb5d883ec25aa2e787b7aa0b32a8f8f7e Mon Sep 17 00:00:00 2001 From: Elliot Nunn Date: Fri, 23 Aug 2019 19:01:56 +0800 Subject: [PATCH] Patch ATALoad to boot from driver-less disks Unreliable: currently this only works on QEMU --- ATALoad.a | 281 ++++++++++++++++++++++++++++++++++++++++++++++++ ATALoad.dmp | 194 +++++++++++++++++++++++++++++++++ DRVR_53_ATADisk | Bin 0 -> 17254 bytes ataboot.py | 100 +++++++++++++++++ 4 files changed, 575 insertions(+) create mode 100644 ATALoad.a create mode 100644 ATALoad.dmp create mode 100644 DRVR_53_ATADisk create mode 100755 ataboot.py diff --git a/ATALoad.a b/ATALoad.a new file mode 100644 index 0000000..9e889ea --- /dev/null +++ b/ATALoad.a @@ -0,0 +1,281 @@ +; Asm ATALoad.a -o ATALoad.a.o; DumpObj ATALoad.a.o > ATALoad.dmp +; The python script does the rest. +; This is messy and brittle. I got very, very sick of it! + + MAIN + MACHINE MC68030 + + lea $10(sp),a0 ; re-push the 12 bytes of arguments onto the stack + move.l -(a0),-(sp) + move.l -(a0),-(sp) + move.l -(a0),-(sp) + bsr.s OriginalFunc ; ... and call the function + add.l #$C,sp ; pop those copied arguments, we don't need them + + cmp.l #$FFFFDB93,d0 ; ATANoDriverErr -> try our method + beq.s NewFunc + cmp.l #$FFFFDB92,d0 ; ATANoDDMErr -> try our method + beq.s NewFunc + rts ; don't try our method + + +OriginalFunc + string asis + dc.b 'Nsrt' ; placeholder for script to insert the clobbered LINK instruction + bra *+2+'ID' ; placeholder for script to jump to remainder of original function + + + +var_regs equ -$4FA + +ataPB equ -$4DA ; to +ataPBQType equ -$4D6 +ataPBVers equ -$4D4 +ataPBReserved2 equ -$4CE +ataPBFunctionCode equ -$4C8 +ataPBIOSpeed equ -$4C7 +ataPBFlags equ -$4C6 +ataPBDeviceID equ -$4C2 +ataPBTimeOut equ -$4BE +ataPBState equ -$4B2 + +; common part of PB ends at offset $30 = -$4AA +; this part below is a bit tricky... + +ataPB34 equ -$4A6 ; 34 +ataPB38 equ -$4A2 ; 38 +ataPB3C equ -$49E ; 3c +ataPB40 equ -$49A ; 40 + +; -492...-48A = "task file" + +ataPBTaskFile_ataTFCount equ -$491 +ataPBTaskFile_ataTFSDH equ -$48C +ataPBTaskFile_ataTFCommand equ -$48B + +; entire PB ends at offset $30 = -$4AA + +; max possible PB size ends at $B8 = -$422 + +var_bstruct_0 equ -$422 +var_bstruct_2 equ -$420 +var_bstruct_4 equ -$41E +var_bstruct_6 equ -$41C + +var_ddmidx equ -$41A +var_drvrcnt equ -$418 +var_arg2 equ -$40E +var_ddmptr equ -$40C + +var_buf1 equ -$408 +var_buf2 equ -$208 + +var_flags equ -8 +var_4 equ -4 + +arg_dev equ 8 +arg_ddtype equ $C ; a long +arg_romdrvr equ $10 + + +NewFunc + link a6,#-$4DA + movem.l d3-d7/a2-a4,-(sp) + + +; Wipe the stack frame to be safe + lea -$4DA(A6),A0 +@lup clr.w (A0)+ + cmp.l A0,A6 + bne.s @lup + +; Check that we are asked for an ATA driver + cmp.l #$00000701,arg_ddtype(a6) ; kDriverTypeMacATA + bne itr_fail + +; Load the actual working driver + move.w #$FFFF,$B9E ; temp ROMMapInsert + move.l #'DRVR',-(SP) + move.w #53,-(SP) ; .ATADisk + dc.w $A9A0 + movea.l (SP)+,A2 + tst.l A2 + beq itr_fail + movea.l (A2),A2 + +; Set pointers to the 512-byte scratch buffer and the param block + lea var_buf1(a6),a3 + lea ataPB(a6),a4 + +; Set bit 31 ("RAM based driver at run time") in the d5 passed to DRVR + move.l #0,var_flags(a6) + tst.b arg_romdrvr+3(a6) + bne.s is_romdrvr + ori.b #$80,var_flags(a6) ; set the flag +is_romdrvr: + +; Get the "IDENTIFY DEVICE" block with CHS information + move.l #0, $00(a4) ; ataPBLink + move.w #0, $04(a4) ; ataPBQType + move.b #2, $06(a4) ; --> ataPBVers + move.b #0, $13(a4) ; --> ataPBIOSpeed + move.w arg_dev+2(a6),d1 + ext.l d1 + move.l d1, $18(a4) ; --> ataPBDeviceID + move.l #0, $08(a4) ; ? ataPBReserved2 + move.l #20000,$1C(a4) ; --> ataPBTimeOut + move.b #$13, $12(a4) ; --> ataPBFunctionCode = kATAMgrDriveIdentify + move.w #$2000,$14(a4) ; --> ataPBFlags = mATAFlagIORead + move.w #0, $28(a4) ; ? ataPBState + move.l a3, $38(a4) ; ataPBBuffer + + sub.l #2,sp + move.l a4,-(sp) + dc.w $AAF1 ; ATAManager + move.w (sp)+,d0 + ext.l d0 + bne itr_return + +; Parse the "IDENTIFY DEVICE" block + move.w 2(a3),var_bstruct_0(a6) ; typically 1041 + move.w 6(a3),var_bstruct_2(a6) ; typically 0010 + move.w $C(a3),var_bstruct_4(a6) ; typically 003f + move.w var_bstruct_2(a6),d0 ; can't safely get rid of these for some reason! + mulu.w var_bstruct_4(a6),d0 + move.w d0,var_bstruct_6(a6) + +; Send "Init drive parameters" + move.b #$1, $12(a4) ; --> ataPBFunctionCode = IO (not in headers) + move.w #0, $14(a4) ; --> ataPBFlags + move.w #0, $28(a4) ; ? ataPBState + move.b #$91, $48+$7(a4) ; ataPBTaskFile.ataTFCommand = kATAcmdInitDrive + move.l arg_dev(a6),d0 ; (leaving bit $40 as zero for CHS) + lsr.l #4,d0 + and.l #$10,d0 ; master/slave bit + or.l #$A0,d0 ; sector size ? 512 + move.w var_bstruct_2(a6),d1 + sub.w #1,d1 + or.w d1,d0 ; head number + move.b d0, $48+$6(a4) ; ataPBTaskFile.ataTFSDH + move.b var_bstruct_4+1(a6),$48+$1(a4); ataPBTaskFile.ataTFCount + + sub.l #2,sp + move.l a4,-(sp) + dc.w $AAF1 ; ATAManager + move.w (sp)+,d0 + +; Loop over all partitions, ask the driver to pick a bootable one + move.w #$2000,ataPBFlags(a6) + move.l #$200,ataPB34(a6) + move.b #$20,ataPBTaskFile_ataTFCommand(a6) + move.l #1,d5 ; Initially check only one partition, increase this number later + moveq #0,d6 ; Partition index counter +tellDriverAboutPartitionLoop: + + move.l d6,d0 + addq.l #1,d6 + cmp.l d0,d5 + bcs.s itr_fail + move.l a3,ataPB38(a6) + move.l #$200,ataPB3C(a6) + move.b #1,ataPBTaskFile_ataTFCount(a6) + pea var_bstruct_0(a6) + move.l d6,-(sp) + pea ataPB(a6) + bsr paramblk_helper_function + subq.l #2,sp + pea ataPB(a6) + dc.w $AAF1 ;;;;;;;;;;;;;;;;;;;;;;;;; kATAcmdRead again (get next PM entry) + move.w (sp)+,d7 + lea $C(sp),sp + moveq #0,d0 + move.w (a3),d0 + cmpi.l #'PM',d0 + bne.s tellDriverAboutPartitionLoop + move.l 4(a3),d5 ; update the *real* number of partitions, so we don't end early + move.l var_flags(a6),-(sp) ; var_flags, obviously + move.w var_arg2(a6),d0 + ext.l d0 + move.l d0,-(sp) ; arg_dev+2 extended to a long, pretty much always zero + move.l a3,-(sp) ; pointer to this partition map entry + move.l a2,-(sp) ; pointer to driver + bsr *+2+'BT' ; BOOT function + move.l d0,d4 + + lea $10(sp),sp + move.w d4,d7 ; -1 means try a different partition, 0 means succes, otherwise error + cmpi.w #$FFFF,d7 + beq.s tellDriverAboutPartitionLoop + + tst.w d7 + bne.s itr_fail + + move.l d4,d0 ; the final pathway for success + bra.s itr_return + +itr_fail: + move.l #$FFFFDB93,d0 ; ATANoDriverErr + +itr_return: + movem.l var_regs(a6),d3-d7/a2-a4 + unlk a6 + rts + + +paramblk_helper_function: + link a6,#0 + movem.l d6-d7/a3-a4,-(sp) + move.l $C(a6),d7 + movea.l $10(a6),a3 + movea.l $8(a6),a4 + move.l $18(a4),d0 + lsr.l #8,d0 + moveq #1,d6 + and.l d0,d6 + clr.w $28(a4) + moveq #0,d0 + move.w 6(a3),d0 + move.l d7,d1 + divu.l d0,d1 + move.w d1,$4C(a4) + moveq #0,d0 + move.w 4(a3),d0 + move.l d7,d1 + divu.l d0,d1 + moveq #0,d0 + move.w 2(a3),d0 + tst.l d0 + tdivs.l d0,d2:d1 + moveq #$F,d0 + and.l d2,d0 + move.b d0,$4E(a4) + move.l d6,d0 + lsl.l #4,d0 + or.b d0,$4E(a4) + ori.b #$A0,$4E(a4) + moveq #0,d0 + move.w 4(a3),d0 + move.l d7,d1 + tdivu.l d0,d2:d1 + addq.b #1,d2 + move.b d2,$4A(a4) + movem.l -$10(a6),d6-d7/a3-a4 + unlk a6 + rts + + + string c +mystring dc.b 'log from ATALoad ^n' +PrintHex ; A0 is already set to a number... + MOVE.L #4, D1 ; r4 arg (1: byte, 2: 2byte, else: 4byte) + MOVE.L #97, D0 ; call NKPrintHex + DC.W $FE1F + + LEA mystring,A0 + MOVE.L #96, D0 ; call NKXprintf + DC.W $FE1F + + RTS ; stack is safe! + + + END diff --git a/ATALoad.dmp b/ATALoad.dmp new file mode 100644 index 0000000..c79df73 --- /dev/null +++ b/ATALoad.dmp @@ -0,0 +1,194 @@ + +First: Flags=0 Version=2 + +Dictionary: Flags $00 FirstId 1 + 1: #0001 + 2: Main +Pad + + + +Module: Flags=$10=(Main Local Code) Module="#0001"(1) Segment="Main"(2) + +Content: Flags $08 +Contents offset $0000 size $0236 +00000000: 41EF 0010 'A...' LEA $0010(A7),A0 +00000004: 2F20 '/ ' MOVE.L -(A0),-(A7) +00000006: 2F20 '/ ' MOVE.L -(A0),-(A7) +00000008: 2F20 '/ ' MOVE.L -(A0),-(A7) +0000000A: 6116 'a.' BSR.S *+$0018 ; 00000022 +0000000C: DEFC 000C '....' ADDA.W #$000C,A7 +00000010: 0C80 FFFF DB93 '......' CMPI.L #$FFFFDB93,D0 +00000016: 6712 'g.' BEQ.S *+$0014 ; 0000002A +00000018: 0C80 FFFF DB92 '......' CMPI.L #$FFFFDB92,D0 +0000001E: 670A 'g.' BEQ.S *+$000C ; 0000002A +00000020: 4E75 'Nu' RTS +00000022: 4E73 'Ns' RTE +00000024: 7274 'rt' MOVEQ #$74,D1 ; 't' +00000026: 6000 4944 '`.ID' BRA *+$4946 ; 0000496C +0000002A: 4E56 FB26 'NV.&' LINK A6,#$FB26 +0000002E: 48E7 1F38 'H..8' MOVEM.L D3-D7/A2-A4,-(A7) +00000032: 41EE FB26 'A..&' LEA -$04DA(A6),A0 +00000036: 4258 'BX' CLR.W (A0)+ +00000038: BDC8 '..' CMPA.L A0,A6 +0000003A: 66FA 'f.' BNE.S *-$0004 ; 00000036 +0000003C: 0CAE 0000 0701 '......' CMPI.L #$00000701,$000C(A6) + 000C +00000044: 6600 0164 'f..d' BNE *+$0166 ; 000001AA +00000048: 31FC FFFF 0B9E '1.....' MOVE.W #$FFFF,$0B9E +0000004E: 2F3C 4452 5652 '/.' MOVE.W (A7)+,D7 +0000016C: 4FEF 000C 'O...' LEA $000C(A7),A7 +00000170: 7000 'p.' MOVEQ #$00,D0 +00000172: 3013 '0.' MOVE.W (A3),D0 +00000174: 0C80 0000 504D '....PM' CMPI.L #$0000504D,D0 +0000017A: 66BE 'f.' BNE.S *-$0040 ; 0000013A +0000017C: 2A2B 0004 '*+..' MOVE.L $0004(A3),D5 +00000180: 2F2E FFF8 '/...' MOVE.L -$0008(A6),-(A7) +00000184: 302E FBF2 '0...' MOVE.W -$040E(A6),D0 +00000188: 48C0 'H.' EXT.L D0 +0000018A: 2F00 '/.' MOVE.L D0,-(A7) +0000018C: 2F0B '/.' MOVE.L A3,-(A7) +0000018E: 2F0A '/.' MOVE.L A2,-(A7) +00000190: 6100 4254 'a.BT' BSR *+$4256 ; 000043E6 +00000194: 2800 '(.' MOVE.L D0,D4 +00000196: 4FEF 0010 'O...' LEA $0010(A7),A7 +0000019A: 3E04 '>.' MOVE.W D4,D7 +0000019C: 0C47 FFFF '.G..' CMPI.W #$FFFF,D7 +000001A0: 6798 'g.' BEQ.S *-$0066 ; 0000013A +000001A2: 4A47 'JG' TST.W D7 +000001A4: 6604 'f.' BNE.S *+$0006 ; 000001AA +000001A6: 2004 ' .' MOVE.L D4,D0 +000001A8: 6006 '`.' BRA.S *+$0008 ; 000001B0 +000001AA: 203C FFFF DB93 ' <....' MOVE.L #$FFFFDB93,D0 +000001B0: 4CEE 1CF8 FB06 'L.....' MOVEM.L -$04FA(A6),D3-D7/A2-A4 +000001B6: 4E5E 'N^' UNLK A6 +000001B8: 4E75 'Nu' RTS +000001BA: 4E56 0000 'NV..' LINK A6,#$0000 +000001BE: 48E7 0318 'H...' MOVEM.L D6/D7/A3/A4,-(A7) +000001C2: 2E2E 000C '....' MOVE.L $000C(A6),D7 +000001C6: 266E 0010 '&n..' MOVEA.L $0010(A6),A3 +000001CA: 286E 0008 '(n..' MOVEA.L $0008(A6),A4 +000001CE: 202C 0018 ' ,..' MOVE.L $0018(A4),D0 +000001D2: E088 '..' LSR.L #$8,D0 +000001D4: 7C01 '|.' MOVEQ #$01,D6 +000001D6: CC80 '..' AND.L D0,D6 +000001D8: 426C 0028 'Bl.(' CLR.W $0028(A4) +000001DC: 7000 'p.' MOVEQ #$00,D0 +000001DE: 302B 0006 '0+..' MOVE.W $0006(A3),D0 +000001E2: 2207 '".' MOVE.L D7,D1 +000001E4: 4C40 1001 'L@..' DIVU.L D0,D1 +000001E8: 3941 004C '9A.L' MOVE.W D1,$004C(A4) +000001EC: 7000 'p.' MOVEQ #$00,D0 +000001EE: 302B 0004 '0+..' MOVE.W $0004(A3),D0 +000001F2: 2207 '".' MOVE.L D7,D1 +000001F4: 4C40 1001 'L@..' DIVU.L D0,D1 +000001F8: 7000 'p.' MOVEQ #$00,D0 +000001FA: 302B 0002 '0+..' MOVE.W $0002(A3),D0 +000001FE: 4A80 'J.' TST.L D0 +00000200: 4C40 1802 'L@..' TDIVS.L D0,D2:D1 +00000204: 700F 'p.' MOVEQ #$0F,D0 +00000206: C082 '..' AND.L D2,D0 +00000208: 1940 004E '.@.N' MOVE.B D0,$004E(A4) +0000020C: 2006 ' .' MOVE.L D6,D0 +0000020E: E988 '..' LSL.L #$4,D0 +00000210: 812C 004E '.,.N' OR.B D0,$004E(A4) +00000214: 002C 00A0 004E '.,...N' ORI.B #$A0,$004E(A4) +0000021A: 7000 'p.' MOVEQ #$00,D0 +0000021C: 302B 0004 '0+..' MOVE.W $0004(A3),D0 +00000220: 2207 '".' MOVE.L D7,D1 +00000222: 4C40 1002 'L@..' TDIVU.L D0,D2:D1 +00000226: 5202 'R.' ADDQ.B #$1,D2 +00000228: 1942 004A '.B.J' MOVE.B D2,$004A(A4) +0000022C: 4CEE 18C0 FFF0 'L.....' MOVEM.L -$0010(A6),D6/D7/A3/A4 +00000232: 4E5E 'N^' UNLK A6 +00000234: 4E75 'Nu' RTS + +Size: Flags $00 ModuleSize 566 + +Last +Record Summary +Type Count + 0 Pad 1 + 1 First 1 + 2 Last 1 + 4 Dictionary 1 + 5 Module 1 + 7 ModSize 1 + 8 Content 1 diff --git a/DRVR_53_ATADisk b/DRVR_53_ATADisk new file mode 100644 index 0000000000000000000000000000000000000000..a05d33d4a787feed42a981aacd12f0b93b67e638 GIT binary patch literal 17254 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', code[k+2:k+4])[0] == j: + return j + + raise ValueError('Function BOOT not found') + + +def find_InitDevice(code): + for i in range(0, len(code), 2): + # checking Driver Descriptor Map magic number (there are two but this one always first) + if code[i:i+2] == b'ER': + for j in reversed(range(0, i, 2)): + if code[j:j+2] == b'NV': # LINK A6,#$xxxx + return j + + raise ValueError('Function InitDevice not found') + + +def patch_ataload(code): + code = bytearray(code) + new = len(code) # boundary between old and new code + + # Parse the DumpObj'd file + with open(path.join(path.dirname(__file__), 'ATALoad.dmp')) as f: + for l in f: + m = re.match(r'^[0-9A-F]{8}: ([0-9A-F ]+)', l) or re.match('^ {13}([0-9A-F][0-9A-F ]*)', l) + if m: + code.extend(binascii.unhexlify(m.group(1).replace(' ', ''))) + + InitDevice = find_InitDevice(code[:new]) + BOOT = find_BOOT(code[:new]) + + print('ATALoad patch: InitDevice=0x%X, NewInitDevice=0x%X, BOOT=0x%X' % (InitDevice, new, BOOT)) + + # "Link" the new code into the old + for i in range(new, len(code), 2): + if code[i:i+4] == b'Nsrt': + code[i:i+4] = code[InitDevice:InitDevice+4] # copy the first LINK from the original function + code[InitDevice:InitDevice+2] = b'\x60\x00' # BRA.W opcode, to... + code[InitDevice+2:InitDevice+4] = struct.pack('>h', new - (InitDevice+2)) # ...the start of the new code + + if code[i:i+2] == b'ID': # reference to original InitDevice, skipping the mangled 4-byte LINK + code[i:i+2] = struct.pack('>h', (InitDevice+4) - i) + + if code[i:i+2] == b'BT': # reference to BOOT function + code[i:i+2] = struct.pack('>h', BOOT - i) + + return bytes(code) + + +for (parent, folders, files) in os.walk(src): + folders.sort(); files.sort() # make it kinda deterministic + for filename in files: + full = path.join(src, parent, filename) + + if filename == 'Romfile': + ataload = path.join(src, parent, 'Rsrc', 'DRVR_-20175_ATALoad') + atadisk = path.join(src, parent, 'Rsrc', 'DRVR_53_ATADisk') + + if path.exists(ataload): + code = open(ataload, 'rb').read() + code = patch_ataload(code) + open(ataload, 'wb').write(code) + + if not path.exists(atadisk): + with open(full, 'a') as f: # append to Romfile + f.write('\ntype=DRVR id=53 name=.ATADisk src=Rsrc/DRVR_53_ATADisk # inserted by ataboot.py\n') + print('ATALoad patch: using .ATADisk DRVR from Drive Setup 2.1') + shutil.copy(path.join(path.dirname(__file__), 'DRVR_53_ATADisk'), atadisk) + + +cleanup()