This is the mail archive of the
newlib@sources.redhat.com
mailing list for the newlib project.
Re: [patch RFA] update MIPS libgloss CFE support to be ... better.
- From: "J. Johnston" <jjohnstn at redhat dot com>
- To: cgd at broadcom dot com
- Cc: newlib at sources dot redhat dot com
- Date: Wed, 20 Aug 2003 15:33:02 -0400
- Subject: Re: [patch RFA] update MIPS libgloss CFE support to be ... better.
- Organization: Red Hat Inc.
- References: <yov5oeyq5z3g.fsf@ldt-sj3-010.sj.broadcom.com>
Patch applied.
-- Jeff J.
cgd@broadcom.com wrote:
>
> This updates the MIPS libgloss CFE support to be ... better.
>
> In particular:
>
> * doesn't do nasty things to CP0 registers at startup.
>
> * less hack-ish startup sequence (no special prestart function
> to squirrel incoming args away).
>
> * detects and makes available all memory in kseg0 for program
> operation.
>
> * provides a more pluggable low-level memory allocation
> interface, so that people who want to can implement
> something Better. (we've had people use this to implement
> access via TLBs, and other stuff... *shudder*)
>
> when applying, be sure to 'patch -E' then cvs delete the
> cfe_prestart.S file. 8-)
>
> tested with mipsisa64-elf against a target board running CFE. Results
> as expected when compared to same target running sim.
>
> BTW, if any of you are wondering what CFE *is*, i can't resist a plug:
>
> http://sibyte.broadcom.com/public/resources/#cfe
>
> 8-)
>
> chris
> --
> 2003-08-15 Chris Demetriou <cgd@broadcom.com>
>
> * mips/crt0_cfe.S: New file.
> * mips/cfe_mem.c: New file.
> * mips/cfe_prestart.S: Remove.
> * mips/cfe.ld: Adjust to use crt0_cfe.o as the startup file, and
> and use _start as the entry point. Align BSS to 32-byte boundary.
> * mips/cfe.c: Reimplement to fit on top of a crt0_cfe.o file.
> * mips/cfe_api.h (__libcfe_stack_size, __libcfe_mem_limit)
> (__libcfe_meminit, __libcfe_stack_top): New prototypes.
> * mips/Makefile.in (CFEOBJS): Replace cfe_prestart.o with cfe_mem.o.
> (cfe.o, cfe_api.o, cfe_mem.o, crt0_cfe.o): New targets.
> * mips/configure.in: Build and install crt0_cfe.o when CFE support
> is built.
> * mips/configure: Regenerate.
>
> Index: mips/Makefile.in
> ===================================================================
> RCS file: /cvs/src/src/libgloss/mips/Makefile.in,v
> retrieving revision 1.4
> diff -u -p -r1.4 Makefile.in
> --- mips/Makefile.in 12 Nov 2002 23:14:24 -0000 1.4
> +++ mips/Makefile.in 13 Aug 2003 20:49:44 -0000
> @@ -73,8 +73,7 @@ PMONOBJS = pmon.o @part_specific_obj@ ${
> LSIOBJS = lsipmon.o @part_specific_obj@ ${GENOBJS}
> DVEOBJS = dvemon.o @part_specific_obj@ ${GENOBJS} ${GENOBJS2}
> JMR3904OBJS = jmr3904-io.o @part_specific_obj@ ${GENOBJS} ${GENOBJS2}
> -CFEOBJS = cfe.o cfe_api.o cfe_prestart.o \
> - @part_specific_obj@ ${GENOBJS} ${GENOBJS2}
> +CFEOBJS = cfe.o cfe_api.o cfe_mem.o @part_specific_obj@ ${GENOBJS} ${GENOBJS2}
> CYGMONOBJS = open.o close.o cygmon.o @part_specific_obj@ ${GENOBJS}
>
> # Nullmon cannot support read and write, but the test cases pull them in via libs
> @@ -136,7 +135,6 @@ libcygmon.a: $(CYGMONOBJS)
> ${AR} ${ARFLAGS} $@ $(CYGMONOBJS)
> ${RANLIB} $@
>
> -
> libcfe.a: $(CFEOBJS)
> ${AR} ${ARFLAGS} $@ $(CFEOBJS)
> ${RANLIB} $@
> @@ -219,6 +217,7 @@ test.o: ${srcdir}/test.c
> crt0.o: ${srcdir}/crt0.S
> pcrt0.o: ${srcdir}/crt0.S
> $(CC) -c $(CFLAGS_FOR_TARGET) $(CFLAGS) -DGCRT0 ${srcdir}/crt0.S -o ${PCRT0}
> +crt0_cfe.o: ${srcdir}/crt0_cfe.S
> crt0_cygmon.o: ${srcdir}/crt0_cygmon.S
> idtmon.o: ${srcdir}/idtmon.S
> pmon.o: ${srcdir}/pmon.S
> @@ -230,6 +229,12 @@ vr5xxx.o: ${srcdir}/vr5xxx.S
> lsipmon.o: $(srcdir)/lsipmon.S $(srcdir)/pmon.S
> jmr3904-io.o: ${srcdir}/jmr3904-io.c
> $(CC) -c $(CFLAGS_FOR_TARGET) $(CFLAGS) ${srcdir}/jmr3904-io.c -o $@
> +cfe.o: ${srcdir}/cfe.c ${srcdir}/cfe_api.h
> + $(CC) -c $(CFLAGS_FOR_TARGET) $(CFLAGS) ${srcdir}/cfe.c -o $@
> +cfe_api.o: ${srcdir}/cfe_api.c ${srcdir}/cfe_api.h ${srcdir}/cfe_api_int.h
> + $(CC) -c $(CFLAGS_FOR_TARGET) $(CFLAGS) ${srcdir}/cfe_api.c -o $@
> +cfe_mem.o: ${srcdir}/cfe_mem.c ${srcdir}/cfe_api.h
> + $(CC) -c $(CFLAGS_FOR_TARGET) $(CFLAGS) ${srcdir}/cfe_mem.c -o $@
>
> # cma101 can not be compiled mips16, if a mips16 version is needed then
> # it will have to be built, then this rule can be scrapped, allowing
> Index: mips/cfe.c
> ===================================================================
> RCS file: /cvs/src/src/libgloss/mips/cfe.c,v
> retrieving revision 1.4
> diff -u -p -r1.4 cfe.c
> --- mips/cfe.c 10 Apr 2003 20:07:57 -0000 1.4
> +++ mips/cfe.c 13 Aug 2003 20:49:44 -0000
> @@ -1,7 +1,7 @@
> /* cfe.c -- I/O code for the MIPS boards running CFE. */
>
> /*
> - * Copyright 2001, 2002
> + * Copyright 2001, 2002, 2003
> * Broadcom Corporation. All rights reserved.
> *
> * This software is furnished under license and may be used and copied only
> @@ -32,37 +32,40 @@
>
> #include "cfe_api.h"
>
> +void *__libcfe_init (long handle, long a1, long cfe_entrypoint, long a3);
> +void __libcfe_exit (long status);
> +
> char inbyte (void);
> int outbyte (char c);
>
> -/* Make sure cfe_prestart is used. It doesn't look like setting the
> - entry symbol in the linker script to a symbol from that fiel will do
> - this! */
> -extern int _prestart;
> -static void *force_prestart = &_prestart;
> -
> -/* The following variables are initialized to non-zero so that they'll be
> - in data, rather than BSS. Used to be that you could init variables to
> - any value to put them into initialized data sections rather than BSS,
> - but that decades-old idiom went out the window with gcc 3.2. Now,
> - either you compile specially (with -fno-zero-initialized-in-bss), or
> - you init to non-zero. In this case, initting to non-zero is OK (and
> - even beneficial; alignment fault via jump to odd if not properly
> - set up by _prestart()), so we do the latter.
> -
> - These variables are 'int's so they can be reliably stored w/ "sw".
> - (longs fall victim to -mlong64.) They are signed so that they remain
> - valid pointers when extended to cfe_xuint_t in the call to cfe_init().
> - This assumes that they are compatibility-space pointers. */
> -int __cfe_handle = 0xdeadbeef;
> -int __cfe_entrypt = 0xdeadbeef;
> -
> /* Echo input characters? */
> -int __cfe_echo_input = 0;
> +int __libcfe_echo_input = 0;
>
> /* CFE handle used to access console device. */
> static int cfe_conshandle;
>
> +
> +/* Initialize firmware callbacks. Called from crt0_cfe. Returns desired
> + stack pointer. */
> +void *
> +__libcfe_init (long handle, long a1, long entrypoint, long a3)
> +{
> + cfe_init (handle, entrypoint);
> + cfe_conshandle = cfe_getstdhandle (CFE_STDHANDLE_CONSOLE);
> +
> + __libcfe_meminit ();
> + return __libcfe_stack_top ();
> +}
> +
> +/* Exit back to monitor, with the given status code. */
> +void
> +__libcfe_exit (long status)
> +{
> + outbyte ('\r');
> + outbyte ('\n');
> + cfe_exit (CFE_FLG_WARMSTART, status);
> +}
> +
> char
> inbyte (void)
> {
> @@ -73,7 +76,7 @@ inbyte (void)
> ;
> if (c == '\r')
> c = '\n';
> - if (__cfe_echo_input)
> + if (__libcfe_echo_input)
> outbyte (c);
> return c;
> }
> @@ -91,41 +94,6 @@ outbyte (char c)
> if (c == '\n')
> outbyte ('\r');
> return 0;
> -}
> -
> -/* Initialize hardware. Called from crt0. */
> -void
> -hardware_init_hook(void)
> -{
> - cfe_init (__cfe_handle, __cfe_entrypt);
> - cfe_conshandle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
> -}
> -
> -/* Exit back to monitor, with the given status code. */
> -void
> -hardware_exit_hook (int status)
> -{
> - outbyte ('\r');
> - outbyte ('\n');
> - cfe_exit (CFE_FLG_WARMSTART, status);
> -}
> -
> -/* Structure filled in by get_mem_info. Only the size field is
> - actually used (by sbrk), so the others aren't even filled in. */
> -struct s_mem
> -{
> - unsigned int size;
> - unsigned int icsize;
> - unsigned int dcsize;
> -};
> -
> -void
> -get_mem_info (mem)
> - struct s_mem *mem;
> -{
> - /* XXX FIXME: Fake this for now. Should invoke cfe_enummem, but we
> - don't have enough stack to do that (yet). */
> - mem->size = 0x4000000; /* Assume 64 MB of RAM */
> }
>
> /* This is the MIPS cache flush function call. No defines are provided
> Index: mips/cfe.ld
> ===================================================================
> RCS file: /cvs/src/src/libgloss/mips/cfe.ld,v
> retrieving revision 1.2
> diff -u -p -r1.2 cfe.ld
> --- mips/cfe.ld 1 Aug 2002 20:21:23 -0000 1.2
> +++ mips/cfe.ld 13 Aug 2003 20:49:44 -0000
> @@ -1,8 +1,8 @@
> /* The following TEXT start address leaves space for the monitor
> workspace. */
>
> -ENTRY(_prestart)
> -STARTUP(crt0.o)
> +ENTRY(_start)
> +STARTUP(crt0_cfe.o)
> OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-littlemips")
> GROUP(-lc -lcfe -lgcc)
> SEARCH_DIR(.)
> @@ -127,6 +127,7 @@ SECTIONS
> *(COMMON)
> }
>
> + . = ALIGN(32);
> PROVIDE (end = .);
> _end = .;
>
> Index: mips/cfe_api.h
> ===================================================================
> RCS file: /cvs/src/src/libgloss/mips/cfe_api.h,v
> retrieving revision 1.1
> diff -u -p -r1.1 cfe_api.h
> --- mips/cfe_api.h 12 Jul 2002 17:55:04 -0000 1.1
> +++ mips/cfe_api.h 13 Aug 2003 20:49:44 -0000
> @@ -71,6 +71,40 @@ typedef unsigned _POINTER_INT uintptr_t;
>
> #define CFE_API_ALL
> #define CFE_API_IMPL_NAMESPACE
> +
> +/* Return the stack size to be used for the program. Normally 32KB. The
> + normal memory allocator uses the bottom of the stack as its heap limit,
> + so if your application uses a lot of stack space define this function
> + appropriately to keep the heap from growing into the stack. */
> +unsigned long __libcfe_stack_size(void) __attribute__((__weak__));
> +
> +/* Return the (max address + 1) to be used by this program. (This address
> + minus '_end' is used as the heap size, so the address should be in the
> + same address space segments as _end. The normal memory allocator
> + queries CFE to determine the available memory. */
> +void *__libcfe_mem_limit(void) __attribute__((__weak__));
> +
> +/* If the configuration ability provided by __libcfe_mem_limit() and
> + __libcfe_stack_size() do not provide enough flexibility for your
> + application's memory allocation needs, you can replace the normal
> + low-level allocator by providing the functions listed below and
> + also the function:
> +
> + void *sbrk(ptrdiff_t incr);
> +
> + If you provide any of these functions, you should provide all three,
> + and be sure to link them into your application as a .o file (rather
> + than a .a).
> +
> + __libcfe_meminit() is responsible for initializing the low-level
> + memory allocator.
> +
> + __libcfe_stack_top() returns a pointer to the top (highest address;
> + the stack grows down from that address) of the stack to be used by
> + the program. */
> +void __libcfe_meminit (void);
> +void *__libcfe_stack_top (void);
> +
> /* End customization. */
>
>
> Index: mips/cfe_mem.c
> ===================================================================
> RCS file: mips/cfe_mem.c
> diff -N mips/cfe_mem.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ mips/cfe_mem.c 13 Aug 2003 20:49:44 -0000
> @@ -0,0 +1,130 @@
> +/* cfe_mem.c -- Replaceable memory management hooks for MIPS boards
> + running CFE. */
> +
> +/*
> + * Copyright 2003
> + * Broadcom Corporation. All rights reserved.
> + *
> + * This software is furnished under license and may be used and copied only
> + * in accordance with the following terms and conditions. Subject to these
> + * conditions, you may download, copy, install, use, modify and distribute
> + * modified or unmodified copies of this software in source and/or binary
> + * form. No title or ownership is transferred hereby.
> + *
> + * 1) Any source code used, modified or distributed must reproduce and
> + * retain this copyright notice and list of conditions as they appear in
> + * the source file.
> + *
> + * 2) No right is granted to use any trade name, trademark, or logo of
> + * Broadcom Corporation. The "Broadcom Corporation" name may not be
> + * used to endorse or promote products derived from this software
> + * without the prior written permission of Broadcom Corporation.
> + *
> + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
> + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
> + * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
> + * LIABLE FOR 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,
> + */
> +
> +#include "cfe_api.h"
> +
> +/* Structure filled in by get_mem_info. Only the size field is
> + actually used (by sbrk), so the others aren't even filled in.
> + Note that 'size' is the __size__ of the heap starting at _end! */
> +struct s_mem {
> + unsigned int size;
> + unsigned int icsize;
> + unsigned int dcsize;
> +};
> +
> +void *get_mem_info (struct s_mem *);
> +
> +extern char _end[];
> +
> +/* Address immediately after available memory. */
> +static unsigned long memtop;
> +
> +/* Program stack size. */
> +static unsigned long stack_size;
> +
> +void
> +__libcfe_meminit (void)
> +{
> + /* If the user has provided a memory-limit function, use it to
> + determine the end of usable memory. */
> + if (&__libcfe_mem_limit != NULL)
> + memtop = __libcfe_mem_limit ();
> + else
> + {
> + uint64_t start, length, type;
> + int i, rv;
> + long end_segbits, end_pa;
> +
> + /* Note that this only works if _end and the program live in kseg0
> + or kseg1. Not a problem with the default linker script, but
> + if you're writing your own, keep it in mind. For more complex
> + memory allocation needs, you're encouraged to copy this file
> + and syscalls.c (for sbrk()), and reimplement as appropriate. */
> + end_segbits = (long)_end & ~ 0x1fffffffL;
> + end_pa = (long)_end & 0x1fffffffL;
> +
> + for (i = 0; ; i++)
> + {
> + rv = cfe_enummem(i, 0, &start, &length, &type);
> + if (rv < 0)
> + {
> + /* Did not find an available entry containing _end.
> + Assume a minimal amount of memory (1MB). */
> + memtop = _end + (1 * 1024 * 1024);
> + break;
> + }
> +
> + /* If not available, try the next. */
> + if (type != CFE_MI_AVAILABLE)
> + continue;
> +
> + /* If end_pa is between start and (start + length) then we have
> + a winner. */
> + if (end_pa >= start && end_pa < (start + length))
> + {
> + memtop = (start + length) | end_segbits;
> + break;
> + }
> + }
> + }
> +
> + /* If the user has provided a memory-limit function, use it to
> + determine the end of usable memory. */
> + if (&__libcfe_stack_size != NULL)
> + stack_size = __libcfe_stack_size ();
> + else
> + stack_size = (32 * 1024); /* Default = 32KB. */
> +
> + /* Chop the top of memory to a 32-byte aligned location, and
> + round the stack size up to a 32-byte multiple. */
> + memtop = memtop & ~(unsigned long)31;
> + stack_size = (stack_size + 31) & ~(unsigned long)31;
> +}
> +
> +void *
> +__libcfe_stack_top (void)
> +{
> + /* Grow down from the top of available memory. Obviously, if
> + code writes above this limit, problems could result! */
> + return (void *) memtop;
> +}
> +
> +/* For compatibility, get_mem_info returns the top of memory
> + (i.e., the stack address). Nothing actually uses that,
> + though. */
> +void *
> +get_mem_info (struct s_mem *meminfo)
> +{
> + meminfo->size = (char *)(memtop - stack_size) - _end;
> + return (void *) memtop;
> +}
> Index: mips/cfe_prestart.S
> ===================================================================
> RCS file: mips/cfe_prestart.S
> diff -N mips/cfe_prestart.S
> --- mips/cfe_prestart.S 5 Feb 2003 17:01:33 -0000 1.2
> +++ /dev/null 1 Jan 1970 00:00:00 -0000
> @@ -1,86 +0,0 @@
> -/*
> - * cfe_prestart.S -- startup file for MIPS running CFE.
> - * Derived from crt0.S.
> - *
> - * Copyright (c) 1995, 1996, 1997 Cygnus Support
> - *
> - * The authors hereby grant permission to use, copy, modify, distribute,
> - * and license this software and its documentation for any purpose, provided
> - * that existing copyright notices are retained in all copies and that this
> - * notice is included verbatim in any distributions. No written agreement,
> - * license, or royalty fee is required for any of the authorized uses.
> - * Modifications to this software may be copyrighted by their authors
> - * and need not follow the licensing terms described here, provided that
> - * the new terms are clearly indicated on the first page of each file where
> - * they apply.
> - */
> -
> -#ifdef __mips16
> -/* This file contains 32 bit assembly code. */
> - .set nomips16
> -#endif
> -
> -#include "regs.S"
> -
> -/* This is for referencing addresses that are not in the .sdata or
> - .sbss section under embedded-pic, or before we've set up gp. */
> -#ifdef __mips_embedded_pic
> -# ifdef __mips64
> -# define LA(t,x) la t,x-PICBASE ; daddu t,s0,t
> -# else
> -# define LA(t,x) la t,x-PICBASE ; addu t,s0,t
> -# endif
> -#else /* __mips_embedded_pic */
> -# define LA(t,x) la t,x
> -#endif /* __mips_embedded_pic */
> -
> - .globl __cfe_handle
> - .globl __cfe_entrypt
> -
> - .text
> - .align 2
> -
> - .globl _prestart
> - .ent _prestart
> -_prestart:
> - .set noreorder
> -#ifdef __mips_embedded_pic
> - PICBASE = .+8
> - bal PICBASE
> - nop
> - move s0,$31
> -#endif
> -
> - /* These are actually pointers, but they're guaranteed to be
> - in compatibility space and it's just easier to store them
> - as words ("unsigned int") than worry about the actual
> - pointer size of the runtime we're building. */
> - LA (v0, __cfe_handle)
> - sw a0, 0(v0)
> - LA (v0, __cfe_entrypt)
> - sw a2, 0(v0)
> -
> - LA (v0, _start)
> - jr v0
> - nop
> - .end _prestart
> -
> -
> -/* Avoid worst-case execution hazards. This is targetted at the SB-1
> - pipe, and is much worse than it needs to be (not even counting
> - the subroutine call and return). */
> - .globl hardware_hazard_hook
> - .ent hardware_hazard_hook
> -hardware_hazard_hook:
> - .set push
> - .set mips32
> - .set noreorder
> - ssnop
> - ssnop
> - ssnop
> - bnel $0, $0, .+4
> - ssnop
> - j ra
> - nop
> - .set pop
> - .end hardware_hazard_hook
> Index: mips/configure.in
> ===================================================================
> RCS file: /cvs/src/src/libgloss/mips/configure.in,v
> retrieving revision 1.8
> diff -u -p -r1.8 configure.in
> --- mips/configure.in 5 Feb 2003 17:10:43 -0000 1.8
> +++ mips/configure.in 13 Aug 2003 20:49:44 -0000
> @@ -94,7 +94,7 @@ case "${target}" in
> ;;
> mipsisa32-*-* | mipsisa32el-*-* | \
> mipsisa32r2-*-* | mipsisa32r2el-*-*)
> - crt0="crt0_cygmon.o crt0.o"
> + crt0="crt0_cfe.o crt0_cygmon.o crt0.o"
> pcrt0="pcrt0.o"
> part_specific_obj=
> part_specific_defines=
> @@ -119,6 +119,7 @@ case "${target}" in
> bsp_list="libpmon.a libnullmon.a"
> ;;
> *)
> + crt0="crt0_cfe.o crt0.o"
> part_specific_obj="vr4300.o cma101.o"
> part_specific_defines=
> script_list="idt pmon ddb ddb-kseg0 lsi cfe idtecoff nullmon"
> Index: mips/crt0_cfe.S
> ===================================================================
> RCS file: mips/crt0_cfe.S
> diff -N mips/crt0_cfe.S
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ mips/crt0_cfe.S 13 Aug 2003 20:49:44 -0000
> @@ -0,0 +1,263 @@
> +/*
> + * crt0_cfe.S -- Runtime startup for MIPS targets running CFE.
> + *
> + * Copyright 2003
> + * Broadcom Corporation. All rights reserved.
> + *
> + * This software is furnished under license and may be used and copied only
> + * in accordance with the following terms and conditions. Subject to these
> + * conditions, you may download, copy, install, use, modify and distribute
> + * modified or unmodified copies of this software in source and/or binary
> + * form. No title or ownership is transferred hereby.
> + *
> + * 1) Any source code used, modified or distributed must reproduce and
> + * retain this copyright notice and list of conditions as they appear in
> + * the source file.
> + *
> + * 2) No right is granted to use any trade name, trademark, or logo of
> + * Broadcom Corporation. The "Broadcom Corporation" name may not be
> + * used to endorse or promote products derived from this software
> + * without the prior written permission of Broadcom Corporation.
> + *
> + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
> + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
> + * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
> + * LIABLE FOR 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), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +/*
> + * Derived from crt0_cygmon.S:
> + *
> + * Copyright (c) 1995, 1996, 1997, 2000 Red Hat, Inc.
> + *
> + * The authors hereby grant permission to use, copy, modify, distribute,
> + * and license this software and its documentation for any purpose, provided
> + * that existing copyright notices are retained in all copies and that this
> + * notice is included verbatim in any distributions. No written agreement,
> + * license, or royalty fee is required for any of the authorized uses.
> + * Modifications to this software may be copyrighted by their authors
> + * and need not follow the licensing terms described here, provided that
> + * the new terms are clearly indicated on the first page of each file where
> + * they apply.
> + */
> +
> +/*
> + * This file does minimal runtime startup for code running under
> + * CFE firmware.
> + *
> + * It does minimal hardware initialization. In particular
> + * it sets Status:FR to match the requested floating point
> + * mode.
> + *
> + * It is meant to be linked with the other files provided by libcfe.a,
> + * and calls routines in those files.
> + */
> +
> +#ifdef __mips16
> +/* This file contains 32 bit assembly code. */
> + .set nomips16
> +#endif
> +#ifdef __mips_embedded_pic
> +# error -membedded-pic is not supported.
> +#endif
> +
> +#include "regs.S"
> +
> +/*
> + * Set up some room for a stack. We just grab a chunk of memory.
> + */
> +#define STARTUP_STACK_SIZE (1 * 1024)
> +
> + .comm _lstack, STARTUP_STACK_SIZE
> +
> + .text
> + .align 4
> +
> + /*
> + * Without the following nop, GDB thinks _start is a data variable.
> + * This is probably a bug in GDB in handling a symbol that is at the
> + * start of the .text section.
> + */
> + nop
> +
> +
> + /*
> + * On entry, the following values have been passed in registers
> + * by the firmware:
> + *
> + * a0: firmware handle
> + * a1: zero (unused)
> + * a2: firmware callback entrypoint
> + * a3: CFE entrypoint seal (unused)
> + *
> + * They must be preserved until the CFE entrypoint and handle
> + * are passed to __libcfe_init().
> + */
> +
> + .globl _start
> + .ent _start
> +_start:
> + .set noreorder
> + /* Set the global data pointer, defined in the linker script. */
> + la gp, _gp
> +
> +#ifndef __mips_soft_float
> + /* If compiled for hard float, set the FPU mode based on the
> + compilation flags. Note that this assumes that enough code
> + will run after the mtc0 to clear any hazards. */
> + mfc0 t0, C0_SR
> + or t0, t0, (SR_CU1 | SR_FR)
> +#if (__mips_fpr == 32)
> + xor t0, t0, SR_FR /* If 32-bit FP mode, clear FR. */
> +#endif
> + mtc0 t0, C0_SR
> +#endif
> + .end _start
> +
> + /*
> + * zero out the bss section.
> + */
> + .globl _zerobss
> + .ent _zerobss
> +_zerobss:
> + /* These variables are defined in the linker script. */
> + la v0, _fbss
> + la v1, _end
> +
> +3:
> + sw zero, 0(v0)
> + bltu v0, v1, 3b
> + addiu v0, v0, 4 /* Delay slot. */
> + .end _zerobss
> +
> + /*
> + * Setup a small stack so we can run some C code, and do
> + * the library initialization. (32 bytes are saved for
> + * the argument registers' stack slots.)
> + */
> + .globl _stackinit
> + .ent _stackinit
> +_stackinit:
> + la t0, _lstack
> + addiu sp, t0, (STARTUP_STACK_SIZE - 32)
> + jal __libcfe_init
> + nop
> +
> + /*
> + * Setup the stack pointer --
> + * __libcfe_init() returns the value to be used as the top of
> + * the program's stack.
> + *
> + * We subtract 32 bytes for the 4 argument registers, in case
> + * main() wants to write them back to the stack. The caller
> + * allocates stack space for parameters in the old MIPS ABIs.
> + * We must do this even though we aren't passing arguments,
> + * because main might be declared to have them.)
> + *
> + * We subtract 32 more bytes for the argv/envp setup for the
> + * call to main().
> + */
> + subu v0, v0, 64
> + move sp, v0
> +
> + .end _stackinit
> +
> + /*
> + * initialize target specific stuff. Only execute these
> + * functions it they exist.
> + */
> + .globl hardware_init_hook .text
> + .globl software_init_hook .text
> + .type _fini,@function
> + .type _init,@function
> + .globl atexit .text
> + .globl exit .text
> + .globl _crt0init
> + .ent _crt0init
> +_crt0init:
> + la t9, hardware_init_hook # init the hardware if needed
> + beq t9, zero, 6f
> + nop
> + jal t9
> + nop
> +6:
> + la t9, software_init_hook # init the software if needed
> + beq t9, zero, 7f
> + nop
> + jal t9
> + nop
> +7:
> + la a0, _fini
> + jal atexit
> + nop
> +
> +#ifdef GCRT0
> + .globl _ftext
> + .globl _extext
> + la a0, _ftext
> + la a1, _etext
> + jal monstartup
> + nop
> +#endif
> +
> + jal _init # run global constructors
> + nop
> +
> + addiu a1,sp,32 # argv = sp + 32
> + addiu a2,sp,40 # envp = sp + 40
> +#if __mips64
> + sd zero,(a1) # argv[argc] = 0
> + sd zero,(a2) # envp[0] = 0
> +#else
> + sw zero,(a1)
> + sw zero,(a2)
> +#endif
> +
> + jal main # call the program start function
> + move a0,zero # set argc to 0; delay slot.
> +
> + # fall through to the "exit" routine
> + jal exit # call libc exit to run the G++
> + # destructors
> + move a0, v0 # pass through the exit code
> + .end _crt0init
> +
> +/*
> + * _exit -- Exit from the application. This is provided in this file because
> + * program exit should shut down profiling (if GCRT0 is defined),
> + * and only this file is compiled with GCRT0 defined.
> + */
> + .globl _exit
> + .ent _exit
> +_exit:
> +7:
> + move s0, a0 /* Save in case we loop. */
> +
> +#ifdef GCRT0
> + jal _mcleanup
> + nop
> +#endif
> +
> + la t0, hardware_exit_hook
> + beq t0,zero,1f
> + nop
> + jal t0
> + nop
> +
> +1:
> + /* Call into the library to do the heavy lifting. */
> + jal __libcfe_exit
> + move a0, s0 /* Delay slot. */
> +
> + b 7b /* Loop back just in case. */
> + nop
> + .end _exit
> +
> +/* EOF crt0_cfe.S */