Prism Leisure Protection
Contents
Prism Leisure Protection
Prism Leisure Protection is a Commodore 64 disk protection that checks
for a data duplication track on track 41: a track outside the normal
35-track range that consists of one byte value, $AC, repeated
around the whole track. A disk copied with a normal 35-track copier lacks
this track, and the check fails.
Disk title in directory is modified to show in green color.
Used by Electric Dreams, Software Studios, Mirrorsoft Ltd., Thalamus
The signature track
- Track 41 has no sectors, headers or checksums. It contains the byte
$ACrepeated about 7,140 times per revolution. - In GCR bits
$ACis10101100. On the disk this appears as a repeating flux interval pattern of 2-2-1-3 bit cells. - The track is written at the bit rate of speed zone 2 (3.50 µs per cell). This is not the zone the 1541 DOS would use for track 41.
- No sync mark was found in the flux of any analyzed disk. The pattern simply runs once around the track.
Track 1 ─────────────────────────────── 35 ordinary CBM DOS layout Track 36 ─ 40 unused Track 41 $AC $AC $AC $AC ... (whole track, about 7,140 bytes, zone 2)
The check
The loader uploads drive code. The drive code runs as an
EXECUTE job ($E0) in buffer 3, so the DOS job loop first
moves the head to track 41. Buffer 3 then starts with
JMP $0530.
Captured from drive RAM at the moment the head is stepped to track 41:
; ---- job setup, called once for track 41 and once for track 18 ---- $0580 A9 29 LDA #$29 ; track 41 $0582 8D FD 05 STA $05FD $0585 A9 30 LDA #$30 ; job code entry -> $0530 (the check) $0587 8D 1C 05 STA $051C $058A 20 03 05 JSR $0503 $058D A9 12 LDA #$12 ; afterwards: track 18 $058F 8D FD 05 STA $05FD $0592 A9 7A LDA #$7A ; job code entry -> $057A (no check, $0594 8D 1C 05 STA $051C ; just puts the head back on 18) $0597 20 03 05 JSR $0503 $059A 60 RTS $0503 20 00 C1 JSR $C100 ; LED on ... $050A AD FD 05 LDA $05FD $050D 85 80 STA $80 ; current track $050F 85 51 STA $51 ... $0516 A9 4C LDA #$4C ; buffer 3: JMP $05xx $0518 8D 00 06 STA $0600 $051B A9 30 LDA #$30 ; (operand patched to $30 / $7A above) $051D 8D 01 06 STA $0601 $0520 A9 05 LDA #$05 $0522 8D 02 06 STA $0602 $0525 A5 7F LDA $7F $0527 09 E0 ORA #$E0 ; EXECUTE job for buffer 3 $0529 85 03 STA $03 $052B A5 03 LDA $03 $052D 30 FC BMI $052B ; wait for the job to finish $052F 60 RTS ; ---- the check (runs on track 41) ---- $0530 AD 0C 1C LDA $1C0C $0533 09 E0 ORA #$E0 ; head to read mode $0535 8D 0C 1C STA $1C0C $0538 A9 00 LDA #$00 $053A 8D 03 1C STA $1C03 ; data port = input $053D A9 FF LDA #$FF $053F 8D FE 05 STA $05FE ; search budget: 255 x 256 bytes $0542 A0 00 LDY #$00 $0544 50 FE BVC $0544 ; wait for byte ready $0546 B8 CLV $0547 AD 01 1C LDA $1C01 $054A C9 AC CMP #$AC ; search for the first $AC $054C F0 10 BEQ $055E $054E 88 DEY $054F D0 F3 BNE $0544 $0551 CE FE 05 DEC $05FE $0554 D0 EC BNE $0542 $0556 A9 00 LDA #$00 ; FAILED: result $00 $0558 8D FF 05 STA $05FF $055B 4C 96 FD JMP $FD96 $055E A2 00 LDX #$00 ; found: now 256 more bytes ... $0560 50 FE BVC $0560 $0562 B8 CLV $0563 AD 01 1C LDA $1C01 $0566 C9 AC CMP #$AC ; ... must all be $AC $0568 D0 E4 BNE $054E ; any other byte -> keep searching $056A 88 DEY $056B D0 05 BNE $0572 $056D CE FE 05 DEC $05FE $0570 F0 E4 BEQ $0556 ; budget used up -> FAILED $0572 CA DEX $0573 D0 EB BNE $0560 $0575 A9 C2 LDA #$C2 ; PASSED: result $C2 $0577 8D FF 05 STA $05FF $057A 4C 96 FD JMP $FD96
In short:
- The drive reads raw bytes from track 41 without looking for a sync or a header.
- It searches up to 255 × 256 bytes (about nine revolutions) for an
$AC. - After that, 256 bytes in a row must be
$AC. - The result goes to drive address
$05FF:$C2means passed,$00means failed. - A second job returns the head to track 18.
The C64 side
The C64 part is in a directory entry with an empty name, loaded to
$F000 (1,280 bytes). It is copied to $C000 and
entered with JMP $C0E0 (from $C475):
$C0E0 20 03 C0 JSR $C003 ; upload the drive code $C0E3 20 B8 C0 JSR $C0B8 ; start it: "M-E" $0500 $C0E6 20 70 C0 JSR $C070 ; read the result: "M-R" $05FF -> $C0FF $C0E9 A9 A6 LDA #$A6 ; build the expected value without $C0EB 49 17 EOR #$17 ; ever writing it as a constant: $C0ED 49 98 EOR #$98 ; $A6^$17^$98^$B6^$AD^$F0 = $C2 $C0EF 49 B6 EOR #$B6 $C0F1 49 AD EOR #$AD $C0F3 49 F0 EOR #$F0 $C0F5 CD FF C0 CMP $C0FF ; compare with the byte read from the drive $C0F8 F0 03 BEQ $C0FD $C0FA 6C FC FF JMP ($FFFC) ; FAILED: reset the C64 $C0FD 4C 00 00 JMP $xx00 ; the high byte of this JMP IS $C0FF
- Upload (
$C003): the drive code is stored in C64 memory
at$C100–$C1FF, XOR-encrypted with$05. That's the high byte of its drive address, which the upload loop uses as the key. It is sent withM-Win 32-byte chunks to drive$0500–$05FFand decrypted on the fly.
- Read-back (
$C070): the C64 opens the command channel,
sendsM-R$FF $05, and stores the single byte it gets back at$C0FF.
- Decision: if the byte is not
$C2, the loader jumps
through the reset vector, and the machine restarts. This is the reset seen when the check fails.
The result byte is used three times, so patching only the
BEQ or the reset jump doesn't crack the protection:
- as the comparison value at
$C0F5; - as the high byte of the jump target.
$C0FFis also the
operand ofJMP $xx00at$C0FD, so only the correct value$C2continues at$C200;
- as the decryption key. The code at
$C200XORs page
$C300with$C0FFand then jumps to$C300:
$C200 78 SEI $C201 A2 00 LDX #$00 $C203 BD 00 C3 LDA $C300,X $C206 4D FF C0 EOR $C0FF ; key = result byte ($C2) $C209 9D 00 C3 STA $C300,X $C20C CA DEX $C20D D0 F4 BNE $C203 $C20F 58 CLI $C210 4C 00 C3 JMP $C300
Copying and imaging
- A 35-track copy or a D64 image loses track 41, and the check fails.
- A track 41 that decodes as "almost
$AC" fails too. The check needs 256 correct bytes in a row, so a single shifted or lost bit in every few bytes is enough to break it. - Back sides (flippy sides) need care when imaging:
- Recording direction. In a double-sided KryoFlux capture, head 1 reads the back side in reverse time order. This applies to track 41 as well as to tracks 1–35. Read without reversal, the
$ACpattern looks like 3-1-2-2 instead of 2-2-1-3. - Signal distortion. The track 41 signal on back sides can be heavily peak-shifted. On Power-Pack source 7, Disk 1 back side, the measured intervals were 1.30 / 1.88 / 2.18 / 2.60 cells instead of 1 / 2 / 2 / 3. It then decodes cleanly only at exactly 3.50 µs per cell.
- Recording direction. In a double-sided KryoFlux capture, head 1 reads the back side in reverse time order. This applies to track 41 as well as to tracks 1–35. Read without reversal, the
See also
Pages that refer to this protection
- Descriptions of old disk copy protections (← links)
- Grand Prix Selection (← links)
- Speedball (← links)
- Tetris (← links)
- Foxx Fights Back (← links)
- Metaplex (← links)
- Hunter's Moon (← links)
- Quedex (← links)
- Football Manager 2 (← links)
- Power-Pack (← links)
- Enduro Racer (← links)
- Big Trouble in Little China (← links)
- Firetrack (← links)
- Future Games 64 (← links)
- Soccer Mania (← links)
- Quartet (← links)
- Pack of Aces (← links)
- International Karate + (← links)
- Football Manager: World Cup Edition 1990 (← links)
- Fun Collection Vol.1 (← links)
- Andy Capp (← links)
- Karnov (← links)
- Predator (← links)
- Super Sprint (← links)
- Championship Sprint (← links)
- Phobia (← links)
- Super Hang-On (← links)
- Mean Streak (← links)
- Tanium (← links)
- Zig-Zag (← links)