## Copyright (C) 2021 Andrius Štikonas
## This file is part of stage0.
##
## stage0 is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## stage0 is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY# without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with stage0.  If not, see <http://www.gnu.org/licenses/>.


## ELF Header
#:ELF_base
7F 45 4C 46        ## e_ident[EI_MAG0-3] ELF's magic number

02                 ## e_ident[EI_CLASS] Indicating 64 bit
01                 ## e_ident[EI_DATA] Indicating little endianness
01                 ## e_ident[EI_VERSION] Indicating original elf

03                 ## e_ident[EI_OSABI] Set at 3 for Linux
00                 ## e_ident[EI_ABIVERSION] Ignored for Statically linked executables

00 00 00 00 00 00 00 ## e_ident[EI_PAD]
02 00              ## e_type Indicating Executable
F3 00              ## e_machine Indicating RISC-V
01 00 00 00        ## e_version Indicating original elf

78 00 60 00 00 00 00 00 ## e_entry Address of the entry point (Number of bytes this header is + Base Address)
40 00 00 00 00 00 00 00 ## e_phoff Address of program header table
00 00 00 00 00 00 00 00 ## e_shoff Address of section header table

00 00 00 00        ## e_flags
40 00              ## e_ehsize Indicating our 64 Byte header

38 00              ## e_phentsize size of a program header table
01 00              ## e_phnum number of entries in program table

00 00              ## e_shentsize size of a section header table
00 00              ## e_shnum number of entries in section table

00 00              ## e_shstrndx index of the section names

## Program Header
#:ELF_program_headers
01 00 00 00             ## p_type
07 00 00 00             ## Flags
00 00 00 00 00 00 00 00 ## p_offset

00 00 60 00 00 00 00 00 ## p_vaddr
00 00 60 00 00 00 00 00 ## p_physaddr

14 01 00 00 00 00 00 00 ## p_filesz
14 01 00 00 00 00 00 00 ## p_memsz

01 00 00 00 00 00 00 00 ## Required alignment

#:ELF_text

; Simply jump to _start
; Our main function
#:_start

# Register use:
# s1: output file descriptor
# s2: buffer
# s3: input file descriptor
# s4: number of bytes read

# Open output file and store the FD in s1
    93 08 80 03     # RD_A7 !56 ADDI                    ; sys_openat
    13 05 C0 F9     # RD_A0 !-100 ADDI                  ; AT_FDCWD
    13 01 01 01     # RD_SP RS1_SP !16 ADDI             ; Prepare stack for reading output file
    83 35 01 00     # RD_A1 RS1_SP LD                   ; Output file (argument 1)
    13 06 10 24     # RD_A2 !577 ADDI                   ; Prepare file as O_WRONLY|O_CREAT|O_TRUNC
    93 06 00 18     # RD_A3 !384 ADDI                   ; Prepare file as RW for owner only (600 in octal)
    73 00 00 00     # ECALL                             ; syscall
    93 04 05 00     # RD_S1 RS1_A0 ADDI                 ; Save fd in for later

    # Prepare heap memory
    93 08 60 0D     # RD_A7 !214 ADDI                   ; sys_brk
    13 05 00 00     # RD_A0 ADDI                        ; Get current brk
    73 00 00 00     # ECALL                             ; syscall
    13 09 05 00     # RD_S2 RS1_A0 ADDI                 ; Set our malloc pointer

    B7 05 10 00     # RD_A1 ~0x100000 LUI               ; a1=1MiB
    33 05 B5 00     # RD_A0 RS1_A0 RS2_A1 ADD           ; Allocate 1MiB
    73 00 00 00     # ECALL                             ; syscall

:c #:core
    13 01 81 00     # RD_SP RS1_SP !8 ADDI              ; Move stack pointer to next input file
    83 35 01 00     # RD_A1 RS1_SP LD                   ; Get the input file name
    @D 63 80 05 00  # RS1_A1 @Done BEQ                  ; This was the last file, we are done

    93 08 80 03     # RD_A7 !56 ADDI                    ; sys_openat
    13 05 C0 F9     # RD_A0 !-100 ADDI                  ; AT_FDCWD
    13 06 00 00     # RD_A2 ADDI                        ; read only
    73 00 00 00     # ECALL                             ; syscall
    93 09 05 00     # RD_S3 RS1_A0 ADDI                 ; protect input fd

:k #:keep
    93 08 F0 03     # RD_A7 !63 ADDI                    ; sys_read
    13 85 09 00     # RD_A0 RS1_S3 ADDI                 ; input fd
    93 05 09 00     # RD_A1 RS1_S2 ADDI                 ; read into buffer
    37 06 10 00     # RD_A2 ~0x100000 LUI               ; a2=1MiB
    73 00 00 00     # ECALL                             ; syscall
    13 0A 05 00     # RD_S4 RS1_A0 ADDI                 ; actual number of bytes read

    93 08 00 04     # RD_A7 !64 ADDI                    ; sys_write
    13 85 04 00     # RD_A0 RS1_S1 ADDI                 ; output fd
    93 05 09 00     # RD_A1 RS1_S2 ADDI                 ; write from buffer
    13 06 0A 00     # RD_A2 RS1_S4 ADDI                 ; number of bytes to write
    73 00 00 00     # ECALL                             ; syscall

    37 06 10 00     # RD_A2 ~0x100000 LUI               ; 1MiB
    @k 63 00 CA 00  # RS1_S4 RS2_A2 @keep BEQ           ; keep looping if buffer was full
    $c 6F 00 00 00  # $core JAL                         ; otherwise move to next file

:D #:Done
    # Terminate program with 0 return code
    93 08 D0 05     # RD_A7 !93 ADDI                    ; sys_exit
    13 05 00 00     # RD_A0 ADDI                        ; Return code 0
    73 00 00 00     # ECALL                             ; exit(0)
    
#:ELF_end
