From a7364adeb97e9950b43d9efcdb3b650cb442f465 Mon Sep 17 00:00:00 2001 From: Jeff Johnston Date: Wed, 9 Jun 2004 19:06:50 +0000 Subject: [PATCH] 2004-06-09 Toralf Lund * arm/crt0.S: Copied from newlib and it now also sets up stacks for FIQ and IRQ mode, plus calls hardware_init_hook() and software_init_hook() if present. * arm/libcfunc.c, arm/swi.h, arm/syscalls.c: Copied from newlib. * arm/Makefile.in: Build crt0.o, rdpmon-crt0.o, rdimon-crt0.o, librdpmon.a, librdimon.a - support file for "bare" setup, as well as "RDP" and "RDI" monitors. * arm/coff-rdpmon.specs, arm/elf-rdpmon.specs, arm/coff-rdimon.specs, arm/elf-rdimon.specs: gcc specs files to go with above mentioned support libs and startfiles. --- libgloss/ChangeLog | 14 + libgloss/arm/Makefile.in | 60 +++- libgloss/arm/coff-rdimon.specs | 8 + libgloss/arm/coff-rdpmon.specs | 8 + libgloss/arm/crt0.S | 359 +++++++++++++++++++ libgloss/arm/elf-rdimon.specs | 8 + libgloss/arm/elf-rdpmon.specs | 8 + libgloss/arm/libcfunc.c | 40 +++ libgloss/arm/swi.h | 60 ++++ libgloss/arm/syscalls.c | 630 +++++++++++++++++++++++++++++++++ libgloss/arm/trap.S | 93 +++++ libgloss/configure | 17 +- libgloss/configure.in | 3 + 13 files changed, 1297 insertions(+), 11 deletions(-) create mode 100644 libgloss/arm/coff-rdimon.specs create mode 100644 libgloss/arm/coff-rdpmon.specs create mode 100644 libgloss/arm/crt0.S create mode 100644 libgloss/arm/elf-rdimon.specs create mode 100644 libgloss/arm/elf-rdpmon.specs create mode 100644 libgloss/arm/libcfunc.c create mode 100644 libgloss/arm/swi.h create mode 100644 libgloss/arm/syscalls.c create mode 100644 libgloss/arm/trap.S diff --git a/libgloss/ChangeLog b/libgloss/ChangeLog index b54e307bb..047f2198d 100644 --- a/libgloss/ChangeLog +++ b/libgloss/ChangeLog @@ -1,3 +1,17 @@ +2004-06-09 Toralf Lund + + * arm/crt0.S: Copied from newlib and it now also sets up stacks for + FIQ and IRQ mode, plus calls hardware_init_hook() and + software_init_hook() if present. + * arm/libcfunc.c, arm/swi.h, arm/syscalls.c: Copied + from newlib. + * arm/Makefile.in: Build crt0.o, rdpmon-crt0.o, rdimon-crt0.o, + librdpmon.a, librdimon.a - support file for "bare" setup, as well + as "RDP" and "RDI" monitors. + * arm/coff-rdpmon.specs, arm/elf-rdpmon.specs, + arm/coff-rdimon.specs, arm/elf-rdimon.specs: gcc specs files to go + with above mentioned support libs and startfiles. + 2004-06-03 Alexandre Oliva * mn10300/sim.ld: Start at address 4, to avoid ambiguity with NULL diff --git a/libgloss/arm/Makefile.in b/libgloss/arm/Makefile.in index 97e3ad451..7d5b0d99d 100644 --- a/libgloss/arm/Makefile.in +++ b/libgloss/arm/Makefile.in @@ -47,9 +47,26 @@ OBJCOPY = `if [ -f ${objroot}/../binutils/objcopy ] ; \ then echo ${objroot}/../binutils/objcopy ; \ else t='$(program_transform_name)'; echo objcopy | sed -e $$t ; fi` -REDBOOT_OBJS = redboot-crt0.o redboot-syscalls.o +CRT0 = crt0.o +CRT0_INSTALL = install-crt0 + +REDBOOT_CRT0 = redboot-crt0.o +REDBOOT_OBJS = redboot-syscalls.o REDBOOT_SCRIPTS = redboot.ld redboot.specs REDBOOT_INSTALL = install-redboot + +RDPMON_CRT0 = rdpmon-crt0.o +RDPMON_BSP = librdpmon.a +RDPMON_OBJS = syscalls.o libcfunc.o trap.o +RDPMON_SCRIPTS = rdpmon.specs +RDPMON_INSTALL = install-rdpmon + +RDIMON_CRT0 = rdimon-crt0.o +RDIMON_BSP = librdimon.a +RDIMON_OBJS = rdimon-syscalls.o rdimon-libcfunc.o rdimon-trap.o +RDIMON_SCRIPTS = rdimon.specs +RDIMON_INSTALL = install-rdimon + CFLAGS = -g # Here is all of the eval board stuff @@ -67,7 +84,7 @@ IQ80310_INSTALL = install-iq80310 # build a test program for each target board. Just trying to get # it to link is a good test, so we ignore all the errors for now. # -all: ${REDBOOT_OBJS} +all: ${CRT0} ${REDBOOT_CRT0} ${REDBOOT_OBJS} ${RDPMON_CRT0} ${RDPMON_BSP} ${RDIMON_CRT0} ${RDIMON_BSP} # # here's where we build the test programs for each target @@ -76,9 +93,33 @@ all: ${REDBOOT_OBJS} test: # +crt0.o: crt0.S redboot-crt0.o: redboot-crt0.S redboot-syscalls.o: redboot-syscalls.c $(srcdir)/../syscall.h +rdpmon-crt0.o: crt0.S + $(CC) $(CFLAGS_FOR_TARGET) $(INCLUDES) -DARM_RDP_MONITOR -o $@ -c $< + +rdimon-crt0.o: crt0.S + $(CC) $(CFLAGS_FOR_TARGET) $(INCLUDES) -DARM_RDI_MONITOR -o $@ -c $< + +rdimon-trap.o: trap.S + $(CC) $(CFLAGS_FOR_TARGET) $(INCLUDES) -DARM_RDI_MONITOR -o $@ -c $< + +rdimon-syscalls.o: syscalls.c + $(CC) $(CFLAGS_FOR_TARGET) $(INCLUDES) -DARM_RDI_MONITOR -o $@ -c $< + +rdimon-libcfunc.o: libcfunc.c + $(CC) $(CFLAGS_FOR_TARGET) $(INCLUDES) -DARM_RDI_MONITOR -o $@ -c $< + +$(RDPMON_BSP): $(RDPMON_OBJS) + ${AR} ${ARFLAGS} $@ $(IDTOBJS) + ${RANLIB} $@ + +$(RDIMON_BSP): $(RDIMON_OBJS) + ${AR} ${ARFLAGS} $@ $(IDTOBJS) + ${RANLIB} $@ + clean mostlyclean: rm -f a.out core *.i *.o *-test *.srec *.dis *.x $(SIM_BSP) $(IQ80310_BSP) @@ -86,13 +127,24 @@ distclean maintainer-clean realclean: clean rm -f Makefile config.status *~ .PHONY: install info install-info clean-info -install: ${REDBOOT_INSTALL} ${IQ80310_INSTALL} ${PID_INSTALL} +install: ${CRT0_INSTALL} ${REDBOOT_INSTALL} ${RDPMON_INSTALL} ${RDIMON_INSTALL} ${IQ80310_INSTALL} ${PID_INSTALL} +install-crt0: + ${INSTALL_DATA} ${CRT0} ${tooldir}/lib${MULTISUBDIR}/$$x install-redboot: - set -e; for x in ${REDBOOT_OBJS}; do ${INSTALL_DATA} $$x ${tooldir}/lib${MULTISUBDIR}/$$x; done + set -e; for x in ${REDBOOT_CRT0} ${REDBOOT_OBJS}; do ${INSTALL_DATA} $$x ${tooldir}/lib${MULTISUBDIR}/$$x; done set -e; for x in ${REDBOOT_SCRIPTS}; do ${INSTALL_DATA} ${srcdir}/${objtype}$$x ${tooldir}/lib${MULTISUBDIR}/$$x; done +install-rdpmon: + set -e; for x in ${RDPMON_CRT0} ${RDPMON_BSP}; do ${INSTALL_DATA} $$x ${tooldir}/lib${MULTISUBDIR}/$$x; done + set -e; for x in ${RDPMON_SCRIPTS}; do ${INSTALL_DATA} ${srcdir}/${objtype}$$x ${tooldir}/lib${MULTISUBDIR}/$$x; done + +install-rdimon: + set -e; for x in ${RDIMON_CRT0} ${RDIMON_BSP}; do ${INSTALL_DATA} $$x ${tooldir}/lib${MULTISUBDIR}/$$x; done + set -e; for x in ${RDIMON_SCRIPTS}; do ${INSTALL_DATA} ${srcdir}/${objtype}$$x ${tooldir}/lib${MULTISUBDIR}/$$x; done + + install-pid: set -e; for x in ${PID_SCRIPTS}; do ${INSTALL_DATA} ${srcdir}/${objtype}$$x ${tooldir}/lib${MULTISUBDIR}/$$x; done diff --git a/libgloss/arm/coff-rdimon.specs b/libgloss/arm/coff-rdimon.specs new file mode 100644 index 000000000..ace550614 --- /dev/null +++ b/libgloss/arm/coff-rdimon.specs @@ -0,0 +1,8 @@ +%rename link old_link + +*link: +%(old_link) -lrdimon + +*startfile: +rdimon-crt0%O%s + diff --git a/libgloss/arm/coff-rdpmon.specs b/libgloss/arm/coff-rdpmon.specs new file mode 100644 index 000000000..661461229 --- /dev/null +++ b/libgloss/arm/coff-rdpmon.specs @@ -0,0 +1,8 @@ +%rename link old_link + +*link: +%(old_link) -lrdpmon + +*startfile: +rdpmon-crt0%O%s + diff --git a/libgloss/arm/crt0.S b/libgloss/arm/crt0.S new file mode 100644 index 000000000..7f36b12fc --- /dev/null +++ b/libgloss/arm/crt0.S @@ -0,0 +1,359 @@ +#include "swi.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 + +/* .text is used instead of .section .text so it works with arm-aout too. */ + .text + .code 32 + .align 0 + + .global _mainCRTStartup + .global _start + .global start +start: +_start: +_mainCRTStartup: + +/* Start by setting up a stack */ +#ifdef ARM_RDP_MONITOR + /* Issue Demon SWI to read stack info */ + swi SWI_GetEnv /* Returns command line in r0 */ + mov sp,r1 /* and the highest memory address in r1 */ + ldr sl, .LC2 /* stack limit is at end of data */ + add sl, sl, #256 /* allow slop for stack overflow handling */ + /* and small frames */ +#else +#ifdef ARM_RDI_MONITOR + /* Issue Angel SWI to read stack info */ + mov r0, #AngelSWI_Reason_HeapInfo + adr r1, .LC0 /* point at ptr to 4 words to receive data */ + swi AngelSWI_ARM /* We are always in ARM mode for startup */ + ldr r0, .LC0 /* point at values read */ + ldr sp, [r0, #8] + ldr sl, [r0, #12] + add sl, sl, #256 /* allow slop for stack overflow handling */ + /* and small frames */ +#else + /* Set up the stack pointer to a fixed value */ + /* Changes by toralf: + - Allow linker script to provide stack via __stack symbol - see + defintion of .Lstack + - Provide "hooks" that may be used by the application to add + custom init code - see .Lhwinit and .Lswinit + - Go through all execution modes and set up stack for each of them. + Loosely based on init.s from ARM/Motorola example code. + Note: Mode switch via CPSR is not allowed once in non-privileged + mode, so we take care not to enter "User" to set up its sp, + and also skip most operations if already in that mode. */ + + ldr r3, .Lstack + cmp r3, #0 + ldreq r3, .LC0 + /* Note: This 'mov' is essential when starting in User, and ensures we + always get *some* sp value for the initial mode, even if we + have somehow missed it below (in which case it gets the same + value as FIQ - not ideal, but better than nothing.) */ + mov sp, r3 + mrs r2, CPSR + tst r2, #0x0F /* Test mode bits - in User of all are 0 */ + beq .LC23 /* "eq" means r2 AND #0x0F is 0 */ + msr CPSR_c, #0xD1 /* FIRQ mode, interrupts disabled */ + mov sp, r3 + sub sl, sp, #0x1000 /* This mode also has its own sl (see below) */ + + mov r3, sl + msr CPSR_c, #0xD7 /* Abort mode, interrupts disabled */ + mov sp, r3 + sub r3, r3, #0x1000 + + msr CPSR_c, #0xDB /* Undefined mode, interrupts disabled */ + mov sp, r3 + sub r3, r3, #0x1000 + + msr CPSR_c, #0xD2 /* IRQ mode, interrupts disabled */ + mov sp, r3 + sub r3, r3, #0x2000 + + msr CPSR_c, #0xD3 /* Supervisory mode, interrupts disabled */ + mov sp, r3 + sub r3, r3, #0x8000 /* Min size 32k */ + bic r3, r3, #0x00FF /* Align with current 64k block */ + bic r3, r3, #0xFF00 + + str r3, [r3, #-4] /* Move value into user mode sp without */ + ldmdb r3, {sp}^ /* changing modes, via '^' form of ldm */ + + orr r2, r2, #0xC0 /* Back to original mode, presumably SVC, */ + msr CPSR_c, r2 /* with FIQ/IRQ disable bits forced to 1 */ +.LC23: + /* Setup a default stack-limit in-case the code has been + compiled with "-mapcs-stack-check". Hard-wiring this value + is not ideal, since there is currently no support for + checking that the heap and stack have not collided, or that + this default 64k is enough for the program being executed. + However, it ensures that this simple crt0 world will not + immediately cause an overflow event: */ + sub sl, r3, #64 << 10 /* Still assumes 256bytes below sl */ +#endif +#endif + /* Zero the memory in the .bss section. */ + mov a2, #0 /* Second arg: fill value */ + mov fp, a2 /* Null frame pointer */ + mov r7, a2 /* Null frame pointer for Thumb */ + + ldr a1, .LC1 /* First arg: start of memory block */ + ldr a3, .LC2 + sub a3, a3, a1 /* Third arg: length of block */ + + +#ifdef __thumb__ /* Enter Thumb mode.... */ + + add a4, pc, #1 /* Get the address of the Thumb block */ + bx a4 /* Go there and start Thumb decoding */ + + .code 16 + .global __change_mode + .thumb_func +__change_mode: +#endif + + bl FUNCTION (memset) +#if !defined (ARM_RDP_MONITOR) && !defined (ARM_RDI_MONITOR) +/* Changes by toralf: Taken from libgloss/m68k/crt0.S + * initialize target specific stuff. Only execute these + * functions it they exist. + */ + ldr r3, .Lhwinit + cmp r3, #0 + beq .LC24 + mov lr, pc + mov pc, r3 +.LC24: + ldr r3, .Lswinit + cmp r3, #0 + beq .LC25 + mov lr, pc + mov pc, r3 +.LC25: + mov r0, #0 /* no arguments */ + mov r1, #0 /* no argv either */ +#else + /* Need to set up standard file handles */ + bl FUNCTION (initialise_monitor_handles) + +#ifdef ARM_RDP_MONITOR + swi SWI_GetEnv /* sets r0 to point to the command line */ + mov r1, r0 +#else + mov r0, #AngelSWI_Reason_GetCmdLine + adr r1, .LC30 /* Space for command line */ + swi AngelSWI + ldr r1, .LC30 +#endif + /* Parse string at r1 */ + mov r0, #0 /* count of arguments so far */ + /* Push a NULL argument onto the end of the list. */ +#ifdef __thumb__ + push {r0} +#else + stmfd sp!, {r0} +#endif +.LC10: +/* Skip leading blanks */ +#ifdef __thumb__ + ldrb r3, [r1] + add r1, #1 +#else + ldrb r3, [r1], #1 +#endif + cmp r3, #0 + beq .LC12 + cmp r3, #' ' + beq .LC10 + +/* See whether we are scanning a string */ + cmp r3, #'"' +#ifdef __thumb__ + beq .LC20 + cmp r3, #'\'' + bne .LC21 +.LC20: + mov r2, r3 + b .LC22 + +.LC21: + mov r2, #' ' /* terminator type */ + sub r1, r1, #1 /* adjust back to point at start char */ +.LC22: +#else + cmpne r3, #'\'' + moveq r2, r3 + movne r2, #' ' /* terminator type */ + subne r1, r1, #1 /* adjust back to point at start char */ +#endif + +/* Stack a pointer to the current argument */ +#ifdef __thumb__ + push {r1} +#else + stmfd sp!, {r1} +#endif + add r0, r0, #1 +.LC11: +#ifdef __thumb__ + ldrb r3, [r1] + add r1, #1 +#else + ldrb r3, [r1], #1 +#endif + cmp r3, #0 + beq .LC12 + cmp r2, r3 /* reached terminator? */ + bne .LC11 + mov r2, #0 + sub r3, r1, #1 + strb r2, [r3] /* terminate the arg string */ + b .LC10 + +.LC12: + mov r1, sp /* point at stacked arg pointers */ + /* We've now got the stacked args in order reverse the */ +#ifdef __thumb__ + mov r2, r0 + lsl r2, #2 + add r2, sp + mov r3, sp +.LC15: cmp r2, r3 + bls .LC14 + sub r2, #4 + ldr r4, [r2] + ldr r5, [r3] + str r5, [r2] + str r4, [r3] + add r3, #4 + b .LC15 +.LC14: +#else + add r2, sp, r0, LSL #2 /* End of args */ + mov r3, sp /* Start of args */ +.LC13: cmp r2, r3 + ldrhi r4,[r2, #-4] /* Reverse ends of list */ + ldrhi r5, [r3] + strhi r5, [r2, #-4]! + strhi r4, [r3], #4 + bhi .LC13 +#endif +#endif + +#ifdef __USES_INITFINI__ + /* Some arm/elf targets use the .init and .fini sections + to create constructors and destructors, and for these + targets we need to call the _init function and arrange + for _fini to be called at program exit. */ + mov r4, r0 + mov r5, r1 + ldr r0, .Lfini + bl FUNCTION (atexit) + bl FUNCTION (_init) + mov r0, r4 + mov r1, r5 +#endif + bl FUNCTION (main) + + bl FUNCTION (exit) /* Should not return. */ + +#ifdef __thumb__ + /* Come out of Thumb mode. This code should be redundant. */ + + mov a4, pc + bx a4 + + .code 32 + .global change_back +change_back: + /* Halt the execution. This code should never be executed. */ + /* With no debug monitor, this probably aborts (eventually). + With a Demon debug monitor, this halts cleanly. + With an Angel debug monitor, this will report 'Unknown SWI'. */ + swi SWI_Exit +#endif + + /* For Thumb, constants must be after the code since only + positive offsets are supported for PC relative addresses. */ + + .align 0 +.LC0: +#ifdef ARM_RDI_MONITOR + .word HeapBase +#else +#ifndef ARM_RDP_MONITOR + /* Changes by toralf: Provide alternative "stack" variable whose value + may be defined externally; .Lstack will be used instead of .LC0 if + it points to a non-0 value. Also set up references to "hooks" that + may be used by the application to provide additional init code. */ + +#ifdef __pe__ + .word 0x800000 +#else + .word 0x80000 /* Top of RAM on the PIE board. */ +#endif +.Lstack: + .word __stack +.Lhwinit: + .word FUNCTION (hardware_init_hook) +.Lswinit: + .word FUNCTION (software_init_hook) + + /* Set up defaults for the above variables in the form of weak symbols + - so that application will link correctly, and get value 0 in + runtime (meaning "ignore setting") for the variables, when the user + does not provide the symbols. (The linker uses a weak symbol if, + and only if, a normal version of the same symbol isn't provided + e.g. by a linker script or another object file.) */ + + .set __stack, 0 + .set FUNCTION (hardware_init_hook), 0 + .set FUNCTION (software_init_hook), 0 + + .weak __stack + .weak FUNCTION (hardware_init_hook) + .weak FUNCTION (software_init_hook) +#endif + +#endif +.LC1: + .word __bss_start__ +.LC2: + .word __bss_end__ +#ifdef __USES_INITFINI__ +.Lfini: + .word FUNCTION(_fini) +#endif +#ifdef ARM_RDI_MONITOR +.LC30: + .word CommandLine + .word 255 + +/* Workspace for Angel calls. */ + .data +/* Data returned by monitor SWI. */ +.global __stack_base__ +HeapBase: .word 0 +HeapLimit: .word 0 +__stack_base__: .word 0 +StackLimit: .word 0 +CommandLine: .space 256,0 /* Maximum length of 255 chars handled. */ +#endif + +#ifdef __pe__ + .section .idata$3 + .long 0,0,0,0,0,0,0,0 +#endif diff --git a/libgloss/arm/elf-rdimon.specs b/libgloss/arm/elf-rdimon.specs new file mode 100644 index 000000000..153cf0c1c --- /dev/null +++ b/libgloss/arm/elf-rdimon.specs @@ -0,0 +1,8 @@ +%rename link old_link + +*link: +%(old_link) -lrdimon + +*startfile: +crti%O%s crtbegin%O%s %{!pg:rdimon-crt0%O%s} %{pg:rdimon-crt0%O%s} + diff --git a/libgloss/arm/elf-rdpmon.specs b/libgloss/arm/elf-rdpmon.specs new file mode 100644 index 000000000..903db1fb1 --- /dev/null +++ b/libgloss/arm/elf-rdpmon.specs @@ -0,0 +1,8 @@ +%rename link old_link + +*link: +%(old_link) -lrdpmon + +*startfile: +crti%O%s crtbegin%O%s %{!pg:rdpmon-crt0%O%s} %{pg:rdpmon-crt0%O%s} + diff --git a/libgloss/arm/libcfunc.c b/libgloss/arm/libcfunc.c new file mode 100644 index 000000000..ddc611f34 --- /dev/null +++ b/libgloss/arm/libcfunc.c @@ -0,0 +1,40 @@ +/* Support files for GNU libc. Files in the C namespace go here. + Files in the system namespace (ie those that start with an underscore) + go in syscalls.c. + + Note: These functions are in a seperate file so that OS providers can + overrride the system call stubs (defined in syscalls.c) without having + to provide libc funcitons as well. */ +#include "swi.h" + +#ifdef ARM_RDI_MONITOR + +static inline int +do_AngelSWI (int reason, void * arg) +{ + int value; + asm volatile ("mov r0, %1; mov r1, %2; swi %a3; mov %0, r0" + : "=r" (value) /* Outputs */ + : "r" (reason), "r" (arg), "i" (AngelSWI) /* Inputs */ + : "r0", "r1", "lr" + /* Clobbers r0 and r1, and lr if in supervisor mode */); + return value; +} +#endif /* ARM_RDI_MONITOR */ + + +void +abort (void) +{ +#ifdef ARM_RDI_MONITOR + do_AngelSWI (AngelSWI_Reason_ReportException, + (void *) ADP_Stopped_RunTimeError); +#else + asm ("mov r0,#17\nswi %a0" :: "i" (SWI_Exit)); +#endif +} + +void +alarm (void) +{ +} diff --git a/libgloss/arm/swi.h b/libgloss/arm/swi.h new file mode 100644 index 000000000..15c3866a1 --- /dev/null +++ b/libgloss/arm/swi.h @@ -0,0 +1,60 @@ +/* SWI numbers for RDP (Demon) monitor. */ +#define SWI_WriteC 0x0 +#define SWI_Write0 0x2 +#define SWI_ReadC 0x4 +#define SWI_CLI 0x5 +#define SWI_GetEnv 0x10 +#define SWI_Exit 0x11 +#define SWI_EnterOS 0x16 + +#define SWI_GetErrno 0x60 +#define SWI_Clock 0x61 +#define SWI_Time 0x63 +#define SWI_Remove 0x64 +#define SWI_Rename 0x65 +#define SWI_Open 0x66 + +#define SWI_Close 0x68 +#define SWI_Write 0x69 +#define SWI_Read 0x6a +#define SWI_Seek 0x6b +#define SWI_Flen 0x6c + +#define SWI_IsTTY 0x6e +#define SWI_TmpNam 0x6f +#define SWI_InstallHandler 0x70 +#define SWI_GenerateError 0x71 + + +/* Now the SWI numbers and reason codes for RDI (Angel) monitors. */ +#define AngelSWI_ARM 0x123456 +#ifdef __thumb__ +#define AngelSWI 0xAB +#else +#define AngelSWI AngelSWI_ARM +#endif + +/* The reason codes: */ +#define AngelSWI_Reason_Open 0x01 +#define AngelSWI_Reason_Close 0x02 +#define AngelSWI_Reason_WriteC 0x03 +#define AngelSWI_Reason_Write0 0x04 +#define AngelSWI_Reason_Write 0x05 +#define AngelSWI_Reason_Read 0x06 +#define AngelSWI_Reason_ReadC 0x07 +#define AngelSWI_Reason_IsTTY 0x09 +#define AngelSWI_Reason_Seek 0x0A +#define AngelSWI_Reason_FLen 0x0C +#define AngelSWI_Reason_TmpNam 0x0D +#define AngelSWI_Reason_Remove 0x0E +#define AngelSWI_Reason_Rename 0x0F +#define AngelSWI_Reason_Clock 0x10 +#define AngelSWI_Reason_Time 0x11 +#define AngelSWI_Reason_System 0x12 +#define AngelSWI_Reason_Errno 0x13 +#define AngelSWI_Reason_GetCmdLine 0x15 +#define AngelSWI_Reason_HeapInfo 0x16 +#define AngelSWI_Reason_EnterSVC 0x17 +#define AngelSWI_Reason_ReportException 0x18 +#define ADP_Stopped_ApplicationExit ((2 << 16) + 38) +#define ADP_Stopped_RunTimeError ((2 << 16) + 35) diff --git a/libgloss/arm/syscalls.c b/libgloss/arm/syscalls.c new file mode 100644 index 000000000..42e69b7b0 --- /dev/null +++ b/libgloss/arm/syscalls.c @@ -0,0 +1,630 @@ +/* Support files for GNU libc. Files in the system namespace go here. + Files in the C namespace (ie those that do not start with an + underscore) go in .c. */ + +#include <_ansi.h> +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "swi.h" + +/* Forward prototypes. */ +int _system _PARAMS ((const char *)); +int _rename _PARAMS ((const char *, const char *)); +int isatty _PARAMS ((int)); +clock_t _times _PARAMS ((struct tms *)); +int _gettimeofday _PARAMS ((struct timeval *, struct timezone *)); +void _raise _PARAMS ((void)); +int _unlink _PARAMS ((void)); +int _link _PARAMS ((void)); +int _stat _PARAMS ((const char *, struct stat *)); +int _fstat _PARAMS ((int, struct stat *)); +caddr_t _sbrk _PARAMS ((int)); +int _getpid _PARAMS ((int)); +int _kill _PARAMS ((int, int)); +void _exit _PARAMS ((int)); +int _close _PARAMS ((int)); +int _swiclose _PARAMS ((int)); +int _open _PARAMS ((const char *, int, ...)); +int _swiopen _PARAMS ((const char *, int)); +int _write _PARAMS ((int, char *, int)); +int _swiwrite _PARAMS ((int, char *, int)); +int _lseek _PARAMS ((int, int, int)); +int _swilseek _PARAMS ((int, int, int)); +int _read _PARAMS ((int, char *, int)); +int _swiread _PARAMS ((int, char *, int)); +void initialise_monitor_handles _PARAMS ((void)); + +static int wrap _PARAMS ((int)); +static int error _PARAMS ((int)); +static int get_errno _PARAMS ((void)); +static int remap_handle _PARAMS ((int)); +static int do_AngelSWI _PARAMS ((int, void *)); +static int findslot _PARAMS ((int)); + +/* Register name faking - works in collusion with the linker. */ +register char * stack_ptr asm ("sp"); + + +/* following is copied from libc/stdio/local.h to check std streams */ +extern void _EXFUN(__sinit,(struct _reent *)); +#define CHECK_INIT(fp) \ + do \ + { \ + if ((fp)->_data == 0) \ + (fp)->_data = _REENT; \ + if (!(fp)->_data->__sdidinit) \ + __sinit ((fp)->_data); \ + } \ + while (0) + +/* Adjust our internal handles to stay away from std* handles. */ +#define FILE_HANDLE_OFFSET (0x20) + +static int std_files_checked; +static int monitor_stdin; +static int monitor_stdout; +static int monitor_stderr; + +/* Struct used to keep track of the file position, just so we + can implement fseek(fh,x,SEEK_CUR). */ +typedef struct +{ + int handle; + int pos; +} +poslog; + +#define MAX_OPEN_FILES 20 +static poslog openfiles [MAX_OPEN_FILES]; + +static int +findslot (int fh) +{ + int i; + for (i = 0; i < MAX_OPEN_FILES; i ++) + if (openfiles[i].handle == fh) + break; + return i; +} + +#ifdef ARM_RDI_MONITOR + +static inline int +do_AngelSWI (int reason, void * arg) +{ + int value; + asm volatile ("mov r0, %1; mov r1, %2; swi %a3; mov %0, r0" + : "=r" (value) /* Outputs */ + : "r" (reason), "r" (arg), "i" (AngelSWI) /* Inputs */ + : "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc" + /* Clobbers r0 and r1, and lr if in supervisor mode */); + /* Accordingly to page 13-77 of ARM DUI 0040D other registers + can also be clobbered. Some memory positions may also be + changed by a system call, so they should not be kept in + registers. Note: we are assuming the manual is right and + Angel is respecting the APCS. */ + return value; +} +#endif /* ARM_RDI_MONITOR */ + +/* Function to convert std(in|out|err) handles to internal versions. */ +static int +remap_handle (int fh) +{ + if (!std_files_checked) + { + CHECK_INIT(stdin); + CHECK_INIT(stdout); + CHECK_INIT(stderr); + std_files_checked = 1; + } + if (fh == STDIN_FILENO) + return monitor_stdin; + if (fh == STDOUT_FILENO) + return monitor_stdout; + if (fh == STDERR_FILENO) + return monitor_stderr; + + return fh - FILE_HANDLE_OFFSET; +} + +void +initialise_monitor_handles (void) +{ + int i; + +#ifdef ARM_RDI_MONITOR + int volatile block[3]; + + block[0] = (int) ":tt"; + block[2] = 3; /* length of filename */ + block[1] = 0; /* mode "r" */ + monitor_stdin = do_AngelSWI (AngelSWI_Reason_Open, (void *) block); + + block[0] = (int) ":tt"; + block[2] = 3; /* length of filename */ + block[1] = 4; /* mode "w" */ + monitor_stdout = monitor_stderr = do_AngelSWI (AngelSWI_Reason_Open, (void *) block); +#else + int fh; + const char * name; + + name = ":tt"; + asm ("mov r0,%2; mov r1, #0; swi %a1; mov %0, r0" + : "=r"(fh) + : "i" (SWI_Open),"r"(name) + : "r0","r1"); + monitor_stdin = fh; + + name = ":tt"; + asm ("mov r0,%2; mov r1, #4; swi %a1; mov %0, r0" + : "=r"(fh) + : "i" (SWI_Open),"r"(name) + : "r0","r1"); + monitor_stdout = monitor_stderr = fh; +#endif + + for (i = 0; i < MAX_OPEN_FILES; i ++) + openfiles[i].handle = -1; + + openfiles[0].handle = monitor_stdin; + openfiles[0].pos = 0; + openfiles[1].handle = monitor_stdout; + openfiles[1].pos = 0; +} + +static int +get_errno (void) +{ +#ifdef ARM_RDI_MONITOR + return do_AngelSWI (AngelSWI_Reason_Errno, NULL); +#else + asm ("swi %a0" :: "i" (SWI_GetErrno)); +#endif +} + +static int +error (int result) +{ + errno = get_errno (); + return result; +} + +static int +wrap (int result) +{ + if (result == -1) + return error (-1); + return result; +} + +/* Returns # chars not! written. */ +int +_swiread (int file, + char * ptr, + int len) +{ + int fh = remap_handle (file); +#ifdef ARM_RDI_MONITOR + int block[3]; + + block[0] = fh; + block[1] = (int) ptr; + block[2] = len; + + return do_AngelSWI (AngelSWI_Reason_Read, block); +#else + asm ("mov r0, %1; mov r1, %2;mov r2, %3; swi %a0" + : /* No outputs */ + : "i"(SWI_Read), "r"(fh), "r"(ptr), "r"(len) + : "r0","r1","r2"); +#endif +} + +int +_read (int file, + char * ptr, + int len) +{ + int slot = findslot (remap_handle (file)); + int x = _swiread (file, ptr, len); + + if (x < 0) + return error (-1); + + if (slot != MAX_OPEN_FILES) + openfiles [slot].pos += len - x; + + /* x == len is not an error, at least if we want feof() to work. */ + return len - x; +} + +int +_swilseek (int file, + int ptr, + int dir) +{ + int res; + int fh = remap_handle (file); + int slot = findslot (fh); +#ifdef ARM_RDI_MONITOR + int block[2]; +#endif + + if (dir == SEEK_CUR) + { + if (slot == MAX_OPEN_FILES) + return -1; + ptr = openfiles[slot].pos + ptr; + dir = SEEK_SET; + } + +#ifdef ARM_RDI_MONITOR + if (dir == SEEK_END) + { + block[0] = fh; + ptr += do_AngelSWI (AngelSWI_Reason_FLen, block); + } + + /* This code only does absolute seeks. */ + block[0] = remap_handle (file); + block[1] = ptr; + res = do_AngelSWI (AngelSWI_Reason_Seek, block); +#else + if (dir == SEEK_END) + { + asm ("mov r0, %2; swi %a1; mov %0, r0" + : "=r" (res) + : "i" (SWI_Flen), "r" (fh) + : "r0"); + ptr += res; + } + + /* This code only does absolute seeks. */ + asm ("mov r0, %2; mov r1, %3; swi %a1; mov %0, r0" + : "=r" (res) + : "i" (SWI_Seek), "r" (fh), "r" (ptr) + : "r0", "r1"); +#endif + + if (slot != MAX_OPEN_FILES && res == 0) + openfiles[slot].pos = ptr; + + /* This is expected to return the position in the file. */ + return res == 0 ? ptr : -1; +} + +int +_lseek (int file, + int ptr, + int dir) +{ + return wrap (_swilseek (file, ptr, dir)); +} + +/* Returns #chars not! written. */ +int +_swiwrite ( + int file, + char * ptr, + int len) +{ + int fh = remap_handle (file); +#ifdef ARM_RDI_MONITOR + int block[3]; + + block[0] = fh; + block[1] = (int) ptr; + block[2] = len; + + return do_AngelSWI (AngelSWI_Reason_Write, block); +#else + asm ("mov r0, %1; mov r1, %2;mov r2, %3; swi %a0" + : /* No outputs */ + : "i"(SWI_Write), "r"(fh), "r"(ptr), "r"(len) + : "r0","r1","r2"); +#endif +} + +int +_write (int file, + char * ptr, + int len) +{ + int slot = findslot (remap_handle (file)); + int x = _swiwrite (file, ptr,len); + + if (x == -1 || x == len) + return error (-1); + + if (slot != MAX_OPEN_FILES) + openfiles[slot].pos += len - x; + + return len - x; +} + +extern int strlen (const char *); + +int +_swiopen (const char * path, + int flags) +{ + int aflags = 0, fh; +#ifdef ARM_RDI_MONITOR + int block[3]; +#endif + + int i = findslot (-1); + + if (i == MAX_OPEN_FILES) + return -1; + + /* The flags are Unix-style, so we need to convert them. */ +#ifdef O_BINARY + if (flags & O_BINARY) + aflags |= 1; +#endif + + if (flags & O_RDWR) + aflags |= 2; + + if (flags & O_CREAT) + aflags |= 4; + + if (flags & O_TRUNC) + aflags |= 4; + + if (flags & O_APPEND) + { + aflags &= ~4; /* Can't ask for w AND a; means just 'a'. */ + aflags |= 8; + } + +#ifdef ARM_RDI_MONITOR + block[0] = (int) path; + block[2] = strlen (path); + block[1] = aflags; + + fh = do_AngelSWI (AngelSWI_Reason_Open, block); + +#else + asm ("mov r0,%2; mov r1, %3; swi %a1; mov %0, r0" + : "=r"(fh) + : "i" (SWI_Open),"r"(path),"r"(aflags) + : "r0","r1"); +#endif + + if (fh >= 0) + { + openfiles[i].handle = fh; + openfiles[i].pos = 0; + } + + return fh >= 0 ? fh + FILE_HANDLE_OFFSET : error (fh); +} + +int +_open (const char * path, + int flags, + ...) +{ + return wrap (_swiopen (path, flags)); +} + +int +_swiclose (int file) +{ + int myhan = remap_handle (file); + int slot = findslot (myhan); + + if (slot != MAX_OPEN_FILES) + openfiles[slot].handle = -1; + +#ifdef ARM_RDI_MONITOR + return do_AngelSWI (AngelSWI_Reason_Close, & myhan); +#else + asm ("mov r0, %1; swi %a0" :: "i" (SWI_Close),"r"(myhan):"r0"); +#endif +} + +int +_close (int file) +{ + return wrap (_swiclose (file)); +} + +void +_exit (int n) +{ + /* FIXME: return code is thrown away. */ + +#ifdef ARM_RDI_MONITOR + do_AngelSWI (AngelSWI_Reason_ReportException, + (void *) ADP_Stopped_ApplicationExit); +#else + asm ("swi %a0" :: "i" (SWI_Exit)); +#endif + n = n; +} + +int +_kill (int n, int m) +{ +#ifdef ARM_RDI_MONITOR + return do_AngelSWI (AngelSWI_Reason_ReportException, + (void *) ADP_Stopped_ApplicationExit); +#else + asm ("swi %a0" :: "i" (SWI_Exit)); +#endif + n = n; m = m; +} + +int +_getpid (int n) +{ + return 1; + n = n; +} + +caddr_t +_sbrk (int incr) +{ + extern char end asm ("end"); /* Defined by the linker. */ + static char * heap_end; + char * prev_heap_end; + + if (heap_end == NULL) + heap_end = & end; + + prev_heap_end = heap_end; + + if (heap_end + incr > stack_ptr) + { + /* Some of the libstdc++-v3 tests rely upon detecting + out of memory errors, so do not abort here. */ +#if 0 + extern void abort (void); + + _write (1, "_sbrk: Heap and stack collision\n", 32); + + abort (); +#else + errno = ENOMEM; + return (caddr_t) -1; +#endif + } + + heap_end += incr; + + return (caddr_t) prev_heap_end; +} + +extern void memset (struct stat *, int, unsigned int); + +int +_fstat (int file, struct stat * st) +{ + memset (st, 0, sizeof (* st)); + st->st_mode = S_IFCHR; + st->st_blksize = 1024; + return 0; + file = file; +} + +int _stat (const char *fname, struct stat *st) +{ + int file; + + /* The best we can do is try to open the file readonly. If it exists, + then we can guess a few things about it. */ + if ((file = _open (fname, O_RDONLY)) < 0) + return -1; + + memset (st, 0, sizeof (* st)); + st->st_mode = S_IFREG | S_IREAD; + st->st_blksize = 1024; + _swiclose (file); /* Not interested in the error. */ + return 0; +} + +int +_link (void) +{ + return -1; +} + +int +_unlink (void) +{ + return -1; +} + +void +_raise (void) +{ + return; +} + +int +_gettimeofday (struct timeval * tp, struct timezone * tzp) +{ + + if (tp) + { + /* Ask the host for the seconds since the Unix epoch. */ +#ifdef ARM_RDI_MONITOR + tp->tv_sec = do_AngelSWI (AngelSWI_Reason_Time,NULL); +#else + { + int value; + asm ("swi %a1; mov %0, r0" : "=r" (value): "i" (SWI_Time) : "r0"); + tp->tv_sec = value; + } +#endif + tp->tv_usec = 0; + } + + /* Return fixed data for the timezone. */ + if (tzp) + { + tzp->tz_minuteswest = 0; + tzp->tz_dsttime = 0; + } + + return 0; +} + +/* Return a clock that ticks at 100Hz. */ +clock_t +_times (struct tms * tp) +{ + clock_t timeval; + +#ifdef ARM_RDI_MONITOR + timeval = do_AngelSWI (AngelSWI_Reason_Clock,NULL); +#else + asm ("swi %a1; mov %0, r0" : "=r" (timeval): "i" (SWI_Clock) : "r0"); +#endif + + if (tp) + { + tp->tms_utime = timeval; /* user time */ + tp->tms_stime = 0; /* system time */ + tp->tms_cutime = 0; /* user time, children */ + tp->tms_cstime = 0; /* system time, children */ + } + + return timeval; +}; + + +int +isatty (int fd) +{ + return 1; + fd = fd; +} + +int +_system (const char *s) +{ + if (s == NULL) + return 0; + errno = ENOSYS; + return -1; +} + +int +_rename (const char * oldpath, const char * newpath) +{ + errno = ENOSYS; + return -1; +} diff --git a/libgloss/arm/trap.S b/libgloss/arm/trap.S new file mode 100644 index 000000000..328fabca5 --- /dev/null +++ b/libgloss/arm/trap.S @@ -0,0 +1,93 @@ + /* Run-time exception support */ +#include "swi.h" + +/* .text is used instead of .section .text so it works with arm-aout too. */ + .text + .align 0 + .global __rt_stkovf_split_big + .global __rt_stkovf_split_small + +/* The following functions are provided for software stack checking. + If hardware stack-checking is being used then the code can be + compiled without the PCS entry checks, and simply rely on VM + management to extend the stack for a thread. + + The stack extension event occurs when the PCS function entry code + would result in a stack-pointer beneath the stack-limit register + value. The system relies on the following map: + + +-----------------------------------+ <-- end of stack block + | ... | + | ... | + | active stack | + | ... | <-- sp (stack-pointer) somewhere in here + | ... | + +-----------------------------------+ <-- sl (stack-limit) + | stack-extension handler workspace | + +-----------------------------------+ <-- base of stack block + + The "stack-extension handler workspace" is an amount of memory in + which the stack overflow support code must execute. It must be + large enough to deal with the worst case path through the extension + code. At the moment the compiler expects this to be AT LEAST + 256bytes. It uses this fact to code functions with small local + data usage within the overflow space. + + In a true target environment We may need to increase the space + between sl and the true limit to allow for the stack extension + code, SWI handlers and for undefined instruction handlers of the + target environment. */ + +__rt_stkovf_split_small: + mov ip,sp @ Ensure we can calculate the stack required + @ and fall through to... +__rt_stkovf_split_big: + @ in: sp = current stack-pointer (beneath stack-limit) + @ sl = current stack-limit + @ ip = low stack point we require for the current function + @ lr = return address into the current function + @ fp = frame-pointer + @ original sp --> +----------------------------------+ + @ | pc (12 ahead of PCS entry store) | + @ current fp ---> +----------------------------------+ + @ | lr (on entry) pc (on exit) | + @ +----------------------------------+ + @ | sp ("original sp" on entry) | + @ +----------------------------------+ + @ | fp (on entry to function) | + @ +----------------------------------+ + @ | | + @ | ..argument and work registers.. | + @ | | + @ current sp ---> +----------------------------------+ + @ + @ The "current sl" is somewhere between "original sp" and "current sp" + @ but above "true sl". The "current sl" should be at least 256bytes + @ above the "true sl". The 256byte stack guard should be large enough + @ to deal with the worst case function entry stacking (160bytes) plus + @ the stack overflow handler stacking requirements, plus the stack + @ required for the memory allocation routines. + @ + @ Normal PCS entry (before stack overflow check) can stack 16 + @ standard registers (64bytes) and 8 floating point registers + @ (96bytes). This gives a minimum stack guard of 160bytes (excluding + @ the stack required for the code). (Actually only a maximum of + @ 14standard registers are ever stacked on entry to a function). + @ + @ NOTE: Structure returns are performed by the caller allocating a + @ dummy space on the stack and passing in a "phantom" arg1 into + @ the function. This means that we do not need to worry about + @ preserving the stack under "sp" even on function return. + @ + @ Code should never poke values beneath sp. The sp register + @ should always be "dropped" first to cover the data. This + @ protects the data against any events that may try and use + @ the stack. + + SUB ip, sp, ip @ extra stack required for function + @ Add stack extension code here. If desired a new stack chunk + @ can be allocated, and the register state updated suitably. + + @ We now know how much extra stack the function requires. + @ Terminate the program for the moment: + swi SWI_Exit diff --git a/libgloss/configure b/libgloss/configure index 9c3fa4f7f..4c6a01528 100755 --- a/libgloss/configure +++ b/libgloss/configure @@ -795,6 +795,9 @@ case "${target}" in arm*-*-elf | arm*-*-coff) configdirs="${configdirs} arm testsuite"; ;; + ep9312-*-elf | ep9312-*-coff) + configdirs="${configdirs} arm testsuite"; + ;; xscale-*-elf | xscale-*-coff) configdirs="${configdirs} arm testsuite"; ;; @@ -818,7 +821,7 @@ subdirs="$configdirs" # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:822: checking for $ac_word" >&5 +echo "configure:825: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -848,7 +851,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:852: checking for $ac_word" >&5 +echo "configure:855: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -897,7 +900,7 @@ fi fi echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:901: checking whether we are using GNU C" >&5 +echo "configure:904: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -906,7 +909,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:910: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:913: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -921,7 +924,7 @@ if test $ac_cv_prog_gcc = yes; then ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:925: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:928: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -953,7 +956,7 @@ AS=${AS-as} # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:957: checking for $ac_word" >&5 +echo "configure:960: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -987,7 +990,7 @@ LD=${LD-ld} # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:991: checking for $ac_word" >&5 +echo "configure:994: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else diff --git a/libgloss/configure.in b/libgloss/configure.in index bc621325d..55e417b61 100644 --- a/libgloss/configure.in +++ b/libgloss/configure.in @@ -106,6 +106,9 @@ case "${target}" in arm*-*-elf | arm*-*-coff) configdirs="${configdirs} arm testsuite"; ;; + ep9312-*-elf | ep9312-*-coff) + configdirs="${configdirs} arm testsuite"; + ;; xscale-*-elf | xscale-*-coff) configdirs="${configdirs} arm testsuite"; ;;