blob: 665e24fee68016141a39840d0d10fc77552e663a [file] [log] [blame]
/*
* Copyright (c) 2016 Cadence Design Systems, Inc.
* SPDX-License-Identifier: Apache-2.0
*/
/*
* For the Xtensa simulator target, this code sets up the C calling context
* and calls main() (via __clibrary_start).
* Control arrives here at _start from the reset vector or from crt0-app.S.
*/
#include <xtensa/simboard.h>
#include <xtensa/simcall.h>
#include <xtensa/coreasm.h>
/* Exports */
.global _start
.global __start
/*
* Imports
* __clibrary_init from C library (eg. newlib or uclibc)
* exit from C library
* main from user application
* __stack from linker script (see LSP Ref Manual)
*/
.type __clibrary_init, @function
.type _Cstart, @function
.type exit, @function
/* Macros to abstract away ABI differences */
#if __XTENSA_CALL0_ABI__
# define CALL call0
# define CALLX callx0
# define ARG1 a2 /* 1st outgoing call argument */
# define ARG2 a3 /* 2nd outgoing call argument */
# define ARG3 a4 /* 3rd outgoing call argument */
# define ARG4 a5 /* 4th outgoing call argument */
# define ARG5 a6 /* 5th outgoing call argument */
#else
# define CALL call4
# define CALLX callx4
# define ARG1 a6 /* 1st outgoing call argument */
# define ARG2 a7 /* 2nd outgoing call argument */
# define ARG3 a8 /* 3rd outgoing call argument */
# define ARG4 a9 /* 4th outgoing call argument */
# define ARG5 a10 /* 5th outgoing call argument */
#endif
.data
.weak _start_envp /* allow overriding */
.align 4
_start_envp: .word 0 /* empty environ */
.text
.align 4
_start:
__start:
/*
* _start is typically NOT at the beginning of the text segment --
* it is always called from either the reset vector or other code
* that does equivalent initialization (such as crt0-app.S).
*
* Assumptions on entry to _start:
* - low (level-one) and medium priority interrupts are disabled
* via PS.INTLEVEL and/or INTENABLE (PS.INTLEVEL is expected to
* be zeroed, to potentially enable them, before calling main)
* - C calling context not initialized:
* - PS not initialized
* - SP not initialized
* - the following are initialized:
* - LITBASE, cache attributes, WindowBase, WindowStart,
* CPENABLE, FP's FCR and FSR, EXCSAVE[n]
* Keep a0 zero. It is used to initialize a few things.
* It is also the return address, where zero indicates
* that the frame used by _start is the bottommost frame.
*
*/
movi a0, 0 /* keep this register zero. */
#if XTOS_RESET_UNNEEDED
#include "reset-unneeded.S"
#endif
/*
* Initialize the stack pointer.
* See the "ABI and Software Conventions" chapter in the
* Xtensa ISA Reference manual for details.
*
* NOTE: Because the _start routine does not use any memory in its
* stack frame, and because all of its CALL instructions use a
* window size of 4, the stack frame for _start can be empty.
*/
movi sp, __stack
/*
* reserve stack space for
* - argv array
* - argument strings
*/
movi a2, SYS_iss_argv_size
simcall /* returns size of argv[] + its strings in a2 */
#if XCHAL_HAVE_PIF
/*
* The stack only needs 16-byte alignment. However, here we round up
* the argv size further to 128 byte multiples so that in most cases,
* variations in argv[0]'s path do not result in different stack
* allocation. Otherwise, such variations can impact execution timing
* (eg. due to cache effects etc) for the same code and data. If we
* have a PIF, it's more likely the extra required space is okay.
*/
addi a2, a2, 127
srli a2, a2, 7
slli a2, a2, 7
#else
/* Keep stack 16-byte aligned. */
addi a2, a2, 15
srli a2, a2, 4
slli a2, a2, 4
#endif
/*
* No need to use MOVSP because we have no caller (we're the
* base caller); in fact it's better not to use MOVSP in this
* context, to avoid unnecessary ALLOCA exceptions and copying
* from undefined memory:
* sub a3, sp, a2
* movsp sp, a3
*/
sub sp, sp, a2
/*
* Now that sp (a1) is set, we can set PS as per the application (user
* vector mode, enable interrupts, enable window exceptions if
* applicable).
*/
#if XCHAL_HAVE_EXCEPTIONS
# ifdef __XTENSA_CALL0_ABI__
/* PS.WOE = 0, PS.UM = 1, PS.EXCM = 0, PS.INTLEVEL = 0 */
movi a3, PS_UM
# else
/* PS.WOE = 1, PS.UM = 1, PS.EXCM = 0, PS.INTLEVEL = 0 */
movi a3, PS_UM|PS_WOE
# endif
wsr a3, PS
rsync
#endif
/*
* Do any initialization that affects the memory map, such as
* setting up TLB entries, that needs to be done before we can
* successfully clear BSS (e.g. if some BSS segments are in
* remapped areas).
*
* NOTE: This hook works where the reset vector does not unpack
* segments (see "ROM packing" in the LSP manual), or where
* unpacking of segments is not affected by memory remapping.
* If ROM unpacking is affected, TLB setup must be done in
* assembler from the reset vector.
*
* The __memmap_init() routine can be a C function, however it
* does not have BSS initialized! In particular, __memmap_init()
* cannot set BSS variables, i.e. uninitialized global variables
* (they'll be wiped out by the following BSS clear), nor can it
* assume they are yet initialized to zero.
*
* The __memmap_init() function is optional. It is marked as a
* weak symbol, so that it gets valued zero if not defined.
*/
.weak __memmap_init
movi a4, __memmap_init
beqz a4, 1f
CALLX a4
1:
/* The new ISS simcall only appeared after RB-2007.2: */
#if !XCHAL_HAVE_BOOTLOADER && \
(XCHAL_HW_MAX_VERSION > XTENSA_HWVERSION_RB_2007_2)
/* pre-LX2 cores only */
/*
* Clear the BSS (uninitialized data) segments.
* This code supports multiple zeroed sections (*.bss).
* For speed, we clear memory using an ISS simcall
* (see crt1-boards.S for more generic BSS clearing code).
*/
movi a6, _bss_table_start
movi a7, _bss_table_end
bgeu a6, a7, .Lnobss
.Lbssloop:
movi a2, SYS_memset
l32i a3, a6, 0 /* arg1 = fill start address */
movi a4, 0 /* arg2 = fill pattern */
l32i a5, a6, 4 /* get end address */
addi a6, a6, 8 /* next bss table entry */
sub a5, a5, a3 /* arg3 = fill size in bytes */
simcall /* memset(a3,a4,a5) */
bltu a6, a7, .Lbssloop /* loop until end of bss table */
.Lnobss:
#endif
/*
* Call __clibrary_init to initialize the C library:
*
* void __clibrary_init(int argc, char ** argv, char ** environ,
* void(*init_func)(void), void(*fini_func)(void));
*/
/* Get argv with the arguments from the ISS */
mov a3, sp /* tell simcall where to write argv[] */
movi a2, SYS_iss_set_argv
simcall /* write argv[] array at a3 */
movi a2, SYS_iss_argc
simcall /* put argc in a2 */
/* Call: int _Cstart(); */
CALL _Cstart
/* The return value is the same register as the first outgoing
* argument.
*/
CALL exit
/* Does not return here. */
.size _start, . - _start
/*
* Local Variables:
* mode:fundamental
* comment-start: "/* "
* comment-start-skip: "/* *"
* End:
*/