From f4515c3082dd413017ae06c25d7e85b1dcee30bf Mon Sep 17 00:00:00 2001 From: Magnus Holmgren Date: Sun, 8 Mar 2009 12:48:58 +0000 Subject: Add setjmp/longjmp for ARM and ColdFire to the codec lib, and use it in the Vorbis codec to better handle out of memory conditions (to exit rather than crash; the AAC codec could use it too). setjmp/longjmp comes from newlib 1.17.0 with a few minor changes (combine parts of some files, remove support for some architectures, change some ifdef's). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20235 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/lib/SOURCES | 5 ++ apps/codecs/lib/setjmp.h | 59 +++++++++++++++ apps/codecs/lib/setjmp_arm.S | 172 +++++++++++++++++++++++++++++++++++++++++++ apps/codecs/lib/setjmp_cf.S | 79 ++++++++++++++++++++ 4 files changed, 315 insertions(+) create mode 100644 apps/codecs/lib/setjmp.h create mode 100644 apps/codecs/lib/setjmp_arm.S create mode 100644 apps/codecs/lib/setjmp_cf.S (limited to 'apps/codecs/lib') diff --git a/apps/codecs/lib/SOURCES b/apps/codecs/lib/SOURCES index 8099620098..b0ebbc5441 100644 --- a/apps/codecs/lib/SOURCES +++ b/apps/codecs/lib/SOURCES @@ -5,11 +5,16 @@ codeclib.c mdct2.c #ifdef CPU_ARM mdct_arm.S +setjmp_arm.S #if ARM_ARCH == 4 udiv32_armv4.S #endif #endif +#ifdef CPU_COLDFIRE +setjmp_cf.S +#endif + #elif defined(SIMULATOR) && defined(__APPLE__) osx.dummy.c #endif diff --git a/apps/codecs/lib/setjmp.h b/apps/codecs/lib/setjmp.h new file mode 100644 index 0000000000..4bcf6af623 --- /dev/null +++ b/apps/codecs/lib/setjmp.h @@ -0,0 +1,59 @@ +#ifndef _SETJMP_H_ +#define _SETJMP_H_ + +/* Combined parts of include/setjmp.h and include/machine/setjmp.h in + * newlib 1.17.0, with minor changes for Rockbox. + */ + +#ifdef CPU_ARM +/* + * All callee preserved registers: + * v1 - v7, fp, ip, sp, lr, f4, f5, f6, f7 + */ +#define _JBLEN 23 +#endif + +/* necv70 was 9 as well. */ + +#ifdef CPU_COLDFIRE +/* + * onsstack,sigmask,sp,pc,psl,d2-d7,a2-a6, + * fp2-fp7 for 68881. + * All else recovered by under/over(flow) handling. + */ +#define _JBLEN 34 +#endif + +#ifdef __mips__ +#ifdef __mips64 +#define _JBTYPE long long +#endif +#ifdef __mips_soft_float +#define _JBLEN 11 +#else +#define _JBLEN 23 +#endif +#endif + +#ifdef __sh__ +#if __SH5__ +#define _JBLEN 50 +#define _JBTYPE long long +#else +#define _JBLEN 20 +#endif /* __SH5__ */ +#endif + +#ifdef _JBLEN +#ifdef _JBTYPE +typedef _JBTYPE jmp_buf[_JBLEN]; +#else +typedef int jmp_buf[_JBLEN]; +#endif +#endif + + +extern void longjmp(jmp_buf __jmpb, int __retval); +extern int setjmp(jmp_buf __jmpb); + +#endif // _SETJMP_H_ diff --git a/apps/codecs/lib/setjmp_arm.S b/apps/codecs/lib/setjmp_arm.S new file mode 100644 index 0000000000..4bb2a46a7a --- /dev/null +++ b/apps/codecs/lib/setjmp_arm.S @@ -0,0 +1,172 @@ +/* This is a simple version of setjmp and longjmp. + + Nick Clifton, Cygnus Solutions, 13 June 1997. */ + +/* ANSI concatenation macros. */ +#define CONCAT(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a##b + +#ifndef __USER_LABEL_PREFIX__ +#error __USER_LABEL_PREFIX__ not defined +#endif + +#define SYM(x) CONCAT (__USER_LABEL_PREFIX__, x) + +#ifdef __ELF__ +#define TYPE(x) .type SYM(x),function +#define SIZE(x) .size SYM(x), . - SYM(x) +#else +#define TYPE(x) +#define SIZE(x) +#endif + +/* Arm/Thumb interworking support: + + The interworking scheme expects functions to use a BX instruction + to return control to their parent. Since we need this code to work + in both interworked and non-interworked environments as well as with + older processors which do not have the BX instruction we do the + following: + Test the return address. + If the bottom bit is clear perform an "old style" function exit. + (We know that we are in ARM mode and returning to an ARM mode caller). + Otherwise use the BX instruction to perform the function exit. + + We know that we will never attempt to perform the BX instruction on + an older processor, because that kind of processor will never be + interworked, and a return address with the bottom bit set will never + be generated. + + In addition, we do not actually assemble the BX instruction as this would + require us to tell the assembler that the processor is an ARM7TDMI and + it would store this information in the binary. We want this binary to be + able to be linked with binaries compiled for older processors however, so + we do not want such information stored there. + + If we are running using the APCS-26 convention however, then we never + test the bottom bit, because this is part of the processor status. + Instead we just do a normal return, since we know that we cannot be + returning to a Thumb caller - the Thumb does not support APCS-26. + + Function entry is much simpler. If we are compiling for the Thumb we + just switch into ARM mode and then drop through into the rest of the + function. The function exit code will take care of the restore to + Thumb mode. + + For Thumb-2 do everything in Thumb mode. */ + +#ifdef __APCS_26__ +#define RET movs pc, lr +#elif defined(__thumb2__) +#define RET bx lr +#else +#define RET tst lr, #1; \ + moveq pc, lr ; \ +.word 0xe12fff1e /* bx lr */ +#endif + +#ifdef __thumb2__ +.macro COND where when + i\where \when +.endm +#else +.macro COND where when +.endm +#endif + +#if defined(__thumb2__) +.syntax unified +.macro MODE + .thumb + .thumb_func +.endm +.macro PROLOGUE name +.endm + +#elif defined(__thumb__) +#define MODE .thumb_func +.macro PROLOGUE name + .code 16 + bx pc + nop + .code 32 +SYM (.arm_start_of.\name): +.endm +#else /* Arm */ +#define MODE .code 32 +.macro PROLOGUE name +.endm +#endif + +.macro FUNC_START name + .text + .align 2 + MODE + .globl SYM (\name) + TYPE (\name) +SYM (\name): + PROLOGUE \name +.endm + +.macro FUNC_END name + RET + SIZE (\name) +.endm + +/* -------------------------------------------------------------------- + int setjmp (jmp_buf); + -------------------------------------------------------------------- */ + + FUNC_START setjmp + + /* Save all the callee-preserved registers into the jump buffer. */ +#ifdef __thumb2__ + stmea a1!, { v1-v7, fp, ip, lr } + str sp, [a1],#+4 +#else + stmea a1!, { v1-v7, fp, ip, sp, lr } +#endif + +#if 0 /* Simulator does not cope with FP instructions yet. */ +#ifndef __SOFTFP__ + /* Save the floating point registers. */ + sfmea f4, 4, [a1] +#endif +#endif + /* When setting up the jump buffer return 0. */ + mov a1, #0 + + FUNC_END setjmp + +/* -------------------------------------------------------------------- + volatile void longjmp (jmp_buf, int); + -------------------------------------------------------------------- */ + + FUNC_START longjmp + + /* If we have stack extension code it ought to be handled here. */ + + /* Restore the registers, retrieving the state when setjmp() was called. */ +#ifdef __thumb2__ + ldmfd a1!, { v1-v7, fp, ip, lr } + ldr sp, [a1],#+4 +#else + ldmfd a1!, { v1-v7, fp, ip, sp, lr } +#endif + +#if 0 /* Simulator does not cope with FP instructions yet. */ +#ifndef __SOFTFP__ + /* Restore floating point registers as well. */ + lfmfd f4, 4, [a1] +#endif +#endif + /* Put the return value into the integer result register. + But if it is zero then return 1 instead. */ + movs a1, a2 +#ifdef __thumb2__ + it eq +#endif + moveq a1, #1 + + FUNC_END longjmp + diff --git a/apps/codecs/lib/setjmp_cf.S b/apps/codecs/lib/setjmp_cf.S new file mode 100644 index 0000000000..acc98c3f59 --- /dev/null +++ b/apps/codecs/lib/setjmp_cf.S @@ -0,0 +1,79 @@ +/* ANSI concatenation macros. */ + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +/* Use the right prefix for registers. */ + +#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x) + +#define d0 REG (d0) +#define d1 REG (d1) +#define d2 REG (d2) +#define d3 REG (d3) +#define d4 REG (d4) +#define d5 REG (d5) +#define d6 REG (d6) +#define d7 REG (d7) +#define a0 REG (a0) +#define a1 REG (a1) +#define a2 REG (a2) +#define a3 REG (a3) +#define a4 REG (a4) +#define a5 REG (a5) +#define a6 REG (a6) +#define fp REG (fp) +#define sp REG (sp) + + +.global SYM (setjmp) +.global SYM (longjmp) + +SYM (setjmp): + moveal sp@(4),a0 + movel sp@(0),a0@(12) + movel sp,a0@(8) + moveml d2-d7/a2-a6,a0@(20) + clrl d0 + rts + +SYM (longjmp): + moveal sp@(4),a0 + movel sp@(8),d0 + bne 1f + movel &1,d0 +1: + moveml a0@(20),d2-d7/a2-a6 + moveal a0@(8),sp + movel a0@(12),sp@ + rts + +#ifdef M68881 +.global SYM (setjmp_68881) +.global SYM (longjmp_68881) + +SYM (setjmp_68881): + moveal sp@(4),a0 + movel sp@(0),a0@(12) + movel sp,a0@(8) + moveml d2-d7/a2-a6,a0@(20) + fmovemx fp2-fp7,a0@(64) + clrl d0 + rts + +SYM (longjmp_68881): + moveal sp@(4),a0 + fmovemx a0@(64),fp2-fp7 + movel sp@(8),d0 + bne 1f + movel &1,d0 +1: + moveml a0@(20),d2-d7/a2-a6 + moveal a0@(8),sp + movel a0@(12),sp@ + rts +#endif -- cgit v1.2.3