hfs-boot/bootblock.aii
Kelvin Sherlock e02675057f Support for variable block size (ie, volumes > 32 MB)
Squashed commit of the following:

commit 44a6544242
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Wed Aug 11 22:10:11 2021 -0400

    improved 32-bit (well, smartport is 24-bit) block support

commit 7fc041289f
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Wed Aug 4 23:49:15 2021 -0400

    convert the extent blocks into 32-bit absolute blocks when loading.
    Currently the block comparisons are still 16-bit, though.

commit 0fabe65aca
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Tue Aug 3 20:13:27 2021 -0400

    move stack adjustment code to take effect from the callback routines

commit 6da1f9fa3c
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Tue Jul 27 21:31:23 2021 -0400

    re-arrange to avoid relative expression warning

commit dbfe66cc99
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Tue Jul 27 21:31:01 2021 -0400

    use smartport.aii

commit 95aa4d8bd5
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Thu Jul 22 23:58:20 2021 -0400

    large volume support (WIP, untested).
    the general theory is, multiply the extents by the allocation adjustment to get physical block offsets.
    currently, comparisons are still 16-bit though.
2021-08-15 20:45:46 -04:00

568 lines
8.0 KiB
Plaintext

;
; 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