| // Copyright 2023 Google LLC. |
| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| /** |
| * CRT library |
| * |
| * Utility functions written in assembly that can be used before the C |
| * runtime has been initialized. These functions should not be used once |
| * the C runtime has been initialized. |
| * |
| * The name of this library is historical. In many toolchains, a file called |
| * "crt0.o" is linked into each executable, which does something similar to |
| * what these functions |
| */ |
| |
| // NOTE: The "ax" flag below is necessary to ensure that this section |
| // is allocated space in ROM by the linker. |
| .section .crt, "ax", @progbits |
| |
| /** |
| * Write zeros into the section bounded by the start and end pointers. |
| * The section must be word (4 byte) aligned. It is valid for the section |
| * to have a length of 0 (i.e. the start and end pointers may be equal). |
| * |
| * This function follows the standard ILP32 calling convention for arguments |
| * but does not require a valid stack pointer, thread pointer or global |
| * pointer. |
| * |
| * Clobbers a0 and t0. |
| * |
| * @param a0 pointer to start of section to clear (inclusive). |
| * @param a1 pointer to end of section to clear (exclusive). |
| */ |
| .balign 4 |
| .global crt_section_clear |
| .type crt_section_clear, @function |
| crt_section_clear: |
| |
| // Check that start is before end. |
| bgeu a0, a1, .L_clear_nothing |
| |
| // Check that start and end are word aligned. |
| or t0, a0, a1 |
| andi t0, t0, 0x3 |
| bnez t0, .L_clear_error |
| |
| .L_clear_loop: |
| // Write zero into section memory word-by-word. |
| // TODO: unroll |
| sw zero, 0(a0) |
| addi a0, a0, 4 |
| bltu a0, a1, .L_clear_loop |
| ret |
| |
| .L_clear_nothing: |
| // If section length is 0 just return. Otherwise end is before start |
| // which is invalid so trigger an error. |
| bne a0, a1, .L_clear_error |
| ret |
| |
| .L_clear_error: |
| ebreak |
| |
| // Set function size to allow disassembly. |
| .size crt_section_clear, .-crt_section_clear |
| |
| // ----------------------------------------------------------------------------- |
| |
| /** |
| * Copy data from the given source into the section bounded by the start and |
| * end pointers. Both the section and the source must be word (4 byte) aligned. |
| * It is valid for the section to have a length of 0 (i.e. the start and end |
| * pointers may be equal). The source is assumed to have the same length as the |
| * target section. |
| * |
| * The destination section and the source must not overlap. |
| * |
| * This function follows the standard ILP32 calling convention for arguments |
| * but does not require a valid stack pointer, thread pointer or global |
| * pointer. |
| * |
| * Clobbers a0, a2, t0 and t1. |
| * |
| * @param a0 pointer to start of destination section (inclusive). |
| * @param a1 pointer to end of destination section (exclusive). |
| * @param a2 pointer to source data (inclusive). |
| */ |
| .balign 4 |
| .global crt_section_copy |
| .type crt_section_copy, @function |
| crt_section_copy: |
| |
| // Check that start is before end. |
| bgeu a0, a1, .L_copy_nothing |
| |
| // Check that start, end and src are word aligned. |
| or t0, a0, a1 |
| or t0, t0, a2 |
| andi t0, t0, 0x3 |
| bnez t0, .L_copy_error |
| |
| // Check that source does not destructively overlap destination |
| // (assuming a forwards copy). |
| // |
| // src start end |
| // | | | |
| // +-------------+ | |
| // | source | | |
| // +-------------+ | |
| // +-------------+ |
| // | destination | |
| // +-------------+ |
| // | | |
| // start end |
| // |
| // TODO: disallow all overlap since it indicates API misuse? |
| sub t0, a0, a2 // (start - src) mod 2**32 |
| sub t1, a1, a0 // end - start |
| bltu t0, t1, .L_copy_error |
| |
| .L_copy_loop: |
| // Copy data from src into section word-by-word. |
| // TODO: unroll |
| lw t0, 0(a2) |
| addi a2, a2, 4 |
| sw t0, 0(a0) |
| addi a0, a0, 4 |
| bltu a0, a1, .L_copy_loop |
| ret |
| |
| .L_copy_nothing: |
| // If section length is 0 just return. Otherwise end is before start |
| // which is invalid so trigger an error. |
| bne a0, a1, .L_copy_error |
| ret |
| |
| .L_copy_error: |
| ebreak |
| .size crt_section_copy, .-crt_section_copy |