diff options
Diffstat (limited to 'utils/mcpu-melf.c')
| -rw-r--r-- | utils/mcpu-melf.c | 435 |
1 files changed, 435 insertions, 0 deletions
diff --git a/utils/mcpu-melf.c b/utils/mcpu-melf.c new file mode 100644 index 0000000..1178c6f --- /dev/null +++ b/utils/mcpu-melf.c @@ -0,0 +1,435 @@ +#include <errno.h> +#include <limits.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "mcpu-melf.h" + +int +cpu_melf_data_encoding( void ) +{ +#if CPU_DATA_BYTE_ORDER_LITTLE_ENDIAN == 1 + return( MELF_DATA_LSB ); +#elif CPU_DATA_BYTE_ORDER_BIG_ENDIAN == 1 + return( MELF_DATA_MSB ); +#else +# error "Unsupported CPU_DATA_BYTE_ORDER" +#endif +} + +static int +is_le( int data ) +{ + return( data == MELF_DATA_LSB ); +} + +void +cpu_melf_put16( unsigned char *p, __mpu_uint16_t v, int data ) +{ + if( is_le( data ) ) + { + p[0] = (unsigned char)v; + p[1] = (unsigned char)(v >> 8); + } + else + { + p[0] = (unsigned char)(v >> 8); + p[1] = (unsigned char)v; + } +} + +void +cpu_melf_put32( unsigned char *p, __mpu_uint32_t v, int data ) +{ + unsigned i; + + if( is_le( data ) ) + for( i = 0; i < 4; ++i ) + p[i] = (unsigned char)(v >> (8 * i)); + else + for( i = 0; i < 4; ++i ) + p[i] = (unsigned char)(v >> (8 * (3 - i))); +} + +void +cpu_melf_put64( unsigned char *p, __mpu_uint64_t v, int data ) +{ + unsigned i; + + if( is_le( data ) ) + for( i = 0; i < 8; ++i ) + p[i] = (unsigned char)(v >> (8 * i)); + else + for( i = 0; i < 8; ++i ) + p[i] = (unsigned char)(v >> (8 * (7 - i))); +} + +__mpu_uint16_t +cpu_melf_get16( const unsigned char *p, int data ) +{ + if( is_le( data ) ) + return (__mpu_uint16_t)(p[0] | ((__mpu_uint16_t)p[1] << 8)); + return (__mpu_uint16_t)(((__mpu_uint16_t)p[0] << 8) | p[1]); +} + +__mpu_uint32_t +cpu_melf_get32( const unsigned char *p, int data ) +{ + __mpu_uint32_t v = 0; + unsigned i; + + if( is_le( data ) ) + for( i = 0; i < 4; ++i ) + v |= (__mpu_uint32_t)p[i] << (8 * i); + else + for( i = 0; i < 4; ++i ) + v = (v << 8) | p[i]; + return( v ); +} + +__mpu_uint64_t +cpu_melf_get64( const unsigned char *p, int data ) +{ + __mpu_uint64_t v = 0; + unsigned i; + + if( is_le( data ) ) + for( i = 0; i < 8; ++i ) + v |= (__mpu_uint64_t)p[i] << (8 * i); + else + for( i = 0; i < 8; ++i ) + v = (v << 8) | p[i]; + return( v ); +} + +int +cpu_melf_span( size_t n, __mpu_uint64_t off, __mpu_uint64_t len ) +{ + return( off <= (__mpu_uint64_t)n && len <= (__mpu_uint64_t)n - off ); +} + +int +cpu_melf_is_pow2( __mpu_uint64_t v ) +{ + return( v != 0 && ( v & ( v - 1 ) ) == 0 ); +} + +__mpu_uint64_t +cpu_melf_align_up( __mpu_uint64_t v, __mpu_uint64_t a, int *ov ) +{ + __mpu_uint64_t r; + + if( ov ) + *ov = 0; + if( a <= 1 ) + return( v ); + if( !cpu_melf_is_pow2( a ) ) + { + if( ov ) + *ov = 1; + return( 0 ); + } + + r = v & (a - 1); + if( !r ) + return( v ); + if( v > UINT64_MAX - ( a - r ) ) + { + if( ov ) + *ov = 1; + return( 0 ); + } + return( v + ( a - r ) ); +} + +int +cpu_melf_readall( const char *path, unsigned char **pp, size_t *pn, + char *err, size_t es) +{ + FILE *f; + long z; + unsigned char *p; + + if( !path || !pp || !pn ) + return( -1 ); + + f = fopen( path, "rb" ); + if( !f ) + { + snprintf( err, es, "%s: %s", path, strerror( errno ) ); + return( -1 ); + } + if( fseek( f, 0, SEEK_END ) || ( z = ftell( f ) ) < 0 || fseek( f, 0, SEEK_SET ) ) + { + snprintf( err, es, "cannot size %s", path ); + fclose( f ); + return( -1 ); + } + + p = (unsigned char *)malloc( z ? (size_t)z : 1 ); + if( !p ) + { + snprintf( err, es, "out of memory" ); + fclose( f ); + return( -1 ); + } + if( z && fread( p, 1, (size_t)z, f ) != (size_t)z ) + { + snprintf( err, es, "cannot read %s", path ); + free( p ); + fclose( f ); + return( -1 ); + } + if( fclose( f ) ) + { + snprintf( err, es, "cannot close %s", path ); + free( p ); + return( -1 ); + } + + *pp = p; + *pn = (size_t)z; + return( 0 ); +} + +int +cpu_melf_writeall( const char *path, const void *data, size_t n, + char *err, size_t es) +{ + FILE *f = fopen( path, "wb" ); + + if( !f ) + { + snprintf( err, es, "%s: %s", path, strerror( errno ) ); + return( -1 ); + } + if( n && fwrite( data, 1, n, f ) != n ) + { + snprintf( err, es, "cannot write %s", path ); + fclose( f ); + return( -1 ); + } + if( fclose( f ) ) + { + snprintf( err, es, "cannot close %s", path ); + return( -1 ); + } + return( 0 ); +} + +void +cpu_melf_fill_target( MElf_McpuTarget *t ) +{ + memset( t, 0, sizeof( *t ) ); + t->mt_version = MELF_MCPU_TARGET_VERSION_CURRENT; + t->mt_size = MELF_MCPU_TARGET_SIZE; + t->mt_isa_revision = MELF_MCPU_ISA_REVISION_CURRENT; + t->mt_abi_revision = MELF_MCPU_ABI_REVISION_CURRENT; + t->mt_program_model = MELF_MCPU_MODEL_NONE; + t->mt_data_byte_order = (__mpu_uint32_t)cpu_melf_data_encoding(); +#if CPU_DATA_WORD_ORDER_LITTLE_ENDIAN == 1 + t->mt_data_word_order = MELF_MCPU_WORD_ORDER_LSB; +#elif CPU_DATA_WORD_ORDER_BIG_ENDIAN == 1 + t->mt_data_word_order = MELF_MCPU_WORD_ORDER_MSB; +#else +# error "Unsupported CPU_DATA_WORD_ORDER" +#endif + t->mt_integer_model = MELF_MCPU_INTEGER_MODEL_TWOS_COMPLEMENT; + t->mt_address_model = MELF_MCPU_ADDRESS_MODEL_PTR64_SEG4_OFF60; + t->mt_register_model = MELF_MCPU_REGISTER_MODEL_REG24_512K; + t->mt_real_model = MELF_MCPU_REAL_MODEL_LIBMPU; + t->mt_complex_model = MELF_MCPU_COMPLEX_MODEL_LIBMPU; + t->mt_max_align = MELF_MCPU_ABI_MAX_ALIGN; + t->mt_flags = MELF_MCPU_TARGET_FLAGS_NONE; + t->mt_required_features = MELF_MCPU_REQUIRED_FEATURES_NONE; +} + +void +cpu_melf_encode_target( unsigned char out[MELF_MCPU_TARGET_SIZE], + const MElf_McpuTarget *t, int data) +{ + memset( out, 0, MELF_MCPU_TARGET_SIZE ); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_VERSION_OFF, t->mt_version, data ); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_SIZE_OFF, t->mt_size, data ); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_ISA_REVISION_OFF, + t->mt_isa_revision, data); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_ABI_REVISION_OFF, + t->mt_abi_revision, data); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_PROGRAM_MODEL_OFF, + t->mt_program_model, data); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_DATA_BYTE_ORDER_OFF, + t->mt_data_byte_order, data); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_DATA_WORD_ORDER_OFF, + t->mt_data_word_order, data); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_INTEGER_MODEL_OFF, + t->mt_integer_model, data); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_ADDRESS_MODEL_OFF, + t->mt_address_model, data); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_REGISTER_MODEL_OFF, + t->mt_register_model, data); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_REAL_MODEL_OFF, + t->mt_real_model, data); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_COMPLEX_MODEL_OFF, + t->mt_complex_model, data); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_MAX_ALIGN_OFF, + t->mt_max_align, data); + cpu_melf_put32( out + MELF_MCPU_TARGET_MT_FLAGS_OFF, + t->mt_flags, data); + cpu_melf_put64( out + MELF_MCPU_TARGET_MT_REQUIRED_FEATURES_OFF, + t->mt_required_features, data); +} + +int +cpu_melf_decode_target( const unsigned char in[MELF_MCPU_TARGET_SIZE], + MElf_McpuTarget *t, int data) +{ + if( data != MELF_DATA_LSB && data != MELF_DATA_MSB ) + return( -1 ); + + memset( t, 0, sizeof( *t ) ); + t->mt_version = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_VERSION_OFF, data ); + t->mt_size = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_SIZE_OFF, data ); + t->mt_isa_revision = cpu_melf_get32( + in + MELF_MCPU_TARGET_MT_ISA_REVISION_OFF, data); + t->mt_abi_revision = cpu_melf_get32( + in + MELF_MCPU_TARGET_MT_ABI_REVISION_OFF, data); + t->mt_program_model = cpu_melf_get32( + in + MELF_MCPU_TARGET_MT_PROGRAM_MODEL_OFF, data); + t->mt_data_byte_order = cpu_melf_get32( + in + MELF_MCPU_TARGET_MT_DATA_BYTE_ORDER_OFF, data); + t->mt_data_word_order = cpu_melf_get32( + in + MELF_MCPU_TARGET_MT_DATA_WORD_ORDER_OFF, data); + t->mt_integer_model = cpu_melf_get32( + in + MELF_MCPU_TARGET_MT_INTEGER_MODEL_OFF, data); + t->mt_address_model = cpu_melf_get32( + in + MELF_MCPU_TARGET_MT_ADDRESS_MODEL_OFF, data); + t->mt_register_model = cpu_melf_get32( + in + MELF_MCPU_TARGET_MT_REGISTER_MODEL_OFF, data); + t->mt_real_model = cpu_melf_get32( + in + MELF_MCPU_TARGET_MT_REAL_MODEL_OFF, data); + t->mt_complex_model = cpu_melf_get32( + in + MELF_MCPU_TARGET_MT_COMPLEX_MODEL_OFF, data); + t->mt_max_align = cpu_melf_get32( + in + MELF_MCPU_TARGET_MT_MAX_ALIGN_OFF, data); + t->mt_flags = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_FLAGS_OFF, data ); + t->mt_required_features = cpu_melf_get64( + in + MELF_MCPU_TARGET_MT_REQUIRED_FEATURES_OFF, data); + return( 0 ); +} + +int +cpu_melf_validate_target( const MElf_McpuTarget *t, int data, + char *err, size_t es) +{ + MElf_McpuTarget x; + + cpu_melf_fill_target( &x ); +#define EQ(FIELD) \ + do { \ + if(t->FIELD != x.FIELD) { \ + snprintf(err, es, "incompatible MCPU target profile field %s", #FIELD); \ + return -1; \ + } \ + } while(0) + + EQ( mt_version ); + if( t->mt_size != MELF_MCPU_TARGET_SIZE ) + { + snprintf( err, es, "bad .mcpu.target record size" ); + return( -1 ); + } + + EQ( mt_isa_revision ); + EQ( mt_abi_revision ); + EQ( mt_program_model ); + EQ( mt_data_byte_order ); + EQ( mt_data_word_order ); + EQ( mt_integer_model ); + EQ( mt_address_model ); + EQ( mt_register_model ); + EQ( mt_real_model ); + EQ( mt_complex_model ); + EQ( mt_max_align ); + EQ( mt_flags ); + EQ( mt_required_features ); +#undef EQ + + if( (int)t->mt_data_byte_order != data ) + { + snprintf( err, es, "MCPU target byte order disagrees with EI_DATA" ); + return( -1 ); + } + + return( 0 ); +} + +void +cpu_melf_fill_lifecycle( MElf_McpuLifecycle *l ) +{ + memset( l, 0, sizeof( *l ) ); + l->ml_version = MELF_MCPU_LIFECYCLE_VERSION_CURRENT; + l->ml_size = MELF_MCPU_LIFECYCLE_SIZE; + l->ml_abi = MELF_MCPU_LIFECYCLE_ABI_CURRENT; + l->ml_flags = MELF_MCPU_LIFECYCLE_ABI1_FLAGS; +} + +void +cpu_melf_encode_lifecycle( unsigned char out[MELF_MCPU_LIFECYCLE_SIZE], + const MElf_McpuLifecycle *l, int data) +{ + memset( out, 0, MELF_MCPU_LIFECYCLE_SIZE ); + cpu_melf_put32( out + MELF_MCPU_LIFECYCLE_ML_VERSION_OFF, + l->ml_version, data); + cpu_melf_put32( out + MELF_MCPU_LIFECYCLE_ML_SIZE_OFF, + l->ml_size, data); + cpu_melf_put32( out + MELF_MCPU_LIFECYCLE_ML_ABI_OFF, + l->ml_abi, data); + cpu_melf_put32( out + MELF_MCPU_LIFECYCLE_ML_RESERVED0_OFF, + l->ml_reserved0, data); + cpu_melf_put64( out + MELF_MCPU_LIFECYCLE_ML_FLAGS_OFF, + l->ml_flags, data); + cpu_melf_put64( out + MELF_MCPU_LIFECYCLE_ML_RESERVED1_OFF, + l->ml_reserved1, data); +} + +int +cpu_melf_decode_lifecycle( const unsigned char in[MELF_MCPU_LIFECYCLE_SIZE], + MElf_McpuLifecycle *l, int data) +{ + if( data != MELF_DATA_LSB && data != MELF_DATA_MSB ) + return( -1 ); + + memset( l, 0, sizeof( *l ) ); + l->ml_version = cpu_melf_get32( + in + MELF_MCPU_LIFECYCLE_ML_VERSION_OFF, data); + l->ml_size = cpu_melf_get32( + in + MELF_MCPU_LIFECYCLE_ML_SIZE_OFF, data); + l->ml_abi = cpu_melf_get32( + in + MELF_MCPU_LIFECYCLE_ML_ABI_OFF, data); + l->ml_reserved0 = cpu_melf_get32( + in + MELF_MCPU_LIFECYCLE_ML_RESERVED0_OFF, data); + l->ml_flags = cpu_melf_get64( + in + MELF_MCPU_LIFECYCLE_ML_FLAGS_OFF, data); + l->ml_reserved1 = cpu_melf_get64( + in + MELF_MCPU_LIFECYCLE_ML_RESERVED1_OFF, data); + return( 0 ); +} + +int +cpu_melf_validate_lifecycle( const MElf_McpuLifecycle *l, + char *err, size_t es) +{ + if( l->ml_version != MELF_MCPU_LIFECYCLE_VERSION_CURRENT || + l->ml_size != MELF_MCPU_LIFECYCLE_SIZE || + l->ml_abi != MELF_MCPU_LIFECYCLE_ABI_CURRENT || + l->ml_reserved0 != 0 || + l->ml_flags != MELF_MCPU_LIFECYCLE_ABI1_FLAGS || + l->ml_reserved1 != 0) + { + snprintf( err, es, "unsupported or malformed .mcpu.lifecycle record" ); + return( -1 ); + } + return( 0 ); +} |
