| /* |
| * 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: |
| */ |