; ; HFS boot. Boot block. ; This is stage 0 of the bootloader. It will find a file named ; '!' in the root directory of an HFS volume, load it, and execute it ; in full 16-bit mode, with a = prodos block call vector. ; ; this currently only works with 512-byte blocks (max volume size = 32M) ; but there's enough room to support variable block sizes. include 'hfs.aii' string asis blanks on __smartport__ set 1 if __smartport__ then include 'smartport.aii' endif ; ; 32-bit version large volumes. ExtendedExtent RECORD 0 startBlock ds.l 1 ; offset: $0 (0) ; first allocation block blockCount ds.l 1 ; offset: $4 (8) ; number of allocation blocks sizeof EQU * ; size: $8 (8) ENDR zp record 0 slot ds.w 1 ;vector ds.w 1 startingBlock ds.w 1 blockMultiplier ds.w 1 bnum ds.w 1 count ds.w 1 extents ds.b 3*ExtendedExtent.sizeof ; multiplication stuff m1 ds.w 1 m2 ds.l 1 m3 ds.l 1 if * >= $42 then aerror 'too much zero-page space' endif endr if not __smartport__ then pro record $42 cmd ds.b 1 unit ds.b 1 dataBuffer ds.b 2 blockNumber ds.b 2 endr endif buffer equ $2000 entry read_block_abs, read_extent_block entry vector entry extent_to_extent boot proc longi off longa off with zp dc.b $01 ; prodos boot id :D if not __smartport__ then stx pro.unit endif txa lsr a lsr a lsr a lsr a ora #$c0 sta vector+1 sta slot+1 stz slot ; check for prodos block-device signature bytes ; todo -- switch to extended smartport? needed for second stage. ; xx $20 xx $00 xx $03 [xx $00 - smarport ] ldy #1 lda (slot),y cmp #$20 bne noboot ldy #3 lda (slot),y bne noboot ldy #5 lda (slot),y cmp #$03 bne noboot if __smartport__ then ldy #7 lda (slot),y bne noboot ; ,$fb = smartport id byte which indicates if extended. not needed (yet) endif ldy #$ff lda (slot),y if __smartport__ then inc a inc a inc a endif sta vector bra ok ; not a prodos/smartport device. noboot brk $ea ok if not __smartport__ then lda #1 ; prodos read block sta pro.cmd endif clc xce rep #$30 longi on longa on ; stz startingBlock ; stz drAlBlkSiz stz bnum stz count if not __smartport__ then lda #buffer sta pro.dataBuffer endif ldx #0 lda #2 jsr read_block_abs ; ; assumes 512-byte blocks (max size = 64MB) ; ; wait a minute... max 65535 blocks, therefore high word of allocation block, etc, always 0. ; i assume hfs use 32-bit links in the btree for in-memory use (24-bit or 32 pointers) ; ; actually, offset could be 32-bit due to large allocation blocks. however, that's unreasonably large for the ; catalog file or boot loader file. ; ; search for a file named ! in the root directory. ; ! is ascii char $21 so it should sort early. ; ; with HFSMasterDirectoryBlock lda buffer+drAlBlSt xba sta startingBlock ; drAlBlkSiz is actually a 32-bit number. ; ; lda buffer+drAlBlkSiz+2 ; xba ; sta drAlBlkSiz ; xba lda buffer+drAlBlkSiz+1 xba lsr a ; / 2 sta blockMultiplier ; 0 = 512 byte blocks, 1 = ; ldx #3*HFSExtentDescriptor.sizeof-2 ;@cloop lda buffer+drCTExtRec,x ; xba ; sta extents,x ; dex ; dex ; bpl @cloop ldy #drCTExtRec ; offset jsr extent_to_extent endwith ; lda drAlBlSt ; clc ; adc extents lda #0 ldx #0 jsr read_extent_block ; ; block should be a btree header block. find the first leaf node. ; with BTHeaderRec ; lda buffer+BTNodeDescriptor.sizeof+firstLeafNode ; xba ; sta leaf+2 lda buffer+BTNodeDescriptor.sizeof+firstLeafNode+2 xba ; sta bnum endwith ; ; assert leaf < # allocated lbocks? ; jsr read_extent_block lda buffer+BTNodeDescriptor.numRecords ; # of records beq advance xba sta count again ldx #512-2 ; last entry @loop lda buffer,x ; entry offset xba tay lda buffer+HFSCatalogKey.parentID,y ; parent id bne notfound lda buffer+HFSCatalogKey.parentID+2,y xba cmp #2 blt @next beq @name bge notfound @name ; name is a p-string. lda buffer+HFSCatalogKey.nodeName,y cmp #$2101 ; pstr ! beq found bge notfound @next dex dex dec count bne @loop advance ; next block! lda buffer+BTNodeDescriptor.fLink+2 beq notfound xba jsr read_extent_block bra again notfound brk $ea found ; y = offset in block ; ; only works with contiguous files.... ; first block? ; 8 is magic offset for a key named ! ; assume < 65535 bytes :) with HFSCatalogFile lda buffer+8+recordType,y and #$00ff cmp #kHFSFileRecord bne notfound lda buffer+8+dataPhysicalSize+2,y ; xba lsr a ; >>9 since already xba and #%01111111 beq notfound sta count ; todo -- all extents... ; lda buffer+8+dataExtents,y ; xba ; sta extents ; lda buffer+8+dataExtents+2,y ; xba ; sta extents+2 tya clc adc #8+dataExtents tay jsr extent_to_extent ; now load the blocks and ; lda #$2000 ; if __smartport__ then ; sta sp.dataBuffer ; else ; sta pro.dataBuffer ; endif stz bnum @loop lda bnum ldx #0 jsr read_extent_block inc bnum lda #512 clc if __smartport__ then import sp:IOBlockDCB adc sp.dataBuffer sta sp.dataBuffer else adc pro.dataBuffer sta pro.dataBuffer endif dec count bne @loop ldy vector if not __smartport__ then ldx slot lda pro.unit and #$00ff endif jmp $2000 ; kiss of life. endp if __smartport__ then sp record pCount dc.b 3 unit dc.b 1 ; hard-coded dataBuffer dc.w $2000 blockNumber dc.l 1 ; actually 24-bit endr endif read_block_abs proc entry read_block_abs_long entry vector ; input ; a = hfs block # ; will be adjusted for allocation block offset ; with zp ; clc ; adc startingBlock ;read_block_abs if __smartport__ then sta sp.blockNumber stx sp.blockNumber+2 else sta pro.blockNumber endif read_block_abs_long php sec xce dc.b $20 ; jsr vector dc.w $ffff if __smartport__ then dc.b Command.ReadBlock dc.w sp endif bcs @fail xce plp rts @fail brk $ea endp macro ifcs &p1,&p2 bcc @0 &p1 &p2 @0 mend read_extent_block proc ; a = block # ; This doesn't check beyond the 3rd extent import read_block_abs_long with zp,ExtendedExtent @0 cmp extents+(sizeof*0)+blockCount bcs @1 ; clc ldx #sizeof*0+startBlock bra found @1 sbc extents+(sizeof*0)+blockCount cmp extents+(sizeof*1)+blockCount bcs @2 ; clc ldx #sizeof*1+startBlock bra found @2 sbc extents+(sizeof*1)+blockCount cmp extents+(sizeof*2)+blockCount bcs @3 ldx #sizeof*2+startBlock bra found @3 brk $ea found ; clc adc extents,x sta sp.blockNumber lda #0 adc extents+2,x sta sp.blockNumber+2 clc lda startingBlock adc sp.blockNumber sta sp.blockNumber lda #0 adc sp.blockNumber+2 sta sp.blockNumber+2 bra read_block_abs_long endp multiply proc ; inputs: m1 (16-bit), m2 (32-bit) ; outputs: m3 (32-bit) ; m1, m2 clobbered with zp stz m3 stz m3+2 lda m1 beq rts lda m2 ora m3 beq rts loop lsr m1 bcc next add clc lda m2 adc m3 sta m3 lda m2+2 adc m3+2 sta m3+2 next asl m2 rol m2+2 lda m1 bne loop rts rts endp extent_to_extent proc ; y = offset into buffer. ; clobbers x, y with zp,ExtendedExtent import multiply ldx #0 loop1 lda buffer,y xba sta extents,x stz extents+2,x iny iny inx inx inx inx cpx #sizeof*3 blt loop1 ; now multiply... lda blockMultiplier dec a beq offset ldx #sizeof*3-4 loop2 lda blockMultiplier sta m1 lda extents+0,x sta m2 stz m2+2 jsr multiply lda m3 sta extents+0,x lda m3+2 sta extents+2,x dex dex dex dex bpl loop2 offset if 0 then ; now add the block offset to the starting block. lda startingBlock clc adc extents+(ExtendedExtent.sizeof*0)+startBlock sta extents+(ExtendedExtent.sizeof*0)+startBlock lda #0 adc extents+(ExtendedExtent.sizeof*0)+startBlock+2 sta extents+(ExtendedExtent.sizeof*0)+startBlock+2 lda startingBlock clc adc extents+(ExtendedExtent.sizeof*1)+startBlock sta extents+(ExtendedExtent.sizeof*1)+startBlock lda #0 adc extents+(ExtendedExtent.sizeof*1)+startBlock+2 sta extents+(ExtendedExtent.sizeof*1)+startBlock+2 lda startingBlock clc adc extents+(ExtendedExtent.sizeof*2)+startBlock sta extents+(ExtendedExtent.sizeof*2)+startBlock lda #0 adc extents+(ExtendedExtent.sizeof*2)+startBlock+2 sta extents+(ExtendedExtent.sizeof*2)+startBlock+2 endif rts endp end