|
| 1 | +/* rt_header is defined by the general linker script (libtock_layout.ld). It has |
| 2 | + * the following layout: |
| 3 | + * |
| 4 | + * Field | Offset |
| 5 | + * ------------------------------------ |
| 6 | + * Address of the start symbol | 0 |
| 7 | + * Initial process break | 4 |
| 8 | + * Top of the stack | 8 |
| 9 | + * Size of .data | 12 |
| 10 | + * Start of .data in flash | 16 |
| 11 | + * Start of .data in ram | 20 |
| 12 | + * Size of .bss | 24 |
| 13 | + * Start of .bss in ram | 28 |
| 14 | + */ |
| 15 | + |
| 16 | +/* start is the entry point -- the first code executed by the kernel. The kernel |
| 17 | + * passes arguments through 4 registers: |
| 18 | + * |
| 19 | + * r0 Pointer to beginning of the process binary's code. The linker script |
| 20 | + * locates rt_header at this address. |
| 21 | + * |
| 22 | + * r1 Address of the beginning of the process's usable memory region. |
| 23 | + * r2 Size of the process' allocated memory region (including grant region) |
| 24 | + * r3 Process break provided by the kernel. |
| 25 | + * |
| 26 | + * We currently only use the value in r0. It is copied into r5 early on because |
| 27 | + * r0 is needed to invoke system calls. |
| 28 | + */ |
| 29 | +.section .start, "ax" |
| 30 | +.global start |
| 31 | +.thumb_func |
| 32 | +start: |
| 33 | + /* First, verify the process binary was loaded at the correct address. The |
| 34 | + * check is performed by comparing the program counter at the start to the |
| 35 | + * address of `start`, which is stored in rt_header. */ |
| 36 | + mov r4, pc /* r4 = address of .start + 4 (Thumb bit unset) */ |
| 37 | + mov r5, r0 /* Save rt_header; we use r0 for syscalls */ |
| 38 | + ldr r0, [r5, #0] /* r0 = rt_header.start */ |
| 39 | + adds r0, #3 /* r0 = rt_header.start + 4 - 1 (for Thumb bit) */ |
| 40 | + cmp r0, r4 |
| 41 | + beq .Lset_brk /* Skip error handling if pc correct */ |
| 42 | + /* If the beq on the previous line did not jump, then the binary is not at |
| 43 | + * the correct location. Report the error via LowLevelDebug then exit. */ |
| 44 | + movs r0, #8 /* LowLevelDebug driver number */ |
| 45 | + movs r1, #1 /* Command: print alert code */ |
| 46 | + movs r2, #2 /* Alert code 2 (incorrect location */ |
| 47 | + svc 2 /* Execute `command` */ |
| 48 | + movs r0, #0 /* Operation: exit-terminate */ |
| 49 | + svc 6 /* Execute `exit` */ |
| 50 | + |
| 51 | +.Lset_brk: |
| 52 | + /* memop(): set brk to rt_header's initial break value */ |
| 53 | + movs r0, #0 /* operation: set break */ |
| 54 | + ldr r1, [r5, #4] /* rt_header`s initial process break */ |
| 55 | + svc 5 /* call `memop` */ |
| 56 | + |
| 57 | + /* Set the stack pointer */ |
| 58 | + ldr r0, [r5, #8] /* r0 = rt_header._stack_top */ |
| 59 | + mov sp, r0 |
| 60 | + |
| 61 | + /* Copy .data into place */ |
| 62 | + ldr r0, [r5, #12] /* remaining = rt_header.data_size */ |
| 63 | + cmp r0, #0 |
| 64 | + beq .Lzero_bss /* Jump to zero_bss if remaining == 0 */ |
| 65 | + ldr r1, [r5, #16] /* src = rt_header.data_flash_start */ |
| 66 | + ldr r2, [r5, #20] /* dest = rt_header.data_ram_start */ |
| 67 | +.Ldata_loop_body: |
| 68 | + ldr r3, [r1] /* r3 = *src */ |
| 69 | + str r3, [r2] /* *(dest) = r3 */ |
| 70 | + subs r0, #4 /* remaining -= 4 */ |
| 71 | + adds r1, #4 /* src += 4 */ |
| 72 | + adds r2, #4 /* dest += 4 */ |
| 73 | + cmp r0, #0 |
| 74 | + bne .Ldata_loop_body /* Iterate again if remaining != 0 */ |
| 75 | + |
| 76 | +.Lzero_bss: |
| 77 | + ldr r0, [r5, #24] /* remaining = rt_header.bss_size */ |
| 78 | + cmp r0, #0 |
| 79 | + beq .Lcall_rust_start /* Jump to call_rust_start if remaining == 0 */ |
| 80 | + ldr r1, [r5, #28] /* dest = rt_header.bss_start */ |
| 81 | + movs r2, #0 /* r2 = 0 */ |
| 82 | +.Lbss_loop_body: |
| 83 | + strb r2, [r1] /* *(dest) = r2 = 0 */ |
| 84 | + subs r0, #1 /* remaining -= 1 */ |
| 85 | + adds r1, #1 /* dest += 1 */ |
| 86 | + cmp r0, #0 |
| 87 | + bne .Lbss_loop_body /* Iterate again if remaining != 0 */ |
| 88 | + |
| 89 | +.Lcall_rust_start: |
| 90 | + bl rust_start |
0 commit comments