/*
 * File:	DataSource.h
 *
 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
 *
 * Freescale Semiconductor, Inc.
 * Proprietary & Confidential
 *
 * This source code and the algorithms implemented therein constitute
 * confidential information and may comprise trade secrets of Freescale Semiconductor, Inc.
 * or its associates, and any use thereof is subject to the terms and
 * conditions of the Confidential Disclosure Agreement pursual to which this
 * source code was originally received.
 */
#if !defined(_IVTDataSource_h_)
#define _IVTDataSource_h_

#include "DataSource.h"

/** Header field components
 * @ingroup hdr
 */
typedef struct hab_hdr {
    uint8_t tag;              /**< Tag field */
    uint8_t len[2];           /**< Length field in bytes (big-endian) */
    uint8_t par;              /**< Parameters field */
} hab_hdr_t;

/** Image entry function prototype
 *  @ingroup rvt
 *
 * This typedef serves as the return type for hab_rvt.authenticate_image().  It
 * specifies a void-void function pointer, but can be cast to another function
 * pointer type if required.
 */
typedef void (*hab_image_entry_f)(void);

/** @ref ivt structure
 * @ingroup ivt
 *
 * @par Format
 *
 * An @ref ivt consists of a @ref hdr followed by a list of addresses as
 * described further below.
 *
 * @warning The @a entry address may not be NULL.
 *
 * @warning On an IC not configured as #HAB_CFG_CLOSED, the
 * @a csf address may be NULL.  If it is not NULL, the @ref csf will be
 * processed, but any failures should be non-fatal.
 *
 * @warning On an IC configured as #HAB_CFG_CLOSED, the @a
 * csf address may not be NULL, and @ref csf failures are typically fatal.
 *
 * @remark The Boot Data located using the @a boot_data field is interpreted
 * by the HAB caller in a boot-mode specific manner.  This may be used by the
 * boot ROM as to determine the load address and boot device configuration for
 * images loaded from block devices (see @ref ref_rug for details).
 *
 * @remark All addresses given in the IVT, including the Boot Data (if
 * present) are those for the final load location. 
 *
 * @anchor ila
 *
 * @par Initial load addresses
 *
 * The @a self field is used to calculate addresses in boot modes where an
 * initial portion of the image is loaded to an initial location.  In such
 * cases, the IVT, Boot Data (if present) and DCD (if present) are used in
 * configuring the IC and loading the full image to its final location.  Only
 * the IVT, Boot Data (if present) and DCD (if present) are required to be
 * within the initial image portion.
 *
 * The method for calculating an initial load address for the DCD is
 * illustrated in the following C fragment.  Similar calculations apply to
 * other fields.
 *
@verbatim
        hab_ivt_t* ivt_initial = <initial IVT load address>;
        const void* dcd_initial = ivt_initial->dcd;
        if (ivt_initial->dcd != NULL)
            dcd_initial = (const uint8_t*)ivt_initial 
                          + (ivt_initial->dcd - ivt_initial->self)
@endverbatim

 * \note The void* types in this structure have been changed to uint32_t so
 *      that this code will work correctly when compiled on a 64-bit host.
 *      Otherwise the structure would come out incorrect.
 */
struct hab_ivt {
    /** @ref hdr with tag #HAB_TAG_IVT, length and HAB version fields
     *  (see @ref data)
     */
    hab_hdr_t hdr;
    /** Absolute address of the first instruction to execute from the
     *  image
     */
    /*hab_image_entry_f*/ uint32_t entry;
    /** Reserved in this version of HAB: should be NULL. */
    /*const void*/ uint32_t reserved1;
    /** Absolute address of the image DCD: may be NULL. */
    /*const void*/ uint32_t dcd;
    /** Absolute address of the Boot Data: may be NULL, but not interpreted
     *  any further by HAB
     */
    /*const void*/ uint32_t boot_data;
    /** Absolute address of the IVT.*/
    /*const void*/ uint32_t self;
    /** Absolute address of the image CSF.*/
    /*const void*/ uint32_t csf;
    /** Reserved in this version of HAB: should be zero. */
    uint32_t reserved2;
};

/** @ref ivt type
 * @ingroup ivt
 */
typedef struct hab_ivt hab_ivt_t;

/*
 *    Helper macros
 */
#define HAB_CMD_UNS     0xff

#define DEFAULT_IMG_KEY_IDX     2

#define GEN_MASK(width)                         \
    ((1UL << (width)) - 1)

#define GEN_FIELD(f, width, shift)              \
    (((f) & GEN_MASK(width)) << (shift))

#define PACK_UINT32(a, b, c, d)                 \
    ( (((a) & 0xFF) << 24)                      \
      |(((b) & 0xFF) << 16)                     \
      |(((c) & 0xFF) << 8)                      \
      |(((d) & 0xFF)) )

#define EXPAND_UINT32(w)                                                \
    (uint8_t)((w)>>24), (uint8_t)((w)>>16), (uint8_t)((w)>>8), (uint8_t)(w)

#define HDR(tag, bytes, par)                                            \
    (uint8_t)(tag), (uint8_t)((bytes)>>8), (uint8_t)(bytes), (uint8_t)(par)

#define HAB_VER(maj, min)                                       \
    (GEN_FIELD((maj), HAB_VER_MAJ_WIDTH, HAB_VER_MAJ_SHIFT)     \
     | GEN_FIELD((min), HAB_VER_MIN_WIDTH, HAB_VER_MIN_SHIFT))

/*
 *    CSF header
 */

#define CSF_HDR(bytes, HABVER)                  \
    HDR(HAB_TAG_CSF, (bytes), HABVER)
    
    
/*
 *    DCD  header
 */

