interested in copy protection ?!? Here is some old text I downloaded from ATP, since I have not visited their site since 2004 there might be a newer version available (if the site still exists). Probably some of the AR protection schemes are missing in this text, anyways, here it is:
-Andreas Koch.
-------------------------------------------------------------------------
Atari Protected Disk Image Format
Version 1.6 Date 2004-4-11
Authors ATP Working Group
1. INTRODUCTION
TRACKS
SECTORS
2. SECTOR STATUS ERRORS
SECTOR OK
DATA CRC ERROR
RECORD TYPE "DELETED"
RECORD TYPE "DELETED" + CRC ERROR
LOST DATA
LOST DATA + CRC ERROR
LOST DATA + RECORD TYPE "DELETED"
LOST DATA + RECORD TYPE "DELETED" + CRC ERROR
RECORD NOT FOUND
RECORD NOT FOUND + HEADER CRC ERROR
3. DOUBLE SECTORS
4. SECTOR TIMING
SECTOR SKEWING
TRACK SKEWING
SECTOR INTERLEAVING
REFERENCE SECTOR
5. WEAK DATA
WEAK HEADER
WEAK SECTOR DATA
WEAK DATA IN ATP
6. TRACK DENSITY CHANGE
7. ATP FILE FORMAT
ATP FILE
ATP DISK DATA
ATP HEADER
ATP TRACK
ATP SECTOR
ATP CRC
ATP TIMING DATA
8. REFERENCES
9. HISTORY
VERSION 1.6
1. Introduction
Why do we need the ATP format? The current format for Atari 8-bit disk images
is ATR. With this format it is not possible to store copy protected disks.
The new ATP format should make this possible.
So, what about the APE PRO format? Thus far it seems that the author of APE
will not release any information about his 'PRO' format. Therefore we're
simply forced to develop our own format. We probably need more supported
protection features and since we propose an 'open' format this will be
possible.
PRESERVE ORIGINALS!
Some disks are around 20 years old and who knows how many original copies or
backups (original backups!) there are? It's time to make good copies where
possible. With the ATP we will be able to store these copies on modern media.
This is not an easy task, since many different copy protections are invented
during the years. Not to mention the copy-programs which can make copies of
protected disks, but not of the copy-program itself!
Tracks
Each disk contains a number of tracks. On the Atari drives the track number
ranges from 0 to 39. The disk drives use the so called soft sectored disks.
This means that a track can be seen as just one long data stream. With help
of markers the FDC knows where to find the right sector data in this stream.
In general a track looks like this:
Start of track:
Marker | Index mark
Gap #1 | Post index mark
NOTE: The XF551 & 1050 both ignore the index (if written to disk)
First sector:
Gap #2 | Pre address mark
Marker | Address mark
Data | Sector header + CRC
Gap #3 | Post address mark
Marker | Data address mark
Data | Sector data + CRC
Gap #4 | Post data mark
The first sector is followed by the rest of the sectors which all have the
same structure as the first sector. Note that the first sector doesn't have
to be numbered as sector #1.
Sectors
A disk sector consists of the following three parts:
- Sector header field (also called 'address field')
. Gap bytes (should be at least 4 Bytes in SD, 8 Bytes in MD/DD)
. Header mark (also called 'address mark')
. Track number (0 - 39)
. Side (0 or 1) the sector belongs to (the FDC ignores this byte)
. Sector number (also called 'sector id')
. Sector size (0=128, 1=256, 2=512, 3=1024 Byte)
. Two CRC checksum bytes (used by the FDC to check the last 4 Bytes)
- Sector data field (also called 'data field')
. Gap bytes
. Data mark
. Sector data (SD/ED: 128 Bytes, DD: 256 Byte)
. Two CRC-Bytes (used by the FDC to check the sector data)
- Gap
. Gap bytes until the next sector
2. Sector Status Errors
After reading a protected sector, the status command returns the Floppy Disk
Controller (FDC) status byte for the last read/written sector. A perfectly good sector
has a status of $FF. The status byte can then be checked for error bits to identify the
protection. Sometimes the sector data is also verified.
Each bit of the FDC-status byte is low active and has the following meaning:
Bit 7: /DOOR No Disk in drive (NOT valid on XF551 drives)
Bit 6: /WP Write protected (valid only after a write command)
Bit 5: /RT Record Type "Deleted" in the sector header field (address field)
Bit 4: /RNF Record not found (sector not found)
Bit 3: /CRC Checksum-Error (in the sector header or sector data field)
Bit 2: /LD Lost data: the drive-CPU didn't send/receive all data to/from the FDC
Bit 1: /DRQ Data request: the FDC asks for a byte read/written to its data register
Bit 0: /BUSY The FDC is busy, the last FDC-Command hasn't completed yet
For copy protection methods only the bits 5,4,3,2 are useful. The other bits are 1
after a read sector command. Bit 1 should always be 1, in combination with LD (Bit 2
= 0), Bit 1 is undefined (depends on the ROM revision of the disk drive).
The possible FDC-status bytes are described below.
Sector Ok
This is a perfectly normal sector without error.
Status: $FF (255)
Data? : yes
Data CRC Error
The two CRC bytes of the sector data field aren't correct. This error is created by
issueing a write command to the FDC and abort it before the complete sector is
written. The sector data may be correct, and some programs verify the complete
sector data since it is VERY difficult to abort the write command exactly when the
CRC bytes are written by the FDC.
Status : $F7 (247)
Data? : yes
Examples:
Great American Road Race, track 32-39
MS Copy, sector 68
Record Type "Deleted"
Also called "Deleted Data Mark". The data mark of the sector is set to "Deleted".
The error can be created by issueing a write sector command to the FDC with Bit 0
set. The FDC treats a "Deleted Data Mark" not as an error, it's simply a possibility to
mark sectors, so a DOS can detect if a sector is free or in use by a file. This is not
used by the ATARI-XL/XE system nor PCs.
Status: 223 ($DF)
Data? : yes
Examples: ?
Record Type "Deleted" + CRC error
This is a combination of a deleted data mark and CRC error. This type of error is
often caused by a so called 'weak' or 'fuzzy' sector. According to the manual of the
Super Archiver a 'Fuzzy' or 'Phantom' sector is "a sector in which the data does not
regain constant. It will almost always carry with it a CRC error, because of the
unstable data."
Status: 215 ($D7)
Data? : yes
Examples:
MS Copy, sector 67, 71
Lost Data
Also called "Long Sector". The size byte in the sector header field is set to 1 or
greater (meaning at least 256 Byte) on a SD/ED disk (resp. at least 512 byte on a
DD disk). So the FDC will read 256 bytes or more data bytes, but the drive ROM will
read only 128 data bytes, which results in lost data. In some ROM revisions the
ROM doesn't reset the FDC after an error, this will result in Bit 1 (DRQ-Bit) set to
zero. Therefore a program must allow $FB or $F9 or it won't work on all ATARI
drives. This error must be created at format time since the
size byte is in the sector header field (the sector header field cannot be modified
when writing a sector). To create the sector data field without a CRC error the
complete "long" sector (256 Byte) must be written by the drive ROM to the FDC. Or
the drive ROM has to calculate the correct CRC.
Status: $F9 (249) or $FB (251)
Data? : yes
Examples:
MS Copy, sector 56-59, 64
Remarks:
Not displayed by 'disk mapper' (a program used to analyse disks).
Lost Data + CRC Error
Same as "Lost Data" but the sector also contains a CRC error. The CRC part of
this error is created the same way as in a simple CRC ($F7).
Status: $F1 (241) or $F3 (243)
Data? : yes
Examples:
MS Copy, sector 72
Lost Data + Record Type "Deleted"
Same as "Lost Data" but the sector also contains a "Record Type" error. The
"Record Type" part of this error is created the same way as in a simple "Record
Type Deleted" ($DF).
Status: $D9 (217) or $DB (219)
Data? : yes
Examples: ?
Lost Data + Record Type "Deleted" + CRC Error
Same as "Lost Data" but the sector also contains a "Record Type" error and a CRC
error. The "Record Type" + CRC part of this error is created the same way as in a
simple "Record Type" + CRC ($D7).
Status: $D1 (209) or $D3 (211)
Data? : yes
Examples:
MS Copy, sector 37
Record Not Found
Also called "Missing Sector". The drive doesn't find the sector at all. There are three
possible causes:
- Sector not found
There is no header field with the correct sector number.
- Track not found
A header field with the correct sector-nr but a wrong track-nr was found.
- Data not found
A correct header field was found but the data mark is missing.
This error is created at format time by not writing the sector, the data mark or writing
a wrong track number in the header field.
Status: $EF (239)
Data? : no
Examples:
Printshop, track 5
Ultra Copier, track 7-39
MS Copy, sector 73-90
Record Not Found + Header CRC Error
Also called "Address CRC error" or "Sector ID CRC error". The sector header field
has a bad CRC. This error is created by writing two zero bytes instead of the CRC
bytes at format time.
Status: $E7
Data? : no
Examples: ?
3. Double sectors
The sector ID can appear more than once on the same track. Often double sectors
are placed 180 degrees away from eachother. That way you can read the same
sector twice and get two sets of data. With the right timing it's possible to read data
from multiple sectors with the same sector ID on one track. Short sectors can be
used to get more sectors on a track to create complex protection schemes.
Examples:
Printshop, track 5
4. Sector timing
Sector skewing
The time between two consequetive sectors on a track is called skew-alignment.
This space between sectors is infuenced by the placement of sectors on the track
and the amount of gap bytes.
Track skewing
Since the Atari drives don't use the index hole to indicate the start of the first sector
in a track, the alignment of two tracks can be different. A track skew of 0 means that
the tracks are aligned, e.g. the first sector from the first track starts at the same
position as the first sector on the second track. With a track skew of 180 degrees,
the first sector on the second track start 180 degrees later on that track.
According to the Super Archiver manual: "Skewing is the measurement of time
between two different tracks. For example, if sector 1 on track 0 is located 180
degrees away from sector 1 on track 1, a program could read each sector 1, time it,
and compare it to a given value. This sort of protection is used, and is quite effective
against sector copiers, but not some enhancements (such as the Super Archiver
1050!). Normally what is done is to line up the first sector of each track (assuming all
tracks in the skew section are the same format).
The software will read that first sector of each track in a certain order, and compare
it with a certain timing. For example, the same time it takes to read sector 1 on track
0 twice should be the same time it takes to read sector 1 on track 0, and sector 1 on
track 1. When stepping more than 2 tracks, allowances need to be made for step
rates, because certain drives step slower than others. Usually measuring the time
between one track the very next one is effective
enough. ... "
Sector interleaving
By sector interleaving sectors are placed on the disk in the most efficient order.
When the sectors are positioned in a normal sequence (0, 1, 2 etc) the interleave
factor is 1. With a sector interleave of 2, the next sector is placed two positions
behind the first sector. Protection schemes can use custom interleaving or
completely different sector layouts. With help of timing information, the original can
be detected.
Reference Sector
Since the index hole is not used, a track has no clear beginning or end. Some
protections measure the time between two sectors, but we don't know which sectors
the program will check. Therefore we will use a specific sector to measure the time
between this sector and all other sectors on the disk.
First definition:
The start of sector "1" on track "0" denotes the "virtual index hole" and serves as a
physical reference position for all other sectors on the disk.
There can be double sectors on the disk, but it's not likely that sector 1 - the
bootsector - is a double sector (contact us if you have an example!). Just to be on
the save side we will use the following definition:
Final definition:
The first, unique (i.e. non-double) sector on the disk (starting with track 0) is called
the "reference sector". This "reference sector" serves as an absolute reference point
(for all timing measurements). The start of this "reference sector" denotes the "virtual
index hole".
If there is no unique sector on the disk (i.e. each sector number occurs at least twice
within a track), the user may choose any sector of the disk as a reference sector.
5. Weak data
Some protections are based on weak data bits. These unstable bits can produce
several errors when they appear in the sector header and/or corrupt data bits in the
sector data part.
Weak Header
If the FDC cannot read the sector header correctly, the header-CRC checksum fails
and the FDC will report 'sector not found'. If the header data is corrupted all the time,
this will look like a completely missing sector. But if the sector header could be read
correctly, the FDC will also read the sector data (without any weak bits in this case)
and return 'sector read successful'.
STEFAN Dorndorf: This only happens if the data CRC is correct. This very
unlikely. A floppy emulator could simulate this case by randomly returning:
1) sector OK (plus valid data)
2) sector not found
STEFAN Dorndorf: No, this error may be combined with Header-CRC or
Record-Type status errors.
FREDDY Offenga: This is not clear. Is the above simply wrong?
Examples: ?
Weak Sector Data
In case of a broken bit in the data part, the data CRC-check will fail and the FDC will
return partially correct data.
This can be simulated by returning:
1) sector OK (plus valid data)
2) data CRC error (plus some partially garbled data)
In the combination of weak bits in the data part and in the header part, we would end
up with three possible cases that a floppy emulator has to return:
1) sector OK (plus valid data)
Header and data read in OK.
2) data CRC error (plus some partially garbled data)
Header was OK, but broken bit(s) in data part.
3) sector not found
Broken bit in header and the FDC didn't have any chance to look into the data part -
so it doesn't matter if there are any further broken/weak bits.
Examples: ?
Weak data in ATP
Weak data is still unresolved for ATP. However, with the chunk-based format it is
possible to add this information later.
Here are the discussions regarding weak data:
DISCUSSION: Multiple corrupted parts in one sector
MATTHIAS Reichl: I'm still not sure how we would have to store the information about the
corrupted part. Theoretically it could be possible to have multiple weak parts (or
holes) within a single sector. Eg: first 16 bytes ok, then 16 weak bytes, then 16 bytes
ok, then 16 weak bytes... I'm not sure if this would make sense, but if the FDC is
actually able to re-synchronize and read in some correct data between garbled
parts, we would also have to reflect this in our
data structures.
STEFAN Dorndorf: Theoretically, it is possible:
A bit on the disk is represented by one (0-Bit) or two (1-Bit) low-to-high or high-to-
low transitions (in SD). So the FDC can synchronize at least on every 0-bit. But if
you write no transitions for some time on the disk (this can't be done by the FDC),
the FDC won't find the transitions to synchronize and may deliver random bytes, the
behaviour of the FDC isn't defined in that case, different revisions of the FDC may
behave different. So I would define the ATP-Format to have this option but not
include it in the first revision.
MATTHIAS: ACK. IMO (for the first version) we should just store the starting position
of the weak data, and assume that the FDC won't be able to re-sync and treat the
following data as random data.
This means: we simply store a single byte (denoting the number of stable bytes)
and then either deliver:
* the correct sector data, or
* the first N "stable" bytes plus (128-N) random bytes and indicate a checksum-error
DISCUSSION: Weak bits in FM and MFM
MATTHIAS:
In FM mode both clock and data bits are written to disk. So if the FDC misses a bit, it
will probably read the following clock bits as data bits and vice versa. OTOH if the
FDC won't get reliable clock bits (since it is actually reading data bits) it _could_
possibly re-sync to the clock bits. [BTW: since the clock bits are "1", the FDC will
report $FF data 'til the end of the
sector or 'til it re-syncs].
In MFM mode only data bits are written to disk, but with a special encoding so that
there will not be long runs of zero-bits. Using this encoding clock bits aren't
necessary any more and it can reliably re-generate the clock (and sync to it). A
missed bit will impact the decoding in two ways: First, the current bit is lost
(obviously) and second, due to the MFM encoding scheme, it will also affect
decoding of the following data bits. IMHO this could show up a some garbeled bits
and then (when the FDC re-synced again) correct data that is shifted by several bits
(not necessarily bytes!).
6. Track density change
Some tracks of the disk are formatted in SD, some in ED. This copy protection is
effective, since there is no backup program that checks the density of a track. And
what is more, this protection method can be created by standard ATARI disk drives:
Simply format a disk in SD, than reformat it in ED but switch off the disk drive after
30 formatted tracks. Now the disk seems to be in ED but the last 10 tracks are in SD.
To access these tracks write protect
the disk, then execute a format command, which will switch the drive in SD read
mode. And maybe the density can be changed in the middle of a track.
Examples: ?
7. ATP File Format
The ATP file format is a so-called chunk-based format. A chunk is simply a 4 bytes
identifier and a 4 bytes length field followed by the amount of data bytes indicated by
the length.
<UINT32> : 32-bit 'big endian' unsigned integer
ATP File
<ATP_File> := <FORM_ID> <FORM_Length> <ATP_Disk_Data> <ATP_CRC>
<ATP_Timing_Data>
<FORM_ID> := "FORM"
<FORM_Length> := <UINT32>
The length of the ATP Disk-Data chunk (file length -
ATP Disk Data
<ATP_Disk_Data> := <ATP_Disk_Data_ID> <ATP_Disk_Data_Length>
<ATP_Header> <ATP_Track>*
<ATP_Disk_Data_ID> := "ATP1"
The magic code to identify an ATP version 1 disk image.
<ATP_Disk_Data_Length> := <UINT32>
Length of ATP Disk Data chunk in bytes.
ATP Header
<ATP_Header> := <ATP_Header_ID> <ATP_Header_Length> <Nr_Of_Tracks>
<Disk_Info>
<ATP_Header_ID> := "INFO"
<ATP_Header_Length> := <UINT32>
Length of the ATP header info chunk (2 bytes).
<Nr_Of_Tracks> := <UINT32>
Number of tracks (chunks) in this ATP Disk Data chunk.
<Disk_Info> := <UINT32>
{ #$00 | #$01 }
bit 0, Disk write protection (0=off, 1=on)
ATP Track
The order of ATP sectors from each ATP track is important. It should be used to
store different interleaves and place double sectors on a track.
When a certain track number is not available in the ATP file, it means that it's an
unformatted track (drive emulators should produce error 239 ($EF) - missing sector).
Note: The tracks have to be stored in strictly ascending order! Sectors within a track
also have to be stored in strictly ascending order, sorted by their sector starting time
(= sector position on disk)!
Each block of track data contains a track header followed by a sequence of sector
blocks:
<ATP_Track> := <ATP_Track_ID> <ATP_Track_Length> <ATP_Track_Data>
<ATP_Track_ID> := "TRAK"
<ATP_Track_Length> := <UINT32>
Length of this ATP_Track chunk in bytes.
<ATP_Track_Data> := <Track_Number> <Nr_Of_Sectors> <Density>
<ATP_Sector>*
<Track_Number> := <UINT32>
Track number.
<Nr_Of_Sectors> := <UINT32>
Number of sectors on the track.
<Density> := <UINT32>
{ #$00 | #$01 }
bit 0, Density - 0=FM (SD,DD), 1=MFM (ED)
ATP Sector
Sectors which are not listed are simply 'missing' sectors and thus produce an error
239 ($EF).
Each sector block has a sector header followed by an amount of data bytes:
<ATP_Sector> := <ATP_Sector_ID> <ATP_Sector_Length> <Sector>
<ATP_Sector_ID> := "SECT"
<ATP_Sector_Length> := <UINT32>
Length of ATP Sector chunk in bytes.
<Sector> := <Sector_Nr> <Sector_Size> <Sector_Status> <Sector_Data>*
<Sector_Nr> := <UINT32>
Sector ID Number.
<Sector_Size> := <UINT32>
Sector Size (in bytes).
<Sector_Status> :=
{ #$D3 | #$D7 | #$DB | #$DF | #$E7 | #$F3 | #$F7 | #$FB | #$FF }
Sector Status
$D3 FDC error $D3 (%11010011) Lost Data + Record Type "Deleted" +
CRC Error
$D7 FDC error $D7 (%11010111) Record Type "Deleted" + CRC error
$DB FDC error $DB (%11011011) Lost Data + Record Type "Deleted"
$DF FDC error $DF (%11011111) Record Type "Deleted"
$E7 FDC error $E7 (%11100111) Record Not Found + Header CRC
Error
$F3 FDC error $F3 (%11110011) Lost Data + CRC Error
$F7 FDC error $F7 (%11110111) Data CRC Error
$FB FDC error $FB (%11111011) Lost Data
$FF FDC status $FF (%11111111) Sector Ok
Note that status $EF (Record Not Found) is not allowed here, because these
missing sectors should not be listed in the track data at all.
<Sector_Data> := <BYTE>*
Sector data bytes indicated by Sector Size.
ATP CRC
A CRC32 checksum of the data part of the ATP_Data chunk (excluding the 4-byte
chunk id and 4-byte chunk length) is stored for quick image comparison.
<ATP_CRC> := <CRC_ID> <CRC_Length> <32_bit_CRC>
CRC_ID := "CRC1"
CRC_Length := <UINT32>
Length of ATP CRC chunk. Currently fixed at 4 (bytes).
<32_bit_CRC> := <UINT32>
A checksum calculated over the data part of the ATP_Data chunk.
ATP Timing Data
Starting with ATP version 1.6 the timing information has been separated from the
sector data/status information and is stored in an own chunk. This is mainly to ease
quick image comparison by using the CRC checksum. Since the timing information
might be a little bit "fuzzy", it would break quick CRC-checks. On the other hand,
there is a high possibility that
two images are identical if they contain exactly the same image data.
Note: the timing data chunk must contain exactly the same number of tracks as the
ATP Disk Data chunk and each track must contain exactly the same number of
sectors as the corresponding tracks in the ATP disk data chunk!
<ATP_Timing_Data> := <ATP_Timing_ID> <ATP_Timing_Length>
<Timing_Nr_Of_Tracks> <ATP_Track_Timing>*
<ATP_Timing_ID> := "TIM1"
Magic code to identify an ATP version 1 timing data chunk.
<ATP_Timing_Lenght> := <UINT32>
Length of the ATP Timing Data chunk in bytes.
<Timing_Nr_Of_Tracks> := <UINT32>
Number of tracks (chunks) in the ATP Timing Data (MUST be the same as
<Nr_Of_Tracks> in Disk Data chunk.
<ATP_Track_Timing> := <ATP_Track_Timing_ID> <ATP_Track_Timing_Length>
<Track_Timing_Data>
<ATP_Track_Timing_ID> := "TTI1"
<ATP_Track_Timing_Length> := <UINT32>
Length of ATP track timing chunk.
<Track_Timing_Data> := <Timing_Track_Number> <Timing_Nr_Of_Sectors>
<Sector_Timing>*
<Timing_Track_Number> := <UINT32>
Track number.
<Timing_Nr_Of_Sectors> := <UINT32>
Number of sectors in the current track.
<Sector_Timing> := <Sector_Start_Time> <Sector_Time_Length>
Timing information for each sector.
<Sector_Start_Time> := <UINT32>
The time distance in microseconds between the start-time of the reference sector
and the start-time of the current sector.
<Sector_Time_Length> := <UINT32>
Length of the sector (from the start of the header til the end of the data block) in
microseconds.
8. References
- Atari 8-bit floppy disk formats, Mega Magazine #6, F.Offenga
- The Super Archiver manual, CSS
- The Happy Enhancement article series, Atari Magazin
- The Hyper-XF manual, Stefan Dorndorf
9. History
Version 1.6
- Adapted the ATP file structure for separate timing information
- Changed all informational values from <BYTE> into <UINT32>
- Removed FDC error $EF (239, Record Not Found) from <Sector_Status>.
Sectors not listed in <Track_Data> should produce this error.
- Removed FDC error values with the same meaning:
+ $D1 : FDC error $D1 Same as $D3
+ $D9 : FDC error $D9 Same as $DB
+ $F1 : FDC error $F1 Same as $F3
+ $F9 : FDC error $F9 Same as $FB
<END>
-------------------------------------------------------------------------------------------------
Edit: Just found the link to the site, no newer version exists though:
http://members.chell...fenga/ATP16.htm
Edited by CharlieChaplin, Sun May 17, 2009 12:29 PM.
















