173 lines
7.6 KiB
Plaintext
173 lines
7.6 KiB
Plaintext
|
PHDR_BUF_SEC_SIZE equ 5
|
||
|
STORAGE_SEC equ $0
|
||
|
STORAGE_CNT equ $4
|
||
|
STORAGE_CMD equ $8
|
||
|
STORAGE_DMADR equ $C
|
||
|
|
||
|
section .text,text
|
||
|
public _start
|
||
|
_start:
|
||
|
move.w #$4, d0 ; Find a storage card
|
||
|
bsr.w find_first_card
|
||
|
; load the first PHDR_BUF_SEC_SIZE sectors of the ELF kernel binary off the disk
|
||
|
move.l #phdr_buf, a1 ; Set the destination address to PHDR_BUF_START
|
||
|
move.l #$2, d0 ; Set the starting sector number to 2
|
||
|
move.l #PHDR_BUF_SEC_SIZE, d1 ; Set the sector count
|
||
|
bsr.w read_sectors
|
||
|
move.l (phdr_buf + $1C), d0 ; Load the offset of the program headers in the file
|
||
|
move.l #phdr_buf, a1 ; Put the address of the program headers in a1
|
||
|
adda.w d0, a1
|
||
|
move.w (phdr_buf + $2C), d0 ; Put the number of program headers - 1 in d0
|
||
|
subq.w #$1, d0
|
||
|
phead_loop:
|
||
|
move.l (a1), d1 ; If the type of the program header isn't 1 (LOAD), skip the header
|
||
|
cmpi.l #$1, d1
|
||
|
bne.b next_seg
|
||
|
; Zero the destination memory
|
||
|
move.l (20,a1), d1 ; Put the memory size - 1 in d1
|
||
|
subq.l #$1, d1
|
||
|
move.l (12,a1), a2 ; Put the starting memory address in a2
|
||
|
zero_loop:
|
||
|
move.b #0, (a2)+ ; Zero a byte of the destination memory
|
||
|
dbra d1, zero_loop ; Loop back if there is more to zero
|
||
|
; Load the segment data off disk
|
||
|
move.l (16,a1), d1 ; Put the file size in d1
|
||
|
beq.b next_seg ; If the file size is 0, skip the copy (ex, .bss section)
|
||
|
movem.l d0/a1,-(a7) ; Save d0 and a1
|
||
|
move.l (4,a1), d0 ; Put the starting byte number in d0
|
||
|
addi.l #$400, d0 ; Add the 2 sector offset in the disk for the kernel file
|
||
|
move.l (12,a1), a1 ; Put the destination memory address in a1
|
||
|
bsr.b read_bytes
|
||
|
movem.l (a7)+,d0/a1 ; Restore d0 and a1
|
||
|
next_seg:
|
||
|
lea ($20,a1), a1 ; Advance a1 to point to the next program header
|
||
|
dbra d0, phead_loop ; If there are more program headers, loop back
|
||
|
move.l (phdr_buf + $18), a1 ; Load the entry point of the program into a1
|
||
|
move.l (phdr_buf + $1C), d0 ; Load the offset of the program headers in the file
|
||
|
move.l #phdr_buf, a0 ; Put the address of the program headers in a0
|
||
|
adda.w d0, a0
|
||
|
move.w (phdr_buf + $2C), d0 ; Put the number of program headers in d0
|
||
|
jmp (a1) ; Jump to the entry point of the program
|
||
|
|
||
|
|
||
|
|
||
|
; Finds the first card with the type in d0.w, and returns it's IO base address in a0, or 0 if not found
|
||
|
find_first_card:
|
||
|
move.l #$ff0000, a0 ; a0 holds the address of the current card
|
||
|
ffc_loop:
|
||
|
lea ($100,a0), a0 ; Move to the next card
|
||
|
move.w ($fe,a0), d1 ; Load the type of the card into d1
|
||
|
beq.b ffc_done ; If the type is 0 (empty slot), we have scanned all cards, so exit the loop
|
||
|
cmp.w d0, d1 ; If the card is the type we want, return with the address in a0
|
||
|
beq.b ffc_done
|
||
|
bra.b ffc_loop ; Loop back and check the next card
|
||
|
ffc_done:
|
||
|
rts
|
||
|
|
||
|
|
||
|
; Reads sectors from a storage card
|
||
|
; Card base in a0
|
||
|
; Destination in a1
|
||
|
; Start sector in d0.l
|
||
|
; Sector count in d1.l
|
||
|
read_sectors:
|
||
|
cmpi.l #0, d1
|
||
|
beq.b read_sectors_done
|
||
|
move.l d0, (STORAGE_SEC,a0) ; Set the sector number
|
||
|
move.l d1, (STORAGE_CNT,a0) ; Set the sector count
|
||
|
move.l a1, (STORAGE_DMADR,a0) ; Set the destination address
|
||
|
move.w #$1, (STORAGE_CMD,a0) ; Issue a DMA read command
|
||
|
read_sectors_done:
|
||
|
rts
|
||
|
|
||
|
; Reads bytes off a storage card
|
||
|
; Card base in a0
|
||
|
; Destination in a1
|
||
|
; Start byte in d0.l
|
||
|
; Byte count in d1.l
|
||
|
read_bytes:
|
||
|
movem.l d2-d5/a2/a3,-(a7) ; Save callee preserved registers
|
||
|
move.l d0, d4 ; Save start byte in d4
|
||
|
move.l d1, d5 ; Save byte count in d5
|
||
|
move.l a1, a3 ; Save destination in a6
|
||
|
lsr.l #8, d0 ; Divide start byte by 512 to compute starting sector
|
||
|
lsr.l #1, d0
|
||
|
move.l d0, d3 ; Save the starting sector in d3
|
||
|
move.l #1, d1 ; Read the starting sector into the sector buffer
|
||
|
move.l #sec_buf, a1
|
||
|
bsr.b read_sectors
|
||
|
move.l a3, a2 ; Load the destination into a2
|
||
|
move.l d4, d0 ; Load the start byte into d0
|
||
|
andi.l #$1FF, d0 ; Modulus start byte by 512 to compute sector data offset
|
||
|
move.l #$200, d1 ; Compute the number of bytes to transfer by subtracting the offset from 512
|
||
|
sub.l d0, d1
|
||
|
cmp d5, d1 ; Compare the number of bytes to transfer with the byte count
|
||
|
ble.b count_ok ; If it was less than the byte count, do not adjust the bytes to transfer
|
||
|
move.l d5, d1 ; Otherwise, cap the transfer count to the total byte count
|
||
|
count_ok:
|
||
|
move.l d1, d4 ; Save the number of bytes in d4
|
||
|
subi.l #1, d1 ; Subtract 1 from the number of bytes to account for the extra loop done by dbra
|
||
|
start_sec_loop: ; Transfer the required bytes from the start sector to the destination buffer
|
||
|
move.b (a1)+, (a2)+
|
||
|
dbra d1, start_sec_loop
|
||
|
move.l d3, d0 ; Load the starting sector into d0
|
||
|
addi #1, d0 ; Compute the start of the middle sectors by adding 1 to the starting sector
|
||
|
move.l d4, d2 ; Load the number of bytes transferred into d2
|
||
|
move.l d5, d1 ; Load the byte count into d1
|
||
|
sub.l d2, d1 ; Compute the number of remaining bytes by subtracting the number of transferred bytes from the byte count
|
||
|
cmpi.l #0, d1 ; If there are no more bytes to read, end early
|
||
|
beq.b read_bytes_done
|
||
|
move.l d1, d4 ; Save the number of remaining bytes in d4
|
||
|
lsr.l #8, d1 ; Divide remaining bytes by 512 to compute the number of middle sectors
|
||
|
lsr.l #1, d1
|
||
|
move.l a2, a1 ; Transfer the sector data to the end of the start sector bytes
|
||
|
bsr.b read_sectors ; Read the middle sectors
|
||
|
move.l d1, d3 ; Save the number of middle sectors in d3
|
||
|
lsl.l #8, d1 ; Multiply the number of middle sectors by 512 to compute the number of bytes transferred
|
||
|
lsl.l #1, d1
|
||
|
sub.l d1, d4 ; Subtract the number of transferred bytes from the number of remaining bytes
|
||
|
cmpi.l #0, d4 ; If there are no more bytes to read, end early
|
||
|
beq.b read_bytes_done
|
||
|
adda.l d1, a2 ; Add the number of bytes transferred to a2
|
||
|
add.l d3, d0 ; Compute the end sector number by adding the start and count of the middle sectors
|
||
|
move.l #1, d1 ; Set the number of sectors to read to 1
|
||
|
move.l #sec_buf, a1 ; Set the read address of the sector to the sector buffer
|
||
|
bsr.w read_sectors ; Read the end sector
|
||
|
move.l d4, d1 ; Load the number of remaining bytes into d1
|
||
|
end_sec_loop: ; Transfer the required bytes from the start sector to the destination buffer
|
||
|
move.b (a1)+, (a2)+
|
||
|
dbra d1, end_sec_loop
|
||
|
read_bytes_done:
|
||
|
movem.l (a7)+, d2-d5/a2/a3 ; Restore callee preserved registers
|
||
|
rts
|
||
|
|
||
|
section .bss,bss
|
||
|
sec_buf:
|
||
|
ds.b 512
|
||
|
phdr_buf:
|
||
|
ds.b (PHDR_BUF_SEC_SIZE * 512)
|
||
|
|
||
|
; read_bytes theory:
|
||
|
|
||
|
; Start sector: Start byte / 512
|
||
|
; Offset in start sector: Start byte % 512
|
||
|
; Rem bytes: Byte count - (512 - Offset in start sector)
|
||
|
; Middle sectors start: start sector + 1
|
||
|
; Middle sectors count: Rem bytes / 512
|
||
|
; End sector: Middle sectors start + Middle sectors count
|
||
|
; End sector copy length: Rem bytes % 512
|
||
|
|
||
|
|
||
|
; 0 1 2 3 4 5 6 7 8 9 A B C D E F * /
|
||
|
; dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
|
||
|
; 0------------------------------------------------------------------------------------------S--------------------------------------------------------------------------------------E
|
||
|
; 91 bytes . 88 bytes
|
||
|
|
||
|
; Start sector: 91 / 16 = 5
|
||
|
; Offset in start sector: 91 % 16 = 11
|
||
|
; Rem bytes: 88 - (16 - 11) = 83
|
||
|
; Middle sectors start: 5 + 1 = 6
|
||
|
; Middle sectors count: 83 / 16 = 5
|
||
|
; End sector: 6 + 5 = B
|
||
|
; End sector copy length: 83 % 16 = 3
|