FreeCalypso > hg > fc-tourmaline
view src/gpf/ccd/asn1_seq.c @ 220:0ed36de51973
ABB semaphore protection overhaul
The ABB semaphone protection logic that came with TCS211 from TI
was broken in several ways:
* Some semaphore-protected functions were called from Application_Initialize()
context. NU_Obtain_Semaphore() called with NU_SUSPEND fails with
NU_INVALID_SUSPEND in this context, but the return value wasn't checked,
and NU_Release_Semaphore() would be called unconditionally at the end.
The latter call would increment the semaphore count past 1, making the
semaphore no longer binary and thus no longer effective for resource
protection. The fix is to check the return value from NU_Obtain_Semaphore()
and skip the NU_Release_Semaphore() call if the semaphore wasn't properly
obtained.
* Some SPI hardware manipulation was being done before entering the semaphore-
protected critical section. The fix is to reorder the code: first obtain
the semaphore, then do everything else.
* In the corner case of L1/DSP recovery, l1_abb_power_on() would call some
non-semaphore-protected ABB & SPI init functions. The fix is to skip those
calls in the case of recovery.
* A few additional corner cases existed, all of which are fixed by making
ABB semaphore protection 100% consistent for all ABB functions and code paths.
There is still one remaining problem of priority inversion: suppose a low-
priority task calls an ABB function, and some medium-priority task just happens
to preempt right in the middle of that semaphore-protected ABB operation. Then
the high-priority SPI task is locked out for a non-deterministic time until
that medium-priority task finishes its work and goes back to sleep. This
priority inversion problem remains outstanding for now.
| author | Mychaela Falconia <falcon@freecalypso.org> |
|---|---|
| date | Mon, 26 Apr 2021 20:55:25 +0000 |
| parents | 4e78acac3d88 |
| children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : | Modul : asn1_seq.c +----------------------------------------------------------------------------- | Copyright 2002 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +----------------------------------------------------------------------------- | Purpose : Definition of encoding and decoding functions for ASN1_SEQUENCE | elements +----------------------------------------------------------------------------- */ #define ASN1_SEQ_C /* * Standard definitions like UCHAR, ERROR etc. */ #include "typedefs.h" #include "header.h" /* * Prototypes of ccd (USE_DRIVER EQ undef) for prototypes only * look at ccdapi.h */ #undef USE_DRIVER #include "ccdapi.h" /* * Types and functions for bit access and manipulation */ #include "ccd_globs.h" #include "bitfun.h" /* * Prototypes and constants in the common part of ccd */ #include "ccd.h" #include "ccd_codingtypes.h" /* * Declaration of coder/decoder tables */ #include "ccdtable.h" #include "ccddata.h" EXTERN T_FUNC_POINTER codec[MAX_CODEC_ID+1][2]; #ifndef RUN_INT_RAM /* +--------------------------------------------------------------------+ | PROJECT : CCD (6144) MODULE : asn1_seq | | STATE : code ROUTINE : Read_SEQ_BitMap | +--------------------------------------------------------------------+ PURPOSE : Decode the bit-map preamble for OPTIONAL elements or those with DEFAULT value. */ void Read_SEQ_BitMap (const ULONG first_elem, const ULONG last_elem, T_CCD_Globs *globs) { ULONG elem = first_elem; while (elem < last_elem) { if (melem[elem].optional) { /* * For optional elements read the corresponding bit in the preamble * and set the valid flag in the C-Structure to it. */ if (melem[elem].elemType < 'P' OR melem[elem].elemType > 'R') { globs->pstruct[melem[elem].structOffs] = (UBYTE) bf_readBit(globs); } else { if(bf_readBit(globs)) /*elemType P, Q or R*/ { /*If present set the pointer to -1 (0xFFFF) - anything else than NULL, because the element is present*/ *(void**) &globs->pstruct[melem[elem].structOffs] = (void *) 0xFFFF; } else /*Not present set the pointer to NULL*/ *(void**) &globs->pstruct[melem[elem].structOffs] = NULL; } } /* * For optional elements read the corresponding bit in the preamble * and set the valid flag in the C-structure to it. */ else if (melem[elem].codingType EQ CCDTYPE_ASN1_INTEGER) { /* * Check if this variable has a default value. * As long as the DEFAULT values are given with ranges it is right to * look for isDefault in the second entry in mval.cdg. * There is no valid flag for elements with default value. But we use * the first byte of this element within the C-structure for giving a * signal to this function. The only simple type which has DEFAULT is INTEGER. */ if (mval[mvar[melem[elem].elemRef].valueDefs+1].isDefault EQ 2) { globs->pstruct[melem[elem].structOffs] = (UBYTE) bf_readBit(globs); } } elem++; } } #endif /* !RUN_INT_RAM */ #ifndef RUN_INT_RAM /* +--------------------------------------------------------------------+ | PROJECT : CCD (6144) MODULE : CDC_GSM | | STATE : code ROUTINE : cdc_asn1_seq_decode | +--------------------------------------------------------------------+ PURPOSE : Decoding of the SEQUENCE and SEQUENCE OF type for UMTS The element can be a field of fixed or variable length. It can contain OPTIONAL elements or integer elements with a DEFAULT value. A special case is when the element is a so called msg_data. According to CCDDATA a message is made of a msg_type and a msg_data part. If the msg_data has a coding type of ASN1_SEQUENCE this function is called. In this case CCD needs to pass over the msg_type by incrementing globs->pstruct. A msg_data sequence can not be optional. Nor it can be an array of msg_data. If the sequence is not a msg_data this function is called as an equivalent to ccd_decodeComposition. Hence the increment on globs->ccd_recurs_level. A non-msg_data sequence can be optional or an array. */ SHORT cdc_asn1_seq_decode (const ULONG c_ref, const ULONG e_ref, T_CCD_Globs *globs) { ULONG repeat=1, max_rep=1; ULONG cSize, first_elem, last_elem, elem; UBYTE *old_pstruct; #ifdef DEBUG_CCD static S8 trace_nesting_level = -1; #endif #ifdef DEBUG_CCD #ifndef CCD_SYMBOLS TRACE_CCD (globs, "cdc_asn1_seq_decode()"); #else TRACE_CCD (globs, "cdc_asn1_seq_decode() %s", mcomp[melem[e_ref].elemRef].name); #endif #endif /* * This function is called as an equivalent to ccd_decodeComposition. * Hence the increment on globs->ccd_recurs_level. */ globs->ccd_recurs_level ++; /* * Set pstrcutOffs and max_rep. * Check the valid flag in case of optional elements. */ if (PER_CommonBegin (e_ref, &max_rep, globs) NEQ ccdOK) { globs->ccd_recurs_level --; return 1; } /* * Prepare for decoding of the same sequence type up to max_rep times. * Set the upper and lower bound of elemRef for processing of each repeatition. * Read the C-size to go ahead in the C-structure after each repeatition. */ switch (melem[e_ref].elemType) { case 'C': case 'D': case 'E': case 'P': case 'Q': elem = (ULONG) melem[e_ref].elemRef; first_elem = (ULONG) mcomp[elem].componentRef; last_elem = first_elem + mcomp[elem].numOfComponents; cSize = (ULONG) mcomp[elem].cSize; break; case 'F': case 'R': first_elem = e_ref; last_elem = e_ref + 1; cSize = (ULONG) mvar[e_ref].cSize; break; default: ccd_setError (globs, ERR_DEFECT_CCDDATA, BREAK, (USHORT) (globs->bitpos), (USHORT) -1); return 1; }; /* * Store the current value of the C-structure pointer. * After decoding the SEQUENCE component we will set the pointer * to this stored value. Then we will use pstructOffs for pointing * to the next element. */ old_pstruct = globs->pstruct; #ifdef DYNAMIC_ARRAYS /* * Allocate memory for this whole composition, if elemType is * one of the pointer types. */ if ( is_pointer_type(e_ref)) { if ( PER_allocmem_and_update(e_ref, max_rep, globs) NEQ ccdOK ) { /* No memory - Return. Error already set in function call above. */ globs->ccd_recurs_level --; return 1; } } #endif globs->pstruct += globs->pstructOffs; /* * Decode all elements of the field. */ while (repeat <= max_rep) { Read_SEQ_BitMap (first_elem, last_elem, globs); elem = first_elem; /* * Decode all elements of the array */ #ifdef DEBUG_CCD trace_nesting_level++; #endif while (elem < last_elem) { #ifdef ERR_TRC_STK_CCD /* * Save the value for tracing in error case. */ globs->error_stack[globs->ccd_recurs_level] = (USHORT) elem; #endif /* ERR_TRC_STK_CCD */ #ifdef DEBUG_CCD #ifndef CCD_SYMBOLS TRACE_CCD (globs, "decoding level %d element %d", trace_nesting_level, elem - first_elem); #else TRACE_CCD (globs, "decoding level %d element %d '%s'",trace_nesting_level, elem - first_elem, ccddata_get_alias((USHORT) elem, 1)); #endif #endif /* * Use the jump-table for selecting the decode function. * Possible types are 0, ASN1_INTEGER, BITSTRING, ASN1_CHOICE and * ASN1_SEQUENCE. In case of 0 function cdc_STD_decode will be called. */ (void) codec[melem[elem].codingType][DECODE_FUN] (c_ref, elem, globs); elem ++; } #ifdef DEBUG_CCD trace_nesting_level--; #endif /* * Set the pointer of the C-structure on the next element. */ globs->pstruct += cSize; repeat ++; } /* * Prepare for decoding the next element. */ globs->pstruct = old_pstruct; globs->ccd_recurs_level--; return 1; } #endif /* !RUN_INT_RAM */ #ifndef RUN_INT_RAM /* +--------------------------------------------------------------------+ | PROJECT : CCD (6144) MODULE : asn1_seq | | STATE : code ROUTINE : Write_SEQ_BitMap | +--------------------------------------------------------------------+ PURPOSE : Encode the bit-map preamble for OPTIONAL elements or those with DEFAULT value. */ void Write_SEQ_BitMap (const ULONG first_elem, const ULONG last_elem, T_CCD_Globs *globs) { ULONG elem = first_elem; while (elem < last_elem) { if (melem[elem].optional) { /* * For optional elements read the valid flag in the C-Structure * and overwrite the corresponding bit in the preamble. */ #if defined _TOOLS_ int patch; U16 stelem; stelem = globs->error_stack[globs->ccd_recurs_level]; globs->error_stack[globs->ccd_recurs_level] = (USHORT) elem; patch = ccd_patch (globs, 1); globs->error_stack[globs->ccd_recurs_level] = stelem; if (patch) { bf_writeBit(1, globs); elem++; continue; } #endif /* _TOOLS_ */ #ifdef DYNAMIC_ARRAYS if ( is_pointer_type(elem) ) { BOOL present; /* * Check for NULL pointer (== notPresent/not valid) for this element. */ present = (*(U8 **)(globs->pstruct + melem[elem].structOffs) NEQ NULL); /* * Double check for 'D' to 'F' types. Both NULL pointer and * valid flag. (Strictly not necessary, but may catch uninitialized * flags/pointers). */ if (present AND (melem[elem].elemType >= 'D' AND melem[elem].elemType <= 'F')) { present = (BOOL)globs->pstruct[melem[elem].structOffs]; } bf_writeBit(present, globs); } else #endif bf_writeBit((BOOL)globs->pstruct[melem[elem].structOffs], globs); } else if (melem[elem].codingType EQ CCDTYPE_ASN1_INTEGER) { /* * Check if this variable has a default value. * As long as the DEFAULT values are given with ranges it is right to * look for isDefault in the second entry in mval.cdg. * There is no valid flag for elements with default value. So we need * to read the value from C-structure and compare it with the DEFAULT * value given in the mval table. The only simple type which has * DEFAULT is INTEGER. */ if (mval[mvar[melem[elem].elemRef].valueDefs+1].isDefault EQ 2) { U32 value=0; UBYTE *p; /* * setup the read pointer to the element in the C-structure */ #ifdef DYNAMIC_ARRAYS if ( is_pointer_type(elem) ) { /* * NULL pointers should be caught as part of the optionality * check in PER_CommonBegin() */ p = *(U8 **)(globs->pstruct + globs->pstructOffs); if (ccd_check_pointer(p) != ccdOK) { ccd_recordFault (globs, ERR_INVALID_PTR, BREAK, (USHORT) elem, &globs->pstruct[globs->pstructOffs]); return; } } else #endif p = globs->pstruct + melem[elem].structOffs; /* * Default values are all positive and small values (< 64K) * in the current version of umts. The cases 'L' and 'C' are added * to be ready for a future change where we need also a check of * possible errors through type casting. */ switch (mvar[melem[elem].elemRef].cType) { case 'B': value = (U32)*(UBYTE *) p; break; case 'C': value = (U32)(S32)*(S8 *) p; break; case 'S': value = (U32)(*(USHORT *) p); break; case 'T': value = (U32)(S32)*(S16 *) p; break; case 'L': value = (U32)*(S32 *) p; break; case 'M': value = (U32)*(U32 *) p; break; default: ccd_setError (globs, ERR_DEFECT_CCDDATA, BREAK, (USHORT) -1); break; } /* * Compare the value to be encoded with the default value. * Write the presence flag into the preamble. */ if (value EQ (U32)mval[mvar[melem[elem].elemRef].valueDefs+1].startValue) { bf_writeBit(0, globs); } else { bf_writeBit(1, globs); } } } elem++; } } #endif /* !RUN_INT_RAM */ #ifndef RUN_INT_RAM /* +--------------------------------------------------------------------+ | PROJECT : CCD (6144) MODULE : CDC_GSM | | STATE : code ROUTINE : cdc_asn1_seq_encode | +--------------------------------------------------------------------+ PURPOSE : Decoding of the SEQUENCE and SEQUENCE OF type for UMTS The element can be a field of fixed or variable length. It can contain OPTIONAL elements or integer elements with a DEFAULT value. A special case is when the element is a so called msg_data. According to CCDDATA a message is made of a msg_type and a msg_data part. If the msg_data has a coding type of ASN1_SEQUENCE this function is called. In this case CCD needs to pass over the msg_type by incrementing globs->pstruct. A msg_data sequence can not be optional. Nor it can be an array of msg_data. If the sequence is not a msg_data this function is called as an equivalent to ccd_encodeComposition. Hence the increment on globs->ccd_recurs_level. A non-msg_data sequence can be optional or an array. */ SHORT cdc_asn1_seq_encode (const ULONG c_ref, const ULONG e_ref, T_CCD_Globs *globs) { ULONG repeat=1, max_rep=1; ULONG cSize, first_elem, last_elem, elem; UBYTE *old_pstruct; #ifdef DEBUG_CCD static S8 trace_nesting_level = -1; #endif #ifdef DEBUG_CCD #ifndef CCD_SYMBOLS TRACE_CCD (globs, "cdc_asn1_seq_encode()"); #else TRACE_CCD (globs, "cdc_asn1_seq_encode() %s", mcomp[melem[e_ref].elemRef].name); #endif #endif /* * This function is called as an equivalent to ccd_encodeComposition. * Hence the increment on globs->ccd_recurs_level. */ globs->ccd_recurs_level ++; /* * Set pstrcutOffs and max_rep. * Check the valid flag in case of optional elements. */ if (PER_CommonBegin (e_ref, &max_rep, globs) NEQ ccdOK) { globs->ccd_recurs_level --; return 1; } /* * Prepare for encoding of the same sequence type up to max_rep times. * Set the upper and lower bound of elemRef for processing of each repeatition. * Read the C-size to go ahead in the C-structure after each repeatition. */ switch (melem[e_ref].elemType) { case 'C': case 'D': case 'E': case 'P': case 'Q': { elem = (ULONG) melem[e_ref].elemRef; first_elem = (ULONG) mcomp[elem].componentRef; last_elem = first_elem + mcomp[elem].numOfComponents; cSize = (ULONG) mcomp[elem].cSize; break; } case 'F': case 'R': { first_elem = e_ref; last_elem = e_ref + 1; cSize = (ULONG) mvar[e_ref].cSize; break; } default: ccd_setError (globs, ERR_DEFECT_CCDDATA, BREAK, (USHORT) (globs->bitpos), (USHORT) -1); return 1; } /* * Store the current value of the C-structure pointer. * After encoding the SEQUENCE component we will set the pointer * to this stored value. Then we will use pstructOffs for pointing * to the next element. */ old_pstruct = globs->pstruct; globs->pstruct += globs->pstructOffs; #ifdef DYNAMIC_ARRAYS if ( is_pointer_type(e_ref) ) { if (ccd_check_pointer(*(U8 **)globs->pstruct) == ccdOK) { globs->pstruct = *(U8 **) globs->pstruct; } else { ccd_recordFault (globs, ERR_INVALID_PTR, BREAK, (USHORT) e_ref, &globs->pstruct[globs->pstructOffs]); return 1; } } #endif /* * Encode all elements of the field. */ while (repeat <= max_rep) { Write_SEQ_BitMap (first_elem, last_elem, globs); /* * Encode all elements */ #ifdef DEBUG_CCD trace_nesting_level++; #endif elem = first_elem; while (elem < last_elem) { #ifdef ERR_TRC_STK_CCD /* * Save the value for tracing in error case. */ globs->error_stack[globs->ccd_recurs_level] = (USHORT) elem; #endif /* ERR_TRC_STK_CCD */ #ifdef DEBUG_CCD #ifndef CCD_SYMBOLS TRACE_CCD (globs, "encoding level %d element %d", trace_nesting_level, elem - first_elem); #else TRACE_CCD (globs, "encoding level %d element %d '%s'", trace_nesting_level, elem - first_elem ,ccddata_get_alias((USHORT) elem, 1)); #endif #endif #if defined _TOOLS_ if (!ccd_patch (globs, 0)) #endif /* _TOOLS_ */ /* * Use the jump-table for selecting the code function. * Possible types are 0, ASN1_INTEGER, BITSTRING, ASN1_CHOICE and * ASN1_SEQUENCE. In case of 0 function cdc_STD_encode will be called. */ (void) codec[melem[elem].codingType][ENCODE_FUN] (c_ref, elem, globs); /* * Set the elemRef to the next element. */ elem ++; } #ifdef DEBUG_CCD trace_nesting_level--; #endif /* * Set the pointer of the C-structure on the next element. */ globs->pstruct += cSize; repeat ++; } /* * Prepare for encoding the next element. */ globs->pstruct = old_pstruct; globs->ccd_recurs_level--; return 1; } #endif /* !RUN_INT_RAM */
