[comp.sys.amiga] What is the checksum used for the Amiga's track & sector information

koster@cory.Berkeley.EDU (Kevin Oster) (06/09/88)

   This is a very technical question. I am going to the disk hardware directly
(Thanks for all the help on getting that going...It was the disk.resource that
solved it.) Anyway, I want to write a format routine and I don't know enough
about the checksum.
   The RKM volume 2 tells a little about the format. It says there are two
32 bit checksums, one for the header information and one for the data area.
How do I compute them? These checksums are on the raw data after MFM decoding,
even lower level than trackdisk. Also is there anything special about the
$4489 matchword? Couldn't it be found by chance in a sector's data area?
($4489 is the MFM encoded version of $A1)

carolyn@cbmvax.UUCP (Carolyn Scheppner CATS) (06/10/88)

In article <3845@pasteur.Berkeley.Edu> koster@cory.Berkeley.EDU.UUCP (Kevin Oster) writes:
>
>   This is a very technical question. I am going to the disk hardware directly
>(Thanks for all the help on getting that going...It was the disk.resource that
>solved it.) Anyway, I want to write a format routine and I don't know enough
>about the checksum.

Here's some info from an AmigaMail article.  It may contain what you need.


                     Notes on 1.2 Amiga Trackdisk Format 
                     ===================================
                     Copyright 1987 Commodore-Amiga, Inc.

   The following notes provide some detailed information on the format of
a 3 1/2" floppy under the current AmigaDOS 1.2 filing system.  These notes
are for informational purposes only and relate only to the layout under the
current filing system.  The structures and layout are private, and are 
subject to change in the future.  In other words, if you write your own
Format code, or use any part of these structures or blocks for your own
purposes, or make any other assumptions based on the current layout, there
is a good chance that you will be incompatible with any future filing system
enhancements, because future enhancements may support additional formats
and may use some of the currently unused areas in the reserved blocks.

   Other information about the current disk layout can be found in the Amiga
manuals.  The format of directory, file header, file list, and data blocks is
discussed in the AmigaDOS Manual (Bantam).  A description of Amiga MFM encoding
can be found on pages C9-C10 of the ROM Kernel "Exec" manual (Addison-Wesley).  


1)  ROOT BLOCK

The Root block is normally in the middle of the disk (halfway through blocks).
On the 3 1/2" floppy, this is block 880 (track 40, sector 0, first surface).


/* Rootblock structure (private)
 * Copyright (c) 1985  Commodore-Amiga Inc.   All Rights Reserved 
 */

#define WORDSPERBLOCK	128   /* NOTE - WORDS means LONGWORDS (BCPLese) */
#define HASHSIZE	(WORDSPERBLOCK - 56)
#define NUMBMPAGES	26

struct RootBlock {
    ULONG rb_Type;                    /* type */
    ULONG rb_HeaderKey;	              /* header key (always zero) */
    ULONG rb_HighSeqNum;              /* highest sequence number (always 0) */
    ULONG rb_HashSize;                /* hash size (= BLOCKSIZE-56)*/
    ULONG rb_Reserved;                /* reserved */
    ULONG rb_CheckSum;	              /* checksum */
    ULONG rb_HashTable[HASHSIZE];     /* hash table */
    ULONG rb_BMFlag;		      /* TRUE if Bitmap on disk is valid */
    ULONG rb_BitMapPages[NUMBMPAGES]; /* indicates blocks containing bitmap */
    struct DateStamp rb_LastDate;     /* volume last altered date and time */
    UBYTE rb_DiskName[13*4];	      /* volume name BCPL string <= 30 chars*/
    struct DateStamp rb_CreateDate;   /* volume creation date and time */
    ULONG rb_HashChain;	  /* next entry on this hash chain (always zero)*/
    ULONG rb_Parent;                  /* parent directory (always zero) */
    ULONG rb_Extension;	              /* extension (always zero) */
    ULONG rb_SecondaryType;           /* secondary type indicates root block*/
};


   When an Amiga 3 1/2" diskette is formatted, the Format command sets up