#define DCD_HDR(bytes, HABVER)                  \
    HDR(HAB_TAG_DCD, (bytes), HABVER)

/*
 *   IVT  header (goes in the struct's hab_hdr_t field, not a byte array)
 */
#define IVT_HDR(bytes, HABVER)                  \
    {HAB_TAG_IVT, {(uint8_t)((bytes)>>8), (uint8_t)(bytes)}, HABVER}

/** @name External data structure tags
 * @anchor dat_tag
 *
 * Tag values 0x00 .. 0xef are reserved for HAB.  Values 0xf0 .. 0xff
 * are available for custom use.
 */
/*@{*/
#define HAB_TAG_IVT  0xd1       /**< Image Vector Table */
#define HAB_TAG_DCD  0xd2       /**< Device Configuration Data */
#define HAB_TAG_CSF  0xd4       /**< Command Sequence File */
#define HAB_TAG_CRT  0xd7       /**< Certificate */
#define HAB_TAG_SIG  0xd8       /**< Signature */
#define HAB_TAG_EVT  0xdb       /**< Event */
#define HAB_TAG_RVT  0xdd       /**< ROM Vector Table */
/* Values b0 ... cf reserved for CSF commands.  Values e0 ... ef reserved for
 * key types.
 *
 * Available values: 03, 05, 06, 09, 0a, 0c, 0f, 11, 12, 14, 17, 18, 1b, 1d,
 * 1e, 21, 22, 24, 27, 28, 2b, 2d, 2e, 30, 33, 35, 36, 39, 3a, 3c, 3f, 41, 42,
 * 44, 47, 48, 4b, 4d, 4e, 50, 53, 55, 56, 59, 5a, 5c, 5f, 60, 63, 65, 66, 69,
 * 6a, 6c, 6f, 71, 72, 74, 77, 78, 7b, 7d, 7e, 81, 82, 84, 87, 88, 8b, 8d, 8e,
 * 90, 93, 95, 96, 99, 9a, 9c, 9f, a0, a3, a5, a6, a9, aa, ac, af, b1, b2, b4,
 * b7, b8, bb, bd, be
 *
 * Custom values: f0, f3, f5, f6, f9, fa, fc, ff
 */
/*@}*/

/** @name HAB version */
/*@{*/
#define HAB_MAJOR_VERSION  4    /**< Major version of this HAB release */
#define HAB_MINOR_VERSION  0    /**< Minor version of this HAB release */
#define HAB_VER_MAJ_WIDTH 4     /**< Major version field width  */
#define HAB_VER_MAJ_SHIFT 4     /**< Major version field offset  */
#define HAB_VER_MIN_WIDTH 4     /**< Minor version field width  */
#define HAB_VER_MIN_SHIFT 0     /**< Minor version field offset  */
/** Full version of this HAB release @hideinitializer */
#define HAB_VERSION HAB_VER(HAB_MAJOR_VERSION, HAB_MINOR_VERSION) 
/** Base version for this HAB release @hideinitializer */
#define HAB_BASE_VERSION HAB_VER(HAB_MAJOR_VERSION, 0) 

/*@}*/

namespace elftosb {

/*!
 * \brief Data source for an IVT structure used by HAB4.
 *
 * This data source represents an IVT structure used by HAB4. Fields of the IVT can be set
 * by name, making it easy to interface with a parser. And it has some intelligence regarding
 * the IVT's self pointer. Before the data is copied out by the getData() method, the self field
 * will be filled in automatically if it has not already been set and there is an associated
 * data target object. This lets the IVT pick up its own address from the location where it is
 * being loaded. Alternatively, if the self pointer is filled in explicitly, then the data
 * source will have a natural location equal to the self pointer.
 *
 * This data source acts as its own segment.
 */
class IVTDataSource : public DataSource, public DataSource::Segment
{
public:
    //! \brief Default constructor.
    IVTDataSource();
    
	//! \brief There is only one segment.
	virtual unsigned getSegmentCount() { return 1; }
	
	//! \brief Returns this object, as it is its own segment.
	virtual DataSource::Segment * getSegmentAt(unsigned index) { return this; }

    //! \name Segment methods
    //@{
    
    //! \brief Copy out some or all of the IVT structure.
    //!
    virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t * buffer);
    
    //! \brief Gets the length of the segment's data.
    virtual unsigned getLength();
    
    //! \brief Returns whether the segment has an associated address.
    virtual bool hasNaturalLocation();
    
    //! \brief Returns the address associated with the segment.
    virtual uint32_t getBaseAddress();
    
    //@}
    
    //! \name IVT access
    //@{
    
    //! \brief Set one of the IVT's fields by providing its name.
    //!
    //! Acceptable field names are:
    //! - entry
    //! - dcd
    //! - boot_data
    //! - self
    //! - csf
    //!
    //! As long as the \a name parameter specifies one of these fields, the return value
    //! will be true. If \a name contains any other value, then false will be returned and
    //! the IVT left unmodified.
    //!
    //! Once the \a self field has been set to any value, the data source will have a
    //! natural location. This works even if the \a self address is 0.
    //!
    //! \param name The name of the field to set. Field names are case sensitive, just like in
    //!     the C language.
    //! \param value The value to which the field will be set.
    //! \retval true The field was set successfully.
    //! \retval false There is no field with the provided name.
    bool setFieldByName(const std::string & name, uint32_t value);
    
    //! \brief Returns a reference to the IVT structure.
    hab_ivt_t & getIVT() { return m_ivt; }
    
    //@}

protected:
    hab_ivt_t m_ivt;  //!< The IVT structure.
    bool m_isSelfSet; //!< True if the IVT self pointer was explicitly set.
};

} // elftosb

#endif // _IVTDataSource_h_