mirror of
https://github.com/LIV2/lide.device.git
synced 2025-12-06 00:32:45 +00:00
347 lines
8.4 KiB
ArmAsm
347 lines
8.4 KiB
ArmAsm
; reloc.S
|
|
; Modified from Open Source A4091.device by Stefan Reinauer and Chris Hooper - https://github.com/A4091/a3091-software
|
|
INCLUDE "exec/memory.i"
|
|
INCLUDE "lvo/exec_lib.i"
|
|
|
|
IFND ROM
|
|
section .text,code
|
|
ENDIF
|
|
|
|
NUM_ENTRIES EQU 5
|
|
|
|
; Frame pointer offsets
|
|
PHUNKS EQU -4
|
|
READHANDLE_TYPE EQU -8
|
|
READHANDLE_CURRENT EQU -12
|
|
FP_SIZE EQU READHANDLE_CURRENT
|
|
|
|
; API:
|
|
; Zorro ROM access:
|
|
; a0: rombase
|
|
; d0: offset
|
|
; Memory (RAM) access:
|
|
; a0: pointer to binary
|
|
; d0: 0
|
|
public _relocate
|
|
_relocate
|
|
movem.l d1-d7/a0-a6,-(sp)
|
|
link a4,#FP_SIZE
|
|
|
|
bsr InitHandle
|
|
|
|
; fetch file header
|
|
bsr RomFetch32
|
|
cmp.l #$3f3,d0 ; We only know hunk_hdr
|
|
bne .RelocateFail
|
|
|
|
; consume the header and remember number of hunks
|
|
bsr RomFetch32
|
|
bsr RomFetch32
|
|
move.l d0,d7 ; table size
|
|
subq.l #1,d7
|
|
move.l d7,d6 ; for HUNK_END
|
|
bsr RomFetch32
|
|
bsr RomFetch32
|
|
|
|
; Go through hunk header and allocate all segments
|
|
move.l 4,a6 ; execbase
|
|
|
|
move.l PHUNKS(a4),a2 ; segment pointers
|
|
lea.l 4*NUM_ENTRIES(a2),a3 ; segment lengths
|
|
.AllocateLoop
|
|
moveq.l #MEMF_PUBLIC,d1
|
|
bsr RomFetch32
|
|
lsl.l #2,d0
|
|
move.l d0,(a3)+ ; segment length
|
|
addq.l #8,d0 ; Add 8 for seglist overhead
|
|
jsr _LVOAllocMem(a6)
|
|
tst.l d0
|
|
beq.s .RelocateFail
|
|
addq.l #8,d0 ; Skip seglist overhead
|
|
move.l d0,(a2)+ ; segment pointer
|
|
dbra d7,.AllocateLoop
|
|
|
|
move.l PHUNKS(a4),a5
|
|
.HunkLoop
|
|
move.l (a5),a0 ; current hunk
|
|
bsr RomFetch32
|
|
|
|
cmp.l #$3e9,d0
|
|
beq .HunkCode
|
|
cmp.l #$3ea,d0
|
|
beq .HunkData
|
|
cmp.l #$3eb,d0
|
|
beq .HunkBSS
|
|
cmp.l #$3ec,d0
|
|
beq .HunkReloc32
|
|
cmp.l #$3fc,d0
|
|
beq .HunkReloc32Short
|
|
cmp.l #$3f7,d0
|
|
beq .HunkDRel32
|
|
cmp.l #$3f0,d0
|
|
beq .HunkSymbol
|
|
cmp.l #$3f2,d0
|
|
beq .HunkEnd
|
|
|
|
; We don't know this hunk
|
|
.RelocateFail
|
|
IFD HAVE_RERRNO
|
|
; Save hunk number in rErrno as error code
|
|
lea _rErrno(pc),a0
|
|
move.l d0,(a0)
|
|
ENDIF
|
|
bsr .RelocateCleanup
|
|
moveq.l #0,d0 ; NULL = Failure
|
|
unlk a4
|
|
movem.l (sp)+,d1-d7/a0-a6
|
|
rts
|
|
|
|
; ---------------------
|
|
|
|
.HunkData
|
|
.HunkCode
|
|
bsr RomFetch32
|
|
move.l d0,d7
|
|
subq.l #1,d7
|
|
.CopyHunk
|
|
bsr RomFetch32
|
|
move.l d0,(a0)+
|
|
dbra d7,.CopyHunk
|
|
bra .HunkLoop
|
|
|
|
; ---------------------
|
|
|
|
.HunkBSS
|
|
bsr RomFetch32
|
|
move.l d0,d7
|
|
subq.l #1,d7
|
|
; hunk address in a0
|
|
.ClearBSS
|
|
move.l #$0,(a0)+
|
|
dbra d7,.ClearBSS
|
|
|
|
bra .HunkLoop
|
|
|
|
; ---------------------
|
|
|
|
.HunkReloc32
|
|
bsr RomFetch32
|
|
|
|
tst.l d0 ; if len is zero the reloc32 block is done
|
|
beq .HunkLoop
|
|
|
|
move.l d0,d1 ; len ; number of offsets for a given hunk
|
|
subq.l #1,d1 ; for dbra
|
|
|
|
bsr RomFetch32
|
|
move.l d0,d2 ; num ; number of the hunk the offsets are to point into
|
|
|
|
lsl.l #2,d2 ; *4 ; offset from Hunks
|
|
move.l PHUNKS(a4),a2
|
|
add.l d2,a2 ; hunk number num
|
|
move.l (a2),d3 ; base address of hunk
|
|
|
|
.Reloc32Tight
|
|
bsr RomFetch32
|
|
; get baseaddr + d0, add d3 to the data there.
|
|
move.l a0,a3
|
|
add.l d0,a3
|
|
add.l d3,(a3)
|
|
dbra d1,.Reloc32Tight
|
|
|
|
bra .HunkReloc32
|
|
; ---------------------
|
|
|
|
.HunkDRel32
|
|
.HunkReloc32Short
|
|
bsr RomFetch16
|
|
|
|
tst.l d0 ; if len is zero the reloc32 block is done
|
|
beq .HunkLoopPrep
|
|
|
|
move.l d0,d1 ; len ; number of offsets for a given hunk
|
|
subq.l #1,d1 ; for dbra
|
|
|
|
bsr RomFetch16
|
|
move.l d0,d2 ; num ; number of the hunk the offsets are to point into
|
|
|
|
lsl.l #2,d2 ; *4 ; offset from Hunks
|
|
move.l PHUNKS(a4),a2
|
|
add.l d2,a2 ; hunk number num
|
|
move.l (a2),d3 ; base address of hunk
|
|
|
|
.Reloc32ShortTight
|
|
bsr RomFetch16
|
|
; get baseaddr + d0, add d3 to the data there.
|
|
move.l a0,a3
|
|
add.l d0,a3
|
|
add.l d3,(a3)
|
|
dbra d1,.Reloc32ShortTight
|
|
|
|
bra .HunkReloc32Short
|
|
.HunkLoopPrep
|
|
lea READHANDLE_CURRENT(a4),a2
|
|
move.l (a2),d0 ; align pointer to longword
|
|
addq.l #2,d0 ; in case we had an odd number
|
|
and.l #$fffffffc,d0 ; of relocations
|
|
move.l d0,(a2)
|
|
bra .HunkLoop
|
|
; ---------------------
|
|
|
|
.HunkSymbol
|
|
bsr RomFetch32
|
|
tst.l d0
|
|
beq .HunkLoop
|
|
move.l d0,d7
|
|
.SkipSymbol
|
|
bsr RomFetch32
|
|
dbra d7,.SkipSymbol
|
|
bra .HunkSymbol
|
|
|
|
; ---------------------
|
|
|
|
.HunkEnd
|
|
addq.l #4,a5
|
|
dbra d6,.HunkLoop
|
|
IFD HAVE_ERRNO
|
|
lea _rErrno(pc),a0
|
|
move.l #0,(a0)
|
|
ENDIF
|
|
|
|
bsr.s CreateSegList
|
|
|
|
move.l PHUNKS(a4),a0
|
|
move.l (a0),d2
|
|
subq.l #4,d2
|
|
|
|
bsr.s .RelocateCleanup
|
|
move.l d2,d0
|
|
unlk a4
|
|
movem.l (sp)+,d1-d7/a0-a6
|
|
rts
|
|
|
|
.RelocateCleanup
|
|
move.l PHUNKS(a4),a1
|
|
moveq.l #(8*NUM_ENTRIES),d0
|
|
jsr _LVOFreeMem(a6)
|
|
rts
|
|
|
|
; ---------------------
|
|
|
|
; +--------------------+
|
|
; | seg length (longs) | <-- = pHunks[x+NUM_ENTRIES]
|
|
; +--------------------+ <-- seglist returned
|
|
; | bptr to next seg | <-- = pHunks[x+1]
|
|
; +--------------------+ <-- pHunks[x] points here
|
|
; | segment data (also |
|
|
; | first entry point) |
|
|
; |/\/\/\/\/\/\/\/\/\/\|
|
|
|
|
; pHunks -+ Hunk Pointers Hunk Lengths
|
|
; | +--+--+--+--+ +--+--+--+--+
|
|
; +->| | | | 0| | | | | 0|
|
|
; +--+--+--+--+ +--+--+--+--+
|
|
CreateSegList:
|
|
move.l PHUNKS(a4),a0
|
|
|
|
.NextSeg
|
|
move.l (a0),a1 ; Hunks[x]
|
|
|
|
move.l 4*NUM_ENTRIES(a0),d0 ; length of current hunk
|
|
addq.l #8,d0 ; add header size
|
|
lsr.l #2,d0 ; MKBADDR
|
|
move.l d0,-8(a1) ; write seg size
|
|
|
|
addq.l #4,a0
|
|
move.l (a0),d0 ; next hunk
|
|
tst.l d0 ; hunk addr zero?
|
|
beq .SegListDone ; we're done
|
|
subq.l #4,d0 ; else: point to linked list
|
|
lsr.l #2,d0 ; MKBADDR
|
|
move.l d0,-4(a1) ; write BPTR to next hunk
|
|
|
|
bra.s .NextSeg
|
|
|
|
.SegListDone
|
|
move.l d0,-4(a1) ; terminate seglist
|
|
rts
|
|
|
|
; ---------------------
|
|
|
|
; data = RomFetch32(void)
|
|
; d0
|
|
RomFetch16
|
|
moveq #1,d0
|
|
bra.s RomFetch
|
|
RomFetch32
|
|
moveq #3,d0
|
|
|
|
RomFetch
|
|
movem.l a0-a1/d1-d3,-(sp)
|
|
lea READHANDLE_CURRENT(a4),a1
|
|
move.l (a1),a0
|
|
|
|
tst.l READHANDLE_TYPE(a4) ; access type Zorro?
|
|
bne.s .RomFetchZ
|
|
|
|
cmp.b #3,d0
|
|
bne.b .RomFetchWord
|
|
move.l (a0)+,d0 ; access type is memory
|
|
bra.s .RomFetchDone
|
|
.RomFetchWord
|
|
move.w (a0)+,d0
|
|
bra.s .RomFetchDone
|
|
|
|
.RomFetchZ ; access type is Zorro
|
|
move.l d0,d3
|
|
.nextnip
|
|
lsl.l #8,d0
|
|
IFND BYTEWIDE
|
|
move.b (a0),d1
|
|
and.l #$f0,d1
|
|
move.b 2(a0),d2
|
|
and.l #$f0,d2
|
|
lsr.w #4,d2
|
|
or.b d1,d2
|
|
|
|
move.b d2,d0
|
|
|
|
addq #4,a0
|
|
ELSE
|
|
move.b (a0),d0
|
|
addq #2,a0
|
|
ENDIF
|
|
dbra d3,.nextnip
|
|
|
|
.RomFetchDone
|
|
move.l a0,(a1)
|
|
movem.l (sp)+,a0-a1/d1-d3
|
|
rts
|
|
|
|
InitHandle
|
|
; initialize READHANDLE_CURRENT to beginning of device driver
|
|
; ROM_OFFSET needs to be multiplied by 4 because of the
|
|
; nibble mapped nature of the AutoConfig ROM.
|
|
; ROM_ADDRESS is passed in a0
|
|
; ROM_OFFSET is passed in d0
|
|
IFND BYTEWIDE
|
|
lsl.l #2,d0
|
|
ENDIF
|
|
|
|
add.l d0,a0
|
|
move.l a0,READHANDLE_CURRENT(a4) ; memory location passed in a0
|
|
move.l d0,READHANDLE_TYPE(a4) ; Set access type: 0 = memory, Zorro otherwise
|
|
|
|
moveq.l #(8*NUM_ENTRIES),d0
|
|
move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
|
|
jsr _LVOAllocMem(a6)
|
|
move.l d0,PHUNKS(a4)
|
|
rts
|
|
|
|
IFD HAVE_ERRNO
|
|
public _rErrno
|
|
_rErrno
|
|
dc.l 0
|
|
ENDIF
|
|
CODE
|