mirror of
https://github.com/ksherlock/hfs-boot.git
synced 2024-12-08 06:49:15 +00:00
e02675057f
Squashed commit of the following: commit44a6544242
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 commit7fc041289f
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. commit0fabe65aca
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 commit6da1f9fa3c
Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Tue Jul 27 21:31:23 2021 -0400 re-arrange to avoid relative expression warning commitdbfe66cc99
Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Tue Jul 27 21:31:01 2021 -0400 use smartport.aii commit95aa4d8bd5
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.
568 lines
8.0 KiB
Plaintext
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
|