261 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			261 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
/* 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 */
 | 
						|
 | 
						|
	/*  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 */
 | 
						|
#ifdef __ILP32__
 | 
						|
	/* Sanity check on the heap base.  */
 | 
						|
	ldr	x0, [x0]		/* get heap_base */
 | 
						|
	tst	x0, #0xffffffff00000000
 | 
						|
	beq	1f
 | 
						|
	/* Exit with 1 if the heap base is not within the 32-bit address
 | 
						|
	   space.  */
 | 
						|
	mov	x0, ADP_Stopped_ApplicationExit & 0xff
 | 
						|
	movk	x0, ADP_Stopped_ApplicationExit >> 16, lsl #16
 | 
						|
	adrp	x1, HeapBase	/* Reuse to construct the parameter block.  */
 | 
						|
	add	x1, x1, #:lo12:HeapBase
 | 
						|
	str	x0, [x1]
 | 
						|
	mov	x0, 1
 | 
						|
	str	x0, [x1, #8]
 | 
						|
	mov	w0, #AngelSVC_Reason_ReportException
 | 
						|
	AngelSVCAsm AngelSVC
 | 
						|
1:
 | 
						|
	/* For the sake of safety, set the stack base to the top end of
 | 
						|
	   the 32-bit address space if the returned value from the
 | 
						|
	   Angel API call is larger than or equal to 4 GiB.  */
 | 
						|
	tst	x1, #0xffffffff00000000
 | 
						|
	csinv	w1, w1, wzr, eq
 | 
						|
#endif
 | 
						|
 | 
						|
	/* 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)
 | 
						|
 | 
						|
	/* Need to set up standard file handles */
 | 
						|
	bl	FUNCTION (initialise_monitor_handles)
 | 
						|
 | 
						|
	/* .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)
 | 
						|
 | 
						|
	/* Fetch and parse the command line.  */
 | 
						|
	adr	x1, .Lcmdline		/* Command line descriptor.  */
 | 
						|
	mov	w0, #AngelSVC_Reason_GetCmdLine
 | 
						|
	AngelSVCAsm AngelSVC
 | 
						|
	ldr	x8, .Lcmdline
 | 
						|
 | 
						|
	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
 | 
						|
 | 
						|
	bl	FUNCTION (main)
 | 
						|
 | 
						|
	b	FUNCTION (exit)		/* Cannot return.  */
 | 
						|
 | 
						|
/* 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
 | 
						|
.LC0:
 | 
						|
	GEN_DWORD HeapBase
 | 
						|
.LC1:
 | 
						|
	GEN_DWORD __bss_start__
 | 
						|
.LC2:
 | 
						|
	GEN_DWORD __bss_end__
 | 
						|
.Lfini:
 | 
						|
	GEN_DWORD FUNCTION(_fini)
 | 
						|
.Lenvp:
 | 
						|
	GEN_DWORD env
 | 
						|
.Lcmdline:
 | 
						|
	GEN_DWORD CommandLine
 | 
						|
	.dword	255
 | 
						|
 | 
						|
/*  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.  */
 |