mirror of
https://github.com/elliotnunn/NetBoot.git
synced 2024-11-19 16:32:45 +00:00
c898af28d3
More gross inefficiencies to be squashed
865 lines
32 KiB
Plaintext
865 lines
32 KiB
Plaintext
myUnitNum equ 52
|
|
myDRefNum equ ~myUnitNum
|
|
|
|
serverBufSize equ 32
|
|
|
|
|
|
Code
|
|
|
|
; This is the entry point, which the ROM jumps to with one of three
|
|
; selectors. This whole block of code lives inside the system heap, in a
|
|
; block that the ROM code forgets ever to free. So we simply drop our
|
|
; driver here, and relegate the one-time init code to the end of the
|
|
; block.
|
|
|
|
bra OneTimeInitCode
|
|
dc.l 'NtBt'
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
DrvrBase
|
|
dc.w $4F00 ; dReadEnable dWritEnable dCtlEnable dStatEnable dNeedLock
|
|
dc.w 0 ; delay
|
|
dc.w 0 ; evt mask
|
|
dc.w 0 ; menu
|
|
|
|
dc.w DrvrOpen-DrvrBase
|
|
dc.w DrvrPrime-DrvrBase
|
|
dc.w DrvrControl-DrvrBase
|
|
dc.w DrvrStatus-DrvrBase
|
|
dc.w DrvrClose-DrvrBase
|
|
DrvrName dc.b 8, ".LANDisk", 0
|
|
|
|
g
|
|
gNumBlks dc.l 0 ; the source of all truth
|
|
gMyDCE dc.l 0
|
|
gExpectHdr dc.l 0
|
|
gProgress dc.l 0
|
|
gQuery dcb.b 20 ; really need to consider the length of this!
|
|
gWDS dcb.b 2+4+2+4+2+4+2 ; room for an address and two data chunks
|
|
gMyPB dcb.b $32+2 ; allow us to clear it with move.l's
|
|
odd
|
|
gSaveAddr dcb.b 16
|
|
gAddr dcb.b 16
|
|
even
|
|
|
|
; a0=iopb, a1=dce on entry to all of these...
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
DrvrOpen
|
|
move.l A0,-(SP)
|
|
lea gMyDCE,A0 ; dodgy, need this for IODone
|
|
move.l A1,(A0)
|
|
move.l (SP)+,A0
|
|
|
|
move.w #0,$10(A0) ; ioResult
|
|
rts
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
DrvrPrime
|
|
|
|
; Convert the ioPosOffset in the parameter block to a block offset (allows large vol support).
|
|
btst.b #0,$2C(A0) ; test ioPosMode & kUseWidePositioning
|
|
bne.s .wide
|
|
.notwide move.l $10(A1),D0
|
|
bra.s .gotD0
|
|
.wide move.l $2E(A0),D0 ; the block offset can only be up to 32 bits
|
|
or.l $32(A0),D0
|
|
.gotD0 ror.l #4,D0 ; now D0 = (LS 23 bits) followed by (MS 9 bits)
|
|
ror.l #5,D0
|
|
move.l D0,$2E(A0) ; ioPosOffset = D0 = byte_offset/512
|
|
|
|
; Return with a "pending" ioResult.
|
|
move.w #1,$10(A0) ; ioResult = pending. We will return without an answer.
|
|
|
|
; Wang the state machine!
|
|
cmp.b #2,7(A0) ; ioTrap == _Read?
|
|
bne DrvrSendWrite ; transition from "Idle" to "Await Comp Send Write Packet"
|
|
bra DrvrSendRead ; transition from "Idle" to "Await Comp Send Read Packet"
|
|
|
|
|
|
|
|
|
|
|
|
; Some wrappers for the routines below...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DrvrSendRead
|
|
; Called from Prime routine or socket listener: PB/DCE in A0/A1 must be preserved (but we only require A0)
|
|
lea gExpectHdr,A2
|
|
clr.w (A2)+
|
|
addq.w #1,(A2) ; packet filter sequence word
|
|
lea gProgress,A2
|
|
clr.l (A2)
|
|
|
|
lea gSaveAddr,A2
|
|
lea gAddr,A3
|
|
move.b (A2)+,(A3)+ ; copy the address struct, dang it!
|
|
move.l (A2)+,(A3)+
|
|
move.l (A2)+,(A3)+
|
|
move.l (A2)+,(A3)+
|
|
move.w (A2)+,(A3)+
|
|
move.b (A2)+,(A3)+
|
|
|
|
lea gQuery,A2
|
|
move.w #$8000,(A2)+ ; Means a polite request
|
|
move.w gExpectHdr+2,(A2)+
|
|
|
|
move.l $28(A0),D0 ; [ioActCount (in bytes)
|
|
lsr.l #4,D0
|
|
lsr.l #5,D0 ; / 512]
|
|
add.l $2E(A0),D0 ; + ioPosOffset (in blocks)
|
|
move.l D0,(A2)+ ; -> "offset" field of request
|
|
|
|
move.l $24(A0),D0 ; [ioReqCount (in bytes)
|
|
sub.l $28(A0),D0 ; - ioActCount (in bytes)]
|
|
lsr.l #4,D0
|
|
lsr.l #5,D0 ; / 512
|
|
move.l D0,(A2)+ ; -> "length" field of request
|
|
|
|
lea gWDS,A2
|
|
clr.w (A2)+ ; WDS+0: reserved field
|
|
pea gAddr
|
|
move.l (SP)+,(A2)+ ; WDS+2: pointer to address struct
|
|
move.w #12,(A2)+ ; WDS: push pointer/length
|
|
pea gQuery
|
|
move.l (SP)+,(A2)+
|
|
clr.w (A2)+ ; WDS: end with zero
|
|
|
|
move.l A0,-(SP)
|
|
lea gMyPB,A0
|
|
bsr DrvrClearBlock
|
|
pea DrvrDidSendRead
|
|
move.l (SP)+,$C(A0) ; ioCompletion
|
|
move.w #-10,$18(A0) ; ioRefNum = .MPP
|
|
move.w #246,$1A(A0) ; csCode = writeDDP
|
|
move.b #10,$1C(A0) ; socket = 10 (hardcoded)
|
|
move.b #1,$1D(A0) ; set checksumFlag
|
|
pea gWDS
|
|
move.l (SP)+,$1E(A0) ; wdsPointer to our WriteDataStructure
|
|
dc.w $A404 ; _Control ,async
|
|
move.l (SP)+,A0
|
|
|
|
rts
|
|
|
|
|
|
DrvrDidSendRead
|
|
; Called as completion routine: PB/result in A0/D0, must preserve all registers other than A0/A1/D0-D2
|
|
|
|
lea gExpectHdr,A2
|
|
move.w #$8100,(A2) ; Enable packet reception
|
|
|
|
rts ; TODO: set up a timeout/retry task
|
|
|
|
|
|
DrvrSendWrite
|
|
; Called from Prime routine or socket listener: PB/DCE in A0/A1 must be preserved (but we only require A0)
|
|
|
|
; D1 = block index within chunk
|
|
move.l $28(A0),D1
|
|
lsr.l #5,D1
|
|
lsr.l #4,D1
|
|
move.l D1,D0
|
|
and.l #32-1,D1
|
|
|
|
move.l $28(A0),D2
|
|
add.l #512,D2
|
|
cmp.l $24(A0),D2
|
|
bne.s .notLastBlock
|
|
bset #7,D1
|
|
.notLastBlock
|
|
|
|
; D0 = first block of chunk
|
|
and.l #-32,D0
|
|
add.l $2E(A0),D0
|
|
|
|
tst.l D1
|
|
bne.s .notFirstBlockOfChunk
|
|
lea gExpectHdr,A2
|
|
clr.w (A2)+
|
|
addq.w #1,(A2) ; packet filter sequence word
|
|
.notFirstBlockOfChunk
|
|
|
|
lea gSaveAddr,A2
|
|
lea gAddr,A3
|
|
move.b (A2)+,(A3)+ ; copy the address struct, dang it!
|
|
move.l (A2)+,(A3)+
|
|
move.l (A2)+,(A3)+
|
|
move.l (A2)+,(A3)+
|
|
move.w (A2)+,(A3)+
|
|
move.b (A2)+,(A3)+
|
|
|
|
lea gQuery,A2
|
|
move.b #$82,(A2)+ ; Means a polite request
|
|
move.b D1,(A2)+ ; nth block of this chunk follows
|
|
move.w gExpectHdr+2,(A2)+
|
|
move.l D0,(A2)+ ; first block of this chunk
|
|
|
|
lea gWDS,A2
|
|
clr.w (A2)+ ; WDS+0: reserved field
|
|
pea gAddr
|
|
move.l (SP)+,(A2)+ ; WDS+2: pointer to address struct
|
|
|
|
move.w #8,(A2)+ ; WDS: push length/ptr of header
|
|
pea gQuery
|
|
move.l (SP)+,(A2)+
|
|
|
|
move.w #512,(A2)+ ; WDS: push length/ptr of body
|
|
move.l $20(A0),D0 ; ptr = ioBuffer
|
|
add.l $28(A0),D0 ; + ioActCount
|
|
move.l D0,(A2)+
|
|
|
|
clr.w (A2)+ ; WDS: end with zero
|
|
|
|
move.l A0,-(SP)
|
|
lea gMyPB,A0
|
|
bsr DrvrClearBlock
|
|
pea DrvrDidSendWrite
|
|
move.l (SP)+,$C(A0) ; ioCompletion
|
|
move.w #-10,$18(A0) ; ioRefNum = .MPP
|
|
move.w #246,$1A(A0) ; csCode = writeDDP
|
|
move.b #10,$1C(A0) ; socket = 10 (hardcoded)
|
|
move.b #1,$1D(A0) ; set checksumFlag
|
|
pea gWDS
|
|
move.l (SP)+,$1E(A0) ; wdsPointer to our WriteDataStructure
|
|
dc.w $A404 ; _Control ,async
|
|
move.l (SP)+,A0
|
|
|
|
rts
|
|
|
|
|
|
DrvrDidSendWrite ; completion routine for the above control call..
|
|
; need to test whether to send another, or switch to wait mode...
|
|
|
|
move.l gMyDCE,A0
|
|
move.l 6+2(A0),A0 ; A3 = dCtlQHdr.qHead = ParamBlk
|
|
|
|
movem.l $24(A0),D0/D1 ; D0=ioReqCount, D1=ioActCount
|
|
add.l #512,D1
|
|
move.l D1,$28(A0)
|
|
|
|
cmp.l D0,D1
|
|
beq.s .sentAllOfChunk
|
|
and.l #(32-1)*512,D0
|
|
beq.s .sentAllOfChunk
|
|
bra DrvrSendWrite
|
|
|
|
.sentAllOfChunk
|
|
rts ; TODO: set up a timeout/retry task
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DrvrClearBlock
|
|
move.w #$32/2-1,D0
|
|
.loop clr.w (A0)+
|
|
dbra D0,.loop
|
|
lea -$32(A0),A0
|
|
rts
|
|
|
|
DrvrSockListener
|
|
; Registers on call to DDP socket listener:
|
|
; A0 Reserved for internal use by the .MPP driver. You must preserve this register
|
|
; until after the ReadRest routine has completed execution.
|
|
; A1 Reserved for internal use by the .MPP driver. You must preserve this register
|
|
; until after the ReadRest routine has completed execution.
|
|
; A2 Pointer to the .MPP driver's local variables. Elliot says: the frame and packet
|
|
; header ("RHA") are at offset 1 from A2 (keeps the 2-byte fields aligned)
|
|
; A3 Pointer to the first byte in the RHA past the DDP header bytes (the first byte
|
|
; after the DDP protocol type field).
|
|
; A4 Pointer to the ReadPacket routine. The ReadRest routine starts 2 bytes after the
|
|
; start of the ReadPacket routine.
|
|
; A5 Free for your use before and until your socket listener calls the ReadRest routine.
|
|
; D0 Lower byte is the destination socket number of the packet.
|
|
; D1 Word indicating the number of bytes in the DDP packet left to be read (that is,
|
|
; the number of bytes following the DDP header).
|
|
; D2 Free for your use.
|
|
; D3 Free for your use.
|
|
|
|
; Registers on entry to the ReadPacket routine
|
|
; A3 Pointer to a buffer to hold the data you want to read
|
|
; D3 Number of bytes to read; must be nonzero
|
|
|
|
; Registers on exit from the ReadPacket routine
|
|
; A0 Unchanged
|
|
; A1 Unchanged
|
|
; A2 Unchanged
|
|
; A3 Address of the first byte after the last byte read into buffer
|
|
; A4 Unchanged
|
|
; D0 Changed
|
|
; D1 Number of bytes left to be read
|
|
; D2 Unchanged
|
|
; D3 Equals 0 if requested number of bytes were read, nonzero if error
|
|
|
|
; Registers on entry to the ReadRest routine
|
|
; A3 Pointer to a buffer to hold the data you want to read
|
|
; D3 Size of the buffer (word length); may be 0
|
|
|
|
; Registers on exit from the ReadRest routine
|
|
; A0 Unchanged
|
|
; A1 Unchanged
|
|
; A2 Unchanged
|
|
; A3 Pointer to first byte after the last byte read into buffer
|
|
; D0 Changed
|
|
; D1 Changed
|
|
; D2 Unchanged
|
|
; D3 Equals 0 if requested number of bytes exactly equaled the size of the buffer;
|
|
; less than 0 if more data was left than would fit in buffer (extra data equals
|
|
; -D3 bytes); greater than 0 if less data was left than the size of the buffer
|
|
; (extra buffer space equals D3 bytes)
|
|
|
|
; cmp.b #10,-1(A3) ; DDP protocol type better be ATBOOT
|
|
; bne.s DrvrTrashPacket
|
|
|
|
moveq.l #4,D3
|
|
jsr (A4) ; Read the nice short packet header
|
|
bne DrvrTrashPacket
|
|
move.l -4(A3),D2
|
|
|
|
move.l gExpectHdr,D3 ; Check the packet header
|
|
eor.l D2,D3
|
|
swap D3
|
|
clr.b D3
|
|
bne DrvrTrashPacket
|
|
|
|
btst #25,D2
|
|
bne.s DrvrDidReceiveWrite
|
|
|
|
|
|
DrvrDidReceiveRead
|
|
swap D2
|
|
and.l #32-1,D2 ; D2.L = block offset within 32blk chunk
|
|
|
|
move.l gMyDCE,A3
|
|
move.l 6+2(A3),A3 ; A3 = dCtlQHdr.qHead
|
|
|
|
move.l $28(A3),D3 ; D3 = .ioActCount...
|
|
lsr.l #5,D3
|
|
lsr.l #4,D3 ; ...now in number of blocks
|
|
and.l #-32,D3 ; ...rounded down to a block chunk
|
|
add.l D2,D3 ; ...added back the received block
|
|
asl.l #8,D3
|
|
add.l D3,D3 ; ... = byte offset within buffer
|
|
|
|
move.l $20(A3),A3 ; .ioBuffer
|
|
add.l D3,A3 ; A3 = ioBuffer + offset
|
|
move.l #512,D3 ; D3 = size
|
|
jsr 2(A4) ; ReadRest (A3=dest, D3=length)
|
|
bne DrvrTrashPacket
|
|
|
|
lea gProgress,A1 ; Skip the next step if this packet is a repeat
|
|
move.l (A1),D1
|
|
bset.l D2,D1 ; (we saved blkidx in D2 before ReadRest)
|
|
bne.s DrvrTrashPacket
|
|
move.l D1,(A1)
|
|
|
|
move.l gMyDCE,A0
|
|
move.l 6+2(A0),A0 ; dCtlQHdr.qHead
|
|
|
|
move.l $28(A0),D0 ; Increment ioActCount and cmp with ioReqCount
|
|
add.l #512,D0
|
|
move.l D0,$28(A0)
|
|
cmp.l $24(A0),D0
|
|
beq.s DrvrIODone
|
|
|
|
addq.l #1,D1 ; If bitmap=$FFFFFFFF then get the next chunk of 32
|
|
beq DrvrSendRead ; A0 must be the PB
|
|
|
|
rts ; Just return to await more packets.
|
|
|
|
|
|
DrvrDidReceiveWrite
|
|
moveq.l #0,D3
|
|
jsr 2(A4) ; ReadRest (D3=0 i.e. discard)
|
|
|
|
move.l gMyDCE,A0
|
|
move.l 6+2(A0),A0 ; A3 = dCtlQHdr.qHead = ParamBlk
|
|
|
|
movem.l $24(A0),D0/D1 ; D0=ioReqCount, D1=ioActCount
|
|
cmp.l D0,D1
|
|
blo DrvrSendWrite
|
|
|
|
bra.s DrvrIODone
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DrvrIODone
|
|
lea gExpectHdr,A1 ; Disable this socket listener
|
|
clr.w (A1)
|
|
|
|
move.l gMyDCE,A1
|
|
moveq.l #0,D0
|
|
move.l $8FC,A0 ; jIODone (D0 = result, A1 = DCE)
|
|
jmp (A0)
|
|
|
|
|
|
|
|
DrvrTrashPacket
|
|
moveq.l #0,D3
|
|
jmp 2(A4) ; ReadRest nothing
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
DrvrControl
|
|
cmp.w #21,$1A(A0)
|
|
beq.s control_kDriveIcon
|
|
cmp.w #22,$1A(A0)
|
|
beq.s control_kMediaIcon
|
|
bra.s control_unknown
|
|
|
|
control_kDriveIcon
|
|
control_kMediaIcon
|
|
lea DrvrIcon,A2
|
|
move.l A2,$1C(A0)
|
|
clr.w $10(A0) ; ioResult = noErr
|
|
bra DrvrFinish
|
|
|
|
control_unknown
|
|
move.w #-17,$10(A0) ; ioResult = controlErr
|
|
bra DrvrFinish
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
DrvrStatus
|
|
cmp.w #6,$1A(A0)
|
|
beq.s status_fmtLstCode
|
|
cmp.w #8,$1A(A0)
|
|
beq.s status_drvStsCode
|
|
bra.s status_unknown
|
|
|
|
status_fmtLstCode ; tell them about our size
|
|
movem.l A2/A3,-(SP)
|
|
|
|
lea gNumBlks,A3
|
|
move.l (A3),D0
|
|
lsl.l #5,D0 ; convert from blocks to bytes
|
|
lsl.l #4,D0
|
|
|
|
move.w #1,$1C(A0)
|
|
move.l $1C+2(A0),A2
|
|
move.l D0,0(A2)
|
|
move.l #$40000000,4(A2)
|
|
|
|
movem.l (SP)+,A2/A3
|
|
|
|
move.w #0,$10(A0) ; ioResult = noErr
|
|
bra DrvrFinish
|
|
|
|
status_drvStsCode ; tell them about some of our flags
|
|
move.w #0,$1C(A0) ; csParam[0..1] = track no (0)
|
|
move.l #$00080000,$1C+2(A0) ; csParam[2..5] = same flags as dqe
|
|
|
|
move.w #0,$10(A0) ; ioResult = noErr
|
|
bra DrvrFinish
|
|
|
|
status_unknown
|
|
move.w $1A(A0),D0 ; dodgy, for debugging
|
|
add.w #$3000,D0
|
|
dc.w $A9C9
|
|
|
|
move.w #-18,$10(A0) ; ioResult
|
|
bra DrvrFinish
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
DrvrClose
|
|
move.w #$4444,D0
|
|
dc.w $A9C9
|
|
|
|
move.w #0,$10(A0) ; ioResult
|
|
rts
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
DrvrFinish
|
|
move.w 6(A0),D1 ; iopb.ioTrap
|
|
btst #9,D1 ; noQueueBit
|
|
bne.s DrvrNoIoDone
|
|
move.l $8FC,-(SP) ; jIODone
|
|
DrvrNoIoDone
|
|
rts
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
DrvrIcon
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %10000000000000000000000000000001
|
|
dc.l %10000000000000001000000000000001
|
|
dc.l %10101010101010011001010101010101
|
|
dc.l %10101010101010000001010101010101
|
|
dc.l %10101010101010000001010101010101
|
|
dc.l %10101010101010000101010101010101
|
|
dc.l %10101010101010000001010101010101
|
|
dc.l %10101010101010100101010101010101
|
|
dc.l %10101010101010000001010101010101
|
|
dc.l %10101010101010100101010101010101
|
|
dc.l %10000000000000000000000000000001
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %00000000000000000000000000000000
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %11111111111111111111111111111111
|
|
dc.l %11111111111111111111111111111111
|
|
dc.b 22, "AppleTalk NetBoot Disk", 0
|
|
DrvrEnd
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
OneTimeInitCode
|
|
cmp.l #1,4(SP)
|
|
beq getBootBlocks
|
|
cmp.l #2,4(SP)
|
|
beq getSysVol
|
|
cmp.l #3,4(SP)
|
|
beq mountSysVol
|
|
|
|
move.l #-1,d0
|
|
rts
|
|
|
|
|
|
getBootBlocks
|
|
; Now is the time to install our DRVR because we are guaranteed an opportunity to boot if we don't fuck up.
|
|
|
|
link A6,#-$32
|
|
movem.l A2-A4/D3-D7,-(SP)
|
|
|
|
; Patch the server address into the DRVR code (TODO: concentrate all global patches here)
|
|
move.l 12(A6),A0 ; global pointer
|
|
move.l 24(A0),D0 ; AddrBlock
|
|
|
|
lea gSaveAddr,A0
|
|
|
|
move.b #10,15(A0) ; hardcode DDP protocol ID
|
|
move.b D0,13(A0) ; socket
|
|
lsr.w #4,D0
|
|
lsr.w #4,D0
|
|
move.b D0,11(A0) ; node
|
|
swap D0
|
|
move.w D0,7(A0) ; network
|
|
|
|
; Patch the disk image name and size into the DRVR code
|
|
; bsr BootPicker ; A0 = pstring ptr
|
|
; lea gNumBlks,A1
|
|
; move.l -4(A0),(A1) ; the size is underneath the pstring ptr
|
|
; move.l -4(A0),D6 ; D6 = block count, needed for DQE
|
|
; lea gQFilename,A1 ; A1 = dest
|
|
; moveq.l #1,D0
|
|
; add.b (A0),D0
|
|
; dc.w $A22E ; _BlockMoveData
|
|
|
|
; Install the driver in the unit table
|
|
lea DrvrBase,A0
|
|
move.l #myDRefNum,D0
|
|
dc.w $A43D ; _DrvrInstall ReserveMem
|
|
|
|
; That call created a DCE. Find and lock.
|
|
move.l $11C,A0 ; UTableBase
|
|
move.l myUnitNum*4(A0),A0
|
|
dc.w $A029 ; _HLock
|
|
move.l (A0),A0
|
|
|
|
; Populate the empty DCE that DrvrInstall left us (forget fields related desk accessories)
|
|
lea DrvrBase,A2
|
|
move.l A2,0(A0) ; dCtlDriver = driver pointer (not handle)
|
|
move.w 0(A2),4(A0) ; dCtlFlags = drvrFlags
|
|
|
|
; Open the driver
|
|
lea -$32(SP),SP
|
|
move.l SP,A0
|
|
bsr clearblock
|
|
lea DrvrName,A1
|
|
move.l A1,$12(A0) ; IOFileName
|
|
dc.w $A000 ; _Open
|
|
lea $32(SP),SP
|
|
|
|
; Create a DQE. The fate of this exact DQE is to be copied and deleted by ROM code.
|
|
move.l #$16,D0
|
|
dc.w $A71E ; _NewPtr ,Sys,Clear
|
|
add.l #4,A0 ; has some cheeky flags at negative offset
|
|
move.l A0,A3
|
|
lea gDQEAddr,A0
|
|
move.l A3,(A0)
|
|
|
|
; Populate the DQE
|
|
move.l D6,D0 ; needs fixing for Ruby Slipper
|
|
lsl.l #5,D0 ; convert to bytes
|
|
lsl.l #4,D0
|
|
swap D0
|
|
move.l D0,$C(A3) ; dQDrvSz/dQDrvSz2
|
|
move.l #$00080000,-4(A3) ; secret flags, see http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/Files/Files-112.html
|
|
move.w #1,4(A3) ; qType
|
|
move.w #0,$A(A3) ; dQFSID should be for a native fs
|
|
|
|
; Into the drive queue (which will further populate the DQE)
|
|
bsr findFreeDriveNum ; get drvnum in D0
|
|
lea gDriveNum,A0
|
|
move.w D0,(A0)
|
|
swap D0
|
|
move.w #myDRefNum,D0 ; D0.H = drvnum, D0.L = drefnum
|
|
move.l D0,D3 ; we need this in a sec
|
|
move.l A3,A0
|
|
dc.w $A04E ; _AddDrive
|
|
|
|
; Open our socket
|
|
lea -$32(SP),SP
|
|
move.l SP,A0
|
|
bsr clearblock
|
|
move.w #-10,$18(A0) ; ioRefNum = .MPP
|
|
move.w #248,$1A(A0) ; csCode = openSkt
|
|
move.b #10,$1C(A0) ; socket = 10, same as ATBOOT uses
|
|
lea DrvrSockListener,A2
|
|
move.l A2,$1E(A0) ; listener
|
|
dc.w $A004 ; _Control
|
|
lea $32(SP),SP
|
|
|
|
; Get the real 1024k of boot blocks to a temp location
|
|
; (it will eventually get trashed, but we have time)
|
|
lea 4096(A5),A4 ; above BootGlobals
|
|
|
|
lea -$32(SP),SP
|
|
move.l SP,A0
|
|
bsr clearblock
|
|
move.l D3,22(A0) ; IOVRefNum=drvnum, IORefNum=drefnum
|
|
move.l A4,32(A0) ; IOBuffer
|
|
move.l #1024,36(A0) ; IOReqCount = 2 blocks
|
|
move.l #0,46(A0) ; IOPosOffset = 0
|
|
move.w #1,44(A0) ; IOPosMode = from start
|
|
dc.w $A002 ; _Read
|
|
lea $32(SP),SP
|
|
|
|
; Put the boot blocks in netBOOT's global data structure as requested
|
|
move.l A4,A0
|
|
move.l 12(A6),A1
|
|
lea $BA(A1),A1
|
|
move.l #$138,D0
|
|
dc.w $A22E ; _BlockMoveData
|
|
|
|
move.l A1,A0 ; A0 = truncated BBs
|
|
move.l A4,A1 ; A1 = full-length BBs
|
|
bsr HealInjuredBootBlocks
|
|
|
|
; Clean up our stack frame
|
|
movem.l (SP)+,A2-A4/D3-D7
|
|
unlk A6
|
|
|
|
move.l #0,D0
|
|
rts
|
|
|
|
getSysVol ; pointless call :(
|
|
move.l #0,D0
|
|
rts
|
|
|
|
mountSysVol
|
|
link A6,#-$32
|
|
movem.l A2-A4/D3,-(SP)
|
|
|
|
lea gDriveNum,A0
|
|
move.w (A0),D3
|
|
|
|
; System 7 needs MountVol to return the right vRefNum
|
|
move.l $366,A0 ; Steal existing PB from FSQHead
|
|
|
|
; Set aside the FS queue to stop MountVol deadlocking
|
|
move.w $360,-(SP) ; FSBusy
|
|
move.l $362,-(SP) ; FSQHead
|
|
move.l $366,-(SP) ; FSQTail
|
|
clr.w $360
|
|
clr.l $362
|
|
clr.l $366
|
|
|
|
; MountVol
|
|
bsr clearblock
|
|
move.w D3,$16(A0) ; ioVRefNum = ioDrvNum = the drive number
|
|
dc.w $A00F ; _MountVol
|
|
bne error
|
|
|
|
; Restore the FS queue
|
|
move.l (SP)+,$366
|
|
move.l (SP)+,$362
|
|
move.w (SP)+,$360
|
|
|
|
; Tattle about the DQE and VCB
|
|
move.l 4+12(A6),A1
|
|
move.l $356+2,A0 ; VCBQHdr.QHead (maybe I should be clever-er)
|
|
move.l A0,(A1)
|
|
|
|
move.l 4+16(A6),A1
|
|
lea gDQEAddr,A0
|
|
move.l (A0),(A1)
|
|
|
|
lea Code,A0
|
|
move.l #OneTimeInitCode-Code,D0
|
|
dc.w $A020 ; Cut the unnecessary code off me
|
|
|
|
movem.l (SP)+,A2-A4/D3
|
|
unlk A6
|
|
|
|
move.l #0,d0
|
|
rts
|
|
|
|
error
|
|
move.w #$7777,D0
|
|
dc.w $A9C9
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
gDriveNum dc.w 0
|
|
gDQEAddr dc.l 0
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
clearblock
|
|
move.w #$32/2-1,D0
|
|
.loop clr.w (A0)+
|
|
dbra D0,.loop
|
|
lea -$32(A0),A0
|
|
rts
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
findFreeDriveNum ; and return it in D0. Free to trash the usual registers
|
|
; Find a free drive number (nicked this code from BootUtils.a:AddMyDrive)
|
|
LEA $308,A0 ; [DrvQHdr]
|
|
MOVEQ #4,D0 ; start with drive number 4
|
|
.CheckDrvNum
|
|
MOVE.L 2(A0),A1 ; [qHead] start with first drive
|
|
.CheckDrv
|
|
CMP.W 6(A1),D0 ; [dqDrive] does this drive already have our number?
|
|
BEQ.S .NextDrvNum ; yep, bump the number and try again.
|
|
CMP.L 6(A0),A1 ; [qTail] no, are we at the end of the queue?
|
|
BEQ.S .GotDrvNum ; if yes, our number's unique! Go use it.
|
|
MOVE.L 0(A1),A1 ; [qLink] point to next queue element
|
|
BRA.S .CheckDrv ; go check it.
|
|
|
|
.NextDrvNum
|
|
; this drive number is taken, pick another
|
|
ADDQ.W #1,D0 ; bump to next possible drive number
|
|
BRA.S .CheckDrvNum ; try the new number
|
|
.GotDrvNum
|
|
rts
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
HealInjuredBootBlocks ; patch the BBs to fix themselves if executed
|
|
|
|
; Args: A0 = truncated boot blocks (138b), A1 = correct boot blocks (1024b)
|
|
|
|
; If these boot blocks are executable (from offset 2), then the 138 bytes of
|
|
; declarative data copied by the netBOOT driver are not enough. We edit the boot
|
|
; blocks with a stub that copies the entire 1k into place. System 7 needs this.
|
|
|
|
; This unfortunately clobbers the declarative part of the boot blocks, so we need to
|
|
; check for declarative boot blocks and leave them unchanged
|
|
|
|
move.l A0,-(SP) ; Save A1 to a global, but need to keep A0
|
|
lea .gFullLoc,A0
|
|
move.l A1,(A0)
|
|
move.l (SP)+,A0
|
|
|
|
move.b 6(A0),D0 ; BBVersion
|
|
cmp.b #$44,D0
|
|
beq.s .executable
|
|
and.b #$C0,D0
|
|
cmp.b #$C0,D0
|
|
beq.s .executable
|
|
rts
|
|
|
|
; Relevant structure of the boot blocks:
|
|
; 0-1 bbID always 'LK'
|
|
; 2-5 bbEntry BRA.W base+128
|
|
; 6-7 bbVersion interpreted as above
|
|
; 8-137 data
|
|
; 138-1023 code (MISSING from netBOOT's short version)
|
|
|
|
; Our self-repairing boot blocks:
|
|
; 0-1 bbID always 'LK'
|
|
; 2-5 bbEntry BRA.W base+8
|
|
; 6-7 bbVersion interpreted as above
|
|
; 8-13 JSR .inPlaceFixRoutine
|
|
; 14-137 junk
|
|
|
|
|
|
.executable ; Need to leave bytes 6,7 intact
|
|
move.l #$60000004,2(A0) ; BB+2: BRA.W BB+8
|
|
move.w #$4EB9,8(A0) ; BB+8: JSR .inPlaceFixRoutine (abs)
|
|
lea .inPlaceFixRoutine,A1
|
|
move.l A1,10(A0)
|
|
|
|
move.l A0,A1 ; Clear the icache with a BlockMove
|
|
move.l #138,D0
|
|
dc.w $A02E ; _BlockMove
|
|
|
|
rts
|
|
|
|
.inPlaceFixRoutine ; The BB stub JSRs to here
|
|
move.l (SP)+,A1 ; so the return address will be at BB+14
|
|
lea -14(A1),A1 ; "Rewind" to the start of the BB
|
|
move.l .gFullLoc,A0 ; And here are our full boot blocks
|
|
move.l #1024,D0
|
|
dc.w $A02E ; _BlockMove (needs to clear cache)
|
|
|
|
jmp 2(A1) ; Jump to the fixed-up BB
|
|
|
|
.gFullLoc dc.l 0 ; Stuff addr of full-length BB in here
|