D33[R2]D2: a DOS 3.3 patch for booting from (drive 2|external drive)

booting from (drive 2|external drive). Author: Benoît Gilon. Introduction. The last hardware purchase I made on the Apple 2 market was a SDFloppy II. (physical ...
340KB taille 3 téléchargements 251 vues
D33[R2]D2: a DOS 3.3 patch for booting from (drive 2|external drive) Author: Benoît Gilon

Introduction The last hardware purchase I made on the Apple 2 market was a SDFloppy II (physical disk emulator from files located on SD cards) from the Web site http://www.a2heaven.com. However, when considering the DOS 3.3 disks, the Apple //c (original ROM) I have on hand as I am writing this article cannot boot from the external drive connected using the external drive connector (I bought the adapter cable also from A2Heaven). Also, using the PR#7 statement or the 7

under the monitor works great with ProDOS 8 images but not with a DOS 3.3 image. What I propose in this article is to allow the DOS 3.3 be started up from whichever drive initially booted (either drive 1 or 2). Warning: the changes described here will have an impact on how your system will boot and so must be handled with precaution. No data that has not been previously backed up should reside on the medium. Now you have been warned… The procedure given will be transparent on the //c and other hosts that allow booting from the external drive using the PR#7 or 7

keyboard entries, not with other hosts like the //e or ][+ for which a monitor specific memory change would be required before the boot can take place.

ROM boot code analysis Here is the extract from the Apple //c reference manual (1st edition for the original //c only /"the two red books"/ vol. 2) C6FB DODRV2 JMP DRV2ENT DS $C700-* C700 HEX FF Make look like nothing in slot C701 DRV2BOOT LDA #$E0 Do device #2 ($60 for device #1) LDY #1 To select drive #2 LDX #$60 BRA DODRV2 SLOTZ BOOTDEV C600

EQU EQU

$2B $4F

LDX #$20 LDY #0 STZ 3 Will serve as a retry count for SEEKZERO STZ $3C LDA #$60 TAX C60B DRV2ENT STX SLOTZ STA BOOTDEV PHY ;Y = 1 if drive2, 0 if drive1 LDA $C08E,X LDA $C08C,X PLY LDA $C0EA,Y Select drive 1 or 2 LDA $C089,X LDY #$50 * Fall into the SEEKZERO subroutine,,, C61F SEEKZERO

* The code below is used as a "subroutine" by Boot1 stage to load extra sectors into * memory pointed to by the $26,$27 page zero pointer, ... C63D EXTENT1 STZ 3 Serves as a retry count RDADR CLC PHP ]LOOP PLP RDDHDR LDX SLOTZ INC 3 If not out of retries, BNE RDHD0 ; go to read data header C65C BRA EXTENT1 ... C6E8 INC $27 Increment dest. address hi byte INC $3D Increment # of read sectors LDA $3D CMP $0800 LDX BOOTDEV BCC BADREAD Still some more sectors to read JMP $0801 Jump to 1st exec. code inst. from Boot1 We see that the device number which discriminates between drive 1 and 2 is kept within memory whose address is $4F. The tail of the ROM based code will be in charge to load sector 0, track 0 (and optionally others) from selected drive into memory starting at address $0800, the first byte of this sector being the number of sectors to load subsequently (1 in the case of DOS 3.3),

DOS 3.3 boot stage 1 code analysis Unlike disassembled code from section above, the code extracts (from DOS 3.3) below are independent related to the host hardware architecture. Also by definition, code segments below can be patched unlike code above which originates from the ROM. SECNUM EQU $3D Sector # for the ROMRWTS routine BUFPTR EQU $26 Buffer pointer for the ROMRWTS routine * Note: BUFPTR memory cell set to zero beforewards. ROMRWTS EQU $3E Pointer to ROMRWTS routine SETKBD EQU $FE89 SETVID EQU $FE93 MONINIT EQU $FB2F 0800 0801

DFB 1 Boot stage 1 is 1 sector large LDA BUFPTR+1 CMP #9 At first time (BUFPTR+1) is set to 9.. BNE :0 Branch iif already initialized * Let ROMRWTS point to read sector subroutine within disk controller card ROM * ($C65C if disk controller card in slot 6) LDA SLOTZ LSR LSR LSR LSR ORA #$C0 STA ROMRWTS+1 LDA #$5C STA ROMRWTS * Compute the highest memory page # involved for Boot stage 2 CLC LDA :10+1 ADC :20 STA :10+1 :0 LDX :20 Index to physical number BMI :1 from table starting @ :30 ($084D)

