blob: adebcb6905543f5af44fad25765b51620664530c [file] [log] [blame]
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* 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