September 1, 2011
The boot sector starts quite interesting: copying code to address 8 and executing it there. The format of the disk is different, but not special: sector 1 in the track is 512 bytes long, sector 2-6 are each 1024 bytes long. 5632 bytes per track out of possible 6250 bytes, pretty good capacity on a double sided disk. The trick is that the last 1024 byte sector starts at the end of the track and extends for more than 500 bytes over the index marker. The first sector is packed right after the sector at the beginning. The tracks 75..79 are not used. Strangely on the back side Track 79 contains an empty 512 sector, which does not seem to be part of the protection.
Track 7 to 10 contain the actual protection. The test starts in track 7 and tests the protection, if it fails it continous till track 10 to find a valid protection. If it fails on all 4 tracks, it erases the memory till it crashes…
The usual 6 sectors exist in these tracks, but they also contain sector 0 and 16 in different positions (the position is not tested). They are supposed to be each 1024 bytes long, but they only have an address mark plus the sector header and can not be read without a CRC error. The reason for this is interesting and István Fábián figured out what is going on the the actual disk medium! http://www.atari-forum.com/viewtopic.php?f=47&t=19948&start=25
Track 7: sector order: 5,3,6, 0,16, 1,4,2 Track 8: sector order: 0,16, 1,4,2,5,3,6 Track 9: sector order: 5,3,6, 0,16, 1,4,2 Track 10: sector order: 0,16, 1,4,2,5,3,6
Sector 0 starts with the following data, as you can see it clearly contains the sector header of sector 16! You can also see four weird bytes: 0x14, 0x14, 0x14, 0x00. These bytes are actually 3 sync markers 0xa1 and another sector header 0xfe, but shifted by one bit and the FDC will re-sync to them when trying to read sector 16. And because data bits and clock bits are interleaved, the re-sync will now actually read the clock bits instead of the data bits! The protection therefore reads the data bits via sector 0 (re-sync is disabled after a 0xFE is found for 1024 bytes plus CRC) and then the clock bits via sector 16.
0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0010 A1 A1 A1 FE 07 00 10 03 BB 21 4E 4E 4E 4E 4E 4E .........!NNNNNN 0020 4E 4E 4E 4E 4E 4E 4E 4E 4E 4E 4E 4E 4E 4E 4E 4E NNNNNNNNNNNNNNNN 0030 FF FF FF FF FF FF FF FF FF FF FF FE 14 14 14 00 ................ 0040 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ 0050 80 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 ................ 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
The DMA read code ignores the first 64 bytes, which is a gap and the re-sync for the sector 16. The following 16 bytes have to contain 0xFF bytes and other 32 bytes have to have more than 204 cleared bits (out of 256 possible bits).
Sector 16 (the clock bits) starts with the following data:
0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0010 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 @............... 0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
The first 16 bytes have to contain 0x00 bytes and other 32 bytes have to have more than 204 cleared bits (out of 256 possible bits), because of clock drift the FDC probably can randomly read a 1 instead of a 0.
copyProtection: MOVEM.L A0-A6/D0-D7,-(A7) MOVE.L #$100000,D0 L056B:SUBQ.L #1,D0 ;delay BNE.S L056B MOVE SR,-(A7) BTST #5,(A7) BNE.S L056C CLR.L -(A7) MOVE.W #$20,-(A7) ;SUPER TRAP #1 MOVE.L D0,2(A7) L056C:MOVE #$2700,SR BSR clearKeyboard LEA $FFFF8000.W,A4 ;ffff8000 LEA 1549(A4),A3 ;ffff860d LEA 1542(A4),A2 ;ffff8606 LEA 1540(A4),A1 ;ffff8604 LEA 31233(A4),A0 ;fffffa01 MOVEQ #5,D0 BSR selectFloppy MOVE.W #$82,(A2) ;track register BSR fdcDelay MOVE.W (A1),D0 ANDI.W #$FF,D0 MOVE.W D0,-(A7) ;current track MOVE.W #$80,(A2) MOVEQ #$01,D2 BSR fdcCommand ;Restore MOVEQ #7,D7 ;start with track 7 L056D:MOVE.W D7,D2 BSR fdcSeek BSR checkSectors TST.W D6 BPL.S L056F ADDQ.W #1,D7 CMPI.W #10,D7 ;up to track 10 BLE.S L056D LEA $80000,A7 L056E:CLR.L -(A7) ;erase everything and crash... BRA.S L056E L056F:MOVE.W (A7)+,D2 ;current track BSR fdcSeek L0570:MOVE.W (A1),D0 ;wait for motor off TST.B D0 BMI.S L0570 MOVEQ #7,D0 BSR selectFloppy ;deselect drive BSR.S clearKeyboard MOVE.W (A7)+,D0 CMPI.W #$20,D0 ;supervisor mode active? BNE.S L0571 MOVEA.L (A7)+,A0 MOVE.W (A7)+,D0 MOVE A7,USP ;back to user mode MOVEA.L A0,A7 L0571:MOVE D0,SR MOVEM.L (A7)+,A0-A6/D0-D7 BRA copyProtectionReturn clearKeyboard MOVEQ #$FF,D0 L0573:BTST #0,$FFFFFC00.W BEQ.S L0574 MOVE.B $FFFFFC02.W,D0 BRA.S clearKeyboard L0574:DBF D0,L0573 RTS checkSectors: MOVEQ #4,D6 ;5 tries checkSectorsTries: MOVEQ #0,D1 ;sector 0 MOVEQ #4,D5 ;skip 5 DMA buffer (one empty at the beginning) LEA -128(A7),A5 ;base address BSR readSector MOVEQ #15,D0 L0577:CMPI.B #$FF,(A5)+ ;16 0xFF bytes have to be at the beginning of the buffer BNE.S checkSectorsFailed DBF D0,L0577 BSR countClearedBits CMPI.W #$CC,D0 ;at least 204 cleared bits have to be in the buffer BLT.S checkSectorsFailed MOVEQ #16,D1 ;sector 16 MOVEQ #0,D5 ;skip 1 DMA buffer (which is empty anyway) LEA -64(A7),A5 ;base address BSR readSector MOVEQ #15,D0 L0578:TST.B (A5)+ ;16 0x00 bytes have to be at the beginning of the buffer BNE.S checkSectorsFailed DBF D0,L0578 BSR.S countClearedBits CMPI.W #$CC,D0 ;at least 204 cleared bits have to be in the buffer BGE.S checkSectorsSuccess checkSectorsFailed: DBF D6,checkSectorsTries checkSectorsSuccess: RTS ;count the number of cleared bits in 32 bytes countClearedBits: MOVEQ #0,D0 MOVEQ #31,D1 L057C:MOVEQ #7,D2 L057D:BTST D2,(A5) BNE.S L057E ADDQ.L #1,D0 L057E:DBF D2,L057D ADDQ.L #1,A5 DBF D1,L057C RTS readSector: MOVE.L A5,D0 MOVE.B D0,(A3) LSR.W #8,D0 MOVE.B D0,1547(A4) ;set the DMA address SWAP D0 MOVE.B D0,1545(A4) MOVE.W #$90,(A2) MOVE.W #$190,(A2) ;read MOVE.W #$90,(A2) MOVEQ #$10,D2 BSR fdcWriteD2 ;16*512 byte MOVE.W #$84,(A2) MOVE.W D1,D2 ;sector number BSR fdcWriteD2 MOVE.W #$80,(A2) BSR fdcDelay MOVE.W #$80,(A1) ;read sector ;5+3 DMA buffer = 128 bytes L0580:MOVEM.L (A5),D0-D3 ;read original bytes from the buffer SUBQ.W #1,D5 ;5 DMA buffers BMI.S L0582 MOVE.W A5,D4 L0581:CMP.B (A3),D4 ;DMA low unchanged? BEQ.S L0581 ;wait! MOVEM.L D0-D3,(A5) LEA 16(A5),A5 BRA.S L0580 L0582:MOVEQ #2,D1 L0583:MOVE.B (A3),D0 L0584:CMP.B (A3),D0 ;wait for DMA low to change 3 times BEQ.S L0584 DBF D1,L0583 MOVE.W #$50,(A2) MOVE.W #$150,(A2) ;just weird... MOVE.W #$50,(A2) BRA fdcWait RTS selectFloppy: MOVE.B #$E,2048(A4) MOVEQ #$F8,D1 AND.B 2048(A4),D1 OR.B D0,D1 MOVE.B D1,2050(A4) RTS fdcSeek: MOVE.W #$86,(A2) BSR.S fdcWriteD2 MOVE.W #$80,(A2) MOVEQ #$11,D2 fdcCommand: BSR.S fdcWriteD2 fdcWait: BTST #5,(A0) BNE.S fdcWait RTS fdcWriteD2: BSR.S fdcDelay MOVE.W D2,(A1) fdcDelay: MOVEQ #$7F,D3 L058B:DBF D3,L058B RTS copyProtectionReturn: RTS