1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Magnus Holmgren 2009-03-08 12:48:58 +00:00
parent 3f69bb2b1d
commit f4515c3082
6 changed files with 340 additions and 2 deletions

View file

@ -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

59
apps/codecs/lib/setjmp.h Normal file
View file

@ -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_

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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;
}