summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorMagnus Holmgren <magnushol@gmail.com>2009-03-08 12:48:58 +0000
committerMagnus Holmgren <magnushol@gmail.com>2009-03-08 12:48:58 +0000
commitf4515c3082dd413017ae06c25d7e85b1dcee30bf (patch)
tree1154b2fd5049aa42a1fdd2047effd39e9da1ccaa /apps
parent3f69bb2b1d00ccc54e2097fd9da750fcd2f7e11b (diff)
downloadrockbox-f4515c3082dd413017ae06c25d7e85b1dcee30bf.tar.gz
rockbox-f4515c3082dd413017ae06c25d7e85b1dcee30bf.zip
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
Diffstat (limited to 'apps')
-rw-r--r--apps/codecs/lib/SOURCES5
-rw-r--r--apps/codecs/lib/setjmp.h59
-rw-r--r--apps/codecs/lib/setjmp_arm.S172
-rw-r--r--apps/codecs/lib/setjmp_cf.S79
-rw-r--r--apps/codecs/libtremor/oggmalloc.c9
-rw-r--r--apps/codecs/vorbis.c18
6 files changed, 340 insertions, 2 deletions
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
diff --git a/apps/codecs/libtremor/oggmalloc.c b/apps/codecs/libtremor/oggmalloc.c
index ca917ff397..4aa2760629 100644
--- a/apps/codecs/libtremor/oggmalloc.c
+++ b/apps/codecs/libtremor/oggmalloc.c
@@ -1,5 +1,10 @@
#include "os_types.h"
+#if defined(CPU_ARM) || defined(CPU_COLDFIRE)
+#include <setjmp.h>
+extern jmp_buf rb_jump_buf;
+#endif
+
static size_t tmp_ptr;
void ogg_malloc_init(void)
@@ -16,7 +21,11 @@ void *ogg_malloc(size_t size)
size = (size + 3) & ~3;
if (mem_ptr + size > tmp_ptr)
+#if defined(CPU_ARM) || defined(CPU_COLDFIRE)
+ longjmp(rb_jump_buf, 1);
+#else
return NULL;
+#endif
x = &mallocbuf[mem_ptr];
mem_ptr += size; /* Keep memory 32-bit aligned */
diff --git a/apps/codecs/vorbis.c b/apps/codecs/vorbis.c
index 74d582ebb3..f14aeead84 100644
--- a/apps/codecs/vorbis.c
+++ b/apps/codecs/vorbis.c
@@ -25,6 +25,11 @@
CODEC_HEADER
+#if defined(CPU_ARM) || defined(CPU_COLDFIRE)
+#include <setjmp.h>
+jmp_buf rb_jump_buf;
+#endif
+
/* Some standard functions and variables needed by Tremor */
static size_t read_handler(void *ptr, size_t size, size_t nmemb, void *datasource)
@@ -107,7 +112,7 @@ enum codec_status codec_main(void)
int error;
long n;
int current_section;
- int previous_section = -1;
+ int previous_section;
int eof;
ogg_int64_t vf_offsets[2];
ogg_int64_t vf_dataoffsets;
@@ -119,6 +124,15 @@ enum codec_status codec_main(void)
* they should be set differently based on quality setting
*/
+#if defined(CPU_ARM) || defined(CPU_COLDFIRE)
+ if (setjmp(rb_jump_buf) != 0)
+ {
+ /* malloc failed; skip to next track */
+ error = CODEC_ERROR;
+ goto done;
+ }
+#endif
+
/* We need to flush reserver memory every track load. */
next_track:
if (codec_init()) {
@@ -181,6 +195,7 @@ next_track:
ci->set_offset(ov_raw_tell(&vf));
}
+ previous_section = -1;
eof = 0;
while (!eof) {
ci->yield();
@@ -227,7 +242,6 @@ done:
vf.serialnos = NULL;
vf.pcmlengths = NULL;
ov_clear(&vf);
- previous_section = -1;
goto next_track;
}