blob: db1036e117d0116e42d6325d79ec7d6774958e21 [file] [log] [blame]
/* rt_header is defined by the general linker script (libtock_layout.ld). It has
* the following layout:
*
* Field | Offset
* ------------------------------------
* Address of the start symbol | 0
* Initial process break | 4
* Top of the stack | 8
* Size of .data | 12
* Start of .data in flash | 16
* Start of .data in ram | 20
* Size of .bss | 24
* Start of .bss in ram | 28
*/
/* start is the entry point -- the first code executed by the kernel. The kernel
* passes arguments through 4 registers:
*
* a0 Pointer to beginning of the process binary's code. The linker script
* locates rt_header at this address.
*
* a1 Address of the beginning of the process's usable memory region.
* a2 Size of the process' allocated memory region (including grant region)
* a3 Process break provided by the kernel.
*
* We currently only use the value in a0. It is copied into a5 early on because
* a0-a4 are needed to invoke system calls.
*/
.section .start, "ax"
.globl start
start:
/* First, verify the process binary was loaded at the correct address. The
* check is performed by comparing the program counter at the start to the
* address of `start`, which is stored in rt_header. */
auipc s0, 0 /* s0 = pc */
mv a5, a0 /* Save rt_header so syscalls don't overwrite it */
lw s1, 0(a5) /* s1 = rt_header.start */
beq s0, s1, .Lset_brk /* Skip error handling code if pc is correct */
/* If the beq on the previous line did not jump, then the binary is not at
* the correct location. Report the error via LowLevelDebug then exit. */
li a0, 8 /* LowLevelDebug driver number */
li a1, 1 /* Command: Print alert code */
li a2, 2 /* Alert code 2 (incorrect location) */
li a4, 2 /* `command` class */
ecall
li a0, 0 /* exit-terminate */
/* TODO: Set a completion code, once completion codes are decided */
li a4, 6 /* `exit` class */
ecall
.Lset_brk:
/* memop(): set brk to rt_header's initial break value */
li a0, 0 /* operation: set break */
lw a1, 4(a5) /* rt_header's initial process break */
li a4, 5 /* `memop` class */
ecall
/* Set the stack pointer */
lw sp, 8(a5) /* sp = rt_header._stack_top */
/* Copy .data into place. */
lw a0, 12(a5) /* remaining = rt_header.data_size */
beqz a0, .Lzero_bss /* Jump to zero_bss if remaining is zero */
lw a1, 16(a5) /* src = rt_header.data_flash_start */
lw a2, 20(a5) /* dest = rt_header.data_ram_start */
.Ldata_loop_body:
lw a3, 0(a1) /* a3 = *src */
sw a3, 0(a2) /* *dest = a3 */
addi a0, a0, -4 /* remaining -= 4 */
addi a1, a1, 4 /* src += 4 */
addi a2, a2, 4 /* dest += 4 */
bnez a0, .Ldata_loop_body /* Iterate again if remaining != 0 */
.Lzero_bss:
lw a0, 24(a5) /* remaining = rt_header.bss_size */
beqz a0, .Lcall_rust_start /* Jump to call_Main if remaining is zero */
lw a1, 28(a5) /* dest = rt_header.bss_start */
.Lbss_loop_body:
sb zero, 0(a1) /* *dest = zero */
addi a0, a0, -1 /* remaining -= 1 */
addi a1, a1, 1 /* dest += 1 */
bnez a0, .Lbss_loop_body /* Iterate again if remaining != 0 */
.Lcall_rust_start:
/* Note: rust_start must be a diverging function (i.e. return `!`) */
jal rust_start