| /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions |
| are met: |
| 1. Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| 2. Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| 3. The name of the company may not be used to endorse or promote |
| products derived from this software without specific prior written |
| permission. |
| |
| THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
| TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
| |
| #include "newlib.h" |
| #include "svc.h" |
| |
| /* ANSI concatenation macros. */ |
| #define CONCAT(a, b) CONCAT2(a, b) |
| #define CONCAT2(a, b) a ## b |
| |
| #ifdef __USER_LABEL_PREFIX__ |
| #define FUNCTION( name ) CONCAT (__USER_LABEL_PREFIX__, name) |
| #else |
| #error __USER_LABEL_PREFIX is not defined |
| #endif |
| |
| #ifdef HAVE_INITFINI_ARRAY |
| #define _init __libc_init_array |
| #define _fini __libc_fini_array |
| #endif |
| |
| /* In ELF64, the large addressing model is used and R_AARCH64_ABS64 |
| reloc is generated to relocate a 64-bit address. Since 64-bit |
| relocation is not available in ELF32, in order to have |
| a single code path for both ELF64 and ELF32 classes, we synthesize |
| a 64-bit relocation by using R_AARCH64_P32_ABS32 on one of the two |
| .word directives, depending on the endianness. */ |
| |
| .macro GEN_DWORD name |
| #if defined(__ILP32__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
| .word \name |
| .word 0 |
| #elif defined(__ILP32__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
| .word 0 |
| .word \name |
| #else |
| .dword \name |
| #endif |
| .endm |
| |
| /* Help tackle the pointer size difference between ELF64 and ELF32. */ |
| #ifdef __ILP32__ |
| #define PTR_REG(n) w##n |
| #define PTR_SIZE 4 |
| #define PTR_LOG_SIZE 2 |
| #else |
| #define PTR_REG(n) x##n |
| #define PTR_SIZE 8 |
| #define PTR_LOG_SIZE 3 |
| #endif |
| |
| .text |
| .macro FUNC_START name |
| .global \name |
| \name: |
| .endm |
| |
| .align 2 |
| |
| FUNC_START _mainCRTStartup |
| FUNC_START _start |
| |
| /* Start by setting up a stack */ |
| #ifdef ARM_RDI_MONITOR |
| /* Issue Angel SVC to read memory info. |
| |
| ptr to ptr to 4 words to receive data. */ |
| adr x1, .LC0 |
| mov w0, #AngelSVC_Reason_HeapInfo |
| AngelSVCAsm AngelSVC |
| |
| /* Initialise the stack pointer */ |
| |
| /* We currently choose to use the heap_limit field rather than |
| stack_base because the AEM validation model |
| returns sane values in the heap fields, but 0 in the stack |
| fields. Note on the VE AEM model it is necessary to pass |
| command line options to the AEM in order to define the values |
| exposed here in the HeapInfo Angel call. */ |
| ldr x0, .LC0 /* point at returned values */ |
| ldr x1, [x0, #8] /* get heap_limit */ |
| |
| /* Set __heap_limit. */ |
| #ifdef __ILP32__ |
| /* Sanity check on the __heap_limit. */ |
| tst x1, #0xffffffff00000000 |
| bne .Linsanepar |
| #endif |
| cmp x1, xzr |
| beq .LC4 |
| adrp x2, __heap_limit |
| add x2, x2, #:lo12:__heap_limit |
| str x1, [x2] |
| .LC4: |
| |
| ldr x1, [x0] /* get heap_base */ |
| #ifdef __ILP32__ |
| /* Sanity check on the heap base. */ |
| tst x1, #0xffffffff00000000 |
| bne .Linsanepar |
| #endif |
| cmp x1, xzr |
| bne .LC5 |
| /* If the heap base value [x0, #0] is 0 then the heap base is actually |
| at the end of program data (i.e. __end__) */ |
| ldr x1, .LC3 |
| str x1, [x0, #0] |
| .LC5: |
| ldr x1, [x0, #16] /* get stack_base */ |
| |
| #ifdef __ILP32__ |
| /* Sanity check on the stack_base. */ |
| tst x1, #0xffffffff00000000 |
| bne .Linsanepar |
| #endif |
| cmp x1, xzr |
| bne .LC6 |
| #endif |
| ldr x1, .Lstack /* Set up the stack pointer to a fixed value */ |
| .LC6: |
| |
| /* Ensure quad-word stack alignment. */ |
| and x0, x1, #~15 |
| mov sp, x0 |
| |
| /* Setup an initial dummy frame with saved fp=0 and saved lr=0 */ |
| mov x29, 0 |
| stp x29, x29, [sp, #-16]! |
| mov x29, sp |
| |
| /* Initialize exception vector table, flatmap, etc. */ |
| bl FUNCTION (_cpu_init_hook) |
| |
| /* Zero the memory in the .bss section. */ |
| ldr x0, .LC1 /* First arg: start of memory block */ |
| mov w1, #0 /* Second arg: fill value */ |
| ldr x2, .LC2 |
| sub x2, x2, x0 /* Third arg: length of block */ |
| bl FUNCTION (memset) |
| |
| #ifdef ARM_RDI_MONITOR |
| /* Need to set up standard file handles */ |
| bl FUNCTION (initialise_monitor_handles) |
| #endif |
| |
| /* .init and .fini sections are used to create constructors |
| and destructors. Here we call the _init function and arrange |
| for _fini to be called at program exit. */ |
| ldr x0, .Lfini |
| bl FUNCTION (atexit) |
| |
| bl FUNCTION (_init) |
| |
| #ifdef ARM_RDI_MONITOR |
| /* Fetch and parse the command line. */ |
| ldr x1, .Lcmdline /* Command line descriptor. */ |
| mov w0, #AngelSVC_Reason_GetCmdLine |
| AngelSVCAsm AngelSVC |
| ldr x8, .Lcmdline |
| ldr x8, [x8] |
| |
| mov x0, #0 /* argc */ |
| mov x1, sp /* argv */ |
| ldr x2, .Lenvp /* envp */ |
| |
| /* Put NULL at end of argv array. */ |
| str PTR_REG (0), [x1, #-PTR_SIZE]! |
| |
| /* Skip leading blanks. */ |
| .Lnext: ldrb w3, [x8], #1 |
| cbz w3, .Lendstr |
| cmp w3, #' ' |
| b.eq .Lnext |
| |
| mov w4, #' ' /* Terminator is space. */ |
| |
| /* See whether we are scanning a quoted string by checking for |
| opening quote (" or '). */ |
| subs w9, w3, #'\"' |
| sub x8, x8, #1 /* Backup if no match. */ |
| ccmp w9, #('\'' - '\"'), 0x4 /* FLG_Z */, ne |
| csel w4, w3, w4, eq /* Terminator = quote if match. */ |
| cinc x8, x8, eq |
| |
| /* Push arg pointer to argv, and bump argc. */ |
| str PTR_REG (8), [x1, #-PTR_SIZE]! |
| add x0, x0, #1 |
| |
| /* Find end of arg string. */ |
| 1: ldrb w3, [x8], #1 |
| cbz w3, .Lendstr |
| cmp w4, w3 /* Reached terminator? */ |
| b.ne 1b |
| |
| /* Terminate the arg string with NUL char. */ |
| mov w4, #0 |
| strb w4, [x8, #-1] |
| b .Lnext |
| |
| /* Reverse argv array. */ |
| .Lendstr: |
| add x3, x1, #0 /* sp = &argv[0] */ |
| add x4, x1, w0, uxtw #PTR_LOG_SIZE /* ep = &argv[argc] */ |
| cmp x4, x3 |
| b.lo 2f |
| 1: ldr PTR_REG (5), [x4, #-PTR_SIZE] /* PTR_REG (5) = ep[-1] */ |
| ldr PTR_REG (6), [x3] /* PTR_REG (6) = *sp */ |
| str PTR_REG (6), [x4, #-PTR_SIZE]! /* *--ep = PTR_REG (6) */ |
| str PTR_REG (5), [x3], #PTR_SIZE /* *sp++ = PTR_REG (5) */ |
| cmp x4, x3 |
| b.hi 1b |
| 2: |
| /* Move sp to the 16B boundary below argv. */ |
| and x4, x1, ~15 |
| mov sp, x4 |
| |
| #else |
| mov x0, #0 /* argc = 0 */ |
| mov x1, #0 /* argv = NULL */ |
| #endif |
| |
| bl FUNCTION (main) |
| |
| b FUNCTION (exit) /* Cannot return. */ |
| |
| #if defined (ARM_RDI_MONITOR) && defined (__ILP32__) |
| .Linsanepar: |
| /* Exit with 1 if the parameter is not within the 32-bit address |
| space. */ |
| mov x1, ADP_Stopped_ApplicationExit & 0xff |
| movk x1, ADP_Stopped_ApplicationExit >> 16, lsl #16 |
| adrp x0, HeapBase /* Reuse to construct the parameter block. */ |
| add x0, x0, #:lo12:HeapBase |
| str x1, [x0] |
| mov x1, 1 |
| str x1, [x0, #8] |
| mov w1, #AngelSVC_Reason_ReportException |
| AngelSVCAsm AngelSVC |
| b . |
| #endif |
| |
| /* Function initializing exception vector table, flatmap, etc. |
| Declared as weak symbol so that user can override this definition |
| by linking in their own version of the function. */ |
| .weak FUNCTION (_cpu_init_hook) |
| FUNCTION (_cpu_init_hook): |
| ret |
| |
| .align 3 |
| #ifdef ARM_RDI_MONITOR |
| .LC0: |
| GEN_DWORD HeapBase |
| .LC3: |
| GEN_DWORD __end__ |
| #endif |
| .Lstack: |
| GEN_DWORD __stack |
| .weak __stack |
| |
| .LC1: |
| GEN_DWORD __bss_start__ |
| .LC2: |
| GEN_DWORD __bss_end__ |
| .Lfini: |
| GEN_DWORD FUNCTION(_fini) |
| #ifdef ARM_RDI_MONITOR |
| .Lenvp: |
| GEN_DWORD env |
| .Lcmdline: |
| GEN_DWORD AngelSVCArgs |
| /* Workspace for Angel calls. */ |
| .data |
| .align 3 |
| /* Data returned by monitor SVC. */ |
| #if defined(__ILP32__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
| .set __stack_base__, StackBase + 4 |
| #else |
| .set __stack_base__, StackBase |
| #endif |
| .global __stack_base__ |
| HeapBase: .dword 0 |
| HeapLimit: .dword 0 |
| StackBase: .dword 0 |
| StackLimit: .dword 0 |
| env: .dword 0 /* Dummy environment array */ |
| CommandLine: .space 256,0 /* Maximum length of 255 chars handled. */ |
| AngelSVCArgs: |
| GEN_DWORD CommandLine |
| .dword 255 |
| #endif |