a new Root block.  Format sets up the RootBlock and BitMap block in a ram
buffer, then writes them to the disk as block 880 and 881.  First it
sets up the RootBlock by clearing the first 128 longwords of the buffer to
zero, then initializing the following RootBlock fields (start of RootBlock
structure is start of buffer):

   rb_Type     = T_SHORT;        /* T_SHORT = 2 */
   rb_HashSize = HASHSIZE;       /* defined above */
   rb_SecondaryType = ST_ROOT;   /* ST_ROOT = 1 */
   DateStamp(&rb_CreateDate);    /* Set up the CreateDate first */
   DateStamp(&rb_LastDate);      /* Then the LastDate */

   /* Format puts the initial BitMap block right after the RootBlock
    * This value is calculated as follows for 3 1/2" Amiga disk:
    *   (((BlocksPerCyl * N_Cyl) - 1 + N_ResBlocks) / 2) + 1
    *   (((    22       *  80  ) - 1 +      2     ) / 2) + 1  = 881
    */
   rb_BitMapPages[0] = 881;      /* Where format places BitMap block */

   rb_BMFlag = TRUE              /* BitMap valid */
   
   The disk name is copied to &rb_DiskName[1], and rb_DiskName[0] is
      set to the length of the name (BCPL string).

   Then the 128 longword buffer is summed and the CheckSum is set to 0-sum.

   rb_CheckSum = 0 - sum;

   Then Format sets up the second 128 longwords of its buffer as the BitMap
block as described below, and writes both block to the disk.
  
   
2)  BITMAP

   Format places the initial BitMap block right after the RootBlock.  
On a 3 1/2" floppy, the RootBlock is placed at block 880, and the
initial BitMap block at 881.

   The first longword is the checksum of the Bitmap block (calculated in
the same way as the RootBlock checksum).

   The second longword is the start of the BitMap, with the LSB representing
the first unreserved block on the disk.  On the 3 1/2" floppy, blocks 0 and 1
are reserved as BootBlocks.  So the LSB of the floppy's first BitMap longword
represents block 2, the next bit represents block 3, etc.  The bit is set
to 1 if the block is free, and to 0 if the block is used.

   When setting up the BitMap block for a 3 1/2" floppy (which has 1758
unreserved blocks, blocks 2 through 1759), Format starts with 128 longwords
set to zero.  Starting at the second longword, it initializes 54 longwords
to 0xffffffff (54 * 32 bits = 1728 blocks marked as unused), then sets
the next longword to (0xffffffff >> 2) to mark the remaining 30 blocks as
unused.  It then clears the two bits representing blocks 880 and 881 to
mark the RootBlock and BitMap block as used.  Format then sums the 128
longwords, places 0-sum in the initial CheckSum longword, and writes the
RootBlock and the BitMap block to the disk.


3)  BOOT BLOCKS

   Blocks 0 and 1 of the 3 1/2" floppy are reserved as BootBlocks.  
Block 0 of a Kickstart disk contains a BootBlock structure with a bb_id
of "KICK".  Blocks 1 through 512 contain the binary image of KickStart.
Block 0 of a bootable DOS disk starts with a BootBlock structure with a
bb_id of "DOS\0", followed currently by the AmigaDOS boot code, or
alternate boot code in the case of some games.

/* BootBlock definition: */
struct BootBlock {
   UBYTE   bb_id[4];      /* 4 character identifier */
   LONG    bb_chksum;     /* boot block checksum (balance) */
   LONG    bb_dosblock;   /* reserved for DOS patch */
};

#define		BOOTSECTS	2	/* 1K bootstrap */

#define BBID_DOS	{ 'D', 'O', 'S', '\0' }
#define BBID_KICK	{ 'K', 'I', 'C', 'K' }

#define BBNAME_DOS	(('D'<<24)|('O'<<16)|('S'<<8))
#define BBNAME_KICK	(('K'<<24)|('I'<<16)|('C'<<8)|('K'))

