This is the DOC file for Amiga floppy disc bootblocks, and because the Amiga disc bootblock has been much misused by certain devious individuals from the first appearance of the Amiga, a section will be included on the subject of Amiga bootblock viruses. List of Contents: Bootblock:Preamble Bootblock:Structure Bootblock:Constructing a User Bootstrap Bootblock:Bootblock Viruses Bootblock:The Getboot Program Bootblock:File Updates Bootblock:Preamble The bootblock of an Amiga disc occupies Track 0, Sector 0, Surface 0 & Track 0, Sector 1, Surface 0 of the Amiga disc. On the file typed_trackdisk.doc in this series of files is a program that reads the bootblock (called getboot.s) from any normal Amiga disc. Because it is useful here too, I reproduce this code in the section 'Bootblock:The Getboot Program' below. The bootblock thus occupies 1024 bytes in total, since there are 512 bytes per sector on an Amiga disc. This menas that there exists space within the bootblock for a fairly sophisticated boot program, capable of performing tasks such as loading up an alternative DOS such as UNIX (for all incurable minicomputer lovers and grizzled hacks everywhere), or changing the response of the system to a disc with an alternative format. Needless to say, the subject of viruses rears its ugly head whenever bootblocks are mentioned, and so a separate section is devoted to the opera- tion of bootblock virus code (note that not ALL viruses are bootblock viruses and hence this separate category of virus, called a Linkvirus, will be cover- ed elsewhere). Bootblock:Structure As regular readers of Amiga DOC files may have guessed, there exists a data structure for the bootblock. The definition of this structure is: rsreset bb_id rs.b 4 bb_CheckSum rs.l 1 bb_DosBlock rs.l 1 bb_Entry rs.w 0 bb_Sizeof rs.w 0 The various fields are defined as follows: bb_id : Contains a four-letter text ID for the disc. Standard Amiga discs contain the text "DOS", terminated by a NULL, to signal that the disc is a proper AmigaDOS disc. Other labels found here include "KICK" for an Amiga 1000 KickStart disc, "NDOS" for a formatted disc that does not conform to the AmigaDOS standard, and "BAD" (NULL terminated) to signal a trashed disc. bb_Checksum : A longword computed in such a way that the sum of all of the longwords within the bootblock (including this one) is -1L ($FFFFFFFF). bb_DosBlock : The exact use of this longword is NOT documented by Commodore-Amiga. It is, in fact, the block number of the 'Root Block' of the disc. See notes below. bb_Entry : Where the bootblock code itself goes. There is room for (1024-12) = 1012 bytes of actual code. Notes:each sector on the disc has a unique number associated with it. Boot- block sectors are number $0000 and $0001. The formula for the block number is: block number = (Track No. * 22) + (Surface No. * 11) + Sector No. where Track No. is any value from 0 to 79 for a normal disc, Sector No. is any value from 0 to 10, and Surface No. is 0 for the upper surface, 1 for the lower surface, of the disc. The 'Root Block' is Track 40, Sector 0, Sur- face 0, which is block number 880 ($0370). The use of the Root Block is to be documented elsewhere, but if the disc is to be a valid AmigaDOS disc even after custom boot code is written to the bootblock, then the bb_id field has to be set to "DOS" as above, and the bb_DosBlock MUST be set to $0370.L. It is also required that the disc is properly formatted (using the FORMAT comm- and or any of its PD analogues) according to the normal AmigaDOS format, & that the Root Block is properly initialised. Note that the checksum is computed using LONGWORDS. The procedure is as follows (following code assumes a pointer to a track buffer containing the custom bootblock data to be checksummed is in A0): * Compute bootblock checksum * Ensure before starting this code, that bb_CheckSum field * is zero, else computed checksum will be incorrect. move.w #512-1,d7 ;no of longwords, corrected ;for DBRA moveq #0,d0 ;init checksum move.l a0,a2 ;copy pointer chksum1 add.l (a2)+,d0 ;longword sum dbra d7,chksum1 ;keep going till all done move.l d0,d1 addq.l #1,d1 neg.l d1 ;THIS is bb_CheckSum move.l d1,bb_Checksum(a0) ;and save it * From here on, the correctly checksummed bootblock can be written to * disc... In case anyone is wondering about the code at the end, the requirement is for a checksum, C, such that the sum of all of the other bootblock data longwords (call this S) and the checksum is -1L: S + C = -1 Rearranging, we get C = -1 - S C = -(1+S) hence the code involving D1 at the end. This code can be executed upon any custom-designed bootblock resid- ing in memory and awaiting transfer to the disc prior to said transfer. Feel free to excise this code and use at will-thie above code segment is Public Domain. Bootblock:Constructing a User Bootstrap Now that the structure of the bootblock has been described, it is proper to consider how a user bootstrap can be constructed. First, let us examine the standard AmigaDOS bootblock created after applying the CLI command 'Install' to the disc in drive 0 (here reproduced in the format obtained by using the CLI TYPE command with OPT H on the file bootblock.data produced by the pro- gram getboot.s below): 0000: 444F5300 C0200F19 00000370 43FA0018 DOS.. .....pC... 0010: 4EAEFFA0 4A80670A 20402068 00167000 N...J.g. @ h..p. 0020: 4E7570FF 60FA646F 732E6C69 62726172 Nup.`.dos.librar 0030: 79000000 00000000 00000000 00000000 y............... The remaining longwords from relative address $0040 onwards are zero, so they can be ignored here. The first longword is the bb_id, containing the text "DOS" (termin- ated with a NULL). The next longword is the checksum. As a check, I added the contents of the bootblock, omitting this checksum value, and then added the checksum value onto the resulting sum. For this bootblock, the value is act- ually -4L, NOT -1L. According to the Amiga ROM Kernel manual, the value ought to be -1L, but the bootblock above is taken from my CLI boot disc, and that disc boots satisfactorily, so more information is needed before confirming or denying this. After the checksum is the value $370.L, which is the pointer to the Root Block of the disc. This is Track 40, Sector 0, Surface 0, and contains the information for the root directory of a standard AmigaDOS disc, such as the pointers to the blocks containing the file headers for files resident in that directory, and the pointers to the blocks for the subdirectories. Also to be found here is the pointer to the block used for the disc bitmap, which determines which blocks are free to be written over (this information being updated by the CLI commands COPY, DELETE etc., and any application that cre- ates its own files). More information about this can be found elsewhere. Following the bb_DosBlock entry is the boot code proper. The system loads this code into memory upon ensuring that the disc is a valid AmigaDOS disc, and begins executing it. Prior to calling the code, which should finish with an RTS instruction, the system passes to the code a pointer to ExecBase in A6, so that Exec library functions can be called within the boot code, and a pointer to a properly initialised and opened IORequest structure linked to the trackdisk device in A1. All boot code MUST be position independent. There is no way that the boot code can possibly know where in memory it is to be loaded, and since it has not been determined until after boot time whether the DOS library is open and linked to the Exec resident library list (open, that is, for the system boot task that loaded and called the bootblock program) DOS library functions that take a program in DOS hunk format cannot be used. Hence boot code is to be found written to disc as raw binary code, NOT in DOS hunk format (the for- mat in which user applications, once written and compiled or assembled, are saved to disc) and must be written so that it can execute from any load add- ress 'as is'. Boot code should use PC relative addressing for its variables unless memory is specifically allocated for them using AllocMem(), which can be called from boot code without restriction. Exec library functions are all available to boot code, but using the OpenLibrary() and OldOpenLibrary() calls may possibly cause one or two prob- lems if done without due care and attention. The trackdisk device can be used without prior calls to OpenDevice() if loading code from DF0: since the sys- tem provides the IORequest for the trackdisk device for such code on the ass- umption that boot code may need to load data from disc, as is the case with any disc providing an alternative operating system such as UNIX. Boot code MUST also provide two return values to the system prior to executing the final RTS. D0 must contain a failure code:zero if all is well, and some other value if not. If the boot code returns a nonzero failure code then the system generates a system alert, and begins a reboot. Register A0 must contain a valid jump address for the system to jump to. A disassembly of the standard Installed boot code illustrates this: lea dosname(pc),a1 ;is DOS library resident? jsr FindResident(a6) ;find it if so tst.l d0 beq.s error ;whoops! exit NOW... move.l d0,a0 ;ptr to ROMTAG in a0 move.l $16(a0),a0 ;ptr to code to run moveq #0,d0 ;signal OK exit rts ;& done. error moveq #-1,d0 ;here, signal REBOOT! bra.s exit ;and exit dosname dc.b "dos.library",0 even This is the standard code written to the bootblock of a disc by the Install command of the CLI. It checks if the DOS library is available, and if so, it signals that all is well, otherwise signals a reboot. When the boot code is run, Exec should be in an advanced state of existence, and several resident structures present in the ROM should by now have been referenced and used to construct a number of resident libraries and devices. Two which are NEEDED are the trackdisk device and the DOS library, both of which should have been set up by the reset code called upon power-up or upon resetting the machine. If the trackdisk device is not available, then the machine needs servicing-prepare for a repair bill. If the DOS library is not available, then sometimes using another boot disc helps, but if this is not the case, again prepare for a repair bill for a sick Amiga. Assuming that Exec is thus constituted, the above code searches for the existence of the DOS library in the Exec resident library list, and if it is found, the address of the code to execute is obtained (the value returned in D0 from FindResident() is the pointer to the ROMTAG structure, and the ad- dress of the code to execute is found at offset $16 from the beginning of the ROMTAG structure) and then passed to the system. Once the boot code has run, the bootstrap module will free the boot sector memory used for loading, then the boot raster memory for the display, close the trackdisk device IORequest, perform any other cleaning up that is required, and call the code pointed to by A0. Obviously, this facility is used heavily by games writers to provide a bootblock intro to the game, or else provide some means of initiating copy- protection code prior to launching the game proper. As a result, NOT ALL of the alien bootblocks to be encountered are viruses (see below!). Many games have their own bootblocks, such as Barbarian, Terrorpods, and others that in times past cost users a hefty sum, before being bundled as freebies with new Amigas bought after a certain date. A comment of my own here:copy-protection code often appears lurking within games, sometimes in the bootblock. I find this practice somewhat irk- some. In theory, copy-protection code is there to prevent pirated copies of popular games circulating. In practice, copy-protection prevents legitimate users from backing up expensive games (at £40 a time, I EXPECT to be able to back up a game, especially if the software house is churlish when asked to replace scrambled copies) while doing nothing at all from preventing profes- sional software pirates from mass-producing thousands of cheap copies, par- ticularly the reverse-engineer mob in Taiwan. Thankfully, serious software such as art packages and compilers don't suffer from this (and I should hope not at £450 a time for Sculpt 4D professional! My Amiga cost less!). Right, that's my personal griping over with for now. Should you take advantage of bootblock code to liven up the presen- tation of your software, take note also that your boot code can discard the IORequest pointer in A1, but it MUST NOT destroy the IORequest itself. Expect to see the Amiga FIREWORKS_MODE if your boot code does this! Oh, and I warn anyone contemplating munging Copper lists within bootblock code to exercise a bit of care unless they wish to see the same thing-this is the best way known to mankind of causing some more temperamental Amigas to behave epileptically, in some cases resulting in a repair bill. As the Amiga ROM Kernel Manual says frequently to those who know a little Latin, Caveat Programmer. Bootblock:Bootblock Viruses Bootblock viruses are pieces of code, resident upon the bootblock, that are constructed of three distinct segments: 1) A segment to bring the entire virus to life during the boot process; 2) A segment to 'clone' the whole, i.e., write copies of the virus code onto the bootblock of any disc inserted into the drive once the virus code is active; 3) A segment to perform some evil deed (optional) once certain internal conditions are fulfilled. The bootblock code for the more sophisticated viruses set up a Resident or ROMTAG structure in memory, linked into Exec's Resident list, to ensure that is it reset-proof. Alternatively, the virus can take control of the ColdCap- ture vector in the ExecBase structure, the CoolCapture vector, or use some other means of protecting itself against a reboot. Many viruses then test for the fulfilment of some condition such as a given amount of system time having elapsed (REVENGE does this before bringing up its erect penis pointer), and then executing some devious code upon fulfilment of this condition. So far, the following bootblock viruses are known to exist: SCA (The original Swiss Cracking Association virus) LSD (How original!) AEK (German origin) DAG (Another Teutonic production) ICE (I don't know much about this one) GRAFFITI (Again, not much info on this one) DASA (Nasty one-scribbles randomly over discs!) BYTEWARRIOR (EVIL one-PHYSICALLY wrecks discs!) OBELISK (More info needed, get in touch-see File Updates below) PENTAGON CIRCLE (Never encountered yet, but it DOES exist) DISKDOCTOR (Several versions-at least one undoes the good work done by DiskDoctor) ASS PROTECTOR (Possibly an Antivirus-see notes below) GADAFFI (More info needed-get in touch!) WARHAWK (More info needed-get in touch!) BYTE BANDIT (Two incarnations, both pretty bad. Writes all over discs!) LAMER EXTERMINATOR (This is THE bad one! Four incarnations at present, randomly corrupts disc sectors by writing 'Lamer!' all over the disc sector. Picks its sectors so as to cause maximum damage, version 4 rumoured to specifically search out GenAm source files & destroy them!) NORTH STAR (Again two incarnations. Not sure what this one does, experts please get in touch) REVENGE (This is a comical one. It changes the mouse pointer to look like an erect penis after a period of time has elapsed) SENDARIAN (Again, send info please!) TIME BOMB (Ominously named. Probably lives up to its name too) AIDS (The product of someone with a sick sense of humour) 16 BIT CREW (Another cracking crew virus. Don't these guys ever grow up?) MICROSYSTEMS (Send info please!) BLACK FLASH (Send info please!) HCS (Send info please!) ULTRAFOX (Send info please!) V-KILL (Pretends to be a virus killer. See notes below) JOSHUA (Who?) GYROS (Send info please!) PARAMOUNT (Send info please!) SYSTEM Z (Pretends to be a virus killer. See notes below) LAMER II (See notes below) BUTTONIC VIRUS (Where the hell do they think up these names?) This completes the list known to me, but anyone finding any others, or having information on those labelled 'send info please!' etc., please get in touch so that I can maintain regular updates. Notes:some persons have come up with the idea of writing a piece of code that behaves like a virus, except that by preventing all other viruses from being written to disc, it effectively acts as an Antivirus. However, it is also possible that these so-called Antiviruses have disastrous effects of their own (some virus writing crews have written mimic viruses to mimic the effect of, say, SYSTEM Z, while STILL preforming evil deeds within the sys- tem!). To the best of my knowledge, the genuine SYSTEM Z does not destroy any disc sectors, but some of the mimic versions DEFINITELY do! As a result, use of Antivirus code is NOT recommended, UNLESS of course it is your own and you know EXACTLY what it does! Having outlined in the section 'Constructing a User Bootstrap' how to place code into the bootblock, I hereby advise AGAINST writing virus code (unless you intend to write an Antivirus for private use) for the following reasons: 1) Viruses are a major source of annoyance for serious computer users; 2) Any virus that destroys files, particularly source code files, can land freelance programmers in serious debt if such viruses are spread successfully. Many thus affected will not hesitate to sue for punitive damages should this occur; 3) The kind of individual who enjoys the prospect of ruining other computer users' enjoyment of the Amiga through the practice of writing viruses is just the sort of education- ally subnormal, emotionally juvenile mental pygmy seen in large numbers passing through police hands every year for such offences as assault under the influence of alcohol, criminal damage, and other equally squalid pastimes. Such a person should, quite simply, GROW UP and use the program- ming talents for something far more constructive. Sad to say, viruses have materialised in disturbingly large numbers on other machines, including IBM PCs and compatibles, and one virus appearance on PCs cost the Royal National Institute for the Blind over £80,000. Put it another way, the cost of training 400 guide dogs from scratch. Thanks to some total and utter shithead, 400 people will have to wait for guide dogs for another year. Do you really want to be classified alongside such disgusting filth as those responsible for this? Are you really that puerile? I hope not. Bootblock:The Getboot Program As promised in the preamble, here is the program getboot.s: * GETBOOT.S * Read bootblock, copy its contents to a file on RAM: * Uses trackdisk device to perform its wonders. * Tabs set to 8 in GenAm preferences opt d+ include VOL12:INCLUDES/my_exec.i include VOL12:INCLUDES/my_dos.i TD_MOTOR equ 9 TD_SEEK equ 10 rsreset dos_base rs.l 1 ;DOS LIBRARY base myself rs.l 1 ;my own task ID trackdisc rs.l 1 ;not needed-take it out trd_ioreq rs.l 1 ;pointer to IORequest trd_mport rs.l 1 ;pointer to message port trd_sigbit rs.w 1 ;signal bit used by mport trd_sigmask rs.l 1 ;signal mask if needed trd_buffer rs.l 1 ;track buffer filehandle rs.l 1 ;DOS file handle vars_sizeof rs.w 0 * IORequest structure rsreset io_MsgNode rs.b mn_sizeof io_Device rs.l 1 io_Unit rs.l 1 io_Command rs.w 1 io_Flags rs.b 1 io_Error rs.b 1 io_sizeof rs.w 0 * IOEXTRequest structure rsreset ioext_Std rs.b io_sizeof ioext_Actual rs.l 1 ioext_Length rs.l 1 ioext_Data rs.l 1 ioext_Offset rs.l 1 ioext_sizeof rs.w 0 * IOTD structure rsreset iotd_Std rs.b ioext_sizeof iotd_Count rs.l 1 iotd_SecLabel rs.l 1 iotd_sizeof rs.w 0 * Main program. I reference all my variables using the RS directives * above, and point A6 to a block allocated for that purpose. This is * for several reasons:1) offset(A6) references are 4 cycles per word * faster than absolute address accesses; 2) I can keep my code size * down by not statically allocating them; 3) offset(A6) uses 1 word * less per access than an absolute long access. Better all round. * The amount of memory to reserve is determined by vars_sizeof : I * suggest implementing this trick with ALL custom-designed data struc- * tures! main move.l #vars_sizeof,d0 move.l #MEMF_PUBLIC+MEMF_CLEAR,d1 ;allocate my vars CALLEXEC AllocMem tst.l d0 beq cock_up_1 ;oops... move.l d0,a6 sub.l a1,a1 CALLEXEC FindTask move.l d0,myself(a6) ;my own task ID move.l #iotd_sizeof,d0 move.l #MEMF_PUBLIC+MEMF_CLEAR,d1 ;allocate IOReq CALLEXEC AllocMem move.l d0,trd_ioreq(a6) beq cock_up_2 ;oops... move.l #mp_sizeof,d0 move.l #MEMF_PUBLIC+MEMF_CLEAR,d1 ;allocate replyport CALLEXEC AllocMem move.l d0,trd_mport(a6) beq cock_up_3 ;oops... moveq #-1,d0 ;get a signal bit CALLEXEC AllocSignal move.w d0,trd_sigbit(a6) bmi cock_up_4 ;oops... moveq #0,d1 bset d0,d1 move.l d1,trd_sigmask(a6) ;make signal mask * Now initialise the ReplyPort including the message list header move.l trd_mport(a6),a0 move.w trd_sigbit(a6),d0 move.b d0,mp_SigBit(a0) ;set Signal Bit move.b #PA_SIGNAL,mp_Flags(a0) ;and Flags move.l myself(a6),mp_SigTask(a0) ;which Task to signal ;(me) when message ;arrives clr.b ln_Pri(a0) move.b #NT_MSGPORT,ln_Type(a0) ;this IS a message ;port! lea portname(pc),a1 move.l a1,ln_Name(a0) ;set port name lea mp_MsgList(a0),a1 * the following five instructions are equivalent to the * NEWLIST macro used on some systems. Initialises the * list header for the ReplyPort. move.l a1,lh_Head(a1) addq.l #4,lh_Head(a1) ;lh_head = &lh_tail clr.l lh_Tail(a1) ;lh_tail = 0 move.l a1,lh_TailPred(a1) ;lh_tailpred = &lh_head move.b #NT_MESSAGE,lh_Type(a1) ;list of messages ;queued to port! move.l a0,a1 CALLEXEC AddPort ;add to public port list * Now initialise the IORequest move.l trd_ioreq(a6),a0 move.b #NT_MESSAGE,ln_Type(a0) move.l trd_mport(a6),mn_ReplyPort(a0) move.w #iotd_sizeof-mn_sizeof,mn_Length(a0) lea ioname(pc),a1 move.l a1,ln_Name(a0) ;gave it a name for debugging! * Now open the Trackdisk device lea trackname(pc),a0 moveq #0,d0 move.l trd_ioreq(a6),a1 moveq #0,d1 CALLEXEC OpenDevice ;Note:zero=success move.l d0,trackdisc(a6) ;unlike OpenLibrary() etc. bne cock_up_5 * Now alloc some memory for a track buffer, enough for cylinder 0 of disc move.l #512*2*11,d0 move.l #MEMF_CHIP+MEMF_PUBLIC+MEMF_CLEAR,d1 CALLEXEC AllocMem move.l d0,trd_buffer(a6) beq cock_up_6 ;can't do it! * Turn on motor. I use DoIO(), but SendIO() is equally OK. move.l trd_ioreq(a6),a1 move.w #TD_MOTOR,io_Command(a1) moveq #1,d0 move.l d0,ioext_Length(a1) CALLEXEC DoIO tst.l d0 bmi cock_up_7 * Find Track Zero & read in bootblock, again using DoIO(). move.l trd_ioreq(a6),a1 move.w #CMD_READ,io_Command(a1) move.l #2*512,ioext_Length(a1) ;2 sectors move.l trd_buffer(a6),ioext_Data(a1) ;read into here clr.l ioext_Offset(a1) ;from bootblock CALLEXEC DoIO tst.l d0 bmi cock_up_7 * Turn off motor, again using DoIO(). move.l trd_ioreq(a6),a1 move.w #TD_MOTOR,io_Command(a1) moveq #0,d0 move.l d0,ioext_Length(a1) CALLEXEC DoIO tst.l d0 bmi.s cock_up_7 * Now open DOS library & write buffer contents to file on RAM disc lea dosname(pc),a1 moveq #0,D0 CALLEXEC OpenLibrary move.l d0,dos_base(a6) beq.s cock_up_7 lea filename(pc),a0 move.l a0,d1 move.l #MODE_NEW,d2 CALLDOS Open move.l d0,filehandle(a6) ;save file handle beq.s cock_up_8 ;oops... * although I don't check for error here, to be well-behaved, all * of your applications should. Returns no. of bytes written in * D0, -1L if error occurred. move.l filehandle(a6),d1 move.l trd_buffer(a6),d2 move.l #512*2,d3 CALLDOS Write * Close file. Nice simple one. cock_up_9 move.l filehandle(a6),d1 CALLDOS Close * Close DOS Library. Nice simple one. cock_up_8 move.l dos_base(a6),a1 CALLEXEC CloseLibrary cock_up_7 move.l #512*9*2,d0 ;free track buffer move.l trd_buffer(a6),a1 CALLEXEC FreeMem * Here I can free the IOReq safely because I used DoIO() above. * Thus my program waited for the IORequest to be completed, & * therefore there's nothing pending for me to accidentally * blast out of existence. If you use SendIO(), ALWAYS do a * CheckIO() before deallocating the IORequest to make sure * that nothing is pending... cock_up_6 move.l trd_ioreq(a6),a1 ;free IORequest CALLEXEC CloseDevice cock_up_5 nop move.w trd_sigbit(a6),d0 ;free the signal bit CALLEXEC FreeSignal cock_up_4 move.l trd_mport(a6),a1 CALLEXEC RemPort move.l #mp_sizeof,d0 ;free the message port move.l trd_mport(a6),a1 CALLEXEC FreeMem cock_up_3 move.l #ioext_sizeof,d0 ;free the IOReq move.l trd_ioreq(a6),a1 CALLEXEC FreeMem cock_up_2 move.l #vars_sizeof,d0 ;free my vars move.l a6,a1 CALLEXEC FreeMem cock_up_1 rts * Various text strings. Pretty obvious what they're for. dosname dc.b "dos.library",0 filename dc.b "RAM:bootblock.data",0 portname dc.b "getboot.port",0 ioname dc.b "getboot.ioreq",0 trackname dc.b "trackdisk.device",0 even Since this code is Public Domain, feel free to rip it out of this file, and mutate according to your preferences/whims/sexual desires etc. READ THE COM- MENTS! They're there to make your your life easier! Bootblock:File Updates For updated versions of this file, or any of the other files in this series of DOC files, the contact addresses are: Dave Edwards Mark Meany 232 Hale Road 1 Cromwell Road WIDNES Polygon Cheshire SOUTHAMPTON WA8 8QA Hants S01 2JH The first of these is mine. Sending a blank formatted disc to me at the above address, with a stamped, self-addressed jiffy bag for return postage (stand- ard 1st class stamp sufficient) will get you the files of your choice, writ- ten to your disc in uncompressed ASCII format. Sending a disc to Mark at the above address (plus jiffy bag, stamp etc.) will get you one of the ACC club discs which contain these files spread over a period (they were intended for the ACC club readership initially, and are now Public Domain DOCs distributed as part of the ACC club material by Mark). All DOC files appearing on the ACC Club discs are in compressed format, and you'll need the packer/depacker that is supplied with the ACC discs to be able to edit them, if this is your wish. Should anyone out there have information to add to the files, please contact either Mark or myself at the addresses above, sending your info as an uncompressed ASCII file. I shall add the info to the relevant file when time allows, and send off the latest version upon request. All contributors will be acknowledged gratefully. UPDATE : typed_bootblock.doc current as of 8/12/90 Contributors : Dave Edwards