LDA :30,X STA SECNUM DEC :20 LDA :10+1 STA BUFPTR+1 DEC :10+1 LDX SLOTZ JMP (ROMRWTS) :1 INC :10+1 INC :10+1 * Boot stage 2 lies in page $B7 so the double increment above * from the final value $B5 is required JSR SETKBD Setup IO hooks within page zero JSR SETVID JSR MONINIT * Boot stage 2 begins at page $B7 (see the two increments above) LDX SLOTZ JMP (:10) * List of sectors (physical) to load from track zero to RAM 084D :30 HEX 000D0B0907 HEX 0503010E0C HEX 0A08060402 HEX 0F ... 08FD :10 DA $B600 Where in memory to load last sector 08FF :20 HEX 09 # of sectors to load (for Boot 2).. We have to check that the location $4F is unchanged by the Boot1 stage (checked for the three F8 ROM subroutines called before Boot stage 2 is entered). Just to sum up the loading process, here is the table used within Boot stage 1 (in charge of loading the sectors for Boot stage 2). Loading Physical order sector

Logical (RWTS) sector (DOS 3.3 interleave)

Dest. Memory page

1

$0C

$09

$BF

2

$0E

$08

$BE

3

$01

$07

$BD

4

$03

$06

$BC

5

$05

$05

$BB

6

$07

$04

$BA

7

$09

$03

$B9

8

$0B

$02

$B8

9

$0D

$01

$B7

10

$00

$00

$B6

From the table above we learn that boot stage 2 code is loaded from physical sector $0D from disk (track zero of course) which corresponds to DOS 3.3 sector 1 (useful when time comes to patch the DOS 3.3 image on disk: see below).

DOS 3.3 boot stage 2 analysis Here is the disassembled listing of the boot stage 2 main code REBOOT EQU $BFC8 SETKBD EQU $FE89 B700 * Boot stage 2 routine is called with X being $60 (slot number times 16) STX SNUM16 STX SLOTFND

B744 P0 B74A PUTDOS ... B78D B793 RWPAGES

:0

LDA STA STA LDA STA LDA STA LDA STA LDY DEY STY LDA STA TXA LSR LSR LSR LSR TAX LDA STA STA JSR LDX TXS STX JMP JSR JMP

#1 DRVFND DNUM NUMPGS NSECSRW #2 TNUM #4 SNUM FRSTBOOT+1 USRBUF+1 #1 CMDCODE

27 sectors to read..

Read Cmd code ;Slot # ; from slot16 value

#0 $04F8,X $0478,X RWPAGES #$FF VOLEXPT REBOOT SETKBD DOSSTRT Writes DOS on first two tracks of disk

DS LDA LDY JSR LDY DEY BPL LDY NOP NOP DEC STY DEC DEC BNE RTS

6 RWTSPPTR+1 RWTSPPTR CALLRWTS SNUM :0 #15 TNUM SNUM USRBUF+1 NSECRWSECS+1 RWPAGES

... B7E0 NUMPGS DFB 27 NSECSRW DS 1 RWTSPPTR DA TBLTYPE FRSTBOOT DA $B600 * Below is the RWTS parm table used by Boot stage 2, and * (I guess) the whole RWTS related activity of DOS 3.3.. B7E8 TBLTYPE HEX 01 SNUM16 HEX 60 B7EA DNUM HEX 01 VOLEXPT HEX FF TNUM HEX 0C SNUM DS 1 DA $B7FB USRBUF DA $9600

CMDCODE ERRCODE VOLFND SLOTFND B7F8 DRVFND

DA DFB DS HEX HEX HEX

$0100 2 1 FE 60 01

Write Cmd Code

Patch content Here we have tagged the lines which are further considered, that is: • The lines that arbitrarily update the drive number to 1; • The lines representing the memory slots for the drive number; • The line where some extra machine language code could be stored. The code segment below inserted within the main routine for Boot stage 2 code (from $B700 to $B78C) would allow the user to boot from external drive (# of additional bytes within the remark column). LDY #2 STY TNUM +0 DEY STY CMDCODE -1 LDA $4F CMP #$E0 BEQ *+3 DEY +5 STY DRVFND STY DNUM 4 additional bytes are required. That would mean that the whole content from $B706 to $B792 be updated or displaced to higher addresses.. The displacement of routines above the 6 bytes hole will imply some relocations within DOS that will be covered in the next section.

User manual for patching a DOS 3.3 image Start a session usually with an unpatched DOS 3.3 (booting complete). Warning: for the time being, only a 48K slave disk can be patched: I might work on a 32K or master image of DOS 3.3 if the need emerges within the community. However, the procedure described below makes no control about the correct version of DOS on the disk. Do not try to run it on an already patched DOS 3.3 image. You have been warned..Now the interesting bits... The use of the mini assembler requires either an enhanced //e, a //gs or the integer language being active. From within the monitor, enter the code below: *B7EB: 0 0 1 N B7F0: 0 17 0 1 1 0 N 45:B7 0 E8 0 *B7B5G The two lines above read the original sector from disk because the data from page $B7 have already been updated.. *172E