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