(followed by boot code)


4)  HASH FUNCTION

   The hash function is applied to the name of a file or directory, and the
resulting value provides an offset into the HashTable which contains either
zero or a key to the first block on a chain linking blocks with the same
hash value.  Each block contains a name field which identifies it.  The
directory and file header block fields are described in the AmigaDOS manual.
 

int HashName(str,hlen)
 
char    *str;           /* The string to find the hash number for       */
int     hlen;           /* The length of the hash table                 */
 
{
  char  xchar;
  int   i, result;

  result = strlen(str);
  for (i=0; i<strlen(str); i++) {
    if (isalpha(str[i])) xchar = toupper(str[i]);
    else xchar = str[i];
    result = ((result * 13) + xchar) & 0x7ff;
  }
  result = result % hlen;
  return(result);
}



5)  CHECKSUMS

BLOCK CHECKSUM
--------------
The format of the actual file blocks
is documented in the white DOS Technical Reference and the Bantam 
AmigaDOS manual. In these blocks the checksum is calculated as follows :

Treat the 512 byte sector as an array of 128 signed 32bit numbers. So
a data block would be:

Byte Address            Long Word       Data Block Format
0000                    0               T.DATA
0004                    1               Block Number of File Header
0008                    2               Sequence Number
000C                    3               Data Size
0010                    4               Next Data Block
0014                    5               CheckSum
0018 thru 01FF          6 - 127         Data Bytes [488]

To calculate the checksum of this block set longword #5 to 0 then
add up all of the longwords in the block (0-127) ignoring any overflow. 
Now take that sum and invert it (eg sum = - sum ) and save it in longword 5. 
You now have a valid data block.
------------------------------------------------------------------------

HEADER and SECTOR CHECKSUM
---------------------------
The header and sector checksum is a longword by longword exclusive OR.

To calculate the data checksum:

(the data checksum is a checksum only on the data and is computed on
the encoded data in the sector)

EOR the first longword with the second with the third, etc.
Then and with $55555555 to get the checksum for the DataSum.

There are a total of 16 encoded longwords in the header.

   2 longword's of mfm & synch as       (A|2)AAAAAAA  44894489
   2 longword's of encoded format,track#,sec#,sec to end bytes 
   8 longwords for encoded O/S recovery info
   2 longword's for encoded data checksum

The EORs are done from the front of the header (from the format longword) to
the end of the os recovery info.  (the first longword of 00 and A1s is not in
the checksum. it starts with the format byte/longword.)

For the header, you take a long, and with $55555555, eor with the next long,
and loop intil you've gotten to the end of the OS recovery info.
so you have a checksum.  Then you take the header checksum, decode
it, compare, and you've got it.
It starts with the format byte. 

-------------------------------------------------------------------

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CATS   >>Commodore Amiga Technical Support<<
                     UUCP  ...{allegra,ihnp4,rutgers}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

neil@amiga.UUCP (Neil Katin) (06/12/88)

In article <3845@pasteur.Berkeley.Edu> koster@cory.Berkeley.EDU.UUCP (Kevin Oster) writes:
>   The RKM volume 2 tells a little about the format. It says there are two
>32 bit checksums, one for the header information and one for the data area.
>How do I compute them? These checksums are on the raw data after MFM decoding,
>even lower level than trackdisk. Also is there anything special about the
>$4489 matchword? Couldn't it be found by chance in a sector's data area?
>($4489 is the MFM encoded version of $A1)

The checksum is a simple XOR of the data bits (the clock bits are
masked off), for both the header and the data portions.

The 4489 pattern is can never be a legal data pattern: A1 encodes
to 44A9; it is the dropped clock bit that makes it possible to find
these sector headers.

I feel a bit "at risk" with this answer since I did the trackdisk
and disk resource; If we can just get you to control your "murderous
tendencies" (:->).

	Neil Katin
	{oliveb,pyramid}!amiga!neil